--- /dev/null
+#------------------------------------------------------------------------------
+# compile the AMD demo (for both GNU make or original make)
+#-----------------------------------------------------------------------------
+
+all: amd_simple amd_demo amd_demo2
+
+include ../Make/Make.include
+
+C = $(CC) $(CFLAGS) $(CONFIG) -I../Include
+
+INC = ../Include/amd.h
+
+../Lib/libamd.a:
+ ( cd ../Source ; make )
+
+../Lib/libamdf77.a:
+ ( cd ../Source ; make fortran )
+
+#------------------------------------------------------------------------------
+# Create the demo program, run it, and compare the output
+#------------------------------------------------------------------------------
+
+dist:
+
+amd_demo: amd_demo.c ../Lib/libamd.a $(INC)
+ $(C) -DDINT -o amd_demo amd_demo.c ../Lib/libamd.a $(LIB)
+ ./amd_demo > my_amd_demo.out
+ - diff amd_demo.out my_amd_demo.out
+
+amd_demo2: amd_demo2.c ../Lib/libamd.a $(INC)
+ $(C) -DDINT -o amd_demo2 amd_demo2.c ../Lib/libamd.a $(LIB)
+ ./amd_demo2 > my_amd_demo2.out
+ - diff amd_demo2.out my_amd_demo2.out
+
+amd_simple: amd_simple.c ../Lib/libamd.a $(INC)
+ $(C) -DDINT -o amd_simple amd_simple.c ../Lib/libamd.a $(LIB)
+ ./amd_simple > my_amd_simple.out
+ - diff amd_simple.out my_amd_simple.out
+
+#------------------------------------------------------------------------------
+# compile the Fortran demo
+#------------------------------------------------------------------------------
+
+fortran: amd_f77demo amd_f77simple
+
+cross: amd_f77cross
+
+amd_f77demo: amd_f77demo.f ../Lib/libamdf77.a
+ $(F77) $(F77FLAGS) -o amd_f77demo amd_f77demo.f ../Lib/libamdf77.a \
+ $(F77LIB)
+ ./amd_f77demo > my_amd_f77demo.out
+ - diff amd_f77demo.out my_amd_f77demo.out
+
+amd_f77simple: amd_f77simple.f ../Lib/libamdf77.a
+ $(F77) $(F77FLAGS) -o amd_f77simple amd_f77simple.f \
+ ../Lib/libamdf77.a $(F77LIB)
+ ./amd_f77simple > my_amd_f77simple.out
+ - diff amd_f77simple.out my_amd_f77simple.out
+
+amd_f77wrapper.o: amd_f77wrapper.c
+ $(C) -DDINT -c amd_f77wrapper.c
+
+amd_f77cross: amd_f77cross.f amd_f77wrapper.o ../Lib/libamd.a
+ $(F77) $(F77FLAGS) -o amd_f77cross amd_f77cross.f amd_f77wrapper.o \
+ ../Lib/libamd.a $(F77LIB)
+ ./amd_f77cross > my_amd_f77cross.out
+ - diff amd_f77cross.out my_amd_f77cross.out
+
+#------------------------------------------------------------------------------
+# Remove all but the files in the original distribution
+#------------------------------------------------------------------------------
+
+purge: clean
+ - $(RM) amd_demo my_amd_demo.out
+ - $(RM) amd_demo2 my_amd_demo2.out
+ - $(RM) amd_simple my_amd_simple.out
+ - $(RM) amd_f77demo my_amd_f77demo.out
+ - $(RM) amd_f77simple my_amd_f77simple.out
+ - $(RM) amd_f77cross my_amd_f77cross.out
--- /dev/null
+/* ========================================================================= */
+/* === AMD demo main program =============================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* A simple C main program that illustrates the use of the ANSI C interface
+ * to AMD.
+ */
+
+#include "amd.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+int main (int argc, char **argv)
+{
+ /* The symmetric can_24 Harwell/Boeing matrix, including upper and lower
+ * triangular parts, and the diagonal entries. Note that this matrix is
+ * 0-based, with row and column indices in the range 0 to n-1. */
+ int n = 24, nz,
+ Ap [ ] = { 0, 9, 15, 21, 27, 33, 39, 48, 57, 61, 70, 76, 82, 88, 94, 100,
+ 106, 110, 119, 128, 137, 143, 152, 156, 160 },
+ Ai [ ] = {
+ /* column 0: */ 0, 5, 6, 12, 13, 17, 18, 19, 21,
+ /* column 1: */ 1, 8, 9, 13, 14, 17,
+ /* column 2: */ 2, 6, 11, 20, 21, 22,
+ /* column 3: */ 3, 7, 10, 15, 18, 19,
+ /* column 4: */ 4, 7, 9, 14, 15, 16,
+ /* column 5: */ 0, 5, 6, 12, 13, 17,
+ /* column 6: */ 0, 2, 5, 6, 11, 12, 19, 21, 23,
+ /* column 7: */ 3, 4, 7, 9, 14, 15, 16, 17, 18,
+ /* column 8: */ 1, 8, 9, 14,
+ /* column 9: */ 1, 4, 7, 8, 9, 13, 14, 17, 18,
+ /* column 10: */ 3, 10, 18, 19, 20, 21,
+ /* column 11: */ 2, 6, 11, 12, 21, 23,
+ /* column 12: */ 0, 5, 6, 11, 12, 23,
+ /* column 13: */ 0, 1, 5, 9, 13, 17,
+ /* column 14: */ 1, 4, 7, 8, 9, 14,
+ /* column 15: */ 3, 4, 7, 15, 16, 18,
+ /* column 16: */ 4, 7, 15, 16,
+ /* column 17: */ 0, 1, 5, 7, 9, 13, 17, 18, 19,
+ /* column 18: */ 0, 3, 7, 9, 10, 15, 17, 18, 19,
+ /* column 19: */ 0, 3, 6, 10, 17, 18, 19, 20, 21,
+ /* column 20: */ 2, 10, 19, 20, 21, 22,
+ /* column 21: */ 0, 2, 6, 10, 11, 19, 20, 21, 22,
+ /* column 22: */ 2, 20, 21, 22,
+ /* column 23: */ 6, 11, 12, 23 } ;
+
+ int P [24], Pinv [24], i, j, k, jnew, p, inew, result ;
+ double Control [AMD_CONTROL], Info [AMD_INFO] ;
+ char A [24][24] ;
+
+ printf ("AMD demo, with the 24-by-24 Harwell/Boeing matrix, can_24:\n") ;
+
+ /* get the default parameters, and print them */
+ amd_defaults (Control) ;
+ amd_control (Control) ;
+
+ /* print the input matrix */
+ nz = Ap [n] ;
+ printf ("\nInput matrix: %d-by-%d, with %d entries.\n"
+ " Note that for a symmetric matrix such as this one, only the\n"
+ " strictly lower or upper triangular parts would need to be\n"
+ " passed to AMD, since AMD computes the ordering of A+A'. The\n"
+ " diagonal entries are also not needed, since AMD ignores them.\n"
+ , n, n, nz) ;
+ for (j = 0 ; j < n ; j++)
+ {
+ printf ("\nColumn: %d, number of entries: %d, with row indices in"
+ " Ai [%d ... %d]:\n row indices:",
+ j, Ap [j+1] - Ap [j], Ap [j], Ap [j+1]-1) ;
+ for (p = Ap [j] ; p < Ap [j+1] ; p++)
+ {
+ i = Ai [p] ;
+ printf (" %d", i) ;
+ }
+ printf ("\n") ;
+ }
+
+ /* print a character plot of the input matrix. This is only reasonable
+ * because the matrix is small. */
+ printf ("\nPlot of input matrix pattern:\n") ;
+ for (j = 0 ; j < n ; j++)
+ {
+ for (i = 0 ; i < n ; i++) A [i][j] = '.' ;
+ for (p = Ap [j] ; p < Ap [j+1] ; p++)
+ {
+ i = Ai [p] ;
+ A [i][j] = 'X' ;
+ }
+ }
+ printf (" ") ;
+ for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ;
+ printf ("\n") ;
+ for (i = 0 ; i < n ; i++)
+ {
+ printf ("%2d: ", i) ;
+ for (j = 0 ; j < n ; j++)
+ {
+ printf (" %c", A [i][j]) ;
+ }
+ printf ("\n") ;
+ }
+
+ /* order the matrix */
+ result = amd_order (n, Ap, Ai, P, Control, Info) ;
+ printf ("return value from amd_order: %d (should be %d)\n",
+ result, AMD_OK) ;
+
+ /* print the statistics */
+ amd_info (Info) ;
+
+ if (result != AMD_OK)
+ {
+ printf ("AMD failed\n") ;
+ exit (1) ;
+ }
+
+ /* print the permutation vector, P, and compute the inverse permutation */
+ printf ("Permutation vector:\n") ;
+ for (k = 0 ; k < n ; k++)
+ {
+ /* row/column j is the kth row/column in the permuted matrix */
+ j = P [k] ;
+ Pinv [j] = k ;
+ printf (" %2d", j) ;
+ }
+ printf ("\n\n") ;
+
+ printf ("Inverse permutation vector:\n") ;
+ for (j = 0 ; j < n ; j++)
+ {
+ k = Pinv [j] ;
+ printf (" %2d", k) ;
+ }
+ printf ("\n\n") ;
+
+ /* print a character plot of the permuted matrix. */
+ printf ("\nPlot of permuted matrix pattern:\n") ;
+ for (jnew = 0 ; jnew < n ; jnew++)
+ {
+ j = P [jnew] ;
+ for (inew = 0 ; inew < n ; inew++) A [inew][jnew] = '.' ;
+ for (p = Ap [j] ; p < Ap [j+1] ; p++)
+ {
+ inew = Pinv [Ai [p]] ;
+ A [inew][jnew] = 'X' ;
+ }
+ }
+ printf (" ") ;
+ for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ;
+ printf ("\n") ;
+ for (i = 0 ; i < n ; i++)
+ {
+ printf ("%2d: ", i) ;
+ for (j = 0 ; j < n ; j++)
+ {
+ printf (" %c", A [i][j]) ;
+ }
+ printf ("\n") ;
+ }
+
+ return (0) ;
+}
--- /dev/null
+AMD demo, with the 24-by-24 Harwell/Boeing matrix, can_24:
+
+amd: approximate minimum degree ordering, parameters:
+ dense row parameter: 10
+ (rows with more than max (10 * sqrt (n), 16) entries are
+ considered "dense", and placed last in output permutation)
+ aggressive absorption: yes
+
+
+Input matrix: 24-by-24, with 160 entries.
+ Note that for a symmetric matrix such as this one, only the
+ strictly lower or upper triangular parts would need to be
+ passed to AMD, since AMD computes the ordering of A+A'. The
+ diagonal entries are also not needed, since AMD ignores them.
+
+Column: 0, number of entries: 9, with row indices in Ai [0 ... 8]:
+ row indices: 0 5 6 12 13 17 18 19 21
+
+Column: 1, number of entries: 6, with row indices in Ai [9 ... 14]:
+ row indices: 1 8 9 13 14 17
+
+Column: 2, number of entries: 6, with row indices in Ai [15 ... 20]:
+ row indices: 2 6 11 20 21 22
+
+Column: 3, number of entries: 6, with row indices in Ai [21 ... 26]:
+ row indices: 3 7 10 15 18 19
+
+Column: 4, number of entries: 6, with row indices in Ai [27 ... 32]:
+ row indices: 4 7 9 14 15 16
+
+Column: 5, number of entries: 6, with row indices in Ai [33 ... 38]:
+ row indices: 0 5 6 12 13 17
+
+Column: 6, number of entries: 9, with row indices in Ai [39 ... 47]:
+ row indices: 0 2 5 6 11 12 19 21 23
+
+Column: 7, number of entries: 9, with row indices in Ai [48 ... 56]:
+ row indices: 3 4 7 9 14 15 16 17 18
+
+Column: 8, number of entries: 4, with row indices in Ai [57 ... 60]:
+ row indices: 1 8 9 14
+
+Column: 9, number of entries: 9, with row indices in Ai [61 ... 69]:
+ row indices: 1 4 7 8 9 13 14 17 18
+
+Column: 10, number of entries: 6, with row indices in Ai [70 ... 75]:
+ row indices: 3 10 18 19 20 21
+
+Column: 11, number of entries: 6, with row indices in Ai [76 ... 81]:
+ row indices: 2 6 11 12 21 23
+
+Column: 12, number of entries: 6, with row indices in Ai [82 ... 87]:
+ row indices: 0 5 6 11 12 23
+
+Column: 13, number of entries: 6, with row indices in Ai [88 ... 93]:
+ row indices: 0 1 5 9 13 17
+
+Column: 14, number of entries: 6, with row indices in Ai [94 ... 99]:
+ row indices: 1 4 7 8 9 14
+
+Column: 15, number of entries: 6, with row indices in Ai [100 ... 105]:
+ row indices: 3 4 7 15 16 18
+
+Column: 16, number of entries: 4, with row indices in Ai [106 ... 109]:
+ row indices: 4 7 15 16
+
+Column: 17, number of entries: 9, with row indices in Ai [110 ... 118]:
+ row indices: 0 1 5 7 9 13 17 18 19
+
+Column: 18, number of entries: 9, with row indices in Ai [119 ... 127]:
+ row indices: 0 3 7 9 10 15 17 18 19
+
+Column: 19, number of entries: 9, with row indices in Ai [128 ... 136]:
+ row indices: 0 3 6 10 17 18 19 20 21
+
+Column: 20, number of entries: 6, with row indices in Ai [137 ... 142]:
+ row indices: 2 10 19 20 21 22
+
+Column: 21, number of entries: 9, with row indices in Ai [143 ... 151]:
+ row indices: 0 2 6 10 11 19 20 21 22
+
+Column: 22, number of entries: 4, with row indices in Ai [152 ... 155]:
+ row indices: 2 20 21 22
+
+Column: 23, number of entries: 4, with row indices in Ai [156 ... 159]:
+ row indices: 6 11 12 23
+
+Plot of input matrix pattern:
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+ 0: X . . . . X X . . . . . X X . . . X X X . X . .
+ 1: . X . . . . . . X X . . . X X . . X . . . . . .
+ 2: . . X . . . X . . . . X . . . . . . . . X X X .
+ 3: . . . X . . . X . . X . . . . X . . X X . . . .
+ 4: . . . . X . . X . X . . . . X X X . . . . . . .
+ 5: X . . . . X X . . . . . X X . . . X . . . . . .
+ 6: X . X . . X X . . . . X X . . . . . . X . X . X
+ 7: . . . X X . . X . X . . . . X X X X X . . . . .
+ 8: . X . . . . . . X X . . . . X . . . . . . . . .
+ 9: . X . . X . . X X X . . . X X . . X X . . . . .
+10: . . . X . . . . . . X . . . . . . . X X X X . .
+11: . . X . . . X . . . . X X . . . . . . . . X . X
+12: X . . . . X X . . . . X X . . . . . . . . . . X
+13: X X . . . X . . . X . . . X . . . X . . . . . .
+14: . X . . X . . X X X . . . . X . . . . . . . . .
+15: . . . X X . . X . . . . . . . X X . X . . . . .
+16: . . . . X . . X . . . . . . . X X . . . . . . .
+17: X X . . . X . X . X . . . X . . . X X X . . . .
+18: X . . X . . . X . X X . . . . X . X X X . . . .
+19: X . . X . . X . . . X . . . . . . X X X X X . .
+20: . . X . . . . . . . X . . . . . . . . X X X X .
+21: X . X . . . X . . . X X . . . . . . . X X X X .
+22: . . X . . . . . . . . . . . . . . . . . X X X .
+23: . . . . . . X . . . . X X . . . . . . . . . . X
+return value from amd_order: 0 (should be 0)
+
+amd: approximate minimum degree ordering, results:
+ status: OK
+ n, dimension of A: 24
+ nz, number of nonzeros in A: 160
+ symmetry of A: 1.0000
+ number of nonzeros on diagonal: 24
+ nonzeros in pattern of A+A' (excl. diagonal): 136
+ # dense rows/columns of A+A': 0
+ memory used, in bytes: 1516
+ # of memory compactions: 0
+
+ The following approximate statistics are for a subsequent
+ factorization of A(P,P) + A(P,P)'. They are slight upper
+ bounds if there are no dense rows/columns in A+A', and become
+ looser if dense rows/columns exist.
+
+ nonzeros in L (excluding diagonal): 97
+ nonzeros in L (including diagonal): 121
+ # divide operations for LDL' or LU: 97
+ # multiply-subtract operations for LDL': 275
+ # multiply-subtract operations for LU: 453
+ max nz. in any column of L (incl. diagonal): 8
+
+ chol flop count for real A, sqrt counted as 1 flop: 671
+ LDL' flop count for real A: 647
+ LDL' flop count for complex A: 3073
+ LU flop count for real A (with no pivoting): 1003
+ LU flop count for complex A (with no pivoting): 4497
+
+Permutation vector:
+ 22 20 10 23 12 5 16 8 14 4 15 7 1 9 13 17 0 2 3 6 11 18 21 19
+
+Inverse permutation vector:
+ 16 12 17 18 9 5 19 11 7 13 2 20 4 14 8 10 6 15 21 23 1 22 0 3
+
+
+Plot of permuted matrix pattern:
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+ 0: X X . . . . . . . . . . . . . . . X . . . . X .
+ 1: X X X . . . . . . . . . . . . . . X . . . . X X
+ 2: . X X . . . . . . . . . . . . . . . X . . X X X
+ 3: . . . X X . . . . . . . . . . . . . . X X . . .
+ 4: . . . X X X . . . . . . . . . . X . . X X . . .
+ 5: . . . . X X . . . . . . . . X X X . . X . . . .
+ 6: . . . . . . X . . X X X . . . . . . . . . . . .
+ 7: . . . . . . . X X . . . X X . . . . . . . . . .
+ 8: . . . . . . . X X X . X X X . . . . . . . . . .
+ 9: . . . . . . X . X X X X . X . . . . . . . . . .
+10: . . . . . . X . . X X X . . . . . . X . . X . .
+11: . . . . . . X . X X X X . X . X . . X . . X . .
+12: . . . . . . . X X . . . X X X X . . . . . . . .
+13: . . . . . . . X X X . X X X X X . . . . . X . .
+14: . . . . . X . . . . . . X X X X X . . . . . . .
+15: . . . . . X . . . . . X X X X X X . . . . X . X
+16: . . . . X X . . . . . . . . X X X . . X . X X X
+17: X X . . . . . . . . . . . . . . . X . X X . X .
+18: . . X . . . . . . . X X . . . . . . X . . X . X
+19: . . . X X X . . . . . . . . . . X X . X X . X X
+20: . . . X X . . . . . . . . . . . . X . X X . X .
+21: . . X . . . . . . . X X . X . X X . X . . X . X
+22: X X X . . . . . . . . . . . . . X X . X X . X X
+23: . X X . . . . . . . . . . . . X X . X X . X X X
--- /dev/null
+/* ========================================================================= */
+/* === AMD demo main program (jumbled matrix version) ====================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* A simple C main program that illustrates the use of the ANSI C interface
+ * to AMD.
+ *
+ * Identical to amd_demo.c, except that it operates on an input matrix that has
+ * unsorted columns and duplicate entries.
+ */
+
+#include "amd.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+int main (int argc, char **argv)
+{
+ /* The symmetric can_24 Harwell/Boeing matrix (jumbled, and not symmetric).
+ * Since AMD operates on A+A', only A(i,j) or A(j,i) need to be specified,
+ * or both. The diagonal entries are optional (some are missing).
+ * There are many duplicate entries, which must be removed. */
+ int n = 24, nz,
+ Ap [ ] = { 0, 9, 14, 20, 28, 33, 37, 44, 53, 58, 63, 63, 66, 69, 72, 75,
+ 78, 82, 86, 91, 97, 101, 112, 112, 116 },
+ Ai [ ] = {
+ /* column 0: */ 0, 17, 18, 21, 5, 12, 5, 0, 13,
+ /* column 1: */ 14, 1, 8, 13, 17,
+ /* column 2: */ 2, 20, 11, 6, 11, 22,
+ /* column 3: */ 3, 3, 10, 7, 18, 18, 15, 19,
+ /* column 4: */ 7, 9, 15, 14, 16,
+ /* column 5: */ 5, 13, 6, 17,
+ /* column 6: */ 5, 0, 11, 6, 12, 6, 23,
+ /* column 7: */ 3, 4, 9, 7, 14, 16, 15, 17, 18,
+ /* column 8: */ 1, 9, 14, 14, 14,
+ /* column 9: */ 7, 13, 8, 1, 17,
+ /* column 10: */
+ /* column 11: */ 2, 12, 23,
+ /* column 12: */ 5, 11, 12,
+ /* column 13: */ 0, 13, 17,
+ /* column 14: */ 1, 9, 14,
+ /* column 15: */ 3, 15, 16,
+ /* column 16: */ 16, 4, 4, 15,
+ /* column 17: */ 13, 17, 19, 17,
+ /* column 18: */ 15, 17, 19, 9, 10,
+ /* column 19: */ 17, 19, 20, 0, 6, 10,
+ /* column 20: */ 22, 10, 20, 21,
+ /* column 21: */ 6, 2, 10, 19, 20, 11, 21, 22, 22, 22, 22,
+ /* column 22: */
+ /* column 23: */ 12, 11, 12, 23 } ;
+
+ int Rp [25], Ri [116] ;
+ int P [24], Pinv [24], i, j, k, jnew, p, inew, result ;
+ double Control [AMD_CONTROL], Info [AMD_INFO] ;
+ char A [24][24] ;
+
+ printf ("AMD demo, with a jumbled version of the 24-by-24\n") ;
+ printf ("Harwell/Boeing matrix, can_24:\n") ;
+
+ /* get the default parameters, and print them */
+ amd_defaults (Control) ;
+ amd_control (Control) ;
+
+ /* print the input matrix */
+ nz = Ap [n] ;
+ printf ("\nJumbled input matrix: %d-by-%d, with %d entries.\n"
+ " Note that for a symmetric matrix such as this one, only the\n"
+ " strictly lower or upper triangular parts would need to be\n"
+ " passed to AMD, since AMD computes the ordering of A+A'. The\n"
+ " diagonal entries are also not needed, since AMD ignores them.\n"
+ " This version of the matrix has jumbled columns and duplicate\n"
+ " row indices, and must be fixed by amd_preprocess prior to\n"
+ " ordering it with amd_order.\n" , n, n, nz) ;
+ for (j = 0 ; j < n ; j++)
+ {
+ printf ("\nColumn: %d, number of entries: %d, with row indices in"
+ " Ai [%d ... %d]:\n row indices:",
+ j, Ap [j+1] - Ap [j], Ap [j], Ap [j+1]-1) ;
+ for (p = Ap [j] ; p < Ap [j+1] ; p++)
+ {
+ i = Ai [p] ;
+ printf (" %d", i) ;
+ }
+ printf ("\n") ;
+ }
+
+ /* print a character plot of the input matrix. This is only reasonable
+ * because the matrix is small. */
+ printf ("\nPlot of (jumbled) input matrix pattern:\n") ;
+ for (j = 0 ; j < n ; j++)
+ {
+ for (i = 0 ; i < n ; i++) A [i][j] = '.' ;
+ for (p = Ap [j] ; p < Ap [j+1] ; p++)
+ {
+ i = Ai [p] ;
+ A [i][j] = 'X' ;
+ }
+ }
+ printf (" ") ;
+ for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ;
+ printf ("\n") ;
+ for (i = 0 ; i < n ; i++)
+ {
+ printf ("%2d: ", i) ;
+ for (j = 0 ; j < n ; j++)
+ {
+ printf (" %c", A [i][j]) ;
+ }
+ printf ("\n") ;
+ }
+
+ /* sort, remove duplicates, and transpose A to get R */
+ result = amd_preprocess (n, Ap, Ai, Rp, Ri) ;
+ printf ("return value from amd_preprocess: %d (should be %d)\n",
+ result, AMD_OK) ;
+
+ if (result != AMD_OK)
+ {
+ printf ("AMD failed\n") ;
+ exit (1) ;
+ }
+
+ /* print the sorted/transposed matrix R */
+ printf ("\nThe column-oriented form of the sorted/transposed matrix R:\n");
+ for (j = 0 ; j < n ; j++)
+ {
+ printf ("\nColumn: %d, number of entries: %d, with row indices in"
+ " Ri [%d ... %d]:\n row indices:",
+ j, Rp [j+1] - Rp [j], Rp [j], Rp [j+1]-1) ;
+ for (p = Rp [j] ; p < Rp [j+1] ; p++)
+ {
+ i = Ri [p] ;
+ printf (" %d", i) ;
+ }
+ printf ("\n") ;
+ }
+
+ /* print a character plot of the matrix R. */
+ printf ("\nPlot of the sorted/transposed matrix R:\n") ;
+ for (j = 0 ; j < n ; j++)
+ {
+ for (i = 0 ; i < n ; i++) A [i][j] = '.' ;
+ for (p = Rp [j] ; p < Rp [j+1] ; p++)
+ {
+ i = Ri [p] ;
+ A [i][j] = 'X' ;
+ }
+ }
+ printf (" ") ;
+ for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ;
+ printf (" \n") ;
+ for (i = 0 ; i < n ; i++)
+ {
+ printf ("%2d: ", i) ;
+ for (j = 0 ; j < n ; j++)
+ {
+ printf (" %c", A [i][j]) ;
+ }
+ printf (" \n") ;
+ }
+
+ /* print a character plot of the matrix R+R'. */
+ printf ("\nPlot of symmetric matrix to be ordered by amd_order:\n") ;
+ for (j = 0 ; j < n ; j++)
+ {
+ for (i = 0 ; i < n ; i++) A [i][j] = '.' ;
+ }
+ for (j = 0 ; j < n ; j++)
+ {
+ A [j][j] = 'X' ;
+ for (p = Rp [j] ; p < Rp [j+1] ; p++)
+ {
+ i = Ri [p] ;
+ A [i][j] = 'X' ;
+ A [j][i] = 'X' ;
+ }
+ }
+ printf (" ") ;
+ for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ;
+ printf ("\n") ;
+ for (i = 0 ; i < n ; i++)
+ {
+ printf ("%2d: ", i) ;
+ for (j = 0 ; j < n ; j++)
+ {
+ printf (" %c", A [i][j]) ;
+ }
+ printf ("\n") ;
+ }
+
+ /* order the matrix */
+ result = amd_order (n, Rp, Ri, P, Control, Info) ;
+ printf ("return value from amd_order: %d (should be %d)\n",
+ result, AMD_OK) ;
+
+ /* print the statistics */
+ amd_info (Info) ;
+
+ if (result != AMD_OK)
+ {
+ printf ("AMD failed\n") ;
+ exit (1) ;
+ }
+
+ /* print the permutation vector, P, and compute the inverse permutation */
+ printf ("Permutation vector:\n") ;
+ for (k = 0 ; k < n ; k++)
+ {
+ /* row/column j is the kth row/column in the permuted matrix */
+ j = P [k] ;
+ Pinv [j] = k ;
+ printf (" %2d", j) ;
+ }
+ printf ("\n\n") ;
+
+ printf ("Inverse permutation vector:\n") ;
+ for (j = 0 ; j < n ; j++)
+ {
+ k = Pinv [j] ;
+ printf (" %2d", k) ;
+ }
+ printf ("\n\n") ;
+
+ /* print a character plot of the permuted matrix. */
+ printf ("\nPlot of (symmetrized) permuted matrix pattern:\n") ;
+ for (j = 0 ; j < n ; j++)
+ {
+ for (i = 0 ; i < n ; i++) A [i][j] = '.' ;
+ }
+ for (jnew = 0 ; jnew < n ; jnew++)
+ {
+ j = P [jnew] ;
+ A [jnew][jnew] = 'X' ;
+ for (p = Rp [j] ; p < Rp [j+1] ; p++)
+ {
+ inew = Pinv [Ri [p]] ;
+ A [inew][jnew] = 'X' ;
+ A [jnew][inew] = 'X' ;
+ }
+ }
+ printf (" ") ;
+ for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ;
+ printf ("\n") ;
+ for (i = 0 ; i < n ; i++)
+ {
+ printf ("%2d: ", i) ;
+ for (j = 0 ; j < n ; j++)
+ {
+ printf (" %c", A [i][j]) ;
+ }
+ printf ("\n") ;
+ }
+
+ return (0) ;
+}
--- /dev/null
+AMD demo, with a jumbled version of the 24-by-24
+Harwell/Boeing matrix, can_24:
+
+amd: approximate minimum degree ordering, parameters:
+ dense row parameter: 10
+ (rows with more than max (10 * sqrt (n), 16) entries are
+ considered "dense", and placed last in output permutation)
+ aggressive absorption: yes
+
+
+Jumbled input matrix: 24-by-24, with 116 entries.
+ Note that for a symmetric matrix such as this one, only the
+ strictly lower or upper triangular parts would need to be
+ passed to AMD, since AMD computes the ordering of A+A'. The
+ diagonal entries are also not needed, since AMD ignores them.
+ This version of the matrix has jumbled columns and duplicate
+ row indices, and must be fixed by amd_preprocess prior to
+ ordering it with amd_order.
+
+Column: 0, number of entries: 9, with row indices in Ai [0 ... 8]:
+ row indices: 0 17 18 21 5 12 5 0 13
+
+Column: 1, number of entries: 5, with row indices in Ai [9 ... 13]:
+ row indices: 14 1 8 13 17
+
+Column: 2, number of entries: 6, with row indices in Ai [14 ... 19]:
+ row indices: 2 20 11 6 11 22
+
+Column: 3, number of entries: 8, with row indices in Ai [20 ... 27]:
+ row indices: 3 3 10 7 18 18 15 19
+
+Column: 4, number of entries: 5, with row indices in Ai [28 ... 32]:
+ row indices: 7 9 15 14 16
+
+Column: 5, number of entries: 4, with row indices in Ai [33 ... 36]:
+ row indices: 5 13 6 17
+
+Column: 6, number of entries: 7, with row indices in Ai [37 ... 43]:
+ row indices: 5 0 11 6 12 6 23
+
+Column: 7, number of entries: 9, with row indices in Ai [44 ... 52]:
+ row indices: 3 4 9 7 14 16 15 17 18
+
+Column: 8, number of entries: 5, with row indices in Ai [53 ... 57]:
+ row indices: 1 9 14 14 14
+
+Column: 9, number of entries: 5, with row indices in Ai [58 ... 62]:
+ row indices: 7 13 8 1 17
+
+Column: 10, number of entries: 0, with row indices in Ai [63 ... 62]:
+ row indices:
+
+Column: 11, number of entries: 3, with row indices in Ai [63 ... 65]:
+ row indices: 2 12 23
+
+Column: 12, number of entries: 3, with row indices in Ai [66 ... 68]:
+ row indices: 5 11 12
+
+Column: 13, number of entries: 3, with row indices in Ai [69 ... 71]:
+ row indices: 0 13 17
+
+Column: 14, number of entries: 3, with row indices in Ai [72 ... 74]:
+ row indices: 1 9 14
+
+Column: 15, number of entries: 3, with row indices in Ai [75 ... 77]:
+ row indices: 3 15 16
+
+Column: 16, number of entries: 4, with row indices in Ai [78 ... 81]:
+ row indices: 16 4 4 15
+
+Column: 17, number of entries: 4, with row indices in Ai [82 ... 85]:
+ row indices: 13 17 19 17
+
+Column: 18, number of entries: 5, with row indices in Ai [86 ... 90]:
+ row indices: 15 17 19 9 10
+
+Column: 19, number of entries: 6, with row indices in Ai [91 ... 96]:
+ row indices: 17 19 20 0 6 10
+
+Column: 20, number of entries: 4, with row indices in Ai [97 ... 100]:
+ row indices: 22 10 20 21
+
+Column: 21, number of entries: 11, with row indices in Ai [101 ... 111]:
+ row indices: 6 2 10 19 20 11 21 22 22 22 22
+
+Column: 22, number of entries: 0, with row indices in Ai [112 ... 111]:
+ row indices:
+
+Column: 23, number of entries: 4, with row indices in Ai [112 ... 115]:
+ row indices: 12 11 12 23
+
+Plot of (jumbled) input matrix pattern:
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+ 0: X . . . . . X . . . . . . X . . . . . X . . . .
+ 1: . X . . . . . . X X . . . . X . . . . . . . . .
+ 2: . . X . . . . . . . . X . . . . . . . . . X . .
+ 3: . . . X . . . X . . . . . . . X . . . . . . . .
+ 4: . . . . . . . X . . . . . . . . X . . . . . . .
+ 5: X . . . . X X . . . . . X . . . . . . . . . . .
+ 6: . . X . . X X . . . . . . . . . . . . X . X . .
+ 7: . . . X X . . X . X . . . . . . . . . . . . . .
+ 8: . X . . . . . . . X . . . . . . . . . . . . . .
+ 9: . . . . X . . X X . . . . . X . . . X . . . . .
+10: . . . X . . . . . . . . . . . . . . X X X X . .
+11: . . X . . . X . . . . . X . . . . . . . . X . X
+12: X . . . . . X . . . . X X . . . . . . . . . . X
+13: X X . . . X . . . X . . . X . . . X . . . . . .
+14: . X . . X . . X X . . . . . X . . . . . . . . .
+15: . . . X X . . X . . . . . . . X X . X . . . . .
+16: . . . . X . . X . . . . . . . X X . . . . . . .
+17: X X . . . X . X . X . . . X . . . X X X . . . .
+18: X . . X . . . X . . . . . . . . . . . . . . . .
+19: . . . X . . . . . . . . . . . . . X X X . X . .
+20: . . X . . . . . . . . . . . . . . . . X X X . .
+21: X . . . . . . . . . . . . . . . . . . . X X . .
+22: . . X . . . . . . . . . . . . . . . . . X X . .
+23: . . . . . . X . . . . X . . . . . . . . . . . X
+return value from amd_preprocess: 0 (should be 0)
+
+The column-oriented form of the sorted/transposed matrix R:
+
+Column: 0, number of entries: 4, with row indices in Ri [0 ... 3]:
+ row indices: 0 6 13 19
+
+Column: 1, number of entries: 4, with row indices in Ri [4 ... 7]:
+ row indices: 1 8 9 14
+
+Column: 2, number of entries: 3, with row indices in Ri [8 ... 10]:
+ row indices: 2 11 21
+
+Column: 3, number of entries: 3, with row indices in Ri [11 ... 13]:
+ row indices: 3 7 15
+
+Column: 4, number of entries: 2, with row indices in Ri [14 ... 15]:
+ row indices: 7 16
+
+Column: 5, number of entries: 4, with row indices in Ri [16 ... 19]:
+ row indices: 0 5 6 12
+
+Column: 6, number of entries: 5, with row indices in Ri [20 ... 24]:
+ row indices: 2 5 6 19 21
+
+Column: 7, number of entries: 4, with row indices in Ri [25 ... 28]:
+ row indices: 3 4 7 9
+
+Column: 8, number of entries: 2, with row indices in Ri [29 ... 30]:
+ row indices: 1 9
+
+Column: 9, number of entries: 5, with row indices in Ri [31 ... 35]:
+ row indices: 4 7 8 14 18
+
+Column: 10, number of entries: 5, with row indices in Ri [36 ... 40]:
+ row indices: 3 18 19 20 21
+
+Column: 11, number of entries: 5, with row indices in Ri [41 ... 45]:
+ row indices: 2 6 12 21 23
+
+Column: 12, number of entries: 5, with row indices in Ri [46 ... 50]:
+ row indices: 0 6 11 12 23
+
+Column: 13, number of entries: 6, with row indices in Ri [51 ... 56]:
+ row indices: 0 1 5 9 13 17
+
+Column: 14, number of entries: 5, with row indices in Ri [57 ... 61]:
+ row indices: 1 4 7 8 14
+
+Column: 15, number of entries: 6, with row indices in Ri [62 ... 67]:
+ row indices: 3 4 7 15 16 18
+
+Column: 16, number of entries: 4, with row indices in Ri [68 ... 71]:
+ row indices: 4 7 15 16
+
+Column: 17, number of entries: 9, with row indices in Ri [72 ... 80]:
+ row indices: 0 1 5 7 9 13 17 18 19
+
+Column: 18, number of entries: 3, with row indices in Ri [81 ... 83]:
+ row indices: 0 3 7
+
+Column: 19, number of entries: 5, with row indices in Ri [84 ... 88]:
+ row indices: 3 17 18 19 21
+
+Column: 20, number of entries: 4, with row indices in Ri [89 ... 92]:
+ row indices: 2 19 20 21
+
+Column: 21, number of entries: 3, with row indices in Ri [93 ... 95]:
+ row indices: 0 20 21
+
+Column: 22, number of entries: 3, with row indices in Ri [96 ... 98]:
+ row indices: 2 20 21
+
+Column: 23, number of entries: 3, with row indices in Ri [99 ... 101]:
+ row indices: 6 11 23
+
+Plot of the sorted/transposed matrix R:
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+ 0: X . . . . X . . . . . . X X . . . X X . . X . .
+ 1: . X . . . . . . X . . . . X X . . X . . . . . .
+ 2: . . X . . . X . . . . X . . . . . . . . X . X .
+ 3: . . . X . . . X . . X . . . . X . . X X . . . .
+ 4: . . . . . . . X . X . . . . X X X . . . . . . .
+ 5: . . . . . X X . . . . . . X . . . X . . . . . .
+ 6: X . . . . X X . . . . X X . . . . . . . . . . X
+ 7: . . . X X . . X . X . . . . X X X X X . . . . .
+ 8: . X . . . . . . . X . . . . X . . . . . . . . .
+ 9: . X . . . . . X X . . . . X . . . X . . . . . .
+10: . . . . . . . . . . . . . . . . . . . . . . . .
+11: . . X . . . . . . . . . X . . . . . . . . . . X
+12: . . . . . X . . . . . X X . . . . . . . . . . .
+13: X . . . . . . . . . . . . X . . . X . . . . . .
+14: . X . . . . . . . X . . . . X . . . . . . . . .
+15: . . . X . . . . . . . . . . . X X . . . . . . .
+16: . . . . X . . . . . . . . . . X X . . . . . . .
+17: . . . . . . . . . . . . . X . . . X . X . . . .
+18: . . . . . . . . . X X . . . . X . X . X . . . .
+19: X . . . . . X . . . X . . . . . . X . X X . . .
+20: . . . . . . . . . . X . . . . . . . . . X X X .
+21: . . X . . . X . . . X X . . . . . . . X X X X .
+22: . . . . . . . . . . . . . . . . . . . . . . . .
+23: . . . . . . . . . . . X X . . . . . . . . . . X
+
+Plot of symmetric matrix to be ordered by amd_order:
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+ 0: X . . . . X X . . . . . X X . . . X X X . X . .
+ 1: . X . . . . . . X X . . . X X . . X . . . . . .
+ 2: . . X . . . X . . . . X . . . . . . . . X X X .
+ 3: . . . X . . . X . . X . . . . X . . X X . . . .
+ 4: . . . . X . . X . X . . . . X X X . . . . . . .
+ 5: X . . . . X X . . . . . X X . . . X . . . . . .
+ 6: X . X . . X X . . . . X X . . . . . . X . X . X
+ 7: . . . X X . . X . X . . . . X X X X X . . . . .
+ 8: . X . . . . . . X X . . . . X . . . . . . . . .
+ 9: . X . . X . . X X X . . . X X . . X X . . . . .
+10: . . . X . . . . . . X . . . . . . . X X X X . .
+11: . . X . . . X . . . . X X . . . . . . . . X . X
+12: X . . . . X X . . . . X X . . . . . . . . . . X
+13: X X . . . X . . . X . . . X . . . X . . . . . .
+14: . X . . X . . X X X . . . . X . . . . . . . . .
+15: . . . X X . . X . . . . . . . X X . X . . . . .
+16: . . . . X . . X . . . . . . . X X . . . . . . .
+17: X X . . . X . X . X . . . X . . . X X X . . . .
+18: X . . X . . . X . X X . . . . X . X X X . . . .
+19: X . . X . . X . . . X . . . . . . X X X X X . .
+20: . . X . . . . . . . X . . . . . . . . X X X X .
+21: X . X . . . X . . . X X . . . . . . . X X X X .
+22: . . X . . . . . . . . . . . . . . . . . X X X .
+23: . . . . . . X . . . . X X . . . . . . . . . . X
+return value from amd_order: 0 (should be 0)
+
+amd: approximate minimum degree ordering, results:
+ status: OK
+ n, dimension of A: 24
+ nz, number of nonzeros in A: 102
+ symmetry of A: 0.4000
+ number of nonzeros on diagonal: 17
+ nonzeros in pattern of A+A' (excl. diagonal): 136
+ # dense rows/columns of A+A': 0
+ memory used, in bytes: 1516
+ # of memory compactions: 0
+
+ The following approximate statistics are for a subsequent
+ factorization of A(P,P) + A(P,P)'. They are slight upper
+ bounds if there are no dense rows/columns in A+A', and become
+ looser if dense rows/columns exist.
+
+ nonzeros in L (excluding diagonal): 97
+ nonzeros in L (including diagonal): 121
+ # divide operations for LDL' or LU: 97
+ # multiply-subtract operations for LDL': 275
+ # multiply-subtract operations for LU: 453
+ max nz. in any column of L (incl. diagonal): 8
+
+ chol flop count for real A, sqrt counted as 1 flop: 671
+ LDL' flop count for real A: 647
+ LDL' flop count for complex A: 3073
+ LU flop count for real A (with no pivoting): 1003
+ LU flop count for complex A (with no pivoting): 4497
+
+Permutation vector:
+ 22 20 10 23 12 5 16 8 14 4 15 7 1 9 13 17 0 2 3 6 11 18 21 19
+
+Inverse permutation vector:
+ 16 12 17 18 9 5 19 11 7 13 2 20 4 14 8 10 6 15 21 23 1 22 0 3
+
+
+Plot of (symmetrized) permuted matrix pattern:
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+ 0: X X . . . . . . . . . . . . . . . X . . . . X .
+ 1: X X X . . . . . . . . . . . . . . X . . . . X X
+ 2: . X X . . . . . . . . . . . . . . . X . . X X X
+ 3: . . . X X . . . . . . . . . . . . . . X X . . .
+ 4: . . . X X X . . . . . . . . . . X . . X X . . .
+ 5: . . . . X X . . . . . . . . X X X . . X . . . .
+ 6: . . . . . . X . . X X X . . . . . . . . . . . .
+ 7: . . . . . . . X X . . . X X . . . . . . . . . .
+ 8: . . . . . . . X X X . X X X . . . . . . . . . .
+ 9: . . . . . . X . X X X X . X . . . . . . . . . .
+10: . . . . . . X . . X X X . . . . . . X . . X . .
+11: . . . . . . X . X X X X . X . X . . X . . X . .
+12: . . . . . . . X X . . . X X X X . . . . . . . .
+13: . . . . . . . X X X . X X X X X . . . . . X . .
+14: . . . . . X . . . . . . X X X X X . . . . . . .
+15: . . . . . X . . . . . X X X X X X . . . . X . X
+16: . . . . X X . . . . . . . . X X X . . X . X X X
+17: X X . . . . . . . . . . . . . . . X . X X . X .
+18: . . X . . . . . . . X X . . . . . . X . . X . X
+19: . . . X X X . . . . . . . . . . X X . X X . X X
+20: . . . X X . . . . . . . . . . . . X . X X . X .
+21: . . X . . . . . . . X X . X . X X . X . . X . X
+22: X X X . . . . . . . . . . . . . X X . X X . X X
+23: . X X . . . . . . . . . . . . X X . X X . X X X
--- /dev/null
+C ======================================================================
+C === AMD_cross ========================================================
+C ======================================================================
+
+C ----------------------------------------------------------------------
+C AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A.
+C Davis, Patrick R. Amestoy, and Iain S. Duff. See ../README for
+C License. email: davis@cise.ufl.edu CISE Department, Univ. of
+C Florida. web: http://www.cise.ufl.edu/research/sparse/amd
+C ----------------------------------------------------------------------
+
+C This program provides an example of how to call the C version of AMD
+C from a Fortran program. It is HIGHLY non-portable.
+
+C The amd_order routine returns PERM (1) < 0 if an error occurs.
+C (-1: out of memory, -2: invalid matrix)
+
+C Note that the input matrix is 0-based. From Fortran, column j of the
+C matrix is in AI (AP (I)+1 ... AP (I+1)). The row indices in this
+C set are in the range 0 to N-1. To demonstrate this translation,
+C the input matrix is printed in 1-based form. This program uses
+C the same 5-by-5 test matrix as amd_simple.c.
+
+ INTEGER N, NZ, K, P
+ PARAMETER (N = 5, NZ = 14)
+ INTEGER AP (N+1), AI (NZ), PERM (N)
+ DATA AP / 0, 2, 6, 10, 12, 14 /
+ DATA AI / 0,1, 0,1,2,4, 1,2,3,4, 2,3, 1,4 /
+ DOUBLE PRECISION CONTROL (5), INFO (20)
+
+C print the input matrix
+ PRINT 10, N, N, NZ
+10 FORMAT ('Input matrix:', I2, '-by-', I2, ' with',I3,' entries')
+ DO 40 J = 1, N
+ PRINT 20, J, AP (J+1) - AP (J), AP (J)+1, AP (J+1)
+20 FORMAT ( /, 'Column: ', I2, ' number of entries: ', I2,
+ $ ' with row indices in AI (', I3, ' ... ', I3, ')')
+ PRINT 30, ((AI (P) + 1), P = AP (J) + 1, AP (J+1))
+30 FORMAT (' row indices: ', 24I3)
+40 CONTINUE
+
+ CALL AMDDEFAULTS (CONTROL)
+ CALL AMDORDER (N, AP, AI, PERM, CONTROL, INFO)
+ CALL AMDINFO (INFO)
+
+ DO 60 K = 1, N
+ PRINT 50, K, PERM (K) + 1
+50 FORMAT ('PERM (',I2,') = ', I2)
+60 CONTINUE
+ END
+
--- /dev/null
+Input matrix: 5-by- 5 with 14 entries
+
+Column: 1 number of entries: 2 with row indices in AI ( 1 ... 2)
+ row indices: 1 2
+
+Column: 2 number of entries: 4 with row indices in AI ( 3 ... 6)
+ row indices: 1 2 3 5
+
+Column: 3 number of entries: 4 with row indices in AI ( 7 ... 10)
+ row indices: 2 3 4 5
+
+Column: 4 number of entries: 2 with row indices in AI ( 11 ... 12)
+ row indices: 3 4
+
+Column: 5 number of entries: 2 with row indices in AI ( 13 ... 14)
+ row indices: 2 5
+
+amd: approximate minimum degree ordering, results:
+ status: OK
+ n, dimension of A: 5
+ nz, number of nonzeros in A: 14
+ symmetry of A: 0.8889
+ number of nonzeros on diagonal: 5
+ nonzeros in pattern of A+A' (excl. diagonal): 10
+ # dense rows/columns of A+A': 0
+ memory used, in bytes: 228
+ # of memory compactions: 0
+
+ The following approximate statistics are for a subsequent
+ factorization of A(P,P) + A(P,P)'. They are slight upper
+ bounds if there are no dense rows/columns in A+A', and become
+ looser if dense rows/columns exist.
+
+ nonzeros in L (excluding diagonal): 5
+ nonzeros in L (including diagonal): 10
+ # divide operations for LDL' or LU: 5
+ # multiply-subtract operations for LDL': 6
+ # multiply-subtract operations for LU: 7
+ max nz. in any column of L (incl. diagonal): 3
+
+ chol flop count for real A, sqrt counted as 1 flop: 22
+ LDL' flop count for real A: 17
+ LDL' flop count for complex A: 93
+ LU flop count for real A (with no pivoting): 19
+ LU flop count for complex A (with no pivoting): 101
+
+PERM ( 1) = 1
+PERM ( 2) = 4
+PERM ( 3) = 3
+PERM ( 4) = 5
+PERM ( 5) = 2
--- /dev/null
+C ======================================================================
+C === Fortran AMD demo main program ====================================
+C ======================================================================
+
+C ----------------------------------------------------------------------
+C AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A.
+C Davis, Patrick R. Amestoy, and Iain S. Duff. See ../README for
+C License. email: davis@cise.ufl.edu CISE Department, Univ. of
+C Florida. web: http://www.cise.ufl.edu/research/sparse/amd
+C ----------------------------------------------------------------------
+
+C A simple Fortran 77 main program that illustrates the use of the
+C Fortran version of AMD (both the AMD and AMDBAR routines). Note
+C that aggressive absorption has no effect on this particular matrix.
+
+C AP and AI contain the symmetric can_24 Harwell/Boeing matrix,
+C including upper and lower triangular parts, but excluding the
+C diagonal entries. Note that this matrix is 1-based, with row
+C and column indices in the range 1 to N.
+
+ INTEGER N, NZ, IWLEN, PFREE, I, J, K, JNEW, P, INEW,
+ $ METHOD, NCMPA
+ PARAMETER (N = 24, NZ = 136, IWLEN = 200)
+ INTEGER PE (N), DEGREE (N), NV (N), NEXT (N), PERM (N), W (N),
+ $ HEAD (N), PINV (N), LEN (N), AP (N+1), AI (NZ), IW (IWLEN)
+ CHARACTER A (24,24)
+
+ DATA AP
+ $ / 1, 9, 14, 19, 24, 29, 34, 42, 50, 53, 61, 66, 71,
+ $ 76, 81, 86, 91, 94, 102, 110, 118, 123, 131, 134, 137 /
+ DATA AI /
+ $ 6, 7, 13, 14, 18, 19, 20, 22,
+ $ 9, 10, 14, 15, 18,
+ $ 7, 12, 21, 22, 23,
+ $ 8, 11, 16, 19, 20,
+ $ 8, 10, 15, 16, 17,
+ $ 1, 7, 13, 14, 18,
+ $ 1, 3, 6, 12, 13, 20, 22, 24,
+ $ 4, 5, 10, 15, 16, 17, 18, 19,
+ $ 2, 10, 15,
+ $ 2, 5, 8, 9, 14, 15, 18, 19,
+ $ 4, 19, 20, 21, 22,
+ $ 3, 7, 13, 22, 24,
+ $ 1, 6, 7, 12, 24,
+ $ 1, 2, 6, 10, 18,
+ $ 2, 5, 8, 9, 10,
+ $ 4, 5, 8, 17, 19,
+ $ 5, 8, 16,
+ $ 1, 2, 6, 8, 10, 14, 19, 20,
+ $ 1, 4, 8, 10, 11, 16, 18, 20,
+ $ 1, 4, 7, 11, 18, 19, 21, 22,
+ $ 3, 11, 20, 22, 23,
+ $ 1, 3, 7, 11, 12, 20, 21, 23,
+ $ 3, 21, 22,
+ $ 7, 12, 13 /
+
+C print the input matrix
+ PRINT 11, N, N, NZ
+11 FORMAT ('AMD Fortran 77 demo, with the 24-by-24',
+ $ ' Harwell/Boeing matrix, can_24:'
+ $ /, 'Input matrix: ', I2, '-by-', I2,' with ',I3,' entries',
+ $ /, 'Note that the Fortran version of AMD requires that'
+ $ /, 'no diagonal entries be present.')
+ DO 20 J = 1, N
+ PRINT 21, J, AP (J+1) - AP (J), AP (J), AP (J+1)-1
+21 FORMAT ( /, 'Column: ', I2, ' number of entries: ', I2,
+ $ ' with row indices in AI (', I3, ' ... ', I3, ')')
+ PRINT 10, ((AI (P)), P = AP (J), AP (J+1) - 1)
+10 FORMAT (' row indices: ', 24I3)
+20 CONTINUE
+
+C print a character plot of the input matrix. This is only
+C reasonable because the matrix is small.
+ PRINT 31
+31 FORMAT ('Plot of input matrix pattern:')
+ DO 50 J = 1,N
+ DO 30 I = 1,N
+ A (I, J) = '.'
+30 CONTINUE
+C add the diagonal entry to the plot
+ A (J, J) = 'X'
+ DO 40 P = AP (J), AP (J+1) - 1
+ I = AI (P)
+ A (I, J) = 'X'
+40 CONTINUE
+50 CONTINUE
+ PRINT 60, ((MOD (J, 10)), J = 1,N)
+60 FORMAT (' ', 24I2)
+ DO 80 I = 1,N
+ PRINT 70, I, (A (I, J), J = 1,N)
+70 FORMAT (' ', I2, ': ', 24A2)
+80 CONTINUE
+
+ DO 190 METHOD = 1,2
+
+C load the matrix into AMD's workspace
+ DO 90 J = 1,N
+ PE (J) = AP (J)
+ LEN (J) = AP (J+1) - AP (J)
+90 CONTINUE
+ DO 100 P = 1,NZ
+ IW (P) = AI (P)
+100 CONTINUE
+ PFREE = NZ + 1
+
+C order the matrix using AMD or AMDBAR
+ IF (METHOD .EQ. 1) THEN
+ PRINT 101
+101 FORMAT (/, '------------------------------------------',
+ $ /, 'ordering the matrix with AMD',
+ $ /, '------------------------------------------')
+ CALL AMD (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT,
+ $ PERM, HEAD, PINV, DEGREE, NCMPA, W)
+ ELSE
+ PRINT 102
+102 FORMAT (/, '------------------------------------------',
+ $ /, 'ordering the matrix with AMDBAR',
+ $ /, '------------------------------------------')
+ CALL AMDBAR (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT,
+ $ PERM, HEAD, PINV, DEGREE, NCMPA, W)
+ ENDIF
+
+C print the permutation vector, PERM, and its inverse, PINV.
+C row/column J = PERM (K) is the Kth row/column in the
+C permuted matrix.
+ PRINT 110, (PERM (K), K = 1,N)
+110 FORMAT (/, 'Permutation vector: ', /, 24I3)
+ PRINT 120, (PINV (J), J = 1,N)
+120 FORMAT (/, 'Inverse permutation vector: ', /, 24I3)
+
+C print a character plot of the permuted matrix.
+ PRINT 121
+121 FORMAT ('Plot of permuted matrix pattern:')
+ DO 150 JNEW = 1,N
+ J = PERM (JNEW)
+ DO 130 INEW = 1,N
+ A (INEW, JNEW) = '.'
+130 CONTINUE
+C add the diagonal entry to the plot
+ A (JNEW, JNEW) = 'X'
+ DO 140 P = AP (J), AP (J+1) - 1
+ INEW = PINV (AI (P))
+ A (INEW, JNEW) = 'X'
+140 CONTINUE
+150 CONTINUE
+ PRINT 60, ((MOD (J, 10)), J = 1,N)
+ DO 160 I = 1,N
+ PRINT 70, I, (A (I, J), J = 1,N)
+160 CONTINUE
+
+C print the permuted matrix, PERM*A*PERM'
+ DO 180 JNEW = 1,N
+ J = PERM (JNEW)
+ PRINT 171, JNEW, J, AP (J+1) - AP (J)
+171 FORMAT (/, 'New column: ', I2, ' old column: ', I2,
+ $ ' number of entries: ', I2)
+ PRINT 170, (PINV (AI (P)), P = AP (J), AP (J+1) - 1)
+170 FORMAT (' new row indices: ', 24I3)
+180 CONTINUE
+190 CONTINUE
+ END
--- /dev/null
+AMD Fortran 77 demo, with the 24-by-24 Harwell/Boeing matrix, can_24:
+Input matrix: 24-by-24 with 136 entries
+Note that the Fortran version of AMD requires that
+no diagonal entries be present.
+
+Column: 1 number of entries: 8 with row indices in AI ( 1 ... 8)
+ row indices: 6 7 13 14 18 19 20 22
+
+Column: 2 number of entries: 5 with row indices in AI ( 9 ... 13)
+ row indices: 9 10 14 15 18
+
+Column: 3 number of entries: 5 with row indices in AI ( 14 ... 18)
+ row indices: 7 12 21 22 23
+
+Column: 4 number of entries: 5 with row indices in AI ( 19 ... 23)
+ row indices: 8 11 16 19 20
+
+Column: 5 number of entries: 5 with row indices in AI ( 24 ... 28)
+ row indices: 8 10 15 16 17
+
+Column: 6 number of entries: 5 with row indices in AI ( 29 ... 33)
+ row indices: 1 7 13 14 18
+
+Column: 7 number of entries: 8 with row indices in AI ( 34 ... 41)
+ row indices: 1 3 6 12 13 20 22 24
+
+Column: 8 number of entries: 8 with row indices in AI ( 42 ... 49)
+ row indices: 4 5 10 15 16 17 18 19
+
+Column: 9 number of entries: 3 with row indices in AI ( 50 ... 52)
+ row indices: 2 10 15
+
+Column: 10 number of entries: 8 with row indices in AI ( 53 ... 60)
+ row indices: 2 5 8 9 14 15 18 19
+
+Column: 11 number of entries: 5 with row indices in AI ( 61 ... 65)
+ row indices: 4 19 20 21 22
+
+Column: 12 number of entries: 5 with row indices in AI ( 66 ... 70)
+ row indices: 3 7 13 22 24
+
+Column: 13 number of entries: 5 with row indices in AI ( 71 ... 75)
+ row indices: 1 6 7 12 24
+
+Column: 14 number of entries: 5 with row indices in AI ( 76 ... 80)
+ row indices: 1 2 6 10 18
+
+Column: 15 number of entries: 5 with row indices in AI ( 81 ... 85)
+ row indices: 2 5 8 9 10
+
+Column: 16 number of entries: 5 with row indices in AI ( 86 ... 90)
+ row indices: 4 5 8 17 19
+
+Column: 17 number of entries: 3 with row indices in AI ( 91 ... 93)
+ row indices: 5 8 16
+
+Column: 18 number of entries: 8 with row indices in AI ( 94 ... 101)
+ row indices: 1 2 6 8 10 14 19 20
+
+Column: 19 number of entries: 8 with row indices in AI (102 ... 109)
+ row indices: 1 4 8 10 11 16 18 20
+
+Column: 20 number of entries: 8 with row indices in AI (110 ... 117)
+ row indices: 1 4 7 11 18 19 21 22
+
+Column: 21 number of entries: 5 with row indices in AI (118 ... 122)
+ row indices: 3 11 20 22 23
+
+Column: 22 number of entries: 8 with row indices in AI (123 ... 130)
+ row indices: 1 3 7 11 12 20 21 23
+
+Column: 23 number of entries: 3 with row indices in AI (131 ... 133)
+ row indices: 3 21 22
+
+Column: 24 number of entries: 3 with row indices in AI (134 ... 136)
+ row indices: 7 12 13
+Plot of input matrix pattern:
+ 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
+ 1: X . . . . X X . . . . . X X . . . X X X . X . .
+ 2: . X . . . . . . X X . . . X X . . X . . . . . .
+ 3: . . X . . . X . . . . X . . . . . . . . X X X .
+ 4: . . . X . . . X . . X . . . . X . . X X . . . .
+ 5: . . . . X . . X . X . . . . X X X . . . . . . .
+ 6: X . . . . X X . . . . . X X . . . X . . . . . .
+ 7: X . X . . X X . . . . X X . . . . . . X . X . X
+ 8: . . . X X . . X . X . . . . X X X X X . . . . .
+ 9: . X . . . . . . X X . . . . X . . . . . . . . .
+ 10: . X . . X . . X X X . . . X X . . X X . . . . .
+ 11: . . . X . . . . . . X . . . . . . . X X X X . .
+ 12: . . X . . . X . . . . X X . . . . . . . . X . X
+ 13: X . . . . X X . . . . X X . . . . . . . . . . X
+ 14: X X . . . X . . . X . . . X . . . X . . . . . .
+ 15: . X . . X . . X X X . . . . X . . . . . . . . .
+ 16: . . . X X . . X . . . . . . . X X . X . . . . .
+ 17: . . . . X . . X . . . . . . . X X . . . . . . .
+ 18: X X . . . X . X . X . . . X . . . X X X . . . .
+ 19: X . . X . . . X . X X . . . . X . X X X . . . .
+ 20: X . . X . . X . . . X . . . . . . X X X X X . .
+ 21: . . X . . . . . . . X . . . . . . . . X X X X .
+ 22: X . X . . . X . . . X X . . . . . . . X X X X .
+ 23: . . X . . . . . . . . . . . . . . . . . X X X .
+ 24: . . . . . . X . . . . X X . . . . . . . . . . X
+
+------------------------------------------
+ordering the matrix with AMD
+------------------------------------------
+
+Permutation vector:
+ 24 23 17 9 15 5 21 13 6 11 16 8 2 10 14 18 1 3 4 19 7 12 22 20
+
+Inverse permutation vector:
+ 17 13 18 19 6 9 21 12 4 14 10 22 8 15 5 11 3 16 20 24 7 23 2 1
+Plot of permuted matrix pattern:
+ 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
+ 1: X . . . . . . X . . . . . . . . . . . . X X . .
+ 2: . X . . . . X . . . . . . . . . . X . . . . X .
+ 3: . . X . . X . . . . X X . . . . . . . . . . . .
+ 4: . . . X X . . . . . . . X X . . . . . . . . . .
+ 5: . . . X X X . . . . . X X X . . . . . . . . . .
+ 6: . . X . X X . . . . X X . X . . . . . . . . . .
+ 7: . X . . . . X . . X . . . . . . . X . . . . X X
+ 8: X . . . . . . X X . . . . . . . X . . . X X . .
+ 9: . . . . . . . X X . . . . . X X X . . . X . . .
+ 10: . . . . . . X . . X . . . . . . . . X X . . X X
+ 11: . . X . . X . . . . X X . . . . . . X X . . . .
+ 12: . . X . X X . . . . X X . X . X . . X X . . . .
+ 13: . . . X X . . . . . . . X X X X . . . . . . . .
+ 14: . . . X X X . . . . . X X X X X . . . X . . . .
+ 15: . . . . . . . . X . . . X X X X X . . . . . . .
+ 16: . . . . . . . . X . . X X X X X X . . X . . . X
+ 17: . . . . . . . X X . . . . . X X X . . X X . X X
+ 18: . X . . . . X . . . . . . . . . . X . . X X X .
+ 19: . . . . . . . . . X X X . . . . . . X X . . . X
+ 20: . . . . . . . . . X X X . X . X X . X X . . . X
+ 21: X . . . . . . X X . . . . . . . X X . . X X X X
+ 22: X . . . . . . X . . . . . . . . . X . . X X X .
+ 23: . X . . . . X . . X . . . . . . X X . . X X X X
+ 24: . . . . . . X . . X . . . . . X X . X X X . X X
+
+New column: 1 old column: 24 number of entries: 3
+ new row indices: 21 22 8
+
+New column: 2 old column: 23 number of entries: 3
+ new row indices: 18 7 23
+
+New column: 3 old column: 17 number of entries: 3
+ new row indices: 6 12 11
+
+New column: 4 old column: 9 number of entries: 3
+ new row indices: 13 14 5
+
+New column: 5 old column: 15 number of entries: 5
+ new row indices: 13 6 12 4 14
+
+New column: 6 old column: 5 number of entries: 5
+ new row indices: 12 14 5 11 3
+
+New column: 7 old column: 21 number of entries: 5
+ new row indices: 18 10 24 23 2
+
+New column: 8 old column: 13 number of entries: 5
+ new row indices: 17 9 21 22 1
+
+New column: 9 old column: 6 number of entries: 5
+ new row indices: 17 21 8 15 16
+
+New column: 10 old column: 11 number of entries: 5
+ new row indices: 19 20 24 7 23
+
+New column: 11 old column: 16 number of entries: 5
+ new row indices: 19 6 12 3 20
+
+New column: 12 old column: 8 number of entries: 8
+ new row indices: 19 6 14 5 11 3 16 20
+
+New column: 13 old column: 2 number of entries: 5
+ new row indices: 4 14 15 5 16
+
+New column: 14 old column: 10 number of entries: 8
+ new row indices: 13 6 12 4 15 5 16 20
+
+New column: 15 old column: 14 number of entries: 5
+ new row indices: 17 13 9 14 16
+
+New column: 16 old column: 18 number of entries: 8
+ new row indices: 17 13 9 12 14 15 20 24
+
+New column: 17 old column: 1 number of entries: 8
+ new row indices: 9 21 8 15 16 20 24 23
+
+New column: 18 old column: 3 number of entries: 5
+ new row indices: 21 22 7 23 2
+
+New column: 19 old column: 4 number of entries: 5
+ new row indices: 12 10 11 20 24
+
+New column: 20 old column: 19 number of entries: 8
+ new row indices: 17 19 12 14 10 11 16 24
+
+New column: 21 old column: 7 number of entries: 8
+ new row indices: 17 18 9 22 8 24 23 1
+
+New column: 22 old column: 12 number of entries: 5
+ new row indices: 18 21 8 23 1
+
+New column: 23 old column: 22 number of entries: 8
+ new row indices: 17 18 21 10 22 24 7 2
+
+New column: 24 old column: 20 number of entries: 8
+ new row indices: 17 19 21 10 16 20 7 23
+
+------------------------------------------
+ordering the matrix with AMDBAR
+------------------------------------------
+
+Permutation vector:
+ 24 23 17 9 15 5 21 13 6 11 16 8 2 10 14 18 1 3 4 19 7 12 22 20
+
+Inverse permutation vector:
+ 17 13 18 19 6 9 21 12 4 14 10 22 8 15 5 11 3 16 20 24 7 23 2 1
+Plot of permuted matrix pattern:
+ 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
+ 1: X . . . . . . X . . . . . . . . . . . . X X . .
+ 2: . X . . . . X . . . . . . . . . . X . . . . X .
+ 3: . . X . . X . . . . X X . . . . . . . . . . . .
+ 4: . . . X X . . . . . . . X X . . . . . . . . . .
+ 5: . . . X X X . . . . . X X X . . . . . . . . . .
+ 6: . . X . X X . . . . X X . X . . . . . . . . . .
+ 7: . X . . . . X . . X . . . . . . . X . . . . X X
+ 8: X . . . . . . X X . . . . . . . X . . . X X . .
+ 9: . . . . . . . X X . . . . . X X X . . . X . . .
+ 10: . . . . . . X . . X . . . . . . . . X X . . X X
+ 11: . . X . . X . . . . X X . . . . . . X X . . . .
+ 12: . . X . X X . . . . X X . X . X . . X X . . . .
+ 13: . . . X X . . . . . . . X X X X . . . . . . . .
+ 14: . . . X X X . . . . . X X X X X . . . X . . . .
+ 15: . . . . . . . . X . . . X X X X X . . . . . . .
+ 16: . . . . . . . . X . . X X X X X X . . X . . . X
+ 17: . . . . . . . X X . . . . . X X X . . X X . X X
+ 18: . X . . . . X . . . . . . . . . . X . . X X X .
+ 19: . . . . . . . . . X X X . . . . . . X X . . . X
+ 20: . . . . . . . . . X X X . X . X X . X X . . . X
+ 21: X . . . . . . X X . . . . . . . X X . . X X X X
+ 22: X . . . . . . X . . . . . . . . . X . . X X X .
+ 23: . X . . . . X . . X . . . . . . X X . . X X X X
+ 24: . . . . . . X . . X . . . . . X X . X X X . X X
+
+New column: 1 old column: 24 number of entries: 3
+ new row indices: 21 22 8
+
+New column: 2 old column: 23 number of entries: 3
+ new row indices: 18 7 23
+
+New column: 3 old column: 17 number of entries: 3
+ new row indices: 6 12 11
+
+New column: 4 old column: 9 number of entries: 3
+ new row indices: 13 14 5
+
+New column: 5 old column: 15 number of entries: 5
+ new row indices: 13 6 12 4 14
+
+New column: 6 old column: 5 number of entries: 5
+ new row indices: 12 14 5 11 3
+
+New column: 7 old column: 21 number of entries: 5
+ new row indices: 18 10 24 23 2
+
+New column: 8 old column: 13 number of entries: 5
+ new row indices: 17 9 21 22 1
+
+New column: 9 old column: 6 number of entries: 5
+ new row indices: 17 21 8 15 16
+
+New column: 10 old column: 11 number of entries: 5
+ new row indices: 19 20 24 7 23
+
+New column: 11 old column: 16 number of entries: 5
+ new row indices: 19 6 12 3 20
+
+New column: 12 old column: 8 number of entries: 8
+ new row indices: 19 6 14 5 11 3 16 20
+
+New column: 13 old column: 2 number of entries: 5
+ new row indices: 4 14 15 5 16
+
+New column: 14 old column: 10 number of entries: 8
+ new row indices: 13 6 12 4 15 5 16 20
+
+New column: 15 old column: 14 number of entries: 5
+ new row indices: 17 13 9 14 16
+
+New column: 16 old column: 18 number of entries: 8
+ new row indices: 17 13 9 12 14 15 20 24
+
+New column: 17 old column: 1 number of entries: 8
+ new row indices: 9 21 8 15 16 20 24 23
+
+New column: 18 old column: 3 number of entries: 5
+ new row indices: 21 22 7 23 2
+
+New column: 19 old column: 4 number of entries: 5
+ new row indices: 12 10 11 20 24
+
+New column: 20 old column: 19 number of entries: 8
+ new row indices: 17 19 12 14 10 11 16 24
+
+New column: 21 old column: 7 number of entries: 8
+ new row indices: 17 18 9 22 8 24 23 1
+
+New column: 22 old column: 12 number of entries: 5
+ new row indices: 18 21 8 23 1
+
+New column: 23 old column: 22 number of entries: 8
+ new row indices: 17 18 21 10 22 24 7 2
+
+New column: 24 old column: 20 number of entries: 8
+ new row indices: 17 19 21 10 16 20 7 23
--- /dev/null
+C ----------------------------------------------------------------------
+C AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A.
+C Davis, Patrick R. Amestoy, and Iain S. Duff. See ../README for
+C License. email: davis@cise.ufl.edu CISE Department, Univ. of
+C Florida. web: http://www.cise.ufl.edu/research/sparse/amd
+C ----------------------------------------------------------------------
+
+C This program provides an example of how to call the Fortran version
+C of AMD. It uses the same matrix as the amd_simple.c demo (in C).
+C Note that the diagonal entries are not present, and the matrix is
+C symmetric.
+
+ INTEGER N, NZ, J, K, P, IWLEN, PFREE, NCMPA
+ PARAMETER (N = 5, NZ = 10, IWLEN = 17)
+ INTEGER AP (N+1), AI (NZ), LAST (N), PE (N), LEN (N), ELEN (N),
+ $ IW (IWLEN), DEGREE (N), NV (N), NEXT (N), HEAD (N), W (N)
+ DATA AP / 1, 2, 5, 8, 9, 11/
+ DATA AI / 2, 1,3,5, 2,4,5, 3, 2,3 /
+
+C load the matrix into the AMD workspace
+ DO 10 J = 1,N
+ PE (J) = AP (J)
+ LEN (J) = AP (J+1) - AP (J)
+10 CONTINUE
+ DO 20 P = 1,NZ
+ IW (P) = AI (P)
+20 CONTINUE
+ PFREE = NZ + 1
+
+C order the matrix (destroys the copy of A in IW, PE, and LEN)
+ CALL AMD (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT, LAST, HEAD,
+ $ ELEN, DEGREE, NCMPA, W)
+
+ DO 60 K = 1, N
+ PRINT 50, K, LAST (K)
+50 FORMAT ('P (',I2,') = ', I2)
+60 CONTINUE
+ END
--- /dev/null
+P ( 1) = 4
+P ( 2) = 1
+P ( 3) = 3
+P ( 4) = 5
+P ( 5) = 2
--- /dev/null
+/* ========================================================================= */
+/* === amd_f77wrapper ====================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* Fortran interface for the C-callable AMD library (int version only). This
+ * is HIGHLY non-portable. You will need to modify this depending on how your
+ * Fortran and C compilers behave. Two examples are provided.
+ *
+ * To avoid using I/O, and to avoid the extra porting step of a Fortran
+ * function, the status code is returned as the first entry in P (P [0] in C
+ * and P (1) in Fortran) if an error occurs. The error codes are negative
+ * (-1: out of memory, -2: invalid matrix).
+ *
+ * For some C and Fortran compilers, the Fortran compiler appends a single "_"
+ * after each routine name. C doesn't do this, so the translation is made
+ * here. Some Fortran compilers don't append an underscore (xlf on IBM AIX,
+ * for * example).
+ *
+ * Tested with the following compilers:
+ * Solaris with cc and f77 from Sun WorkShop 6 update 1.
+ * SGI Irix with MIPSpro cc and f77 compilers version 7.4
+ * Linux with GNU gcc or Intel's icc, and GNU g77 Intel's ifc Fortran compiler.
+ * (any combination). Note that with g77, a call to amd_order in Fortran
+ * gets translated to a call to amd_order__, with two underscores ("_").
+ * Thus, the Fortran names do not include an underscore.
+ */
+
+#include "amd.h"
+#include <stdio.h>
+
+/* ------------------------------------------------------------------------- */
+/* Linux, Solaris, SGI */
+/* ------------------------------------------------------------------------- */
+
+void amdorder_ (int *n, const int *Ap, const int *Ai, int *P,
+ double *Control, double *Info)
+{
+ int result = amd_order (*n, Ap, Ai, P, Control, Info) ;
+ if (result != AMD_OK && P) P [0] = result ;
+}
+
+void amddefaults_ (double *Control)
+{
+ amd_defaults (Control) ;
+}
+
+void amdcontrol_ (double *Control)
+{
+ fflush (stdout) ;
+ amd_control (Control) ;
+ fflush (stdout) ;
+}
+
+void amdinfo_ (double *Info)
+{
+ fflush (stdout) ;
+ amd_info (Info) ;
+ fflush (stdout) ;
+}
+
+void amdpreproc_ (int *n, const int *Ap, const int *Ai, int *Rp, int *Ri)
+{
+ int result = amd_preprocess (*n, Ap, Ai, Rp, Ri) ;
+ if (result != AMD_OK && Rp) Rp [0] = result ;
+}
+
+/* ------------------------------------------------------------------------- */
+/* IBM AIX. Probably Windows, Compaq Alpha, and HP Unix as well. */
+/* ------------------------------------------------------------------------- */
+
+void amdorder (int *n, const int *Ap, const int *Ai, int *P,
+ double *Control, double *Info)
+{
+ int result = amd_order (*n, Ap, Ai, P, Control, Info) ;
+ if (result != AMD_OK && P) P [0] = result ;
+}
+
+void amddefaults (double *Control)
+{
+ amd_defaults (Control) ;
+}
+
+void amdcontrol (double *Control)
+{
+ fflush (stdout) ;
+ amd_control (Control) ;
+ fflush (stdout) ;
+}
+
+void amdinfo (double *Info)
+{
+ fflush (stdout) ;
+ amd_info (Info) ;
+ fflush (stdout) ;
+}
+
+void amdpreproc (int *n, const int *Ap, const int *Ai, int *Rp, int *Ri)
+{
+ int result = amd_preprocess (*n, Ap, Ai, Rp, Ri) ;
+ if (result != AMD_OK && Rp) Rp [0] = result ;
+}
--- /dev/null
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include "amd.h"
+
+int n = 5 ;
+int Ap [ ] = { 0, 2, 6, 10, 12, 14} ;
+int Ai [ ] = { 0,1, 0,1,2,4, 1,2,3,4, 2,3, 1,4 } ;
+int P [5] ;
+
+int main (void)
+{
+ int k ;
+ (void) amd_order (n, Ap, Ai, P, (double *) NULL, (double *) NULL) ;
+ for (k = 0 ; k < n ; k++) printf ("P [%d] = %d\n", k, P [k]) ;
+ return (0) ;
+}
+
--- /dev/null
+P [0] = 0
+P [1] = 3
+P [2] = 2
+P [3] = 4
+P [4] = 1
--- /dev/null
+@string{SIREV = "{SIAM} Review"}
+@string{SIMAX = "{SIAM} J. Matrix Anal. Applic."}
+@string{SIAMJSC = "{SIAM} J. Sci. Comput."}
+@string{TOMS = "{ACM} Trans. Math. Softw."}
+
+@article{schu:01,
+ author = {J. Schulze},
+ title = {Towards a tighter coupling of bottom-up and top-down sparse matrix ordering methods},
+ journal = {BIT},
+ volume = {41},
+ number = {4},
+ pages = "800--841",
+ year = {2001}
+ }
+
+@article{GeorgeLiu89,
+ author={George, A. and Liu, J. W. H.},
+ year={1989},
+ title={The Evolution of the Minimum Degree Ordering Algorithm},
+ journal=SIREV,
+ volume={31},
+ number={1},
+ pages={1--19}}
+
+@article{AmestoyDavisDuff96,
+ author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.},
+ title={An approximate minimum degree ordering algorithm},
+ journal=SIMAX,
+ year={1996}
+ ,volume={17}
+ ,number={4}
+ ,pages={886-905}
+ }
+
+@misc{hsl:2002,
+ author = {HSL},
+ title = "{HSL} 2002: {A} collection of {F}ortran codes for large
+ scale scientific computation",
+ note = {{\tt www.cse.clrc.ac.uk/nag/hsl}},
+ year = 2002}
+
+
+@article{RothbergEisenstat98,
+ author={Rothberg, E. and Eisenstat, S. C.},
+ title={Node selection strategies for bottom-up sparse matrix orderings},
+ journal=SIMAX,
+ year={1998}
+ ,volume={19}
+ ,number={3}
+ ,pages={682-695}
+ }
+
+@article{KarypisKumar98e,
+ author={Karypis, G. and Kumar, V.},
+ title={A fast and high quality multilevel scheme for partitioning irregular graphs},
+ journal=SIAMJSC,
+ year={1998}
+ ,volume={20}
+ ,pages={359-392}
+ }
+
+@article{Chaco,
+ author={B. Hendrickson and E. Rothberg},
+ title={Improving the runtime and quality of nested dissection ordering},
+ journal=SIAMJSC,
+ year={1999}
+ ,volume={20}
+ ,pages={468--489}
+ }
+
+@article{PellegriniRomanAmestoy00,
+ author={Pellegrini, F. and Roman, J. and Amestoy, P.},
+ title={Hybridizing nested dissection and halo approximate minimum degree for efficient sparse matrix ordering},
+ journal={Concurrency: Practice and Experience},
+ year={2000}
+ ,volume={12}
+ ,pages={68-84}
+ }
+
+@article{DavisGilbertLarimoreNg00pending,
+ author={Davis, T. A. and Gilbert, J. R. and Larimore, S. I. and Ng, E. G.},
+ title={A column approximate minimum degree ordering algorithm},
+ journal=TOMS,
+ year={(to appear)}
+ }
+
--- /dev/null
+\documentclass[11pt]{article}
+
+\newcommand{\m}[1]{{\bf{#1}}} % for matrices and vectors
+\newcommand{\tr}{^{\sf T}} % transpose
+
+\topmargin 0in
+\textheight 9in
+\oddsidemargin 0pt
+\evensidemargin 0pt
+\textwidth 6.5in
+
+%------------------------------------------------------------------------------
+\begin{document}
+%------------------------------------------------------------------------------
+
+\title{AMD Version 1.1 User Guide}
+\author{Patrick R. Amestoy\thanks{ENSEEIHT-IRIT,
+2 rue Camichel 31017 Toulouse, France.
+email: amestoy@enseeiht.fr. http://www.enseeiht.fr/$\sim$amestoy.}
+\and Timothy A. Davis\thanks{
+Dept.~of Computer and Information Science and Engineering,
+Univ.~of Florida, Gainesville, FL, USA.
+email: davis@cise.ufl.edu.
+http://www.cise.ufl.edu/$\sim$davis.
+This work was supported by the National
+Science Foundation, under grants ASC-9111263, DMS-9223088, and CCR-0203270.
+Portions of the work were done while on sabbatical at Stanford University
+and Lawrence Berkeley National Laboratory (with funding from Stanford
+University and the SciDAC program).
+}
+\and Iain S. Duff\thanks{Rutherford Appleton Laboratory, Chilton, Didcot,
+Oxon OX11 0QX, England. email: i.s.duff@rl.ac.uk.
+http://www.numerical.rl.ac.uk/people/isd/isd.html.
+This work was supported by the EPSRC under grant GR/R46441.
+}}
+
+\date{January 29, 2004}
+\maketitle
+
+%------------------------------------------------------------------------------
+\begin{abstract}
+AMD is a set of routines that implements the approximate minimum degree ordering
+algorithm to permute sparse matrices prior to
+numerical factorization.
+There are versions written in both C and Fortran 77.
+A MATLAB interface is included.
+\end{abstract}
+%------------------------------------------------------------------------------
+
+Technical report TR-04-002, CISE Department, University of Florida,
+Gainesville, FL, 2004.
+
+AMD Version 1.1 (Jan. 21, 2004), Copyright\copyright 2004 by Timothy A.
+Davis, Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved.
+
+{\bf AMD License:}
+ Your use or distribution of AMD or any modified version of
+ AMD implies that you agree to this License.
+
+ THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+ EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+
+ Permission is hereby granted to use or copy this program, provided
+ that the Copyright, this License, and the Availability of the original
+ version is retained on all copies. User documentation of any code that
+ uses AMD or any modified version of AMD code must cite the
+ Copyright, this License, the Availability note, and ``Used by permission.''
+ Permission to modify the code and to distribute modified code is granted,
+ provided the Copyright, this License, and the Availability note are
+ retained, and a notice that the code was modified is included. This
+ software was developed with support from the National Science Foundation,
+ and is provided to you free of charge.
+
+{\bf Availability:}
+ http://www.cise.ufl.edu/research/sparse/amd
+
+{\bf Acknowledgments:}
+
+ This work was supported by the National Science Foundation, under
+ grants ASC-9111263 and DMS-9223088 and CCR-0203270.
+ The conversion to C, the addition of the elimination tree
+ post-ordering, and the handling of dense rows and columns
+ were done while Davis was on sabbatical at
+ Stanford University and Lawrence Berkeley National Laboratory.
+
+%------------------------------------------------------------------------------
+\newpage
+\section{Overview}
+%------------------------------------------------------------------------------
+
+AMD is a set of routines for preordering a sparse matrix prior to
+numerical factorization. It uses an approximate minimum degree ordering
+algorithm \cite{AmestoyDavisDuff96} to find a permutation matrix $\m{P}$
+so that the Cholesky factorization $\m{PAP}\tr=\m{LL}\tr$ has fewer
+(often much fewer) nonzero entries than the Cholesky factorization of $\m{A}$.
+The algorithm is typically much faster than other ordering methods
+and minimum degree ordering
+algorithms that compute an exact degree \cite{GeorgeLiu89}.
+Some methods, such as approximate deficiency
+\cite{RothbergEisenstat98} and graph-partitioning based methods
+\cite{Chaco,KarypisKumar98e,PellegriniRomanAmestoy00,schu:01}
+can produce better orderings, depending on the matrix.
+
+The algorithm starts with an undirected graph representation of a
+symmetric sparse matrix $\m{A}$. Node $i$ in the graph corresponds to row
+and column $i$ of the matrix, and there is an edge $(i,j)$ in the graph if
+$a_{ij}$ is nonzero.
+The degree of a node is initialized to the number of off-diagonal nonzeros
+in row $i$, which is the size of the set of nodes
+adjacent to $i$ in the graph.
+
+The selection of a pivot $a_{ii}$ from the diagonal of $\m{A}$ and the first
+step of Gaussian elimination corresponds to one step of graph elimination.
+Numerical fill-in causes new nonzero entries in the matrix
+(fill-in refers to
+nonzeros in $\m{L}$ that are not in $\m{A}$).
+Node $i$ is eliminated and edges are added to its neighbors
+so that they form a clique (or {\em element}). To reduce fill-in,
+node $i$ is selected as the node of least degree in the graph.
+This process repeats until the graph is eliminated.
+
+The clique is represented implicitly. Rather than listing all the
+new edges in the graph, a single list of nodes is kept which represents
+the clique. This list corresponds to the nonzero pattern of the first
+column of $\m{L}$. As the elimination proceeds, some of these cliques
+become subsets of subsequent cliques, and are removed. This graph
+can be stored in place, that is
+using the same amount of memory as the original graph.
+
+The most costly part of the minimum degree algorithm is the recomputation
+of the degrees of nodes adjacent to the current pivot element.
+Rather than keep track of the exact degree, the approximate minimum degree
+algorithm finds an upper bound on the degree that is easier to compute.
+For nodes of least degree, this bound tends to be tight. Using the
+approximate degree instead of the exact degree leads to a substantial savings
+in run time, particularly for very irregularly structured matrices.
+It has no effect on the quality of the ordering.
+
+In the C version of AMD, the elimination phase is followed by an
+elimination tree post-ordering. This has no effect on fill-in, but
+reorganizes the ordering so that the subsequent numerical factorization is
+more efficient. It also includes a pre-processing phase in which nodes of
+very high degree are removed (without causing fill-in), and placed last in the
+permutation $\m{P}$. This reduces the run time substantially if the matrix
+has a few rows with many nonzero entries, and has little effect on the quality
+of the ordering.
+The C version operates on the
+symmetric nonzero pattern of $\m{A}+\m{A}\tr$, so it can be given
+an unsymmetric matrix, or either the lower or upper triangular part of
+a symmetric matrix.
+
+The two Fortran versions of AMD are essentially identical to two versions of
+the AMD algorithm discussed in an earlier paper \cite{AmestoyDavisDuff96}
+(approximate minimum external degree, both with and without aggressive
+absorption).
+For a discussion of the long history of the minimum degree algorithm,
+see \cite{GeorgeLiu89}.
+
+%------------------------------------------------------------------------------
+\section{Availability}
+%------------------------------------------------------------------------------
+
+In addition to appearing as a Collected Algorithm of the ACM,
+AMD Version 1.1 is available at http://www.cise.ufl.edu/research/sparse.
+The Fortran version is available as the routine {\tt MC47} in HSL
+(formerly the Harwell Subroutine Library) \cite{hsl:2002}.
+
+%------------------------------------------------------------------------------
+\section{Using AMD in MATLAB}
+%------------------------------------------------------------------------------
+
+To use AMD in MATLAB, you must first compile the AMD mexFunction.
+Just type {\tt make} in the Unix system shell, while in the {\tt AMD}
+directory. You can also type {\tt amd\_make} in MATLAB, while in the
+{\tt AMD/MATLAB} directory. Place the {\tt AMD/MATLAB} directory in your
+MATLAB path. This can be done on any system with MATLAB, including Windows.
+See Section~\ref{Install} for more details on how to install AMD.
+
+The MATLAB statement {\tt p=amd(A)} finds a permutation vector {\tt p} such
+that the Cholesky factorization {\tt chol(A(p,p))} is typically sparser than
+{\tt chol(A)}.
+If {\tt A} is unsymmetric, {\tt amd(A)} is identical to {\tt amd(A+A')}
+(ignoring numerical cancellation).
+If {\tt A} is not symmetric positive definite,
+but has substantial diagonal entries and a mostly symmetric nonzero pattern,
+then this ordering is also suitable for LU factorization. A partial pivoting
+threshold may be required to prevent pivots from being selected off the
+diagonal, such as the statement {\tt [L,U,P] = lu (A (p,p), 0.1)}.
+Type {\tt help lu} for more details.
+The statement {\tt [L,U,P,Q] = lu (A (p,p))} in MATLAB 6.5 is
+not suitable, however, because it uses UMFPACK Version 4.0 and thus
+does not attempt to select pivots from the diagonal. UMFPACK Version 4.1
+uses several strategies, including a symmetric pivoting strategy, and
+will give you better results if you want to factorize an unsymmetric matrix
+of this type. Refer to the UMFPACK User Guide for more details, at
+http://www.cise.ufl.edu/research/sparse/umfpack.
+
+The AMD mexFunction is much faster than the built-in MATLAB symmetric minimum
+degree ordering methods, SYMAMD and SYMMMD. Its ordering quality is
+comparable to SYMAMD, and better than SYMMMD
+\cite{DavisGilbertLarimoreNg00pending}.
+
+An optional input argument can be used to modify the control parameters for
+AMD (aggressive absorption, dense row/column handling, and printing of
+statistics). An optional output
+argument provides statistics on the ordering, including an analysis of the
+fill-in and the floating-point operation count for a subsequent factorization.
+For more details (once AMD is installed),
+type {\tt help amd} in the MATLAB command window.
+
+%------------------------------------------------------------------------------
+\section{Using AMD in a C program}
+\label{Cversion}
+%------------------------------------------------------------------------------
+
+The C-callable AMD library consists of five user-callable routines and one
+include file. There are two versions of each of the routines, with
+{\tt int} and {\tt long} integers.
+The routines with prefix
+{\tt amd\_l\_} use {\tt long} integer arguments; the others use
+{\tt int} integer arguments. If you compile AMD in the standard
+ILP32 mode (32-bit {\tt int}'s, {\tt long}'s, and pointers) then the versions
+are essentially identical. You will be able to solve problems using up to 2GB
+of memory. If you compile AMD in the standard LP64 mode, the size of an
+{\tt int} remains 32-bits, but the size of a {\tt long} and a pointer both get
+promoted to 64-bits.
+
+The following routines are fully described in Section~\ref{Primary}:
+
+\begin{itemize}
+\item {\tt amd\_order}
+({\tt long} version: {\tt amd\_l\_order})
+ {\footnotesize
+ \begin{verbatim}
+ #include "amd.h"
+ int n, Ap [n+1], Ai [nz], P [n] ;
+ double Control [AMD_CONTROL], Info [AMD_INFO] ;
+ int result = amd_order (n, Ap, Ai, P, Control, Info) ;
+ \end{verbatim}
+ }
+ Computes the approximate minimum degree ordering of an $n$-by-$n$ matrix
+ $\m{A}$. Returns a permutation vector {\tt P} of size {\tt n}, where
+ {\tt P[k] = i} if row and column {\tt i} are the {\tt k}th row and
+ column in the permuted matrix.
+ This routine allocates its own memory of size $1.2e+9n$ integers,
+ where $e$ is the number of nonzeros in $\m{A}+\m{A}\tr$.
+ It computes statistics about the matrix $\m{A}$, such as the symmetry of
+ its nonzero pattern, the number of nonzeros in $\m{L}$,
+ and the number of floating-point operations required for Cholesky and LU
+ factorizations (which are returned in the {\tt Info} array).
+ The user's input matrix is not modified.
+ It returns {\tt AMD\_OK} if successful, {\tt AMD\_INVALID} if
+ the matrix is invalid, or {\tt AMD\_OUT\_OF\_MEMORY} if out of memory.
+
+\item {\tt amd\_defaults}
+({\tt long} version: {\tt amd\_l\_defaults})
+ {\footnotesize
+ \begin{verbatim}
+ #include "amd.h"
+ double Control [AMD_CONTROL] ;
+ amd_defaults (Control) ;
+ \end{verbatim}
+ }
+ Sets the default control parameters in the {\tt Control} array. These can
+ then be modified as desired before passing the array to the other AMD
+ routines.
+
+\item {\tt amd\_control}
+({\tt long} version: {\tt amd\_l\_control})
+ {\footnotesize
+ \begin{verbatim}
+ #include "amd.h"
+ double Control [AMD_CONTROL] ;
+ amd_control (Control) ;
+ \end{verbatim}
+ }
+ Prints a description of the control parameters, and their values.
+
+\item {\tt amd\_info}
+({\tt long} version: {\tt amd\_l\_info})
+ {\footnotesize
+ \begin{verbatim}
+ #include "amd.h"
+ double Info [AMD_INFO] ;
+ amd_info (Info) ;
+ \end{verbatim}
+ }
+ Prints a description of the statistics computed by AMD, and their values.
+
+\item {\tt amd\_preprocess}
+({\tt long} version: {\tt amd\_l\_info})
+ {\footnotesize
+ \begin{verbatim}
+ #include "amd.h"
+ int n, Ap [n+1], Ai [nz], Rp [n+1], Ri [nz] ;
+ int result = amd_preprocess (n, Ap, Ai, Rp, Ri) ;
+ \end{verbatim}
+ }
+ Removes duplicate entries and sorts each column of its input $\m{A}$,
+ and returns the nonzero pattern of the transpose, $\m{R}=\m{A}\tr$.
+ It returns the transpose because this is the simplest way to sort
+ a matrix and remove duplicate entries. Either $\m{A}$ or $\m{A}\tr$
+ can be passed to {\tt amd\_order} with little effect on the
+ ordering (except for minor tie-breaking changes).
+
+\end{itemize}
+
+The nonzero pattern of the matrix $\m{A}$ is represented in compressed column
+form.
+For an $n$-by-$n$ matrix $\m{A}$ with {\tt nz} nonzero entries, the
+representation consists of two arrays: {\tt Ap} of size {\tt n+1} and {\tt Ai}
+of size {\tt nz}. The row indices of entries in column {\tt j} are stored in
+ {\tt Ai[Ap[j]} $\ldots$ {\tt Ap[j+1]-1]}.
+For {\tt amd\_order},
+no duplicate row indices may be present, and the row indices in any given
+column must be sorted in ascending order.
+The matrix is 0-based, and thus
+row indices must be in the range {\tt 0} to {\tt n-1}.
+The first entry {\tt Ap[0]} must be zero.
+The total number of entries in the matrix is thus {\tt nz = Ap[n]}.
+
+The matrix must be square, but it does not need to be symmetric.
+The {\tt amd\_order} routine constructs the nonzero pattern of
+$\m{B} = \m{A}+\m{A}\tr$ (without forming $\m{A}\tr$ explicitly),
+and then orders the matrix $\m{B}$. Thus, either the
+lower triangular part of $\m{A}$, the upper triangular part,
+or any combination may be passed. The transpose $\m{A}\tr$ may also be
+passed to {\tt amd\_order}.
+The diagonal entries may be present, but are ignored.
+
+The input to {\tt amd\_order} must have sorted columns because it uses
+an in-place algorithm to construct $\m{A}+\m{A}\tr$ without first constructing
+$\m{A}\tr$. This saves memory, but places an additional restriction on
+the input. If the input matrix has columns with unsorted and/or duplicate
+row indices, it is not valid as input to {\tt amd\_order}. To handle this
+case, the {\tt amd\_preprocess} routine is provided. It sorts, transposes,
+and removes duplicate entries from its input matrix, returning its result
+as another compressed-column matrix $\m{R}$ which can then be passed to
+{\tt amd\_order}.
+
+%------------------------------------------------------------------------------
+\subsection{Control parameters}
+\label{control_param}
+%------------------------------------------------------------------------------
+
+Control parameters are set an optional {\tt Control} array.
+It is optional in the sense that if
+a {\tt NULL} pointer is passed for the {\tt Control} input argument,
+then default control parameters are used.
+%
+\begin{itemize}
+\item {\tt Control[AMD\_DENSE]} (or {\tt Control(1)} in MATLAB):
+controls the threshold for ``dense''
+rows/columns. A dense row/column in $\m{A}+\m{A}\tr$
+can cause AMD to spend significant time
+in ordering the matrix. If {\tt Control[AMD\_DENSE]} $\ge 0$,
+rows/columns with
+more than {\tt Control[AMD\_DENSE]} $\sqrt{n}$ entries are ignored during
+the ordering, and placed last in the output order. The default
+value of {\tt Control[AMD\_DENSE]} is 10. If negative, no rows/columns
+are treated as ``dense.'' Rows/columns with 16 or fewer off-diagonal
+entries are never considered ``dense.''
+%
+\item {\tt Control[AMD\_AGGRESSIVE]} (or {\tt Control(2)} in MATLAB):
+controls whether or not to use
+aggressive absorption, in which a prior element is absorbed into the current
+element if it is a subset of the current element, even if it is not
+adjacent to the current pivot element (refer to \cite{AmestoyDavisDuff96}
+for more details). The default value is nonzero,
+which means that aggressive absorption will be performed. This nearly always
+leads to a better ordering (because the approximate degrees are more
+accurate) and a lower execution time. There are cases where it can
+lead to a slightly worse ordering, however. To turn it off, set
+{\tt Control[AMD\_AGGRESSIVE]} to 0.
+%
+\end{itemize}
+
+Statistics are returned in the {\tt Info} array
+(if {\tt Info} is {\tt NULL}, then no statistics are returned).
+Refer to {\tt amd.h} file, for more details
+(14 different statistics are returned, so the list is not included here).
+
+%------------------------------------------------------------------------------
+\subsection{Sample C program}
+%------------------------------------------------------------------------------
+
+The following program, {\tt amd\_demo.c}, illustrates the basic use of AMD.
+See Section~\ref{Synopsis} for a short description
+of each calling sequence.
+
+{\footnotesize
+\begin{verbatim}
+#include <stdio.h>
+#include "amd.h"
+
+int n = 5 ;
+int Ap [ ] = { 0, 2, 6, 10, 12, 14} ;
+int Ai [ ] = { 0,1, 0,1,2,4, 1,2,3,4, 2,3, 1,4 } ;
+int P [5] ;
+
+int main (void)
+{
+ int k ;
+ (void) amd_order (n, Ap, Ai, P, (double *) NULL, (double *) NULL) ;
+ for (k = 0 ; k < n ; k++) printf ("P [%d] = %d\n", k, P [k]) ;
+ return (0) ;
+}
+\end{verbatim}
+}
+
+The {\tt Ap} and {\tt Ai} arrays represent the binary matrix
+\[
+\m{A} = \left[
+\begin{array}{rrrrr}
+ 1 & 1 & 0 & 0 & 0 \\
+ 1 & 1 & 1 & 0 & 1 \\
+ 0 & 1 & 1 & 1 & 0 \\
+ 0 & 0 & 1 & 1 & 0 \\
+ 0 & 1 & 1 & 0 & 1 \\
+\end{array}
+\right].
+\]
+The diagonal entries are ignored.
+%
+AMD constructs the pattern of $\m{A}+\m{A}\tr$,
+and returns a permutation vector of $(0, 3, 1, 4, 2)$.
+%
+Since the matrix is unsymmetric but with a mostly symmetric nonzero
+pattern, this would be a suitable permutation for an LU factorization of a
+matrix with this nonzero pattern and whose diagonal entries are not too small.
+The program uses default control settings and does not return any statistics
+about the ordering, factorization, or solution ({\tt Control} and {\tt Info}
+are both {\tt (double *) NULL}). It also ignores the status value returned by
+{\tt amd\_order}.
+
+More example programs are included with the AMD package.
+The {\tt amd\_demo.c} program provides a more detailed demo of AMD.
+Another example is the AMD mexFunction, {\tt amd\_mex.c}.
+
+%------------------------------------------------------------------------------
+\subsection{A note about zero-sized arrays}
+%------------------------------------------------------------------------------
+
+AMD uses several user-provided arrays of size {\tt n} or {\tt nz}.
+Either {\tt n} or {\tt nz} can be zero.
+If you attempt to {\tt malloc} an array of size zero,
+however, {\tt malloc} will return a null pointer which AMD will report
+as invalid. If you {\tt malloc} an array of
+size {\tt n} or {\tt nz} to pass to AMD, make sure that you handle the
+{\tt n} = 0 and {\tt nz = 0} cases correctly.
+
+%------------------------------------------------------------------------------
+\section{Synopsis of C-callable routines}
+\label{Synopsis}
+%------------------------------------------------------------------------------
+
+The matrix $\m{A}$ is {\tt n}-by-{\tt n} with {\tt nz} entries.
+
+{\footnotesize
+\begin{verbatim}
+#include "amd.h"
+int n, status, Ap [n+1], Ai [nz], P [n], Rp [n+1], Ri [nz] ;
+double Control [AMD_CONTROL], Info [AMD_INFO] ;
+amd_defaults (Control) ;
+status = amd_order (n, Ap, Ai, P, Control, Info) ;
+amd_control (Control) ;
+amd_info (Info) ;
+amd_preprocess (n, Ap, Ai, Rp, Ri) ;
+\end{verbatim}
+}
+
+The {\tt amd\_l\_*} routines are identical, except that all {\tt int}
+arguments become {\tt long}:
+
+{\footnotesize
+\begin{verbatim}
+#include "amd.h"
+long n, status, Ap [n+1], Ai [nz], P [n], Rp [n+1], Ri [nz] ;
+double Control [AMD_CONTROL], Info [AMD_INFO] ;
+amd_l_defaults (Control) ;
+status = amd_l_order (n, Ap, Ai, P, Control, Info) ;
+amd_l_control (Control) ;
+amd_l_info (Info) ;
+amd_l_preprocess (n, Ap, Ai, Rp, Ri) ;
+\end{verbatim}
+}
+
+%------------------------------------------------------------------------------
+\section{Using AMD in a Fortran program}
+%------------------------------------------------------------------------------
+
+Two Fortran versions of AMD are provided. The {\tt AMD} routine computes the
+approximate minimum degree ordering, using aggressive absorption. The
+{\tt AMDBAR} routine is identical, except that it does not perform aggressive
+absorption. The {\tt AMD} routine is essentially identical to the HSL
+routine {\tt MC47B/BD}.
+Note that earlier versions of the Fortran
+{\tt AMD} and {\tt AMDBAR} routines included an {\tt IOVFLO} argument,
+which is no longer present.
+
+In contrast to the C version, the Fortran routines require a symmetric
+nonzero pattern, with no diagonal entries present although the {\tt MC47A/AD}
+wrapper in HSL allows duplicates, ignores out-of-range entries, and only
+uses entries from the upper triangular part of the matrix. Although we
+have an experimental Fortran code for treating ``dense'' rows, the Fortran
+codes in this release do not treat
+``dense'' rows and columns of $\m{A}$ differently, and thus their run time
+can be high if there are a few dense rows and columns in the matrix.
+They do not perform a post-ordering of the elimination tree,
+compute statistics on the ordering, or check the validity of their input
+arguments. These facilities are provided by {\tt MC47A/AD} and other
+subroutines from HSL.
+Only one {\tt integer}
+version of each Fortran routine is provided.
+Both Fortran routines overwrite the user's input
+matrix, in contrast to the C version.
+%
+The C version does not return the elimination or assembly tree.
+The Fortran version returns an assembly tree;
+refer to the User Guide for details.
+The following is the syntax of the {\tt AMD} Fortran routine.
+The {\tt AMDBAR} routine is identical except for the routine name.
+
+{\footnotesize
+\begin{verbatim}
+ INTEGER N, IWLEN, PFREE, NCMPA, IW (IWLEN), PE (N), DEGREE (N), NV (N),
+ $ NEXT (N), LAST (N), HEAD (N), ELEN (N), W (N), LEN (N)
+ CALL AMD (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT,
+ $ LAST, HEAD, ELEN, DEGREE, NCMPA, W)
+ CALL AMDBAR (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT,
+ $ LAST, HEAD, ELEN, DEGREE, NCMPA, W)
+\end{verbatim}
+}
+
+The input matrix is provided to {\tt AMD} and {\tt AMDBAR}
+in three arrays, {\tt PE}, of size {\tt N},
+{\tt LEN}, of size {\tt N}, and {\tt IW}, of size {\tt IWLEN}. The size of
+{\tt IW} must be at least {\tt NZ+N}. The recommended size is
+{\tt 1.2*NZ + N}.
+On input, the indices of nonzero entries in row {\tt I} are stored in {\tt IW}.
+{\tt PE(I)} is the index in {\tt IW} of the start of row {\tt I}.
+{\tt LEN(I)} is the number of entries in row {\tt I}.
+The matrix is 1-based, with row and column indices in the range 1 to {\tt N}.
+Row {\tt I} is contained in
+{\tt IW (PE(I)} $\ldots \:$ {\tt PE(I) + LEN(I) - 1)}.
+The diagonal entries must not be present. The indices within each row must
+not contain any duplicates, but they need not be sorted. The rows
+themselves need not be in any particular order, and there may be empty space
+between the rows. If {\tt LEN(I)} is zero, then there are no off-diagonal
+entries in row {\tt I}, and {\tt PE(I)} is ignored. The integer
+{\tt PFREE} defines what part of {\tt IW} contains the user's input matrix,
+which is held in {\tt IW(1}~$\ldots~\:${\tt PFREE-1)}.
+The contents of {\tt IW} and {\tt LEN} are undefined on output,
+and {\tt PE} is modified to contain information about the ordering.
+
+As the algorithm proceeds, it modifies the {\tt IW} array, placing the
+pattern of the partially eliminated matrix in
+{\tt IW(PFREE} $\ldots \:${\tt IWLEN)}.
+If this space is exhausted, the space is compressed.
+The number of compressions performed on the {\tt IW} array is
+returned in the scalar {\tt NCMPA}. The value of {\tt PFREE} on output is the
+length of {\tt IW} required for no compressions to be needed.
+
+The output permutation is returned in the array {\tt LAST}, of size {\tt N}.
+If {\tt I=LAST(K)}, then {\tt I} is the {\tt K}th row in the permuted
+matrix. The inverse permutation is returned in the array {\tt ELEN}, where
+{\tt K=ELEN(I)} if {\tt I} is the {\tt K}th row in the permuted matrix.
+On output, the {\tt PE} and {\tt NV} arrays hold the assembly tree,
+a supernodal elimination tree that represents the relationship between
+columns of the Cholesky factor $\m{L}$.
+If {\tt NV(I)} $> 0$, then {\tt I} is a node in the assembly
+tree, and the parent of {\tt I} is {\tt -PE(I)}. If {\tt I} is a root of
+the tree, then {\tt PE(I)} is zero. The value of {\tt NV(I)} is the
+number of entries in the corresponding column of $\m{L}$, including the
+diagonal.
+If {\tt NV(I)} is zero, then {\tt I} is a non-principal node that is
+not in the assembly tree. Node {\tt -PE(I)} is the parent of node {\tt I}
+in a subtree, the root of which is a node in the assembly tree. All nodes
+in one subtree belong to the same supernode in the assembly tree.
+The other size {\tt N} arrays
+({\tt DEGREE}, {\tt HEAD}, {\tt NEXT}, and {\tt W}) are used as workspace,
+and are not defined on input or output.
+
+If you want to use a simpler user-interface and compute the elimination
+tree post-ordering, you should be able to call the C routines {\tt amd\_order}
+or {\tt amd\_l\_order} from a Fortran program. Just be sure to take into
+account the 0-based indexing in the {\tt P}, {\tt Ap}, and {\tt Ai} arguments
+to {\tt amd\_order} and {\tt amd\_l\_order}. A sample interface is provided
+in the files {\tt AMD/Demo/amd\_f77cross.f} and
+{\tt AMD/Demo/amd\_f77wrapper.c}. To compile the {\tt amd\_f77cross} program,
+type {\tt make cross} in the {\tt AMD/Demo} directory. The
+Fortran-to-C calling conventions are highly non-portable, so this example
+is not guaranteed to work with your compiler C and Fortran compilers.
+The output of {\tt amd\_f77cross} is in {\tt amd\_f77cross.out}.
+
+%------------------------------------------------------------------------------
+\section{Sample Fortran main program}
+%------------------------------------------------------------------------------
+
+The following program illustrates the basic usage of the Fortran version of AMD.
+The {\tt AP} and {\tt AI} arrays represent the binary matrix
+\[
+\m{A} = \left[
+\begin{array}{rrrrr}
+ 1 & 1 & 0 & 0 & 0 \\
+ 1 & 1 & 1 & 0 & 1 \\
+ 0 & 1 & 1 & 1 & 1 \\
+ 0 & 0 & 1 & 1 & 0 \\
+ 0 & 1 & 1 & 0 & 1 \\
+\end{array}
+\right]
+\]
+in a conventional 1-based column-oriented form,
+except that the diagonal entries are not present.
+The matrix has the same as nonzero pattern of $\m{A}+\m{A}\tr$ in the C
+program, in Section~\ref{Cversion}.
+The output permutation is $(4, 1, 3, 5, 2)$.
+It differs from the permutation returned by the C routine {\tt amd\_order}
+because a post-order of the elimination tree has not yet been performed.
+
+{\footnotesize
+\begin{verbatim}
+ INTEGER N, NZ, J, K, P, IWLEN, PFREE, NCMPA
+ PARAMETER (N = 5, NZ = 10, IWLEN = 17)
+ INTEGER AP (N+1), AI (NZ), LAST (N), PE (N), LEN (N), ELEN (N),
+ $ IW (IWLEN), DEGREE (N), NV (N), NEXT (N), HEAD (N), W (N)
+ DATA AP / 1, 2, 5, 8, 9, 11/
+ DATA AI / 2, 1,3,5, 2,4,5, 3, 2,3 /
+C load the matrix into the AMD workspace
+ DO 10 J = 1,N
+ PE (J) = AP (J)
+ LEN (J) = AP (J+1) - AP (J)
+10 CONTINUE
+ DO 20 P = 1,NZ
+ IW (P) = AI (P)
+20 CONTINUE
+ PFREE = NZ + 1
+C order the matrix (destroys the copy of A in IW, PE, and LEN)
+ CALL AMD (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT, LAST, HEAD,
+ $ ELEN, DEGREE, NCMPA, W)
+ DO 60 K = 1, N
+ PRINT 50, K, LAST (K)
+50 FORMAT ('P (',I2,') = ', I2)
+60 CONTINUE
+ END
+\end{verbatim}
+}
+
+The {\tt Demo} directory contains an example of how the C version
+may be called from a Fortran program, but this is highly non-portable.
+For this reason, it is placed in the {\tt Demo} directory, not in the
+primary {\tt Source} directory.
+
+%------------------------------------------------------------------------------
+\section{Installation}
+\label{Install}
+%------------------------------------------------------------------------------
+
+The following discussion assumes you have the {\tt make} program, either in
+Unix, or in Windows with Cygwin.
+
+System-dependent configurations are in the {\tt AMD/Make}
+directory. You can edit the {\tt Make.include}
+file in that directory to customize the compilation. The default
+settings will work on most systems.
+Sample configuration files are provided
+for Linux, Sun Solaris, SGI IRIX, IBM AIX, and the DEC/Compaq Alpha.
+
+To compile and install the C-callable AMD library,
+go to the {\tt AMD} directory and type {\tt make}.
+The library will be placed in {\tt AMD/Lib/libamd.a}.
+Two demo programs of the AMD ordering routine will be compiled and tested in
+the {\tt AMD/Demo} directory.
+The outputs of these demo programs will then be compared with output
+files in the distribution. The AMD mexFunction for
+use in MATLAB will also be compiled. If you do not have MATLAB
+type {\tt make lib} instead.
+
+To compile and install the Fortran-callable AMD library,
+go to the {\tt AMD} directory and type {\tt make fortran}.
+The library will be placed in {\tt AMD/Lib/libamdf77.a}.
+A demo program will be compiled and tested in the {\tt AMD/Demo} directory.
+The output will be compared with an output file in the distribution.
+
+Typing {\tt make clean} will remove all but the final compiled libraries
+and demo programs. Typing {\tt make purge} removes all files not in the
+original distribution.
+If you compile AMD and then later change the {\tt Make.include}
+file or your system-specific configuration file such as {\tt Make.linux},
+then you should type {\tt make purge} and then {\tt make} to recompile.
+
+Here are the various parameters that you can control in your
+{\tt Make.include} file:
+
+\begin{itemize}
+\item {\tt CC = } your C compiler, such as {\tt cc}.
+\item {\tt RANLIB = } your system's {\tt ranlib} program, if needed.
+\item {\tt CFLAGS = } optimization flags, such as {\tt -O}.
+\item {\tt LIB = } your libraries, such as {\tt -lm} or {\tt -lblas}.
+\item {\tt RM =} the command to delete a file.
+\item {\tt MV =} the command to rename a file.
+\item {\tt MEX =} the command to compile a MATLAB mexFunction.
+\item {\tt F77 =} the command to compile a Fortran program (optional).
+\item {\tt F77FLAGS =} the Fortran compiler flags (optional).
+\item {\tt F77LIB =} the Fortran libraries (optional).
+\end{itemize}
+
+The {\tt Make.include} includes some definitions regarding the BLAS.
+This is so that AMD and UMFPACK (which requires AMD) can share
+the same configuration files. If you wish to use AMD only, then
+you can ignore any references to the BLAS (the -DNBLAS compile flag).
+
+When you compile your program that uses the C-callable AMD library,
+you need to add the {\tt AMD/Lib/libamd.a} library
+and you need to tell your compiler to look in the
+{\tt AMD/Include} directory for include
+files. To compile a Fortran program that calls the Fortran AMD library,
+you need to add the {\tt AMD/Lib/libamdf77.a} library.
+See {\tt AMD/Demo/Makefile} for an example.
+
+If all you want to use is the AMD mexFunction in MATLAB, you can skip
+the use of the {\tt make} command entirely. Simply type
+{\tt amd\_make} in MATLAB while in the {\tt AMD/MATLAB} directory.
+This works on any system with MATLAB, including Windows.
+
+If you are including AMD as a subset of a larger library and do not want
+to link the C standard I/O library, or if you simply do not need to use
+them, you can safely remove the {\tt amd\_control.c} and {\tt amd\_info.c}
+files. Similarly, if you use default parameters (or define your
+own {\tt Control} array), then you can exclude the {\tt amd\_defaults.c}
+file. The {\tt amd\_preprocess.c} file is optional as well, if you
+can ensure that the input matrix to {\tt amd\_order} is always sorted
+and has no duplicate entries.
+Each of these files contains the user-callable routines of the same
+name. None of these auxiliary routines are directly called by
+{\tt amd\_order}.
+The {\tt amd\_dump.c} file contains debugging routines
+that are neither used nor compiled unless debugging is enabled.
+The {\tt amd\_internal.h} file must be edited to enable debugging;
+refer to the instructions in that file. Thus, it too can be excluded
+if compiled into a larger production program or library.
+The bare minimum files required to use just {\tt amd\_order} are
+{\tt amd.h} in the {\tt Include} directory,
+and
+{\tt amd\_1.c},
+{\tt amd\_2.c},
+{\tt amd\_aat.c},
+{\tt and\_order.c},
+{\tt amd\_postorder.c},
+{\tt amd\_post\_tree.c},
+{\tt amd\_valid.c},
+and
+{\tt amd\_internal.h},
+in the {\tt Source} directory.
+
+%------------------------------------------------------------------------------
+\newpage
+\section{The AMD routines}
+\label{Primary}
+%------------------------------------------------------------------------------
+
+The file {\tt AMD/Include/amd.h} listed below
+describes each user-callable routine in the C version of AMD,
+and gives details on their use.
+
+{\footnotesize
+\begin{verbatim}
+/* ========================================================================= */
+/* === AMD: approximate minimum degree ordering =========================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* AMD finds a symmetric ordering P of a matrix A so that the Cholesky
+ * factorization of P*A*P' has fewer nonzeros and takes less work than the
+ * Cholesky factorization of A. If A is not symmetric, then it performs its
+ * ordering on the matrix A+A'. Two sets of user-callable routines are
+ * provided, one for "int" integers and the other for "long" integers.
+ *
+ * The method is based on the approximate minimum degree algorithm, discussed
+ * in Amestoy, Davis, and Duff, "An approximate degree ordering algorithm",
+ * SIAM Journal of Matrix Analysis and Applications, vol. 17, no. 4, pp.
+ * 886-905, 1996. This package can perform both the AMD ordering (with
+ * aggressive absorption), and the AMDBAR ordering (without aggressive
+ * absorption) discussed in the above paper. This package differs from the
+ * Fortran codes discussed in the paper:
+ *
+ * (1) it can ignore "dense" rows and columns, leading to faster run times
+ * (2) it computes the ordering of A+A' if A is not symmetric
+ * (3) it is followed by a depth-first post-ordering of the assembly tree
+ * (or supernodal elimination tree)
+ *
+ * For historical reasons, the Fortran versions, amd.f and amdbar.f, have
+ * been left (nearly) unchanged. They compute the identical ordering as
+ * described in the above paper.
+ */
+
+#ifndef AMD_H
+#define AMD_H
+
+int amd_order ( /* returns 0 if OK, negative value if error */
+ int n, /* A is n-by-n. n must be >= 0. */
+ const int Ap [ ], /* column pointers for A, of size n+1 */
+ const int Ai [ ], /* row indices of A, of size nz = Ap [n] */
+ int P [ ], /* output permutation, of size n */
+ double Control [ ], /* input Control settings, of size AMD_CONTROL */
+ double Info [ ] /* output Info statistics, of size AMD_INFO */
+) ;
+
+long amd_l_order ( /* see above for description of arguments */
+ long n,
+ const long Ap [ ],
+ const long Ai [ ],
+ long P [ ],
+ double Control [ ],
+ double Info [ ]
+) ;
+
+/* Input arguments (not modified):
+ *
+ * n: the matrix A is n-by-n.
+ * Ap: an int/long array of size n+1, containing the column pointers of A.
+ * Ai: an int/long array of size nz, containing the row indices of A,
+ * where nz = Ap [n].
+ * Control: a double array of size AMD_CONTROL, containing control
+ * parameters. Defaults are used if Control is NULL.
+ *
+ * Output arguments (not defined on input):
+ *
+ * P: an int/long array of size n, containing the output permutation. If
+ * row i is the kth pivot row, then P [k] = i. In MATLAB notation,
+ * the reordered matrix is A (P,P).
+ * Info: a double array of size AMD_INFO, containing statistical
+ * information. Ignored if Info is NULL.
+ *
+ * On input, the matrix A is stored in column-oriented form. The row indices
+ * of nonzero entries in column j are stored in Ai [Ap [j] ... Ap [j+1]-1].
+ * The row indices must appear in ascending order in each column, and there
+ * must not be any duplicate entries. Row indices must be in the range 0 to
+ * n-1. Ap [0] must be zero, and thus nz = Ap [n] is the number of nonzeros
+ * in A. The array Ap is of size n+1, and the array Ai is of size nz = Ap [n].
+ * The matrix does not need to be symmetric, and the diagonal does not need to
+ * be present (if diagonal entries are present, they are ignored except for
+ * the output statistic Info [AMD_NZDIAG]). The arrays Ai and Ap are not
+ * modified. This form of the Ap and Ai arrays to represent the nonzero
+ * pattern of the matrix A is the same as that used internally by MATLAB.
+ * If you wish to use a more flexible input structure, please see the
+ * umfpack_*_triplet_to_col routines in the UMFPACK package, at
+ * http://www.cise.ufl.edu/research/sparse/umfpack, or use the amd_preprocess
+ * routine discussed below.
+ *
+ * Restrictions: n >= 0. Ap [0] = 0. Ap [j] <= Ap [j+1] for all j in the
+ * range 0 to n-1. nz = Ap [n] >= 0. For all j in the range 0 to n-1,
+ * and for all p in the range Ap [j] to Ap [j+1]-2, Ai [p] < Ai [p+1] must
+ * hold. Ai [0..nz-1] must be in the range 0 to n-1. To avoid integer
+ * overflow, (2.4*nz + 8*n) < INT_MAX / sizeof (int) for must hold for the
+ * "int" version. (2.4*nz + 8*n) < LONG_MAX / sizeof (long) must hold
+ * for the "long" version. Finally, Ai, Ap, and P must not be NULL. If
+ * any of these restrictions are not met, AMD returns AMD_INVALID.
+ *
+ * AMD returns:
+ *
+ * AMD_OK if the matrix is valid and sufficient memory can be allocated to
+ * perform the ordering.
+ *
+ * AMD_OUT_OF_MEMORY if not enough memory can be allocated.
+ *
+ * AMD_INVALID if the input arguments n, Ap, Ai are invalid, or if P is
+ * NULL.
+ *
+ * The AMD routine first forms the pattern of the matrix A+A', and then
+ * computes a fill-reducing ordering, P. If P [k] = i, then row/column i of
+ * the original is the kth pivotal row. In MATLAB notation, the permuted
+ * matrix is A (P,P), except that 0-based indexing is used instead of the
+ * 1-based indexing in MATLAB.
+ *
+ * The Control array is used to set various parameters for AMD. If a NULL
+ * pointer is passed, default values are used. The Control array is not
+ * modified.
+ *
+ * Control [AMD_DENSE]: controls the threshold for "dense" rows/columns.
+ * A dense row/column in A+A' can cause AMD to spend a lot of time in
+ * ordering the matrix. If Control [AMD_DENSE] >= 0, rows/columns
+ * with more than Control [AMD_DENSE] * sqrt (n) entries are ignored
+ * during the ordering, and placed last in the output order. The
+ * default value of Control [AMD_DENSE] is 10. If negative, no
+ * rows/columns are treated as "dense". Rows/columns with 16 or
+ * fewer off-diagonal entries are never considered "dense".
+ *
+ * Control [AMD_AGGRESSIVE]: controls whether or not to use aggressive
+ * absorption, in which a prior element is absorbed into the current
+ * element if is a subset of the current element, even if it is not
+ * adjacent to the current pivot element (refer to Amestoy, Davis,
+ * & Duff, 1996, for more details). The default value is nonzero,
+ * which means to perform aggressive absorption. This nearly always
+ * leads to a better ordering (because the approximate degrees are
+ * more accurate) and a lower execution time. There are cases where
+ * it can lead to a slightly worse ordering, however. To turn it off,
+ * set Control [AMD_AGGRESSIVE] to 0.
+ *
+ * Control [2..4] are not used in the current version, but may be used in
+ * future versions.
+ *
+ * The Info array provides statistics about the ordering on output. If it is
+ * not present, the statistics are not returned. This is not an error
+ * condition.
+ *
+ * Info [AMD_STATUS]: the return value of AMD, either AMD_OK,
+ * AMD_OUT_OF_MEMORY, or AMD_INVALID.
+ *
+ * Info [AMD_N]: n, the size of the input matrix
+ *
+ * Info [AMD_NZ]: the number of nonzeros in A, nz = Ap [n]
+ *
+ * Info [AMD_SYMMETRY]: the symmetry of the matrix A. It is the number
+ * of "matched" off-diagonal entries divided by the total number of
+ * off-diagonal entries. An entry A(i,j) is matched if A(j,i) is also
+ * an entry, for any pair (i,j) for which i != j. In MATLAB notation,
+ * S = spones (A) ;
+ * B = tril (S, -1) + triu (S, 1) ;
+ * symmetry = nnz (B & B') / nnz (B) ;
+ *
+ * Info [AMD_NZDIAG]: the number of entries on the diagonal of A.
+ *
+ * Info [AMD_NZ_A_PLUS_AT]: the number of nonzeros in A+A', excluding the
+ * diagonal. If A is perfectly symmetric (Info [AMD_SYMMETRY] = 1)
+ * with a fully nonzero diagonal, then Info [AMD_NZ_A_PLUS_AT] = nz-n
+ * (the smallest possible value). If A is perfectly unsymmetric
+ * (Info [AMD_SYMMETRY] = 0, for an upper triangular matrix, for
+ * example) with no diagonal, then Info [AMD_NZ_A_PLUS_AT] = 2*nz
+ * (the largest possible value).
+ *
+ * Info [AMD_NDENSE]: the number of "dense" rows/columns of A+A' that were
+ * removed from A prior to ordering. These are placed last in the
+ * output order P.
+ *
+ * Info [AMD_MEMORY]: the amount of memory used by AMD, in bytes. In the
+ * current version, this is 1.2 * Info [AMD_NZ_A_PLUS_AT] + 9*n
+ * times the size of an integer. This is at most 2.4nz + 9n. This
+ * excludes the size of the input arguments Ai, Ap, and P, which have
+ * a total size of nz + 2*n + 1 integers.
+ *
+ * Info [AMD_NCMPA]: the number of garbage collections performed.
+ *
+ * Info [AMD_LNZ]: the number of nonzeros in L (excluding the diagonal).
+ * This is a slight upper bound because mass elimination is combined
+ * with the approximate degree update. It is a rough upper bound if
+ * there are many "dense" rows/columns. The rest of the statistics,
+ * below, are also slight or rough upper bounds, for the same reasons.
+ * The post-ordering of the assembly tree might also not exactly
+ * correspond to a true elimination tree postordering.
+ *
+ * Info [AMD_NDIV]: the number of divide operations for a subsequent LDL'
+ * or LU factorization of the permuted matrix A (P,P).
+ *
+ * Info [AMD_NMULTSUBS_LDL]: the number of multiply-subtract pairs for a
+ * subsequent LDL' factorization of A (P,P).
+ *
+ * Info [AMD_NMULTSUBS_LU]: the number of multiply-subtract pairs for a
+ * subsequent LU factorization of A (P,P), assuming that no numerical
+ * pivoting is required.
+ *
+ * Info [AMD_DMAX]: the maximum number of nonzeros in any column of L,
+ * including the diagonal.
+ *
+ * Info [14..19] are not used in the current version, but may be used in
+ * future versions.
+ */
+
+/* ------------------------------------------------------------------------- */
+/* AMD preprocess */
+/* ------------------------------------------------------------------------- */
+
+/* amd_preprocess: sorts, removes duplicate entries, and transposes the
+ * nonzero pattern of a column-form matrix A, to obtain the matrix R.
+ *
+ * Alternatively, you can consider this routine as constructing a row-form
+ * matrix from a column-form matrix. Duplicate entries are allowed in A (and
+ * removed in R). The columns of R are sorted. Checks its input A for errors.
+ *
+ * On input, A can have unsorted columns, and can have duplicate entries.
+ * Ap [0] must still be zero, and Ap must be monotonically nondecreasing.
+ * Row indices must be in the range 0 to n-1.
+ *
+ * On output, if this routine returns AMD_OK, then the matrix R is a valid
+ * input matrix for AMD_order. It has sorted columns, with no duplicate
+ * entries in each column. Since AMD_order operates on the matrix A+A', it
+ * can just as easily use A or A', so the transpose has no significant effect
+ * (except for minor tie-breaking, which can lead to a minor effect in the
+ * quality of the ordering). As an example, compare the output of amd_demo.c
+ * and amd_demo2.c.
+ *
+ * This routine transposes A to get R because that's the simplest way to
+ * sort and remove duplicate entries from a matrix.
+ *
+ * Allocates 2*n integer work arrays, and free's them when done.
+ *
+ * If you wish to call amd_order, but do not know if your matrix has unsorted
+ * columns or duplicate entries, then you can use the following code, which is
+ * fairly efficient. amd_order will not allocate any internal matrix until
+ * it checks that the input matrix is valid, so the method below is memory-
+ * efficient as well. This code snippet assumes that Rp and Ri are already
+ * allocated, and are the same size as Ap and Ai respectively.
+
+ result = amd_order (n, p, Ap, Ai, Control, Info) ;
+ if (result == AMD_INVALID)
+ {
+ if (amd_preprocess (n, Ap, Ai, Rp, Ri) == AMD_OK)
+ {
+ result = amd_order (n, p, Rp, Ri, Control, Info) ;
+ }
+ }
+
+ * amd_preprocess will still return AMD_INVALID if any row index in Ai is out
+ * of range or if the Ap array is invalid. These errors are not corrected by
+ * amd_preprocess since they represent a more serious error that should be
+ * flagged with the AMD_INVALID error code.
+ */
+
+int amd_preprocess
+(
+ int n,
+ const int Ap [ ],
+ const int Ai [ ],
+ int Rp [ ],
+ int Ri [ ]
+) ;
+
+long amd_l_preprocess
+(
+ long n,
+ const long Ap [ ],
+ const long Ai [ ],
+ long Rp [ ],
+ long Ri [ ]
+) ;
+
+/* Input arguments (not modified):
+ *
+ * n: the matrix A is n-by-n.
+ * Ap: an int/long array of size n+1, containing the column pointers of A.
+ * Ai: an int/long array of size nz, containing the row indices of A,
+ * where nz = Ap [n].
+ * The nonzero pattern of column j of A is in Ai [Ap [j] ... Ap [j+1]-1].
+ * Ap [0] must be zero, and Ap [j] <= Ap [j+1] must hold for all j in the
+ * range 0 to n-1. Row indices in Ai must be in the range 0 to n-1.
+ * The row indices in any one column need not be sorted, and duplicates
+ * may exist.
+ *
+ * Output arguments (not defined on input):
+ *
+ * Rp: an int/long array of size n+1, containing the column pointers of R.
+ * Ri: an int/long array of size rnz, containing the row indices of R,
+ * where rnz = Rp [n]. Note that Rp [n] will be less than Ap [n] if
+ * duplicates appear in A. In general, Rp [n] <= Ap [n].
+ * The data structure for R is the same as A, except that each column of
+ * R contains sorted row indices, and no duplicates appear in any column.
+ *
+ * amd_preprocess returns:
+ *
+ * AMD_OK if the matrix A is valid and sufficient memory can be allocated
+ * to perform the preprocessing.
+ *
+ * AMD_OUT_OF_MEMORY if not enough memory can be allocated.
+ *
+ * AMD_INVALID if the input arguments n, Ap, Ai are invalid, or if Rp or
+ * Ri are NULL.
+ */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Control and Info arrays */
+/* ------------------------------------------------------------------------- */
+
+/* amd_defaults: sets the default control settings */
+void amd_defaults (double Control [ ]) ;
+void amd_l_defaults (double Control [ ]) ;
+
+/* amd_control: prints the control settings */
+void amd_control (double Control [ ]) ;
+void amd_l_control (double Control [ ]) ;
+
+/* amd_info: prints the statistics */
+void amd_info (double Info [ ]) ;
+void amd_l_info (double Info [ ]) ;
+
+#define AMD_CONTROL 5 /* size of Control array */
+#define AMD_INFO 20 /* size of Info array */
+
+/* contents of Control */
+#define AMD_DENSE 0 /* "dense" if degree > Control [0] * sqrt (n) */
+#define AMD_AGGRESSIVE 1 /* do aggressive absorption if Control [1] != 0 */
+
+/* default Control settings */
+#define AMD_DEFAULT_DENSE 10.0 /* default "dense" degree 10*sqrt(n) */
+#define AMD_DEFAULT_AGGRESSIVE 1 /* do aggressive absorption by default */
+
+/* contents of Info */
+#define AMD_STATUS 0 /* return value of amd_order and amd_l_order */
+#define AMD_N 1 /* A is n-by-n */
+#define AMD_NZ 2 /* number of nonzeros in A */
+#define AMD_SYMMETRY 3 /* symmetry of pattern (1 is sym., 0 is unsym.) */
+#define AMD_NZDIAG 4 /* # of entries on diagonal */
+#define AMD_NZ_A_PLUS_AT 5 /* nz in A+A' */
+#define AMD_NDENSE 6 /* number of "dense" rows/columns in A */
+#define AMD_MEMORY 7 /* amount of memory used by AMD */
+#define AMD_NCMPA 8 /* number of garbage collections in AMD */
+#define AMD_LNZ 9 /* approx. nz in L, excluding the diagonal */
+#define AMD_NDIV 10 /* number of fl. point divides for LU and LDL' */
+#define AMD_NMULTSUBS_LDL 11 /* number of fl. point (*,-) pairs for LDL' */
+#define AMD_NMULTSUBS_LU 12 /* number of fl. point (*,-) pairs for LU */
+#define AMD_DMAX 13 /* max nz. in any column of L, incl. diagonal */
+
+/* ------------------------------------------------------------------------- */
+/* return values of AMD */
+/* ------------------------------------------------------------------------- */
+
+#define AMD_OK 0 /* success */
+#define AMD_OUT_OF_MEMORY -1 /* malloc failed */
+#define AMD_INVALID -2 /* input arguments are not valid */
+
+#endif
+\end{verbatim}
+}
+
+%------------------------------------------------------------------------------
+\newpage
+% References
+%------------------------------------------------------------------------------
+
+\bibliographystyle{plain}
+\bibliography{AMD_UserGuide}
+
+\end{document}
--- /dev/null
+Jan. 21, 2004: AMD Version 1.1
+
+ * No bugs found or fixed - new features added, only
+ * amd_preprocess added, to allow for more general input of the matrix A.
+ * ME=0 added to amd*.f, unused DEXT variable removed from amdbar.f,
+ to avoid spurious compiler warnings (this was not a bug).
+ * amd_demo2.c and amd_demo2.out added, to test/demo amd_preprocess.
+ * option to allow compile-time redefinition of malloc, free, printf added
+ * amd_demo.c shortened slightly (removed printing of PAP')
+ * User Guide modified (more details added)
+ * linewidth reduced from 80 to 79 columns
+
+Oct. 7, 2003: AMD version 1.0.1.
+
+ * MATLAB mexFunction modified, to remove call to mexCallMATLAB function.
+ This function can take a long time to call, particularly if you are
+ ordering many small matrices.
+
+May 6, 2003: AMD Version 1.0 released.
+
+ * converted to C (compare amd.f and amdbar.f with amd_2.c)
+ * dense rows/column removed prior to ordering
+ * elimination tree post-ordering added
+ * demos, user guide written
+ * statistics added (nz in L, flop count, symmetry of A)
+ * computes the pattern of A+A' if A is unsymmetric
+ * user's input matrix no longer overwritten
+ * degree lists initialized differently
+ * IOVFLO argument removed from Fortran versions (amd.f and amdbar.f)
+ * parameters added (dense row/column detection, aggressive absorption)
+ * MATLAB mexFunction added
+
+Jan, 1996:
+
+ * amdbar.f posted at http://www.netlib.org (with a restricted License)
+ * amd.f appears as MC47B/BD in the Harwell Subroutine Library
+ (without the IOVFLO argument)
--- /dev/null
+AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A.
+Davis, Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved.
+
+AMD License:
+
+ Your use or distribution of AMD or any modified version of
+ AMD implies that you agree to this License.
+
+ THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+ EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+
+ Permission is hereby granted to use or copy this program, provided
+ that the Copyright, this License, and the Availability of the original
+ version is retained on all copies. User documentation of any code that
+ uses AMD or any modified version of AMD code must cite the
+ Copyright, this License, the Availability note, and "Used by permission."
+ Permission to modify the code and to distribute modified code is granted,
+ provided the Copyright, this License, and the Availability note are
+ retained, and a notice that the code was modified is included. This
+ software was developed with support from the National Science Foundation,
+ and is provided to you free of charge.
+
+Availability:
+
+ http://www.cise.ufl.edu/research/sparse/amd
--- /dev/null
+#------------------------------------------------------------------------------
+# AMD Makefile for compiling on Unix systems (for GNU or original make)
+#------------------------------------------------------------------------------
+
+all: dist
+
+include ../Make/Make.include
+
+#------------------------------------------------------------------------------
+# Remove all but the files in the original distribution
+#------------------------------------------------------------------------------
+
+purge: clean
+ - $(RM) *.aux *.bbl *.blg *.log *.toc
+
+#------------------------------------------------------------------------------
+# Create the User Guide and Quick Start Guide
+#------------------------------------------------------------------------------
+
+AMD_UserGuide.pdf: AMD_UserGuide.tex AMD_UserGuide.bib
+ pdflatex AMD_UserGuide
+ bibtex AMD_UserGuide
+ pdflatex AMD_UserGuide
+ pdflatex AMD_UserGuide
+
+dist: AMD_UserGuide.pdf
+ - $(RM) *.aux *.bbl *.blg *.log *.toc
+
--- /dev/null
+/* ========================================================================= */
+/* === AMD: approximate minimum degree ordering =========================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* AMD finds a symmetric ordering P of a matrix A so that the Cholesky
+ * factorization of P*A*P' has fewer nonzeros and takes less work than the
+ * Cholesky factorization of A. If A is not symmetric, then it performs its
+ * ordering on the matrix A+A'. Two sets of user-callable routines are
+ * provided, one for "int" integers and the other for "long" integers.
+ *
+ * The method is based on the approximate minimum degree algorithm, discussed
+ * in Amestoy, Davis, and Duff, "An approximate degree ordering algorithm",
+ * SIAM Journal of Matrix Analysis and Applications, vol. 17, no. 4, pp.
+ * 886-905, 1996. This package can perform both the AMD ordering (with
+ * aggressive absorption), and the AMDBAR ordering (without aggressive
+ * absorption) discussed in the above paper. This package differs from the
+ * Fortran codes discussed in the paper:
+ *
+ * (1) it can ignore "dense" rows and columns, leading to faster run times
+ * (2) it computes the ordering of A+A' if A is not symmetric
+ * (3) it is followed by a depth-first post-ordering of the assembly tree
+ * (or supernodal elimination tree)
+ *
+ * For historical reasons, the Fortran versions, amd.f and amdbar.f, have
+ * been left (nearly) unchanged. They compute the identical ordering as
+ * described in the above paper.
+ */
+
+#ifndef AMD_H
+#define AMD_H
+
+int amd_order ( /* returns 0 if OK, negative value if error */
+ int n, /* A is n-by-n. n must be >= 0. */
+ const int Ap [ ], /* column pointers for A, of size n+1 */
+ const int Ai [ ], /* row indices of A, of size nz = Ap [n] */
+ int P [ ], /* output permutation, of size n */
+ double Control [ ], /* input Control settings, of size AMD_CONTROL */
+ double Info [ ] /* output Info statistics, of size AMD_INFO */
+) ;
+
+long amd_l_order ( /* see above for description of arguments */
+ long n,
+ const long Ap [ ],
+ const long Ai [ ],
+ long P [ ],
+ double Control [ ],
+ double Info [ ]
+) ;
+
+/* Input arguments (not modified):
+ *
+ * n: the matrix A is n-by-n.
+ * Ap: an int/long array of size n+1, containing the column pointers of A.
+ * Ai: an int/long array of size nz, containing the row indices of A,
+ * where nz = Ap [n].
+ * Control: a double array of size AMD_CONTROL, containing control
+ * parameters. Defaults are used if Control is NULL.
+ *
+ * Output arguments (not defined on input):
+ *
+ * P: an int/long array of size n, containing the output permutation. If
+ * row i is the kth pivot row, then P [k] = i. In MATLAB notation,
+ * the reordered matrix is A (P,P).
+ * Info: a double array of size AMD_INFO, containing statistical
+ * information. Ignored if Info is NULL.
+ *
+ * On input, the matrix A is stored in column-oriented form. The row indices
+ * of nonzero entries in column j are stored in Ai [Ap [j] ... Ap [j+1]-1].
+ * The row indices must appear in ascending order in each column, and there
+ * must not be any duplicate entries. Row indices must be in the range 0 to
+ * n-1. Ap [0] must be zero, and thus nz = Ap [n] is the number of nonzeros
+ * in A. The array Ap is of size n+1, and the array Ai is of size nz = Ap [n].
+ * The matrix does not need to be symmetric, and the diagonal does not need to
+ * be present (if diagonal entries are present, they are ignored except for
+ * the output statistic Info [AMD_NZDIAG]). The arrays Ai and Ap are not
+ * modified. This form of the Ap and Ai arrays to represent the nonzero
+ * pattern of the matrix A is the same as that used internally by MATLAB.
+ * If you wish to use a more flexible input structure, please see the
+ * umfpack_*_triplet_to_col routines in the UMFPACK package, at
+ * http://www.cise.ufl.edu/research/sparse/umfpack, or use the amd_preprocess
+ * routine discussed below.
+ *
+ * Restrictions: n >= 0. Ap [0] = 0. Ap [j] <= Ap [j+1] for all j in the
+ * range 0 to n-1. nz = Ap [n] >= 0. For all j in the range 0 to n-1,
+ * and for all p in the range Ap [j] to Ap [j+1]-2, Ai [p] < Ai [p+1] must
+ * hold. Ai [0..nz-1] must be in the range 0 to n-1. To avoid integer
+ * overflow, (2.4*nz + 8*n) < INT_MAX / sizeof (int) for must hold for the
+ * "int" version. (2.4*nz + 8*n) < LONG_MAX / sizeof (long) must hold
+ * for the "long" version. Finally, Ai, Ap, and P must not be NULL. If
+ * any of these restrictions are not met, AMD returns AMD_INVALID.
+ *
+ * AMD returns:
+ *
+ * AMD_OK if the matrix is valid and sufficient memory can be allocated to
+ * perform the ordering.
+ *
+ * AMD_OUT_OF_MEMORY if not enough memory can be allocated.
+ *
+ * AMD_INVALID if the input arguments n, Ap, Ai are invalid, or if P is
+ * NULL.
+ *
+ * The AMD routine first forms the pattern of the matrix A+A', and then
+ * computes a fill-reducing ordering, P. If P [k] = i, then row/column i of
+ * the original is the kth pivotal row. In MATLAB notation, the permuted
+ * matrix is A (P,P), except that 0-based indexing is used instead of the
+ * 1-based indexing in MATLAB.
+ *
+ * The Control array is used to set various parameters for AMD. If a NULL
+ * pointer is passed, default values are used. The Control array is not
+ * modified.
+ *
+ * Control [AMD_DENSE]: controls the threshold for "dense" rows/columns.
+ * A dense row/column in A+A' can cause AMD to spend a lot of time in
+ * ordering the matrix. If Control [AMD_DENSE] >= 0, rows/columns
+ * with more than Control [AMD_DENSE] * sqrt (n) entries are ignored
+ * during the ordering, and placed last in the output order. The
+ * default value of Control [AMD_DENSE] is 10. If negative, no
+ * rows/columns are treated as "dense". Rows/columns with 16 or
+ * fewer off-diagonal entries are never considered "dense".
+ *
+ * Control [AMD_AGGRESSIVE]: controls whether or not to use aggressive
+ * absorption, in which a prior element is absorbed into the current
+ * element if is a subset of the current element, even if it is not
+ * adjacent to the current pivot element (refer to Amestoy, Davis,
+ * & Duff, 1996, for more details). The default value is nonzero,
+ * which means to perform aggressive absorption. This nearly always
+ * leads to a better ordering (because the approximate degrees are
+ * more accurate) and a lower execution time. There are cases where
+ * it can lead to a slightly worse ordering, however. To turn it off,
+ * set Control [AMD_AGGRESSIVE] to 0.
+ *
+ * Control [2..4] are not used in the current version, but may be used in
+ * future versions.
+ *
+ * The Info array provides statistics about the ordering on output. If it is
+ * not present, the statistics are not returned. This is not an error
+ * condition.
+ *
+ * Info [AMD_STATUS]: the return value of AMD, either AMD_OK,
+ * AMD_OUT_OF_MEMORY, or AMD_INVALID.
+ *
+ * Info [AMD_N]: n, the size of the input matrix
+ *
+ * Info [AMD_NZ]: the number of nonzeros in A, nz = Ap [n]
+ *
+ * Info [AMD_SYMMETRY]: the symmetry of the matrix A. It is the number
+ * of "matched" off-diagonal entries divided by the total number of
+ * off-diagonal entries. An entry A(i,j) is matched if A(j,i) is also
+ * an entry, for any pair (i,j) for which i != j. In MATLAB notation,
+ * S = spones (A) ;
+ * B = tril (S, -1) + triu (S, 1) ;
+ * symmetry = nnz (B & B') / nnz (B) ;
+ *
+ * Info [AMD_NZDIAG]: the number of entries on the diagonal of A.
+ *
+ * Info [AMD_NZ_A_PLUS_AT]: the number of nonzeros in A+A', excluding the
+ * diagonal. If A is perfectly symmetric (Info [AMD_SYMMETRY] = 1)
+ * with a fully nonzero diagonal, then Info [AMD_NZ_A_PLUS_AT] = nz-n
+ * (the smallest possible value). If A is perfectly unsymmetric
+ * (Info [AMD_SYMMETRY] = 0, for an upper triangular matrix, for
+ * example) with no diagonal, then Info [AMD_NZ_A_PLUS_AT] = 2*nz
+ * (the largest possible value).
+ *
+ * Info [AMD_NDENSE]: the number of "dense" rows/columns of A+A' that were
+ * removed from A prior to ordering. These are placed last in the
+ * output order P.
+ *
+ * Info [AMD_MEMORY]: the amount of memory used by AMD, in bytes. In the
+ * current version, this is 1.2 * Info [AMD_NZ_A_PLUS_AT] + 9*n
+ * times the size of an integer. This is at most 2.4nz + 9n. This
+ * excludes the size of the input arguments Ai, Ap, and P, which have
+ * a total size of nz + 2*n + 1 integers.
+ *
+ * Info [AMD_NCMPA]: the number of garbage collections performed.
+ *
+ * Info [AMD_LNZ]: the number of nonzeros in L (excluding the diagonal).
+ * This is a slight upper bound because mass elimination is combined
+ * with the approximate degree update. It is a rough upper bound if
+ * there are many "dense" rows/columns. The rest of the statistics,
+ * below, are also slight or rough upper bounds, for the same reasons.
+ * The post-ordering of the assembly tree might also not exactly
+ * correspond to a true elimination tree postordering.
+ *
+ * Info [AMD_NDIV]: the number of divide operations for a subsequent LDL'
+ * or LU factorization of the permuted matrix A (P,P).
+ *
+ * Info [AMD_NMULTSUBS_LDL]: the number of multiply-subtract pairs for a
+ * subsequent LDL' factorization of A (P,P).
+ *
+ * Info [AMD_NMULTSUBS_LU]: the number of multiply-subtract pairs for a
+ * subsequent LU factorization of A (P,P), assuming that no numerical
+ * pivoting is required.
+ *
+ * Info [AMD_DMAX]: the maximum number of nonzeros in any column of L,
+ * including the diagonal.
+ *
+ * Info [14..19] are not used in the current version, but may be used in
+ * future versions.
+ */
+
+/* ------------------------------------------------------------------------- */
+/* AMD preprocess */
+/* ------------------------------------------------------------------------- */
+
+/* amd_preprocess: sorts, removes duplicate entries, and transposes the
+ * nonzero pattern of a column-form matrix A, to obtain the matrix R.
+ *
+ * Alternatively, you can consider this routine as constructing a row-form
+ * matrix from a column-form matrix. Duplicate entries are allowed in A (and
+ * removed in R). The columns of R are sorted. Checks its input A for errors.
+ *
+ * On input, A can have unsorted columns, and can have duplicate entries.
+ * Ap [0] must still be zero, and Ap must be monotonically nondecreasing.
+ * Row indices must be in the range 0 to n-1.
+ *
+ * On output, if this routine returns AMD_OK, then the matrix R is a valid
+ * input matrix for AMD_order. It has sorted columns, with no duplicate
+ * entries in each column. Since AMD_order operates on the matrix A+A', it
+ * can just as easily use A or A', so the transpose has no significant effect
+ * (except for minor tie-breaking, which can lead to a minor effect in the
+ * quality of the ordering). As an example, compare the output of amd_demo.c
+ * and amd_demo2.c.
+ *
+ * This routine transposes A to get R because that's the simplest way to
+ * sort and remove duplicate entries from a matrix.
+ *
+ * Allocates 2*n integer work arrays, and free's them when done.
+ *
+ * If you wish to call amd_order, but do not know if your matrix has unsorted
+ * columns or duplicate entries, then you can use the following code, which is
+ * fairly efficient. amd_order will not allocate any internal matrix until
+ * it checks that the input matrix is valid, so the method below is memory-
+ * efficient as well. This code snippet assumes that Rp and Ri are already
+ * allocated, and are the same size as Ap and Ai respectively.
+
+ result = amd_order (n, p, Ap, Ai, Control, Info) ;
+ if (result == AMD_INVALID)
+ {
+ if (amd_preprocess (n, Ap, Ai, Rp, Ri) == AMD_OK)
+ {
+ result = amd_order (n, p, Rp, Ri, Control, Info) ;
+ }
+ }
+
+ * amd_preprocess will still return AMD_INVALID if any row index in Ai is out
+ * of range or if the Ap array is invalid. These errors are not corrected by
+ * amd_preprocess since they represent a more serious error that should be
+ * flagged with the AMD_INVALID error code.
+ */
+
+int amd_preprocess
+(
+ int n,
+ const int Ap [ ],
+ const int Ai [ ],
+ int Rp [ ],
+ int Ri [ ]
+) ;
+
+long amd_l_preprocess
+(
+ long n,
+ const long Ap [ ],
+ const long Ai [ ],
+ long Rp [ ],
+ long Ri [ ]
+) ;
+
+/* Input arguments (not modified):
+ *
+ * n: the matrix A is n-by-n.
+ * Ap: an int/long array of size n+1, containing the column pointers of A.
+ * Ai: an int/long array of size nz, containing the row indices of A,
+ * where nz = Ap [n].
+ * The nonzero pattern of column j of A is in Ai [Ap [j] ... Ap [j+1]-1].
+ * Ap [0] must be zero, and Ap [j] <= Ap [j+1] must hold for all j in the
+ * range 0 to n-1. Row indices in Ai must be in the range 0 to n-1.
+ * The row indices in any one column need not be sorted, and duplicates
+ * may exist.
+ *
+ * Output arguments (not defined on input):
+ *
+ * Rp: an int/long array of size n+1, containing the column pointers of R.
+ * Ri: an int/long array of size rnz, containing the row indices of R,
+ * where rnz = Rp [n]. Note that Rp [n] will be less than Ap [n] if
+ * duplicates appear in A. In general, Rp [n] <= Ap [n].
+ * The data structure for R is the same as A, except that each column of
+ * R contains sorted row indices, and no duplicates appear in any column.
+ *
+ * amd_preprocess returns:
+ *
+ * AMD_OK if the matrix A is valid and sufficient memory can be allocated
+ * to perform the preprocessing.
+ *
+ * AMD_OUT_OF_MEMORY if not enough memory can be allocated.
+ *
+ * AMD_INVALID if the input arguments n, Ap, Ai are invalid, or if Rp or
+ * Ri are NULL.
+ */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Control and Info arrays */
+/* ------------------------------------------------------------------------- */
+
+/* amd_defaults: sets the default control settings */
+void amd_defaults (double Control [ ]) ;
+void amd_l_defaults (double Control [ ]) ;
+
+/* amd_control: prints the control settings */
+void amd_control (double Control [ ]) ;
+void amd_l_control (double Control [ ]) ;
+
+/* amd_info: prints the statistics */
+void amd_info (double Info [ ]) ;
+void amd_l_info (double Info [ ]) ;
+
+#define AMD_CONTROL 5 /* size of Control array */
+#define AMD_INFO 20 /* size of Info array */
+
+/* contents of Control */
+#define AMD_DENSE 0 /* "dense" if degree > Control [0] * sqrt (n) */
+#define AMD_AGGRESSIVE 1 /* do aggressive absorption if Control [1] != 0 */
+
+/* default Control settings */
+#define AMD_DEFAULT_DENSE 10.0 /* default "dense" degree 10*sqrt(n) */
+#define AMD_DEFAULT_AGGRESSIVE 1 /* do aggressive absorption by default */
+
+/* contents of Info */
+#define AMD_STATUS 0 /* return value of amd_order and amd_l_order */
+#define AMD_N 1 /* A is n-by-n */
+#define AMD_NZ 2 /* number of nonzeros in A */
+#define AMD_SYMMETRY 3 /* symmetry of pattern (1 is sym., 0 is unsym.) */
+#define AMD_NZDIAG 4 /* # of entries on diagonal */
+#define AMD_NZ_A_PLUS_AT 5 /* nz in A+A' */
+#define AMD_NDENSE 6 /* number of "dense" rows/columns in A */
+#define AMD_MEMORY 7 /* amount of memory used by AMD */
+#define AMD_NCMPA 8 /* number of garbage collections in AMD */
+#define AMD_LNZ 9 /* approx. nz in L, excluding the diagonal */
+#define AMD_NDIV 10 /* number of fl. point divides for LU and LDL' */
+#define AMD_NMULTSUBS_LDL 11 /* number of fl. point (*,-) pairs for LDL' */
+#define AMD_NMULTSUBS_LU 12 /* number of fl. point (*,-) pairs for LU */
+#define AMD_DMAX 13 /* max nz. in any column of L, incl. diagonal */
+
+/* ------------------------------------------------------------------------- */
+/* return values of AMD */
+/* ------------------------------------------------------------------------- */
+
+#define AMD_OK 0 /* success */
+#define AMD_OUT_OF_MEMORY -1 /* malloc failed */
+#define AMD_INVALID -2 /* input arguments are not valid */
+
+#endif
--- /dev/null
+%Contents of the AMD sparse matrix ordering package:
+%
+% amd p = amd (A), the approximate minimum degree ordering of A
+% amd_demo a demo of amd, using the can_24 matrix
+% amd_make to comple amd for use in MATLAB
+% can_24.mat a sample sparse matrix from the Harwell/Boeing collection
+%
+% See also: amd, colamd, symamd, colmmd, symmmd, umfpack
+%
+% AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,
+% Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved.
+
+help Contents
--- /dev/null
+#------------------------------------------------------------------------------
+# GNUmakefile for the AMD MATLAB mexFunction
+#------------------------------------------------------------------------------
+
+all: amd
+
+include ../Make/Make.include
+
+MX = $(MEX) -I../Include
+
+AMD = amd_aat amd_1 amd_2 amd_dump amd_postorder amd_post_tree amd_defaults \
+ amd_order amd_control amd_info amd_valid
+
+INC = ../Include/amd.h ../Source/amd_internal.h
+
+MEXAMD = $(addsuffix .o, $(subst amd_,amd_m_,$(AMD)))
+
+amd_m_%.o: ../Source/amd_%.c $(INC)
+ $(MX) -DDINT -c $<
+ - $(MV) amd_$*.o $@
+
+amd: amd_mex.c $(MEXAMD) $(INC)
+ $(MX) -output amd amd_mex.c $(MEXAMD)
+
+#------------------------------------------------------------------------------
+# Remove all but the files in the original distribution
+#------------------------------------------------------------------------------
+
+purge: clean
+ - $(RM) amd.mex* amd.dll
--- /dev/null
+#------------------------------------------------------------------------------
+# compile the AMD mexFunction for MATLAB (original make only)
+#------------------------------------------------------------------------------
+
+# This is a very ugly Makefile, and is only provided for those who do not
+# have GNU make. Note that it is not used if you have GNU make. It ignores
+# dependency checking and just compiles everything. It was created
+# automatically, via make -n using the GNUmakefile. That way, I don't have
+# maintain two Makefiles.
+
+all: amd
+
+include ../Make/Make.include
+
+MX = $(MEX) -I../Include
+
+amd:
+ $(MX) -DDINT -c ../Source/amd_aat.c
+ $(MV) amd_aat.o amd_m_aat.o
+ $(MX) -DDINT -c ../Source/amd_1.c
+ $(MV) amd_1.o amd_m_1.o
+ $(MX) -DDINT -c ../Source/amd_2.c
+ $(MV) amd_2.o amd_m_2.o
+ $(MX) -DDINT -c ../Source/amd_dump.c
+ $(MV) amd_dump.o amd_m_dump.o
+ $(MX) -DDINT -c ../Source/amd_postorder.c
+ $(MV) amd_postorder.o amd_m_postorder.o
+ $(MX) -DDINT -c ../Source/amd_post_tree.c
+ $(MV) amd_post_tree.o amd_m_post_tree.o
+ $(MX) -DDINT -c ../Source/amd_defaults.c
+ $(MV) amd_defaults.o amd_m_defaults.o
+ $(MX) -DDINT -c ../Source/amd_order.c
+ $(MV) amd_order.o amd_m_order.o
+ $(MX) -DDINT -c ../Source/amd_control.c
+ $(MV) amd_control.o amd_m_control.o
+ $(MX) -DDINT -c ../Source/amd_info.c
+ $(MV) amd_info.o amd_m_info.o
+ $(MX) -DDINT -c ../Source/amd_valid.c
+ $(MV) amd_valid.o amd_m_valid.o
+ $(MX) -output amd amd_mex.c amd_m_aat.o \
+ amd_m_1.o amd_m_2.o amd_m_dump.o amd_m_postorder.o \
+ amd_m_post_tree.o amd_m_defaults.o amd_m_order.o amd_m_control.o \
+ amd_m_info.o amd_m_valid.o
+
+#------------------------------------------------------------------------------
+# Remove all but the files in the original distribution
+#------------------------------------------------------------------------------
+
+purge: clean
+ - $(RM) amd.mex* amd.dll
--- /dev/null
+function [p, Info] = amd (A, Control)
+%AMD Approximate minimum degree permutation.
+% P = AMD (S) returns the approximate minimum degree permutation vector for
+% the sparse matrix C = S+S'. The Cholesky factorization of C (P,P), or
+% S (P,P), tends to be sparser than that of C or S. AMD tends to be faster
+% than SYMMMD and SYMAMD, and tends to return better orderings than SYMMMD.
+% S must be square. If S is full, amd (S) is equivalent to amd (sparse (S)).
+%
+% Usage: P = amd (S) ; % finds the ordering
+% [P, Info] = amd (S, Control) ; % optional parameters & statistics
+% Control = amd ; % returns default parameters
+% amd ; % prints default parameters.
+%
+% Control (1); If S is n-by-n, then rows/columns with more than
+% max (16, (Control (1))* sqrt(n)) entries in S+S' are considered
+% "dense", and ignored during ordering. They are placed last in the
+% output permutation. The default is 10.0 if Control is not present.
+% Control (2): If nonzero, then aggressive absorption is performed.
+% This is the default if Control is not present.
+% Control (3): If nonzero, print statistics about the ordering.
+%
+% Info (1): status (0: ok, -1: out of memory, -2: matrix invalid)
+% Info (2): n = size (A,1)
+% Info (3): nnz (A)
+% Info (4): the symmetry of the matrix S (0.0 means purely unsymmetric,
+% 1.0 means purely symmetric). Computed as:
+% B = tril (S, -1) + triu (S, 1) ; symmetry = nnz (B & B') / nnz (B);
+% Info (5): nnz (diag (S))
+% Info (6): nnz in S+S', excluding the diagonal (= nnz (B+B'))
+% Info (7): number "dense" rows/columns in S+S'
+% Info (8): the amount of memory used by AMD, in bytes
+% Info (9): the number of memory compactions performed by AMD
+%
+% The following statistics are slight upper bounds because of the
+% approximate degree in AMD. The bounds are looser if "dense" rows/columns
+% are ignored during ordering (Info (7) > 0). The statistics are for a
+% subsequent factorization of the matrix C (P,P). The LU factorization
+% statistics assume no pivoting.
+%
+% Info (10): the number of nonzeros in L, excluding the diagonal
+% Info (11): the number of divide operations for LL', LDL', or LU
+% Info (12): the number of multiply-subtract pairs for LL' or LDL'
+% Info (13): the number of multiply-subtract pairs for LU
+% Info (14): the max # of nonzeros in any column of L (incl. diagonal)
+% Info (15:20): unused, reserved for future use
+%
+% An assembly tree post-ordering is performed, which is typically the same
+% as an elimination tree post-ordering. It is not always identical because
+% of the approximate degree update used, and because "dense" rows/columns
+% do not take part in the post-order. It well-suited for a subsequent
+% "chol", however. If you require a precise elimination tree post-ordering,
+% then do:
+%
+% P = amd (S) ;
+% C = spones (S) + spones (S') ; % skip this if S already symmetric
+% [ignore, Q] = sparsfun ('symetree', C (P,P)) ;
+% P = P (Q) ;
+%
+% --------------------------------------------------------------------------
+% AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,
+% Patrick R. Amestoy, and Iain S. Duff. See ../README for License.
+% email: davis@cise.ufl.edu CISE Department, Univ. of Florida.
+% web: http://www.cise.ufl.edu/research/sparse/amd
+% --------------------------------------------------------------------------
+%
+% Acknowledgements: This work was supported by the National Science
+% Foundation, under grants ASC-9111263, DMS-9223088, and CCR-0203270.
+%
+% See also COLMMD, COLAMD, COLPERM, SYMAMD, SYMMMD, SYMRCM.
+
+more on
+help amd
+more off
+error ('amd mexFunction not found! Type "amd_make" in MATLAB to compile amd');
--- /dev/null
+function amd_demo
+% AMD DEMO
+%
+% A demo of AMD for MATLAB.
+%
+% --------------------------------------------------------------------------
+% AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,
+% Patrick R. Amestoy, and Iain S. Duff. See ../README for License.
+% email: davis@cise.ufl.edu CISE Department, Univ. of Florida.
+% web: http://www.cise.ufl.edu/research/sparse/amd
+% --------------------------------------------------------------------------
+%
+% See also: amd, amd_make
+
+% This orders the same matrix as the ANSI C demo, amd_demo.c. It includes an
+% additional analysis of the matrix via MATLAB's symbfact routine.
+
+% First, print the help information for AMD
+help amd
+
+% Get the Harwell/Boeing can_24 matrix. This is an example matrix from the
+% MATLAB-accessible UF sparse matrix collection, and can be loaded into
+% MATLAB with the statment "Problem = UFget ('HB/can_24')", after obtaining
+% the UFget function and its supporting routines at
+% http://www.cise.ufl.edu/sparse/mat .
+
+load can_24
+A = Problem.A ;
+n = size (A,1) ;
+
+figure (1)
+clf
+hold off
+subplot (2,2,1) ;
+spy (A)
+% remove the "_" from the name before printing it in the plot title
+title (sprintf ('%s', strrep (Problem.name, '_', '-'))) ;
+fprintf ('Matrix name: %s\n', Problem.name) ;
+fprintf ('Matrix title: %s\n', Problem.title) ;
+
+% print the details during AMD ordering and SYMBFACT
+spparms ('spumoni', 1) ;
+
+% order the matrix. Note that the Info argument is optional.
+fprintf ('\nIf the next step fails, then you have\n') ;
+fprintf ('not yet compiled the AMD mexFunction.\n') ;
+[p, Info] = amd (A) ;
+
+% order again, but this time print some statistics
+[p, Info] = amd (A, [10 1 1]) ;
+
+fprintf ('Permutation vector:\n') ;
+fprintf (' %2d', p) ;
+fprintf ('\n\n') ;
+
+subplot (2,2,2) ;
+spy (A (p,p))
+title ('Permuted matrix') ;
+
+% The amd_demo.c program stops here.
+
+fprintf ('Analyze A(p,p) with MATLAB''s symbfact routine:\n') ;
+[cn, height, parent, post, R] = symbfact (A (p,p)) ;
+
+subplot (2,2,3) ;
+spy (R') ;
+title ('Cholesky factor, L') ;
+
+subplot (2,2,4) ;
+treeplot (parent) ;
+title ('elimination tree') ;
+
+% results from symbfact
+lnz = sum (cn) ; % number of nonzeros in L, incl. diagonal
+cn = cn - 1 ; % get the count of off-diagonal entries
+fl = n + sum (cn.^2 + 2*cn) ; % flop count for chol (A (p,p)
+fprintf ('number of nonzeros in L (including diagonal): %d\n', lnz) ;
+fprintf ('floating point operation count for chol (A (p,p)): %d\n', fl) ;
+
+% approximations from amd:
+lnz2 = n + Info (10) ;
+fl2 = n + Info (11) + 2 * Info (12) ;
+fprintf ('\nResults from AMD''s approximate analysis:\n') ;
+fprintf ('number of nonzeros in L (including diagonal): %d\n', lnz2) ;
+fprintf ('floating point operation count for chol (A (p,p)): %d\n\n', fl2) ;
+
+if (lnz2 ~= lnz | fl ~= fl2)
+ fprintf ('Note that the nonzero and flop counts from AMD are slight\n') ;
+ fprintf ('upper bounds. This is due to the approximate minimum degree\n');
+ fprintf ('method used, in conjunction with "mass elimination".\n') ;
+ fprintf ('See the discussion about mass elimination in amd.h and\n') ;
+ fprintf ('amd_2.c for more details.\n') ;
+end
+
+% turn off diagnostic output in MATLAB's sparse matrix routines
+spparms ('spumoni', 0) ;
--- /dev/null
+>> amd_demo
+
+ AMD Approximate minimum degree permutation.
+ P = AMD (S) returns the approximate minimum degree permutation vector for
+ the sparse matrix C = S+S'. The Cholesky factorization of C (P,P), or
+ S (P,P), tends to be sparser than that of C or S. AMD tends to be faster
+ than SYMMMD and SYMAMD, and tends to return better orderings than SYMMMD.
+ S must be square. If S is full, amd (S) is equivalent to amd (sparse (S)).
+
+ Usage: P = amd (S) ; % finds the ordering
+ [P, Info] = amd (S, Control) ; % optional parameters & statistics
+ Control = amd ; % returns default parameters
+ amd ; % prints default parameters.
+
+ Control (1); If S is n-by-n, then rows/columns with more than
+ max (16, (Control (1))* sqrt(n)) entries in S+S' are considered
+ "dense", and ignored during ordering. They are placed last in the
+ output permutation. The default is 10.0 if Control is not present.
+ Control (2): If nonzero, then aggressive absorption is performed.
+ This is the default if Control is not present.
+ Control (3): If nonzero, print statistics about the ordering.
+
+ Info (1): status (0: ok, -1: out of memory, -2: matrix invalid)
+ Info (2): n = size (A,1)
+ Info (3): nnz (A)
+ Info (4): the symmetry of the matrix S (0.0 means purely unsymmetric,
+ 1.0 means purely symmetric). Computed as:
+ B = tril (S, -1) + triu (S, 1) ; symmetry = nnz (B & B') / nnz (B);
+ Info (5): nnz (diag (S))
+ Info (6): nnz in S+S', excluding the diagonal (= nnz (B+B'))
+ Info (7): number "dense" rows/columns in S+S'
+ Info (8): the amount of memory used by AMD, in bytes
+ Info (9): the number of memory compactions performed by AMD
+
+ The following statistics are slight upper bounds because of the
+ approximate degree in AMD. The bounds are looser if "dense" rows/columns
+ are ignored during ordering (Info (7) > 0). The statistics are for a
+ subsequent factorization of the matrix C (P,P). The LU factorization
+ statistics assume no pivoting.
+
+ Info (10): the number of nonzeros in L, excluding the diagonal
+ Info (11): the number of divide operations for LL', LDL', or LU
+ Info (12): the number of multiply-subtract pairs for LL' or LDL'
+ Info (13): the number of multiply-subtract pairs for LU
+ Info (14): the max # of nonzeros in any column of L (incl. diagonal)
+ Info (15:20): unused, reserved for future use
+
+ An assembly tree post-ordering is performed, which is typically the same
+ as an elimination tree post-ordering. It is not always identical because
+ of the approximate degree update used, and because "dense" rows/columns
+ do not take part in the post-order. It well-suited for a subsequent
+ "chol", however. If you require a precise elimination tree post-ordering,
+ then do:
+
+ P = amd (S) ;
+ C = spones (S) + spones (S') ; % skip this if S already symmetric
+ [ignore, Q] = sparsfun ('symetree', C (P,P)) ;
+ P = P (Q) ;
+
+ --------------------------------------------------------------------------
+ AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,
+ Patrick R. Amestoy, and Iain S. Duff. See ../README for License.
+ email: davis@cise.ufl.edu CISE Department, Univ. of Florida.
+ web: http://www.cise.ufl.edu/research/sparse/amd
+ --------------------------------------------------------------------------
+
+ Acknowledgements: This work was supported by the National Science
+ Foundation, under grants ASC-9111263, DMS-9223088, and CCR-0203270.
+
+ See also COLMMD, COLAMD, COLPERM, SYMAMD, SYMMMD, SYMRCM.
+
+Matrix name: HB/can_24
+Matrix title: 1SYMMETRIC PATTERN FROM CANNES,LUCIEN MARRO,JUNE 1981.
+
+If the next step fails, then you have
+not yet compiled the AMD mexFunction.
+
+amd: approximate minimum degree ordering, parameters:
+ dense row parameter: 10
+ (rows with more than max (10 * sqrt (n), 16) entries are
+ considered "dense", and placed last in output permutation)
+ aggressive absorption: yes
+
+ input matrix A is 24-by-24
+ input matrix A has 160 nonzero entries
+
+amd: approximate minimum degree ordering, results:
+ status: OK
+ n, dimension of A: 24
+ nz, number of nonzeros in A: 160
+ symmetry of A: 1.0000
+ number of nonzeros on diagonal: 24
+ nonzeros in pattern of A+A' (excl. diagonal): 136
+ # dense rows/columns of A+A': 0
+ memory used, in bytes: 1516
+ # of memory compactions: 0
+
+ The following approximate statistics are for a subsequent
+ factorization of A(P,P) + A(P,P)'. They are slight upper
+ bounds if there are no dense rows/columns in A+A', and become
+ looser if dense rows/columns exist.
+
+ nonzeros in L (excluding diagonal): 97
+ nonzeros in L (including diagonal): 121
+ # divide operations for LDL' or LU: 97
+ # multiply-subtract operations for LDL': 275
+ # multiply-subtract operations for LU: 453
+ max nz. in any column of L (incl. diagonal): 8
+
+ chol flop count for real A, sqrt counted as 1 flop: 671
+ LDL' flop count for real A: 647
+ LDL' flop count for complex A: 3073
+ LU flop count for real A (with no pivoting): 1003
+ LU flop count for complex A (with no pivoting): 4497
+
+Permutation vector:
+ 23 21 11 24 13 6 17 9 15 5 16 8 2 10 14 18 1 3 4 7 12 19 22 20
+
+Analyze A(p,p) with MATLAB's symbfact routine:
+predicted nonzeros: 120
+predicted flops: 656
+predicted height: 16
+predicted front size: 7
+number of nonzeros in L (including diagonal): 120
+floating point operation count for chol (A (p,p)): 656
+
+Results from AMD's approximate analysis:
+number of nonzeros in L (including diagonal): 121
+floating point operation count for chol (A (p,p)): 671
+
+Note that the nonzero and flop counts from AMD are slight
+upper bounds. This is due to the approximate minimum degree
+method used, in conjunction with "mass elimination".
+See the discussion about mass elimination in amd.h and
+amd_2.c for more details.
+>> diary off
--- /dev/null
+function amd_make
+% AMD_MAKE: compiles the AMD mexFunction for MATLAB
+%
+% --------------------------------------------------------------------------
+% AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis,
+% Patrick R. Amestoy, and Iain S. Duff. See ../README for License.
+% email: davis@cise.ufl.edu CISE Department, Univ. of Florida.
+% web: http://www.cise.ufl.edu/research/sparse/amd
+% --------------------------------------------------------------------------
+%
+% See also: amd, amd_demo
+
+help amd_make
+fprintf ('Compiling the AMD mexFunction:\n') ;
+cmd = sprintf ('mex -inline -O -output amd -I..%sInclude amd_mex.c', filesep) ;
+files = {'amd_order', 'amd_dump', 'amd_postorder', 'amd_post_tree', ...
+ 'amd_aat', 'amd_2', 'amd_1', 'amd_defaults', 'amd_control', 'amd_info', ...
+ 'amd_valid' } ;
+for i = 1 : length (files)
+ cmd = sprintf ('%s ..%sSource%s%s.c', cmd, filesep, filesep, files {i}) ;
+end
+fprintf ('%s\n', cmd) ;
+try
+ eval (cmd) ;
+catch
+ fprintf ('Compilation not successful.\n') ;
+end
+
+input ('\nHit enter to run the AMD demo\n') ;
+more on
+amd_demo
+more off
--- /dev/null
+/* ========================================================================= */
+/* === AMD mexFunction ===================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Usage:
+ * p = amd (A)
+ * p = amd (A, Control)
+ * [p, Info] = amd (A)
+ * [p, Info] = amd (A, Control)
+ * Control = amd ; % return the default Control settings for AMD
+ * amd ; % print the default Control settings for AMD
+ *
+ * Given a square matrix A, compute a permutation P suitable for a Cholesky
+ * factorization of the matrix B (P,P), where B = spones (A) + spones (A').
+ * The method used is the approximate minimum degree ordering method. See
+ * amd.m and amd.h for more information.
+ */
+
+#include "amd.h"
+#include "mex.h"
+#include "matrix.h"
+
+void mexFunction
+(
+ int nlhs,
+ mxArray *plhs[],
+ int nrhs,
+ const mxArray *prhs[]
+)
+{
+ int i, m, n, *Ap, *Ai, *P, nc, result, spumoni, full ;
+ double *Pout, *InfoOut, Control [AMD_CONTROL], Info [AMD_INFO], *ControlIn;
+ mxArray *A, *string, *parameter ;
+
+ /* --------------------------------------------------------------------- */
+ /* get control parameters */
+ /* --------------------------------------------------------------------- */
+
+ spumoni = 0 ;
+ if (nrhs == 0)
+ {
+ /* get the default control parameters, and return */
+ plhs [0] = mxCreateDoubleMatrix (AMD_CONTROL, 1, mxREAL) ;
+ amd_defaults (mxGetPr (plhs [0])) ;
+ if (nlhs == 0)
+ {
+ amd_control (mxGetPr (plhs [0])) ;
+ }
+ return ;
+ }
+
+ amd_defaults (Control) ;
+ if (nrhs > 1)
+ {
+ ControlIn = mxGetPr (prhs [1]) ;
+ nc = mxGetM (prhs [1]) * mxGetN (prhs [1]) ;
+ Control [AMD_DENSE]
+ = (nc > 0) ? ControlIn [AMD_DENSE] : AMD_DEFAULT_DENSE ;
+ Control [AMD_AGGRESSIVE]
+ = (nc > 1) ? ControlIn [AMD_AGGRESSIVE] : AMD_DEFAULT_AGGRESSIVE ;
+ spumoni = (nc > 2) ? (ControlIn [2] != 0) : 0 ;
+ }
+
+ if (spumoni > 0)
+ {
+ amd_control (Control) ;
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* get inputs */
+ /* --------------------------------------------------------------------- */
+
+ if (nlhs > 2 || nrhs > 2)
+ {
+ mexErrMsgTxt ("Usage: p = amd (A)\nor [p, Info] = amd (A, Control)") ;
+ }
+
+ A = (mxArray *) prhs [0] ;
+ n = mxGetN (A) ;
+ m = mxGetM (A) ;
+ if (spumoni > 0)
+ {
+ mexPrintf (" input matrix A is %d-by-%d\n", m, n) ;
+ }
+ if (mxGetNumberOfDimensions (A) != 2)
+ {
+ mexErrMsgTxt ("amd: A must be 2-dimensional") ;
+ }
+ if (m != n)
+ {
+ mexErrMsgTxt ("amd: A must be square") ;
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* allocate workspace for output permutation */
+ /* --------------------------------------------------------------------- */
+
+ P = mxMalloc ((n+1) * sizeof (int)) ;
+
+ /* --------------------------------------------------------------------- */
+ /* if A is full, convert to a sparse matrix */
+ /* --------------------------------------------------------------------- */
+
+ full = !mxIsSparse (A) ;
+ if (full)
+ {
+ if (spumoni > 0)
+ {
+ mexPrintf (
+ " input matrix A is full (sparse copy of A will be created)\n");
+ }
+ mexCallMATLAB (1, &A, 1, (mxArray **) prhs, "sparse") ;
+ }
+ Ap = mxGetJc (A) ;
+ Ai = mxGetIr (A) ;
+ if (spumoni > 0)
+ {
+ mexPrintf (" input matrix A has %d nonzero entries\n", Ap [n]) ;
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* order the matrix */
+ /* --------------------------------------------------------------------- */
+
+ result = amd_order (n, Ap, Ai, P, Control, Info) ;
+
+ /* --------------------------------------------------------------------- */
+ /* if A is full, free the sparse copy of A */
+ /* --------------------------------------------------------------------- */
+
+ if (full)
+ {
+ mxDestroyArray (A) ;
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* print results (including return value) */
+ /* --------------------------------------------------------------------- */
+
+ if (spumoni > 0)
+ {
+ amd_info (Info) ;
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* check error conditions */
+ /* --------------------------------------------------------------------- */
+
+ if (result == AMD_OUT_OF_MEMORY)
+ {
+ mexErrMsgTxt ("amd: out of memory") ;
+ }
+ else if (result == AMD_INVALID)
+ {
+ mexErrMsgTxt ("amd: input matrix A is corrupted") ;
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* copy the outputs to MATLAB */
+ /* --------------------------------------------------------------------- */
+
+ /* output permutation, P */
+ plhs [0] = mxCreateDoubleMatrix (1, n, mxREAL) ;
+ Pout = mxGetPr (plhs [0]) ;
+ for (i = 0 ; i < n ; i++)
+ {
+ Pout [i] = P [i] + 1 ; /* change to 1-based indexing for MATLAB */
+ }
+ mxFree (P) ;
+
+ /* Info */
+ if (nlhs > 1)
+ {
+ plhs [1] = mxCreateDoubleMatrix (AMD_INFO, 1, mxREAL) ;
+ InfoOut = mxGetPr (plhs [1]) ;
+ for (i = 0 ; i < AMD_INFO ; i++)
+ {
+ InfoOut [i] = Info [i] ;
+ }
+ }
+}
--- /dev/null
+AMD version 1.1: a set of routines for permuting sparse matrices prior to
+ factorization. Includes a version in C, a version in Fortran, and a MATLAB
+ mexFunction.
+
+Quick start (Unix, or Windows with Cygwin):
+
+ To compile, test, and install AMD, you may wish to first configure the
+ installation by editting the AMD/Make/Make.include file. Next, cd to this
+ directory (AMD) and type "make" (or "make lib" if you do not have MATLAB).
+ To compile and run a demo program for the Fortran version, type
+ "make fortran". When done, type "make clean" to remove unused *.o files
+ (keeps the compiled libraries and demo programs). See the User Guide
+ (Doc/AMD_UserGuide.pdf), or AMD/Make/Make.include, for more details.
+
+Quick start (for MATLAB users);
+
+ To compile, test, and install the AMD mexFunction, cd to the
+ AMD/MATLAB directory and type amd_make at the MATLAB prompt.
+ This works on any system supported by MATLAB.
+
+-------------------------------------------------------------------------------
+
+AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A.
+Davis, Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved.
+
+AMD License:
+
+ Your use or distribution of AMD or any modified version of
+ AMD implies that you agree to this License.
+
+ THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+ EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+
+ Permission is hereby granted to use or copy this program, provided
+ that the Copyright, this License, and the Availability of the original
+ version is retained on all copies. User documentation of any code that
+ uses AMD or any modified version of AMD code must cite the
+ Copyright, this License, the Availability note, and "Used by permission."
+ Permission to modify the code and to distribute modified code is granted,
+ provided the Copyright, this License, and the Availability note are
+ retained, and a notice that the code was modified is included. This
+ software was developed with support from the National Science Foundation,
+ and is provided to you free of charge.
+
+Availability:
+
+ http://www.cise.ufl.edu/research/sparse/amd
+
+-------------------------------------------------------------------------------
+
+This is the AMD Version 1.1 README file. It is a terse overview of AMD.
+Refer to the User Guide (Doc/AMD_UserGuide.pdf) for how to install and use AMD.
+
+Description:
+
+ AMD is a set of routines for pre-ordering sparse matrices prior to Cholesky
+ or LU factorization, using the approximate minimum degree ordering
+ algorithm. Written in ANSI/ISO C with a MATLAB interface, and in
+ Fortran 77.
+
+Authors:
+
+ Timothy A. Davis (davis@cise.ufl.edu), University of Florida.
+ Patrick R. Amestory, ENSEEIHT, Toulouse, France.
+ Iain S. Duff, Rutherford Appleton Laboratory, UK.
+
+Acknowledgements:
+
+ This work was supported by the National Science Foundation, under
+ grants DMS-9504974, DMS-9803599, and CCR-0203270.
+
+ Portions of this work were done while on sabbatical at Stanford University
+ and Lawrence Berkeley National Laboratory (with funding from the SciDAC
+ program). I would like to thank Gene Golub, Esmond Ng, and Horst Simon
+ for making this sabbatical possible.
+
+-------------------------------------------------------------------------------
+Files and directories in the AMD v1.0 distribution:
+-------------------------------------------------------------------------------
+
+ ---------------------------------------------------------------------------
+ Subdirectories of the AMD directory:
+ ---------------------------------------------------------------------------
+
+ Doc documentation
+ Make for compiling AMD
+ Source primary source code
+ Include include file for use in your code that calls AMD
+ Demo demo programs. also serves as test of the AMD installation.
+ MATLAB AMD mexFunction for MATLAB, and supporting m-files
+ Lib where the compiled C-callable and Fortran-callable
+ AMD libraries placed.
+
+ ---------------------------------------------------------------------------
+ Files in the AMD directory:
+ ---------------------------------------------------------------------------
+
+ Makefile top-level Makefile for GNU make or original make.
+ Windows users would require Cygwin to use "make"
+
+ README this file
+
+ ---------------------------------------------------------------------------
+ Doc directory: documentation
+ ---------------------------------------------------------------------------
+
+ ChangeLog change log
+ License the AMD License
+ Makefile for creating the documentation
+ AMD_UserGuide.bib AMD User Guide (references)
+ AMD_UserGuide.tex AMD User Guide (LaTeX)
+ AMD_UserGuide.pdf AmD User Guide (PDF)
+
+ ---------------------------------------------------------------------------
+ Make directory: for compiling AMD (Lib/libamd.a and Lib/libamdf77.a)
+ ---------------------------------------------------------------------------
+
+ Make.include overall configurations. Can use one of:
+ Make.alpha Makefile additions for Compaq Alpha
+ Make.linux Makefile additions for Linux
+ Make.rs6000 Makefile additions for RS 6000
+ Make.sgi Makefile additions for SGI
+ Make.solaris Makefile additions for Solaris
+
+ ---------------------------------------------------------------------------
+ Source directory:
+ ---------------------------------------------------------------------------
+
+ GNUmakefile a nice Makefile, for GNU make
+ Makefile an ugly Unix Makefile (for older make's)
+
+ amd_order.c user-callable, primary AMD ordering routine
+ amd_control.c user-callable, prints the control parameters
+ amd_defaults.c user-callable, sets default control parameters
+ amd_info.c user-callable, prints the statistics from AMD
+
+ amd_1.c non-user-callable, construct A+A'
+ amd_2.c non-user-callable, primary ordering kernel
+ (a C version of amd.f and amdbar.f, with
+ post-ordering added)
+ amd_aat.c non-user-callable, computes nnz (A+A')
+ amd_dump.c non-user-callable, debugging routines
+ amd_internal.h non-user-callable, include file for AMD
+ amd_mex.c non-user-callable, MATLAB mexFunction
+ amd_postorder.c non-user-callable, postorder
+ amd_post_tree.c non-user-callable, postorder just one tree
+ amd_valid.c non-user-callable, verifies a matrix
+
+ amd.f user-callable Fortran 77 version
+ amdbar.f user-callable Fortran 77 version
+
+ ---------------------------------------------------------------------------
+ Include directory:
+ ---------------------------------------------------------------------------
+
+ amd.h include file for C programs that use AMD
+
+ ---------------------------------------------------------------------------
+ Demo directory:
+ ---------------------------------------------------------------------------
+
+ Makefile for GNU make or original make
+
+ amd_demo.c C demo program for AMD
+ amd_demo.out output of amd_demo.c
+
+ amd_simple.c simple C demo program for AMD
+ amd_simple.out output of amd_simple.c
+
+ amd_f77demo.f Fortran 77 demo program for AMD
+ amd_f77demo.out output of amd_f77demo.f
+
+ amd_f77simple.c simple Fortran 77 demo program for AMD
+ amd_f77simple.out output of amd_f77simple.f
+
+ amd_f77cross.f Fortran 77 demo, calls the C version of AMD
+ amd_f77cross.out output of amd_f77cross.f
+ amd_f77wrapper.c Fortran-callable wrapper for C version of AMD
+
+ ---------------------------------------------------------------------------
+ MATLAB directory:
+ ---------------------------------------------------------------------------
+
+ GNUmakefile a nice Makefile, for GNU make
+ Makefile an ugly Unix Makefile (for older make's)
+
+ Contents.m for "help amd" listing of toolbox contents
+
+ amd.m MATLAB help file for AMD
+ amd_make.m MATLAB m-file for compiling AMD mexFunction
+
+ amd_mex.c AMD mexFunction for MATLAB
+
+ amd_demo.m MATLAB demo for AMD
+ amd_demo.m.out diary output of amd_demo.m
+ can_24.mat input file for AMD demo
+
+ ---------------------------------------------------------------------------
+ Lib directory: libamd.a and libamdf77.a libraries placed here
+ ---------------------------------------------------------------------------
+
+ libamd.def AMD definitions for Windows
--- /dev/null
+#-------------------------------------------------------------------------------
+# AMD Makefile for compiling on Unix systems (for GNU make only)
+#-------------------------------------------------------------------------------
+
+include ../../../../common/Make.global_options
+
+#-------------------------------------------------------------------------------
+# source files
+#-------------------------------------------------------------------------------
+
+AMD = amd_aat amd_1 amd_2 amd_dump amd_postorder amd_post_tree amd_defaults \
+ amd_order amd_control amd_info amd_valid amd_preprocess
+
+INC = ../Include/amd.h amd_internal.h
+
+#-------------------------------------------------------------------------------
+# object files for each version
+#-------------------------------------------------------------------------------
+
+AMDI = $(addprefix $D/lib/umfpack/, $(addsuffix .$(OBJEXT), $(subst amd_,amd_i_,$(AMD))))
+AMDL = $(addprefix $D/lib/umfpack/, $(addsuffix .$(OBJEXT), $(subst amd_,amd_l_,$(AMD))))
+
+#-------------------------------------------------------------------------------
+# compile each int and long routine (with no real/complex version)
+#-------------------------------------------------------------------------------
+
+$D/lib/umfpack/amd_i_%.$(OBJEXT): amd_%.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -DDINT -c $< -o $@
+
+$D/lib/umfpack/amd_l_%.$(OBJEXT): amd_%.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -DDLONG -c $< -o $@
+
+all: $(AMDI) $(AMDL)
--- /dev/null
+C-----------------------------------------------------------------------
+C AMD: approximate minimum degree, with aggressive absorption
+C-----------------------------------------------------------------------
+
+ SUBROUTINE AMD
+ $ (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT,
+ $ LAST, HEAD, ELEN, DEGREE, NCMPA, W)
+
+ INTEGER N, IWLEN, PFREE, NCMPA, IW (IWLEN), PE (N),
+ $ DEGREE (N), NV (N), NEXT (N), LAST (N), HEAD (N),
+ $ ELEN (N), W (N), LEN (N)
+
+C Given a representation of the nonzero pattern of a symmetric matrix,
+C A, (excluding the diagonal) perform an approximate minimum
+C (UMFPACK/MA38-style) degree ordering to compute a pivot order
+C such that the introduction of nonzeros (fill-in) in the Cholesky
+C factors A = LL^T are kept low. At each step, the pivot
+C selected is the one with the minimum UMFPACK/MA38-style
+C upper-bound on the external degree.
+C
+C Aggresive absorption is used to tighten the bound on the degree.
+
+C **********************************************************************
+C ***** CAUTION: ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT. ******
+C **********************************************************************
+
+C References:
+C
+C [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern
+C multifrontal method for sparse LU factorization", SIAM J.
+C Matrix Analysis and Applications, vol. 18, no. 1, pp.
+C 140-158. Discusses UMFPACK / MA38, which first introduced
+C the approximate minimum degree used by this routine.
+C
+C [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An
+C approximate degree ordering algorithm," SIAM J. Matrix
+C Analysis and Applications, vol. 17, no. 4, pp. 886-905,
+C 1996. Discusses AMD, AMDBAR, and MC47B.
+C
+C [3] Alan George and Joseph Liu, "The evolution of the minimum
+C degree ordering algorithm," SIAM Review, vol. 31, no. 1,
+C pp. 1-19, 1989. We list below the features mentioned in
+C that paper that this code includes:
+C
+C mass elimination:
+C Yes. MA27 relied on supervariable detection for mass
+C elimination.
+C indistinguishable nodes:
+C Yes (we call these "supervariables"). This was also in
+C the MA27 code - although we modified the method of
+C detecting them (the previous hash was the true degree,
+C which we no longer keep track of). A supervariable is
+C a set of rows with identical nonzero pattern. All
+C variables in a supervariable are eliminated together.
+C Each supervariable has as its numerical name that of
+C one of its variables (its principal variable).
+C quotient graph representation:
+C Yes. We use the term "element" for the cliques formed
+C during elimination. This was also in the MA27 code.
+C The algorithm can operate in place, but it will work
+C more efficiently if given some "elbow room."
+C element absorption:
+C Yes. This was also in the MA27 code.
+C external degree:
+C Yes. The MA27 code was based on the true degree.
+C incomplete degree update and multiple elimination:
+C No. This was not in MA27, either. Our method of
+C degree update within MC47B/BD is element-based, not
+C variable-based. It is thus not well-suited for use
+C with incomplete degree update or multiple elimination.
+
+C-----------------------------------------------------------------------
+C Authors, and Copyright (C) 1995 by:
+C Timothy A. Davis, Patrick Amestoy, Iain S. Duff, & John K. Reid.
+C
+C Acknowledgements:
+C This work (and the UMFPACK package) was supported by the
+C National Science Foundation (ASC-9111263 and DMS-9223088).
+C The UMFPACK/MA38 approximate degree update algorithm, the
+C unsymmetric analog which forms the basis of MC47B/BD, was
+C developed while Tim Davis was supported by CERFACS (Toulouse,
+C France) in a post-doctoral position.
+C
+C Date: September, 1995
+C-----------------------------------------------------------------------
+
+C-----------------------------------------------------------------------
+C INPUT ARGUMENTS (unaltered):
+C-----------------------------------------------------------------------
+
+C n: The matrix order.
+C
+C Restriction: 1 .le. n .lt. (iovflo/2)-2, where iovflo is
+C the largest positive integer that your computer can represent.
+
+C iwlen: The length of iw (1..iwlen). On input, the matrix is
+C stored in iw (1..pfree-1). However, iw (1..iwlen) should be
+C slightly larger than what is required to hold the matrix, at
+C least iwlen .ge. pfree + n is recommended. Otherwise,
+C excessive compressions will take place.
+C *** We do not recommend running this algorithm with ***
+C *** iwlen .lt. pfree + n. ***
+C *** Better performance will be obtained if ***
+C *** iwlen .ge. pfree + n ***
+C *** or better yet ***
+C *** iwlen .gt. 1.2 * pfree ***
+C *** (where pfree is its value on input). ***
+C The algorithm will not run at all if iwlen .lt. pfree-1.
+C
+C Restriction: iwlen .ge. pfree-1
+
+C-----------------------------------------------------------------------
+C INPUT/OUPUT ARGUMENTS:
+C-----------------------------------------------------------------------
+
+C pe: On input, pe (i) is the index in iw of the start of row i, or
+C zero if row i has no off-diagonal non-zeros.
+C
+C During execution, it is used for both supervariables and
+C elements:
+C
+C * Principal supervariable i: index into iw of the
+C description of supervariable i. A supervariable
+C represents one or more rows of the matrix
+C with identical nonzero pattern.
+C * Non-principal supervariable i: if i has been absorbed
+C into another supervariable j, then pe (i) = -j.
+C That is, j has the same pattern as i.
+C Note that j might later be absorbed into another
+C supervariable j2, in which case pe (i) is still -j,
+C and pe (j) = -j2.
+C * Unabsorbed element e: the index into iw of the description
+C of element e, if e has not yet been absorbed by a
+C subsequent element. Element e is created when
+C the supervariable of the same name is selected as
+C the pivot.
+C * Absorbed element e: if element e is absorbed into element
+C e2, then pe (e) = -e2. This occurs when the pattern of
+C e (that is, Le) is found to be a subset of the pattern
+C of e2 (that is, Le2). If element e is "null" (it has
+C no nonzeros outside its pivot block), then pe (e) = 0.
+C
+C On output, pe holds the assembly tree/forest, which implicitly
+C represents a pivot order with identical fill-in as the actual
+C order (via a depth-first search of the tree).
+C
+C On output:
+C If nv (i) .gt. 0, then i represents a node in the assembly tree,
+C and the parent of i is -pe (i), or zero if i is a root.
+C If nv (i) = 0, then (i,-pe (i)) represents an edge in a
+C subtree, the root of which is a node in the assembly tree.
+
+C pfree: On input the tail end of the array, iw (pfree..iwlen),
+C is empty, and the matrix is stored in iw (1..pfree-1).
+C During execution, additional data is placed in iw, and pfree
+C is modified so that iw (pfree..iwlen) is always the unused part
+C of iw. On output, pfree is set equal to the size of iw that
+C would have been needed for no compressions to occur. If
+C ncmpa is zero, then pfree (on output) is less than or equal to
+C iwlen, and the space iw (pfree+1 ... iwlen) was not used.
+C Otherwise, pfree (on output) is greater than iwlen, and all the
+C memory in iw was used.
+
+C-----------------------------------------------------------------------
+C INPUT/MODIFIED (undefined on output):
+C-----------------------------------------------------------------------
+
+C len: On input, len (i) holds the number of entries in row i of the
+C matrix, excluding the diagonal. The contents of len (1..n)
+C are undefined on output.
+
+C iw: On input, iw (1..pfree-1) holds the description of each row i
+C in the matrix. The matrix must be symmetric, and both upper
+C and lower triangular parts must be present. The diagonal must
+C not be present. Row i is held as follows:
+C
+C len (i): the length of the row i data structure
+C iw (pe (i) ... pe (i) + len (i) - 1):
+C the list of column indices for nonzeros
+C in row i (simple supervariables), excluding
+C the diagonal. All supervariables start with
+C one row/column each (supervariable i is just
+C row i).
+C if len (i) is zero on input, then pe (i) is ignored
+C on input.
+C
+C Note that the rows need not be in any particular order,
+C and there may be empty space between the rows.
+C
+C During execution, the supervariable i experiences fill-in.
+C This is represented by placing in i a list of the elements
+C that cause fill-in in supervariable i:
+C
+C len (i): the length of supervariable i
+C iw (pe (i) ... pe (i) + elen (i) - 1):
+C the list of elements that contain i. This list
+C is kept short by removing absorbed elements.
+C iw (pe (i) + elen (i) ... pe (i) + len (i) - 1):
+C the list of supervariables in i. This list
+C is kept short by removing nonprincipal
+C variables, and any entry j that is also
+C contained in at least one of the elements
+C (j in Le) in the list for i (e in row i).
+C
+C When supervariable i is selected as pivot, we create an
+C element e of the same name (e=i):
+C
+C len (e): the length of element e
+C iw (pe (e) ... pe (e) + len (e) - 1):
+C the list of supervariables in element e.
+C
+C An element represents the fill-in that occurs when supervariable
+C i is selected as pivot (which represents the selection of row i
+C and all non-principal variables whose principal variable is i).
+C We use the term Le to denote the set of all supervariables
+C in element e. Absorbed supervariables and elements are pruned
+C from these lists when computationally convenient.
+C
+C CAUTION: THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
+C The contents of iw are undefined on output.
+
+C-----------------------------------------------------------------------
+C OUTPUT (need not be set on input):
+C-----------------------------------------------------------------------
+
+C nv: During execution, abs (nv (i)) is equal to the number of rows
+C that are represented by the principal supervariable i. If i is
+C a nonprincipal variable, then nv (i) = 0. Initially,
+C nv (i) = 1 for all i. nv (i) .lt. 0 signifies that i is a
+C principal variable in the pattern Lme of the current pivot
+C element me. On output, nv (e) holds the true degree of element
+C e at the time it was created (including the diagonal part).
+
+C ncmpa: The number of times iw was compressed. If this is
+C excessive, then the execution took longer than what could have
+C been. To reduce ncmpa, try increasing iwlen to be 10% or 20%
+C larger than the value of pfree on input (or at least
+C iwlen .ge. pfree + n). The fastest performance will be
+C obtained when ncmpa is returned as zero. If iwlen is set to
+C the value returned by pfree on *output*, then no compressions
+C will occur.
+
+C elen: See the description of iw above. At the start of execution,
+C elen (i) is set to zero. During execution, elen (i) is the
+C number of elements in the list for supervariable i. When e
+C becomes an element, elen (e) = -nel is set, where nel is the
+C current step of factorization. elen (i) = 0 is done when i
+C becomes nonprincipal.
+C
+C For variables, elen (i) .ge. 0 holds until just before the
+C permutation vectors are computed. For elements,
+C elen (e) .lt. 0 holds.
+C
+C On output elen (1..n) holds the inverse permutation (the same
+C as the 'INVP' argument in Sparspak). That is, if k = elen (i),
+C then row i is the kth pivot row. Row i of A appears as the
+C (elen(i))-th row in the permuted matrix, PAP^T.
+
+C last: In a degree list, last (i) is the supervariable preceding i,
+C or zero if i is the head of the list. In a hash bucket,
+C last (i) is the hash key for i. last (head (hash)) is also
+C used as the head of a hash bucket if head (hash) contains a
+C degree list (see head, below).
+C
+C On output, last (1..n) holds the permutation (the same as the
+C 'PERM' argument in Sparspak). That is, if i = last (k), then
+C row i is the kth pivot row. Row last (k) of A is the k-th row
+C in the permuted matrix, PAP^T.
+
+C-----------------------------------------------------------------------
+C LOCAL (not input or output - used only during execution):
+C-----------------------------------------------------------------------
+
+C degree: If i is a supervariable, then degree (i) holds the
+C current approximation of the external degree of row i (an upper
+C bound). The external degree is the number of nonzeros in row i,
+C minus abs (nv (i)) (the diagonal part). The bound is equal to
+C the external degree if elen (i) is less than or equal to two.
+C
+C We also use the term "external degree" for elements e to refer
+C to |Le \ Lme|. If e is an element, then degree (e) holds |Le|,
+C which is the degree of the off-diagonal part of the element e
+C (not including the diagonal part).
+
+C head: head is used for degree lists. head (deg) is the first
+C supervariable in a degree list (all supervariables i in a
+C degree list deg have the same approximate degree, namely,
+C deg = degree (i)). If the list deg is empty then
+C head (deg) = 0.
+C
+C During supervariable detection head (hash) also serves as a
+C pointer to a hash bucket.
+C If head (hash) .gt. 0, there is a degree list of degree hash.
+C The hash bucket head pointer is last (head (hash)).
+C If head (hash) = 0, then the degree list and hash bucket are
+C both empty.
+C If head (hash) .lt. 0, then the degree list is empty, and
+C -head (hash) is the head of the hash bucket.
+C After supervariable detection is complete, all hash buckets
+C are empty, and the (last (head (hash)) = 0) condition is
+C restored for the non-empty degree lists.
+
+C next: next (i) is the supervariable following i in a link list, or
+C zero if i is the last in the list. Used for two kinds of
+C lists: degree lists and hash buckets (a supervariable can be
+C in only one kind of list at a time).
+
+C w: The flag array w determines the status of elements and
+C variables, and the external degree of elements.
+C
+C for elements:
+C if w (e) = 0, then the element e is absorbed
+C if w (e) .ge. wflg, then w (e) - wflg is the size of
+C the set |Le \ Lme|, in terms of nonzeros (the
+C sum of abs (nv (i)) for each principal variable i that
+C is both in the pattern of element e and NOT in the
+C pattern of the current pivot element, me).
+C if wflg .gt. w (e) .gt. 0, then e is not absorbed and has
+C not yet been seen in the scan of the element lists in
+C the computation of |Le\Lme| in loop 150 below.
+C
+C for variables:
+C during supervariable detection, if w (j) .ne. wflg then j is
+C not in the pattern of variable i
+C
+C The w array is initialized by setting w (i) = 1 for all i,
+C and by setting wflg = 2. It is reinitialized if wflg becomes
+C too large (to ensure that wflg+n does not cause integer
+C overflow).
+
+C-----------------------------------------------------------------------
+C LOCAL INTEGERS:
+C-----------------------------------------------------------------------
+
+ INTEGER DEG, DEGME, DEXT, DMAX, E, ELENME, ELN, HASH, HMOD, I,
+ $ ILAST, INEXT, J, JLAST, JNEXT, K, KNT1, KNT2, KNT3,
+ $ LENJ, LN, MAXMEM, ME, MEM, MINDEG, NEL, NEWMEM,
+ $ NLEFT, NVI, NVJ, NVPIV, SLENME, WE, WFLG, WNVI, X
+
+C deg: the degree of a variable or element
+C degme: size, |Lme|, of the current element, me (= degree (me))
+C dext: external degree, |Le \ Lme|, of some element e
+C dmax: largest |Le| seen so far
+C e: an element
+C elenme: the length, elen (me), of element list of pivotal var.
+C eln: the length, elen (...), of an element list
+C hash: the computed value of the hash function
+C hmod: the hash function is computed modulo hmod = max (1,n-1)
+C i: a supervariable
+C ilast: the entry in a link list preceding i
+C inext: the entry in a link list following i
+C j: a supervariable
+C jlast: the entry in a link list preceding j
+C jnext: the entry in a link list, or path, following j
+C k: the pivot order of an element or variable
+C knt1: loop counter used during element construction
+C knt2: loop counter used during element construction
+C knt3: loop counter used during compression
+C lenj: len (j)
+C ln: length of a supervariable list
+C maxmem: amount of memory needed for no compressions
+C me: current supervariable being eliminated, and the
+C current element created by eliminating that
+C supervariable
+C mem: memory in use assuming no compressions have occurred
+C mindeg: current minimum degree
+C nel: number of pivots selected so far
+C newmem: amount of new memory needed for current pivot element
+C nleft: n - nel, the number of nonpivotal rows/columns remaining
+C nvi: the number of variables in a supervariable i (= nv (i))
+C nvj: the number of variables in a supervariable j (= nv (j))
+C nvpiv: number of pivots in current element
+C slenme: number of variables in variable list of pivotal variable
+C we: w (e)
+C wflg: used for flagging the w array. See description of iw.
+C wnvi: wflg - nv (i)
+C x: either a supervariable or an element
+
+C-----------------------------------------------------------------------
+C LOCAL POINTERS:
+C-----------------------------------------------------------------------
+
+ INTEGER P, P1, P2, P3, PDST, PEND, PJ, PME, PME1, PME2, PN, PSRC
+
+C Any parameter (pe (...) or pfree) or local variable
+C starting with "p" (for Pointer) is an index into iw,
+C and all indices into iw use variables starting with
+C "p." The only exception to this rule is the iwlen
+C input argument.
+
+C p: pointer into lots of things
+C p1: pe (i) for some variable i (start of element list)
+C p2: pe (i) + elen (i) - 1 for some var. i (end of el. list)
+C p3: index of first supervariable in clean list
+C pdst: destination pointer, for compression
+C pend: end of memory to compress
+C pj: pointer into an element or variable
+C pme: pointer into the current element (pme1...pme2)
+C pme1: the current element, me, is stored in iw (pme1...pme2)
+C pme2: the end of the current element
+C pn: pointer into a "clean" variable, also used to compress
+C psrc: source pointer, for compression
+
+C-----------------------------------------------------------------------
+C FUNCTIONS CALLED:
+C-----------------------------------------------------------------------
+
+ INTRINSIC MAX, MIN, MOD
+
+C=======================================================================
+C INITIALIZATIONS
+C=======================================================================
+
+ WFLG = 2
+ MINDEG = 1
+ NCMPA = 0
+ NEL = 0
+ HMOD = MAX (1, N-1)
+ DMAX = 0
+ MEM = PFREE - 1
+ MAXMEM = MEM
+ ME = 0
+
+ DO 10 I = 1, N
+ LAST (I) = 0
+ HEAD (I) = 0
+ NV (I) = 1
+ W (I) = 1
+ ELEN (I) = 0
+ DEGREE (I) = LEN (I)
+10 CONTINUE
+
+C ----------------------------------------------------------------
+C initialize degree lists and eliminate rows with no off-diag. nz.
+C ----------------------------------------------------------------
+
+ DO 20 I = 1, N
+
+ DEG = DEGREE (I)
+
+ IF (DEG .GT. 0) THEN
+
+C ----------------------------------------------------------
+C place i in the degree list corresponding to its degree
+C ----------------------------------------------------------
+
+ INEXT = HEAD (DEG)
+ IF (INEXT .NE. 0) LAST (INEXT) = I
+ NEXT (I) = INEXT
+ HEAD (DEG) = I
+
+ ELSE
+
+C ----------------------------------------------------------
+C we have a variable that can be eliminated at once because
+C there is no off-diagonal non-zero in its row.
+C ----------------------------------------------------------
+
+ NEL = NEL + 1
+ ELEN (I) = -NEL
+ PE (I) = 0
+ W (I) = 0
+
+ ENDIF
+
+20 CONTINUE
+
+C=======================================================================
+C WHILE (selecting pivots) DO
+C=======================================================================
+
+30 CONTINUE
+ IF (NEL .LT. N) THEN
+
+C=======================================================================
+C GET PIVOT OF MINIMUM DEGREE
+C=======================================================================
+
+C -------------------------------------------------------------
+C find next supervariable for elimination
+C -------------------------------------------------------------
+
+ DO 40 DEG = MINDEG, N
+ ME = HEAD (DEG)
+ IF (ME .GT. 0) GOTO 50
+40 CONTINUE
+50 CONTINUE
+ MINDEG = DEG
+
+C -------------------------------------------------------------
+C remove chosen variable from link list
+C -------------------------------------------------------------
+
+ INEXT = NEXT (ME)
+ IF (INEXT .NE. 0) LAST (INEXT) = 0
+ HEAD (DEG) = INEXT
+
+C -------------------------------------------------------------
+C me represents the elimination of pivots nel+1 to nel+nv(me).
+C place me itself as the first in this set. It will be moved
+C to the nel+nv(me) position when the permutation vectors are
+C computed.
+C -------------------------------------------------------------
+
+ ELENME = ELEN (ME)
+ ELEN (ME) = - (NEL + 1)
+ NVPIV = NV (ME)
+ NEL = NEL + NVPIV
+
+C=======================================================================
+C CONSTRUCT NEW ELEMENT
+C=======================================================================
+
+C -------------------------------------------------------------
+C At this point, me is the pivotal supervariable. It will be
+C converted into the current element. Scan list of the
+C pivotal supervariable, me, setting tree pointers and
+C constructing new list of supervariables for the new element,
+C me. p is a pointer to the current position in the old list.
+C -------------------------------------------------------------
+
+C flag the variable "me" as being in Lme by negating nv (me)
+ NV (ME) = -NVPIV
+ DEGME = 0
+
+ IF (ELENME .EQ. 0) THEN
+
+C ----------------------------------------------------------
+C construct the new element in place
+C ----------------------------------------------------------
+
+ PME1 = PE (ME)
+ PME2 = PME1 - 1
+
+ DO 60 P = PME1, PME1 + LEN (ME) - 1
+ I = IW (P)
+ NVI = NV (I)
+ IF (NVI .GT. 0) THEN
+
+C ----------------------------------------------------
+C i is a principal variable not yet placed in Lme.
+C store i in new list
+C ----------------------------------------------------
+
+ DEGME = DEGME + NVI
+C flag i as being in Lme by negating nv (i)
+ NV (I) = -NVI
+ PME2 = PME2 + 1
+ IW (PME2) = I
+
+C ----------------------------------------------------
+C remove variable i from degree list.
+C ----------------------------------------------------
+
+ ILAST = LAST (I)
+ INEXT = NEXT (I)
+ IF (INEXT .NE. 0) LAST (INEXT) = ILAST
+ IF (ILAST .NE. 0) THEN
+ NEXT (ILAST) = INEXT
+ ELSE
+C i is at the head of the degree list
+ HEAD (DEGREE (I)) = INEXT
+ ENDIF
+
+ ENDIF
+60 CONTINUE
+C this element takes no new memory in iw:
+ NEWMEM = 0
+
+ ELSE
+
+C ----------------------------------------------------------
+C construct the new element in empty space, iw (pfree ...)
+C ----------------------------------------------------------
+
+ P = PE (ME)
+ PME1 = PFREE
+ SLENME = LEN (ME) - ELENME
+
+ DO 120 KNT1 = 1, ELENME + 1
+
+ IF (KNT1 .GT. ELENME) THEN
+C search the supervariables in me.
+ E = ME
+ PJ = P
+ LN = SLENME
+ ELSE
+C search the elements in me.
+ E = IW (P)
+ P = P + 1
+ PJ = PE (E)
+ LN = LEN (E)
+ ENDIF
+
+C -------------------------------------------------------
+C search for different supervariables and add them to the
+C new list, compressing when necessary. this loop is
+C executed once for each element in the list and once for
+C all the supervariables in the list.
+C -------------------------------------------------------
+
+ DO 110 KNT2 = 1, LN
+ I = IW (PJ)
+ PJ = PJ + 1
+ NVI = NV (I)
+ IF (NVI .GT. 0) THEN
+
+C -------------------------------------------------
+C compress iw, if necessary
+C -------------------------------------------------
+
+ IF (PFREE .GT. IWLEN) THEN
+C prepare for compressing iw by adjusting
+C pointers and lengths so that the lists being
+C searched in the inner and outer loops contain
+C only the remaining entries.
+
+ PE (ME) = P
+ LEN (ME) = LEN (ME) - KNT1
+ IF (LEN (ME) .EQ. 0) THEN
+C nothing left of supervariable me
+ PE (ME) = 0
+ ENDIF
+ PE (E) = PJ
+ LEN (E) = LN - KNT2
+ IF (LEN (E) .EQ. 0) THEN
+C nothing left of element e
+ PE (E) = 0
+ ENDIF
+
+ NCMPA = NCMPA + 1
+C store first item in pe
+C set first entry to -item
+ DO 70 J = 1, N
+ PN = PE (J)
+ IF (PN .GT. 0) THEN
+ PE (J) = IW (PN)
+ IW (PN) = -J
+ ENDIF
+70 CONTINUE
+
+C psrc/pdst point to source/destination
+ PDST = 1
+ PSRC = 1
+ PEND = PME1 - 1
+
+C while loop:
+80 CONTINUE
+ IF (PSRC .LE. PEND) THEN
+C search for next negative entry
+ J = -IW (PSRC)
+ PSRC = PSRC + 1
+ IF (J .GT. 0) THEN
+ IW (PDST) = PE (J)
+ PE (J) = PDST
+ PDST = PDST + 1
+C copy from source to destination
+ LENJ = LEN (J)
+ DO 90 KNT3 = 0, LENJ - 2
+ IW (PDST + KNT3) = IW (PSRC + KNT3)
+90 CONTINUE
+ PDST = PDST + LENJ - 1
+ PSRC = PSRC + LENJ - 1
+ ENDIF
+ GOTO 80
+ ENDIF
+
+C move the new partially-constructed element
+ P1 = PDST
+ DO 100 PSRC = PME1, PFREE - 1
+ IW (PDST) = IW (PSRC)
+ PDST = PDST + 1
+100 CONTINUE
+ PME1 = P1
+ PFREE = PDST
+ PJ = PE (E)
+ P = PE (ME)
+ ENDIF
+
+C -------------------------------------------------
+C i is a principal variable not yet placed in Lme
+C store i in new list
+C -------------------------------------------------
+
+ DEGME = DEGME + NVI
+C flag i as being in Lme by negating nv (i)
+ NV (I) = -NVI
+ IW (PFREE) = I
+ PFREE = PFREE + 1
+
+C -------------------------------------------------
+C remove variable i from degree link list
+C -------------------------------------------------
+
+ ILAST = LAST (I)
+ INEXT = NEXT (I)
+ IF (INEXT .NE. 0) LAST (INEXT) = ILAST
+ IF (ILAST .NE. 0) THEN
+ NEXT (ILAST) = INEXT
+ ELSE
+C i is at the head of the degree list
+ HEAD (DEGREE (I)) = INEXT
+ ENDIF
+
+ ENDIF
+110 CONTINUE
+
+ IF (E .NE. ME) THEN
+C set tree pointer and flag to indicate element e is
+C absorbed into new element me (the parent of e is me)
+ PE (E) = -ME
+ W (E) = 0
+ ENDIF
+120 CONTINUE
+
+ PME2 = PFREE - 1
+C this element takes newmem new memory in iw (possibly zero)
+ NEWMEM = PFREE - PME1
+ MEM = MEM + NEWMEM
+ MAXMEM = MAX (MAXMEM, MEM)
+ ENDIF
+
+C -------------------------------------------------------------
+C me has now been converted into an element in iw (pme1..pme2)
+C -------------------------------------------------------------
+
+C degme holds the external degree of new element
+ DEGREE (ME) = DEGME
+ PE (ME) = PME1
+ LEN (ME) = PME2 - PME1 + 1
+
+C -------------------------------------------------------------
+C make sure that wflg is not too large. With the current
+C value of wflg, wflg+n must not cause integer overflow
+C -------------------------------------------------------------
+
+ IF (WFLG + N .LE. WFLG) THEN
+ DO 130 X = 1, N
+ IF (W (X) .NE. 0) W (X) = 1
+130 CONTINUE
+ WFLG = 2
+ ENDIF
+
+C=======================================================================
+C COMPUTE (w (e) - wflg) = |Le\Lme| FOR ALL ELEMENTS
+C=======================================================================
+
+C -------------------------------------------------------------
+C Scan 1: compute the external degrees of previous elements
+C with respect to the current element. That is:
+C (w (e) - wflg) = |Le \ Lme|
+C for each element e that appears in any supervariable in Lme.
+C The notation Le refers to the pattern (list of
+C supervariables) of a previous element e, where e is not yet
+C absorbed, stored in iw (pe (e) + 1 ... pe (e) + iw (pe (e))).
+C The notation Lme refers to the pattern of the current element
+C (stored in iw (pme1..pme2)). If (w (e) - wflg) becomes
+C zero, then the element e will be absorbed in scan 2.
+C -------------------------------------------------------------
+
+ DO 150 PME = PME1, PME2
+ I = IW (PME)
+ ELN = ELEN (I)
+ IF (ELN .GT. 0) THEN
+C note that nv (i) has been negated to denote i in Lme:
+ NVI = -NV (I)
+ WNVI = WFLG - NVI
+ DO 140 P = PE (I), PE (I) + ELN - 1
+ E = IW (P)
+ WE = W (E)
+ IF (WE .GE. WFLG) THEN
+C unabsorbed element e has been seen in this loop
+ WE = WE - NVI
+ ELSE IF (WE .NE. 0) THEN
+C e is an unabsorbed element
+C this is the first we have seen e in all of Scan 1
+ WE = DEGREE (E) + WNVI
+ ENDIF
+ W (E) = WE
+140 CONTINUE
+ ENDIF
+150 CONTINUE
+
+C=======================================================================
+C DEGREE UPDATE AND ELEMENT ABSORPTION
+C=======================================================================
+
+C -------------------------------------------------------------
+C Scan 2: for each i in Lme, sum up the degree of Lme (which
+C is degme), plus the sum of the external degrees of each Le
+C for the elements e appearing within i, plus the
+C supervariables in i. Place i in hash list.
+C -------------------------------------------------------------
+
+ DO 180 PME = PME1, PME2
+ I = IW (PME)
+ P1 = PE (I)
+ P2 = P1 + ELEN (I) - 1
+ PN = P1
+ HASH = 0
+ DEG = 0
+
+C ----------------------------------------------------------
+C scan the element list associated with supervariable i
+C ----------------------------------------------------------
+
+ DO 160 P = P1, P2
+ E = IW (P)
+C dext = | Le \ Lme |
+ DEXT = W (E) - WFLG
+ IF (DEXT .GT. 0) THEN
+ DEG = DEG + DEXT
+ IW (PN) = E
+ PN = PN + 1
+ HASH = HASH + E
+ ELSE IF (DEXT .EQ. 0) THEN
+C aggressive absorption: e is not adjacent to me, but
+C the |Le \ Lme| is 0, so absorb it into me
+ PE (E) = -ME
+ W (E) = 0
+ ELSE
+C element e has already been absorbed, due to
+C regular absorption, in do loop 120 above. Ignore it.
+ CONTINUE
+ ENDIF
+160 CONTINUE
+
+C count the number of elements in i (including me):
+ ELEN (I) = PN - P1 + 1
+
+C ----------------------------------------------------------
+C scan the supervariables in the list associated with i
+C ----------------------------------------------------------
+
+ P3 = PN
+ DO 170 P = P2 + 1, P1 + LEN (I) - 1
+ J = IW (P)
+ NVJ = NV (J)
+ IF (NVJ .GT. 0) THEN
+C j is unabsorbed, and not in Lme.
+C add to degree and add to new list
+ DEG = DEG + NVJ
+ IW (PN) = J
+ PN = PN + 1
+ HASH = HASH + J
+ ENDIF
+170 CONTINUE
+
+C ----------------------------------------------------------
+C update the degree and check for mass elimination
+C ----------------------------------------------------------
+
+ IF (DEG .EQ. 0) THEN
+
+C -------------------------------------------------------
+C mass elimination
+C -------------------------------------------------------
+
+C There is nothing left of this node except for an
+C edge to the current pivot element. elen (i) is 1,
+C and there are no variables adjacent to node i.
+C Absorb i into the current pivot element, me.
+
+ PE (I) = -ME
+ NVI = -NV (I)
+ DEGME = DEGME - NVI
+ NVPIV = NVPIV + NVI
+ NEL = NEL + NVI
+ NV (I) = 0
+ ELEN (I) = 0
+
+ ELSE
+
+C -------------------------------------------------------
+C update the upper-bound degree of i
+C -------------------------------------------------------
+
+C the following degree does not yet include the size
+C of the current element, which is added later:
+ DEGREE (I) = MIN (DEGREE (I), DEG)
+
+C -------------------------------------------------------
+C add me to the list for i
+C -------------------------------------------------------
+
+C move first supervariable to end of list
+ IW (PN) = IW (P3)
+C move first element to end of element part of list
+ IW (P3) = IW (P1)
+C add new element to front of list.
+ IW (P1) = ME
+C store the new length of the list in len (i)
+ LEN (I) = PN - P1 + 1
+
+C -------------------------------------------------------
+C place in hash bucket. Save hash key of i in last (i).
+C -------------------------------------------------------
+
+ HASH = MOD (HASH, HMOD) + 1
+ J = HEAD (HASH)
+ IF (J .LE. 0) THEN
+C the degree list is empty, hash head is -j
+ NEXT (I) = -J
+ HEAD (HASH) = -I
+ ELSE
+C degree list is not empty
+C use last (head (hash)) as hash head
+ NEXT (I) = LAST (J)
+ LAST (J) = I
+ ENDIF
+ LAST (I) = HASH
+ ENDIF
+180 CONTINUE
+
+ DEGREE (ME) = DEGME
+
+C -------------------------------------------------------------
+C Clear the counter array, w (...), by incrementing wflg.
+C -------------------------------------------------------------
+
+ DMAX = MAX (DMAX, DEGME)
+ WFLG = WFLG + DMAX
+
+C make sure that wflg+n does not cause integer overflow
+ IF (WFLG + N .LE. WFLG) THEN
+ DO 190 X = 1, N
+ IF (W (X) .NE. 0) W (X) = 1
+190 CONTINUE
+ WFLG = 2
+ ENDIF
+C at this point, w (1..n) .lt. wflg holds
+
+C=======================================================================
+C SUPERVARIABLE DETECTION
+C=======================================================================
+
+ DO 250 PME = PME1, PME2
+ I = IW (PME)
+ IF (NV (I) .LT. 0) THEN
+C i is a principal variable in Lme
+
+C -------------------------------------------------------
+C examine all hash buckets with 2 or more variables. We
+C do this by examing all unique hash keys for super-
+C variables in the pattern Lme of the current element, me
+C -------------------------------------------------------
+
+ HASH = LAST (I)
+C let i = head of hash bucket, and empty the hash bucket
+ J = HEAD (HASH)
+ IF (J .EQ. 0) GOTO 250
+ IF (J .LT. 0) THEN
+C degree list is empty
+ I = -J
+ HEAD (HASH) = 0
+ ELSE
+C degree list is not empty, restore last () of head
+ I = LAST (J)
+ LAST (J) = 0
+ ENDIF
+ IF (I .EQ. 0) GOTO 250
+
+C while loop:
+200 CONTINUE
+ IF (NEXT (I) .NE. 0) THEN
+
+C ----------------------------------------------------
+C this bucket has one or more variables following i.
+C scan all of them to see if i can absorb any entries
+C that follow i in hash bucket. Scatter i into w.
+C ----------------------------------------------------
+
+ LN = LEN (I)
+ ELN = ELEN (I)
+C do not flag the first element in the list (me)
+ DO 210 P = PE (I) + 1, PE (I) + LN - 1
+ W (IW (P)) = WFLG
+210 CONTINUE
+
+C ----------------------------------------------------
+C scan every other entry j following i in bucket
+C ----------------------------------------------------
+
+ JLAST = I
+ J = NEXT (I)
+
+C while loop:
+220 CONTINUE
+ IF (J .NE. 0) THEN
+
+C -------------------------------------------------
+C check if j and i have identical nonzero pattern
+C -------------------------------------------------
+
+ IF (LEN (J) .NE. LN) THEN
+C i and j do not have same size data structure
+ GOTO 240
+ ENDIF
+ IF (ELEN (J) .NE. ELN) THEN
+C i and j do not have same number of adjacent el
+ GOTO 240
+ ENDIF
+C do not flag the first element in the list (me)
+ DO 230 P = PE (J) + 1, PE (J) + LN - 1
+ IF (W (IW (P)) .NE. WFLG) THEN
+C an entry (iw(p)) is in j but not in i
+ GOTO 240
+ ENDIF
+230 CONTINUE
+
+C -------------------------------------------------
+C found it! j can be absorbed into i
+C -------------------------------------------------
+
+ PE (J) = -I
+C both nv (i) and nv (j) are negated since they
+C are in Lme, and the absolute values of each
+C are the number of variables in i and j:
+ NV (I) = NV (I) + NV (J)
+ NV (J) = 0
+ ELEN (J) = 0
+C delete j from hash bucket
+ J = NEXT (J)
+ NEXT (JLAST) = J
+ GOTO 220
+
+C -------------------------------------------------
+240 CONTINUE
+C j cannot be absorbed into i
+C -------------------------------------------------
+
+ JLAST = J
+ J = NEXT (J)
+ GOTO 220
+ ENDIF
+
+C ----------------------------------------------------
+C no more variables can be absorbed into i
+C go to next i in bucket and clear flag array
+C ----------------------------------------------------
+
+ WFLG = WFLG + 1
+ I = NEXT (I)
+ IF (I .NE. 0) GOTO 200
+ ENDIF
+ ENDIF
+250 CONTINUE
+
+C=======================================================================
+C RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVAR. FROM ELEMENT
+C=======================================================================
+
+ P = PME1
+ NLEFT = N - NEL
+ DO 260 PME = PME1, PME2
+ I = IW (PME)
+ NVI = -NV (I)
+ IF (NVI .GT. 0) THEN
+C i is a principal variable in Lme
+C restore nv (i) to signify that i is principal
+ NV (I) = NVI
+
+C -------------------------------------------------------
+C compute the external degree (add size of current elem)
+C -------------------------------------------------------
+
+ DEG = MIN (DEGREE (I) + DEGME - NVI, NLEFT - NVI)
+
+C -------------------------------------------------------
+C place the supervariable at the head of the degree list
+C -------------------------------------------------------
+
+ INEXT = HEAD (DEG)
+ IF (INEXT .NE. 0) LAST (INEXT) = I
+ NEXT (I) = INEXT
+ LAST (I) = 0
+ HEAD (DEG) = I
+
+C -------------------------------------------------------
+C save the new degree, and find the minimum degree
+C -------------------------------------------------------
+
+ MINDEG = MIN (MINDEG, DEG)
+ DEGREE (I) = DEG
+
+C -------------------------------------------------------
+C place the supervariable in the element pattern
+C -------------------------------------------------------
+
+ IW (P) = I
+ P = P + 1
+ ENDIF
+260 CONTINUE
+
+C=======================================================================
+C FINALIZE THE NEW ELEMENT
+C=======================================================================
+
+ NV (ME) = NVPIV + DEGME
+C nv (me) is now the degree of pivot (including diagonal part)
+C save the length of the list for the new element me
+ LEN (ME) = P - PME1
+ IF (LEN (ME) .EQ. 0) THEN
+C there is nothing left of the current pivot element
+ PE (ME) = 0
+ W (ME) = 0
+ ENDIF
+ IF (NEWMEM .NE. 0) THEN
+C element was not constructed in place: deallocate part
+C of it (final size is less than or equal to newmem,
+C since newly nonprincipal variables have been removed).
+ PFREE = P
+ MEM = MEM - NEWMEM + LEN (ME)
+ ENDIF
+
+C=======================================================================
+C END WHILE (selecting pivots)
+ GOTO 30
+ ENDIF
+C=======================================================================
+
+C=======================================================================
+C COMPUTE THE PERMUTATION VECTORS
+C=======================================================================
+
+C ----------------------------------------------------------------
+C The time taken by the following code is O(n). At this
+C point, elen (e) = -k has been done for all elements e,
+C and elen (i) = 0 has been done for all nonprincipal
+C variables i. At this point, there are no principal
+C supervariables left, and all elements are absorbed.
+C ----------------------------------------------------------------
+
+C ----------------------------------------------------------------
+C compute the ordering of unordered nonprincipal variables
+C ----------------------------------------------------------------
+
+ DO 290 I = 1, N
+ IF (ELEN (I) .EQ. 0) THEN
+
+C ----------------------------------------------------------
+C i is an un-ordered row. Traverse the tree from i until
+C reaching an element, e. The element, e, was the
+C principal supervariable of i and all nodes in the path
+C from i to when e was selected as pivot.
+C ----------------------------------------------------------
+
+ J = -PE (I)
+C while (j is a variable) do:
+270 CONTINUE
+ IF (ELEN (J) .GE. 0) THEN
+ J = -PE (J)
+ GOTO 270
+ ENDIF
+ E = J
+
+C ----------------------------------------------------------
+C get the current pivot ordering of e
+C ----------------------------------------------------------
+
+ K = -ELEN (E)
+
+C ----------------------------------------------------------
+C traverse the path again from i to e, and compress the
+C path (all nodes point to e). Path compression allows
+C this code to compute in O(n) time. Order the unordered
+C nodes in the path, and place the element e at the end.
+C ----------------------------------------------------------
+
+ J = I
+C while (j is a variable) do:
+280 CONTINUE
+ IF (ELEN (J) .GE. 0) THEN
+ JNEXT = -PE (J)
+ PE (J) = -E
+ IF (ELEN (J) .EQ. 0) THEN
+C j is an unordered row
+ ELEN (J) = K
+ K = K + 1
+ ENDIF
+ J = JNEXT
+ GOTO 280
+ ENDIF
+C leave elen (e) negative, so we know it is an element
+ ELEN (E) = -K
+ ENDIF
+290 CONTINUE
+
+C ----------------------------------------------------------------
+C reset the inverse permutation (elen (1..n)) to be positive,
+C and compute the permutation (last (1..n)).
+C ----------------------------------------------------------------
+
+ DO 300 I = 1, N
+ K = ABS (ELEN (I))
+ LAST (K) = I
+ ELEN (I) = K
+300 CONTINUE
+
+C=======================================================================
+C RETURN THE MEMORY USAGE IN IW
+C=======================================================================
+
+C If maxmem is less than or equal to iwlen, then no compressions
+C occurred, and iw (maxmem+1 ... iwlen) was unused. Otherwise
+C compressions did occur, and iwlen would have had to have been
+C greater than or equal to maxmem for no compressions to occur.
+C Return the value of maxmem in the pfree argument.
+
+ PFREE = MAXMEM
+
+ RETURN
+ END
+
--- /dev/null
+/* ========================================================================= */
+/* === AMD_1 =============================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* AMD_1: Construct A+A' for a sparse matrix A and perform the AMD ordering.
+ *
+ * The n-by-n sparse matrix A can be unsymmetric. It is stored in MATLAB-style
+ * compressed-column form, with sorted row indices in each column, and no
+ * duplicate entries. Diagonal entries may be present, but they are ignored.
+ * Row indices of column j of A are stored in Ai [Ap [j] ... Ap [j+1]-1].
+ * Ap [0] must be zero, and nz = Ap [n] is the number of entries in A. The
+ * size of the matrix, n, must be greater than or equal to zero.
+ *
+ * This routine must be preceded by a call to AMD_aat, which computes the
+ * number of entries in each row/column in A+A', excluding the diagonal.
+ * Len [j], on input, is the number of entries in row/column j of A+A'. This
+ * routine constructs the matrix A+A' and then calls AMD_2. No error checking
+ * is performed (this was done in AMD_aat).
+ */
+
+#include "amd_internal.h"
+
+GLOBAL void AMD_1
+(
+ Int n, /* n > 0 */
+ const Int Ap [ ], /* input of size n+1, not modified */
+ const Int Ai [ ], /* input of size nz = Ap [n], not modified */
+ Int P [ ], /* size n output permutation */
+ Int Pinv [ ], /* size n output inverse permutation */
+ Int Len [ ], /* size n input, undefined on output */
+ Int slen, /* slen >= sum (Len [0..n-1]) + 7n,
+ * ideally slen = 1.2 * sum (Len) + 8n */
+ Int S [ ], /* size slen workspace */
+ double Control [ ], /* input array of size AMD_CONTROL */
+ double Info [ ] /* output array of size AMD_INFO */
+)
+{
+ Int i, j, k, p, pfree, iwlen, pj, p1, p2, pj2, *Iw, *Pe, *Nv, *Head,
+ *Elen, *Degree, *s, *W, *Sp, *Tp ;
+
+ /* --------------------------------------------------------------------- */
+ /* construct the matrix for AMD_2 */
+ /* --------------------------------------------------------------------- */
+
+ ASSERT (n > 0) ;
+
+ iwlen = slen - 6*n ;
+ s = S ;
+ Pe = s ; s += n ;
+ Nv = s ; s += n ;
+ Head = s ; s += n ;
+ Elen = s ; s += n ;
+ Degree = s ; s += n ;
+ W = s ; s += n ;
+ Iw = s ; s += iwlen ;
+
+ ASSERT (AMD_valid (n, n, Ap, Ai)) ;
+
+ /* construct the pointers for A+A' */
+ Sp = Nv ; /* use Nv and W as workspace for Sp and Tp [ */
+ Tp = W ;
+ pfree = 0 ;
+ for (j = 0 ; j < n ; j++)
+ {
+ Pe [j] = pfree ;
+ Sp [j] = pfree ;
+ pfree += Len [j] ;
+ }
+
+ /* Note that this restriction on iwlen is slightly more restrictive than
+ * what is strictly required in AMD_2. AMD_2 can operate with no elbow
+ * room at all, but it will be very slow. For better performance, at
+ * least size-n elbow room is enforced. */
+ ASSERT (iwlen >= pfree + n) ;
+
+#ifndef NDEBUG
+ for (p = 0 ; p < iwlen ; p++) Iw [p] = EMPTY ;
+#endif
+
+ for (k = 0 ; k < n ; k++)
+ {
+ AMD_DEBUG1 (("Construct row/column k= "ID" of A+A'\n", k)) ;
+ p1 = Ap [k] ;
+ p2 = Ap [k+1] ;
+
+ /* construct A+A' */
+ for (p = p1 ; p < p2 ; )
+ {
+ /* scan the upper triangular part of A */
+ j = Ai [p] ;
+ ASSERT (j >= 0 && j < n) ;
+ if (j < k)
+ {
+ /* entry A (j,k) in the strictly upper triangular part */
+ ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
+ ASSERT (Sp [k] < (k == n-1 ? pfree : Pe [k+1])) ;
+ Iw [Sp [j]++] = k ;
+ Iw [Sp [k]++] = j ;
+ p++ ;
+ }
+ else if (j == k)
+ {
+ /* skip the diagonal */
+ p++ ;
+ break ;
+ }
+ else /* j > k */
+ {
+ /* first entry below the diagonal */
+ break ;
+ }
+ /* scan lower triangular part of A, in column j until reaching
+ * row k. Start where last scan left off. */
+ ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
+ pj2 = Ap [j+1] ;
+ for (pj = Tp [j] ; pj < pj2 ; )
+ {
+ i = Ai [pj] ;
+ ASSERT (i >= 0 && i < n) ;
+ if (i < k)
+ {
+ /* A (i,j) is only in the lower part, not in upper */
+ ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
+ ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
+ Iw [Sp [i]++] = j ;
+ Iw [Sp [j]++] = i ;
+ pj++ ;
+ }
+ else if (i == k)
+ {
+ /* entry A (k,j) in lower part and A (j,k) in upper */
+ pj++ ;
+ break ;
+ }
+ else /* i > k */
+ {
+ /* consider this entry later, when k advances to i */
+ break ;
+ }
+ }
+ Tp [j] = pj ;
+ }
+ Tp [k] = p ;
+ }
+
+ /* clean up, for remaining mismatched entries */
+ for (j = 0 ; j < n ; j++)
+ {
+ for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
+ {
+ i = Ai [pj] ;
+ ASSERT (i >= 0 && i < n) ;
+ /* A (i,j) is only in the lower part, not in upper */
+ ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
+ ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
+ Iw [Sp [i]++] = j ;
+ Iw [Sp [j]++] = i ;
+ }
+ }
+
+#ifndef NDEBUG
+ for (j = 0 ; j < n-1 ; j++) ASSERT (Sp [j] == Pe [j+1]) ;
+ ASSERT (Sp [n-1] == pfree) ;
+#endif
+
+ /* Tp and Sp no longer needed ] */
+
+ /* --------------------------------------------------------------------- */
+ /* order the matrix */
+ /* --------------------------------------------------------------------- */
+
+ AMD_2 (n, Pe, Iw, Len, iwlen, pfree,
+ Nv, Pinv, P, Head, Elen, Degree, W, Control, Info) ;
+}
--- /dev/null
+/* ========================================================================= */
+/* === AMD_2 =============================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* AMD_2: performs the AMD ordering on a symmetric sparse matrix A, followed
+ * by a postordering (via depth-first search) of the assembly tree using the
+ * AMD_postorder routine.
+ */
+
+#include "amd_internal.h"
+
+GLOBAL void AMD_2
+(
+ Int n, /* A is n-by-n, where n > 0 */
+ Int Pe [ ], /* Pe [0..n-1]: index in Iw of row i on input */
+ Int Iw [ ], /* workspace of size iwlen. Iw [0..pfree-1]
+ * holds the matrix on input */
+ Int Len [ ], /* Len [0..n-1]: length for row/column i on input */
+ Int iwlen, /* length of Iw. iwlen >= pfree + n */
+ Int pfree, /* Iw [pfree ... iwlen-1] is empty on input */
+
+ /* 7 size-n workspaces, not defined on input: */
+ Int Nv [ ], /* the size of each supernode on output */
+ Int Next [ ], /* the output inverse permutation */
+ Int Last [ ], /* the output permutation */
+ Int Head [ ],
+ Int Elen [ ], /* the size columns of L for each supernode */
+ Int Degree [ ],
+ Int W [ ],
+
+ /* control parameters and output statistics */
+ double Control [ ], /* array of size AMD_CONTROL */
+ double Info [ ] /* array of size AMD_INFO */
+)
+{
+
+/*
+ * Given a representation of the nonzero pattern of a symmetric matrix, A,
+ * (excluding the diagonal) perform an approximate minimum (UMFPACK/MA38-style)
+ * degree ordering to compute a pivot order such that the introduction of
+ * nonzeros (fill-in) in the Cholesky factors A = LL' is kept low. At each
+ * step, the pivot selected is the one with the minimum UMFAPACK/MA38-style
+ * upper-bound on the external degree. This routine can optionally perform
+ * aggresive absorption (as done by MC47B in the Harwell Subroutine
+ * Library).
+ *
+ * The approximate degree algorithm implemented here is the symmetric analog of
+ * the degree update algorithm in MA38 and UMFPACK (the Unsymmetric-pattern
+ * MultiFrontal PACKage, both by Davis and Duff). The routine is based on the
+ * MA27 minimum degree ordering algorithm by Iain Duff and John Reid.
+ *
+ * This routine is a translation of the original AMDBAR and MC47B routines,
+ * in Fortran, with the following modifications:
+ *
+ * (1) dense rows/columns are removed prior to ordering the matrix, and placed
+ * last in the output order. The presence of a dense row/column can
+ * increase the ordering time by up to O(n^2), unless they are removed
+ * prior to ordering.
+ *
+ * (2) the minimum degree ordering is followed by a postordering (depth-first
+ * search) of the assembly tree. Note that mass elimination (discussed
+ * below) combined with the approximate degree update can lead to the mass
+ * elimination of nodes with lower exact degree than the current pivot
+ * element. No additional fill-in is caused in the representation of the
+ * Schur complement. The mass-eliminated nodes merge with the current
+ * pivot element. They are ordered prior to the current pivot element.
+ * Because they can have lower exact degree than the current element, the
+ * merger of two or more of these nodes in the current pivot element can
+ * lead to a single element that is not a "fundamental supernode". The
+ * diagonal block can have zeros in it. Thus, the assembly tree used here
+ * is not guaranteed to be the precise supernodal elemination tree (with
+ * "funadmental" supernodes), and the postordering performed by this
+ * routine is not guaranteed to be a precise postordering of the
+ * elimination tree.
+ *
+ * (3) input parameters are added, to control aggressive absorption and the
+ * detection of "dense" rows/columns of A.
+ *
+ * (4) additional statistical information is returned, such as the number of
+ * nonzeros in L, and the flop counts for subsequent LDL' and LU
+ * factorizations. These are slight upper bounds, because of the mass
+ * elimination issue discussed above.
+ *
+ * (5) additional routines are added to interface this routine to MATLAB
+ * to provide a simple C-callable user-interface, to check inputs for
+ * errors, compute the symmetry of the pattern of A and the number of
+ * nonzeros in each row/column of A+A', to compute the pattern of A+A',
+ * to perform the assembly tree postordering, and to provide debugging
+ * ouput. Many of these functions are also provided by the Fortran
+ * Harwell Subroutine Library routine MC47A.
+ *
+ * (6) both "int" and "long" versions are provided. In the descriptions below
+ * and integer is and "int" or "long", depending on which version is
+ * being used.
+
+ **********************************************************************
+ ***** CAUTION: ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT. ******
+ **********************************************************************
+ ** If you want error checking, a more versatile input format, and a **
+ ** simpler user interface, use amd_order or amd_l_order instead. **
+ ** This routine is not meant to be user-callable. **
+ **********************************************************************
+
+ * ----------------------------------------------------------------------------
+ * References:
+ * ----------------------------------------------------------------------------
+ *
+ * [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern multifrontal
+ * method for sparse LU factorization", SIAM J. Matrix Analysis and
+ * Applications, vol. 18, no. 1, pp. 140-158. Discusses UMFPACK / MA38,
+ * which first introduced the approximate minimum degree used by this
+ * routine.
+ *
+ * [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An approximate
+ * minimum degree ordering algorithm," SIAM J. Matrix Analysis and
+ * Applications, vol. 17, no. 4, pp. 886-905, 1996. Discusses AMDBAR and
+ * MC47B, which are the Fortran versions of this routine.
+ *
+ * [3] Alan George and Joseph Liu, "The evolution of the minimum degree
+ * ordering algorithm," SIAM Review, vol. 31, no. 1, pp. 1-19, 1989.
+ * We list below the features mentioned in that paper that this code
+ * includes:
+ *
+ * mass elimination:
+ * Yes. MA27 relied on supervariable detection for mass elimination.
+ *
+ * indistinguishable nodes:
+ * Yes (we call these "supervariables"). This was also in the MA27
+ * code - although we modified the method of detecting them (the
+ * previous hash was the true degree, which we no longer keep track
+ * of). A supervariable is a set of rows with identical nonzero
+ * pattern. All variables in a supervariable are eliminated together.
+ * Each supervariable has as its numerical name that of one of its
+ * variables (its principal variable).
+ *
+ * quotient graph representation:
+ * Yes. We use the term "element" for the cliques formed during
+ * elimination. This was also in the MA27 code. The algorithm can
+ * operate in place, but it will work more efficiently if given some
+ * "elbow room."
+ *
+ * element absorption:
+ * Yes. This was also in the MA27 code.
+ *
+ * external degree:
+ * Yes. The MA27 code was based on the true degree.
+ *
+ * incomplete degree update and multiple elimination:
+ * No. This was not in MA27, either. Our method of degree update
+ * within MC47B is element-based, not variable-based. It is thus
+ * not well-suited for use with incomplete degree update or multiple
+ * elimination.
+ *
+ * Authors, and Copyright (C) 2004 by:
+ * Timothy A. Davis, Patrick Amestoy, Iain S. Duff, John K. Reid.
+ *
+ * Acknowledgements: This work (and the UMFPACK package) was supported by the
+ * National Science Foundation (ASC-9111263, DMS-9223088, and CCR-0203270).
+ * The UMFPACK/MA38 approximate degree update algorithm, the unsymmetric analog
+ * which forms the basis of AMD, was developed while Tim Davis was supported by
+ * CERFACS (Toulouse, France) in a post-doctoral position. This C version, and
+ * the etree postorder, were written while Tim Davis was on sabbatical at
+ * Stanford University and Lawrence Berkeley National Laboratory.
+
+ * ----------------------------------------------------------------------------
+ * INPUT ARGUMENTS (unaltered):
+ * ----------------------------------------------------------------------------
+
+ * n: The matrix order. Restriction: n >= 1.
+ *
+ * iwlen: The size of the Iw array. On input, the matrix is stored in
+ * Iw [0..pfree-1]. However, Iw [0..iwlen-1] should be slightly larger
+ * than what is required to hold the matrix, at least iwlen >= pfree + n.
+ * Otherwise, excessive compressions will take place. The recommended
+ * value of iwlen is 1.2 * pfree + n, which is the value used in the
+ * user-callable interface to this routine (amd_order.c). The algorithm
+ * will not run at all if iwlen < pfree. Restriction: iwlen >= pfree + n.
+ * Note that this is slightly more restrictive than the actual minimum
+ * (iwlen >= pfree), but AMD_2 will be very slow with no elbow room.
+ * Thus, this routine enforces a bare minimum elbow room of size n.
+ *
+ * pfree: On input the tail end of the array, Iw [pfree..iwlen-1], is empty,
+ * and the matrix is stored in Iw [0..pfree-1]. During execution,
+ * additional data is placed in Iw, and pfree is modified so that
+ * Iw [pfree..iwlen-1] is always the unused part of Iw.
+ *
+ * Control: A double array of size AMD_CONTROL containing input parameters
+ * that affect how the ordering is computed. If NULL, then default
+ * settings are used.
+ *
+ * Control [AMD_DENSE] is used to determine whether or not a given input
+ * row is "dense". A row is "dense" if the number of entries in the row
+ * exceeds Control [AMD_DENSE] times sqrt (n), except that rows with 16 or
+ * fewer entries are never considered "dense". To turn off the detection
+ * of dense rows, set Control [AMD_DENSE] to a negative number, or to a
+ * number larger than sqrt (n). The default value of Control [AMD_DENSE]
+ * is AMD_DEFAULT_DENSE, which is defined in amd.h as 10.
+ *
+ * Control [AMD_AGGRESSIVE] is used to determine whether or not aggressive
+ * absorption is to be performed. If nonzero, then aggressive absorption
+ * is performed (this is the default).
+
+ * ----------------------------------------------------------------------------
+ * INPUT/OUPUT ARGUMENTS:
+ * ----------------------------------------------------------------------------
+ *
+ * Pe: An integer array of size n. On input, Pe [i] is the index in Iw of
+ * the start of row i. Pe [i] is ignored if row i has no off-diagonal
+ * entries. Thus Pe [i] must be in the range 0 to pfree-1 for non-empty
+ * rows.
+ *
+ * During execution, it is used for both supervariables and elements:
+ *
+ * Principal supervariable i: index into Iw of the description of
+ * supervariable i. A supervariable represents one or more rows of
+ * the matrix with identical nonzero pattern. In this case,
+ * Pe [i] >= 0.
+ *
+ * Non-principal supervariable i: if i has been absorbed into another
+ * supervariable j, then Pe [i] = FLIP (j), where FLIP (j) is defined
+ * as (-(j)-2). Row j has the same pattern as row i. Note that j
+ * might later be absorbed into another supervariable j2, in which
+ * case Pe [i] is still FLIP (j), and Pe [j] = FLIP (j2) which is
+ * < EMPTY, where EMPTY is defined as (-1) in amd_internal.h.
+ *
+ * Unabsorbed element e: the index into Iw of the description of element
+ * e, if e has not yet been absorbed by a subsequent element. Element
+ * e is created when the supervariable of the same name is selected as
+ * the pivot. In this case, Pe [i] >= 0.
+ *
+ * Absorbed element e: if element e is absorbed into element e2, then
+ * Pe [e] = FLIP (e2). This occurs when the pattern of e (which we
+ * refer to as Le) is found to be a subset of the pattern of e2 (that
+ * is, Le2). In this case, Pe [i] < EMPTY. If element e is "null"
+ * (it has no nonzeros outside its pivot block), then Pe [e] = EMPTY,
+ * and e is the root of an assembly subtree (or the whole tree if
+ * there is just one such root).
+ *
+ * Dense variable i: if i is "dense", then Pe [i] = EMPTY.
+ *
+ * On output, Pe holds the assembly tree/forest, which implicitly
+ * represents a pivot order with identical fill-in as the actual order
+ * (via a depth-first search of the tree), as follows. If Nv [i] > 0,
+ * then i represents a node in the assembly tree, and the parent of i is
+ * Pe [i], or EMPTY if i is a root. If Nv [i] = 0, then (i, Pe [i])
+ * represents an edge in a subtree, the root of which is a node in the
+ * assembly tree. Note that i refers to a row/column in the original
+ * matrix, not the permuted matrix.
+ *
+ * Info: A double array of size AMD_INFO. If present, (that is, not NULL),
+ * then statistics about the ordering are returned in the Info array.
+ * See amd.h for a description.
+
+ * ----------------------------------------------------------------------------
+ * INPUT/MODIFIED (undefined on output):
+ * ----------------------------------------------------------------------------
+ *
+ * Len: An integer array of size n. On input, Len [i] holds the number of
+ * entries in row i of the matrix, excluding the diagonal. The contents
+ * of Len are undefined on output.
+ *
+ * Iw: An integer array of size iwlen. On input, Iw [0..pfree-1] holds the
+ * description of each row i in the matrix. The matrix must be symmetric,
+ * and both upper and lower triangular parts must be present. The
+ * diagonal must not be present. Row i is held as follows:
+ *
+ * Len [i]: the length of the row i data structure in the Iw array.
+ * Iw [Pe [i] ... Pe [i] + Len [i] - 1]:
+ * the list of column indices for nonzeros in row i (simple
+ * supervariables), excluding the diagonal. All supervariables
+ * start with one row/column each (supervariable i is just row i).
+ * If Len [i] is zero on input, then Pe [i] is ignored on input.
+ *
+ * Note that the rows need not be in any particular order, and there
+ * may be empty space between the rows.
+ *
+ * During execution, the supervariable i experiences fill-in. This is
+ * represented by placing in i a list of the elements that cause fill-in
+ * in supervariable i:
+ *
+ * Len [i]: the length of supervariable i in the Iw array.
+ * Iw [Pe [i] ... Pe [i] + Elen [i] - 1]:
+ * the list of elements that contain i. This list is kept short
+ * by removing absorbed elements.
+ * Iw [Pe [i] + Elen [i] ... Pe [i] + Len [i] - 1]:
+ * the list of supervariables in i. This list is kept short by
+ * removing nonprincipal variables, and any entry j that is also
+ * contained in at least one of the elements (j in Le) in the list
+ * for i (e in row i).
+ *
+ * When supervariable i is selected as pivot, we create an element e of
+ * the same name (e=i):
+ *
+ * Len [e]: the length of element e in the Iw array.
+ * Iw [Pe [e] ... Pe [e] + Len [e] - 1]:
+ * the list of supervariables in element e.
+ *
+ * An element represents the fill-in that occurs when supervariable i is
+ * selected as pivot (which represents the selection of row i and all
+ * non-principal variables whose principal variable is i). We use the
+ * term Le to denote the set of all supervariables in element e. Absorbed
+ * supervariables and elements are pruned from these lists when
+ * computationally convenient.
+ *
+ * CAUTION: THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
+ * The contents of Iw are undefined on output.
+
+ * ----------------------------------------------------------------------------
+ * OUTPUT (need not be set on input):
+ * ----------------------------------------------------------------------------
+ *
+ * Nv: An integer array of size n. During execution, ABS (Nv [i]) is equal to
+ * the number of rows that are represented by the principal supervariable
+ * i. If i is a nonprincipal or dense variable, then Nv [i] = 0.
+ * Initially, Nv [i] = 1 for all i. Nv [i] < 0 signifies that i is a
+ * principal variable in the pattern Lme of the current pivot element me.
+ * After element me is constructed, Nv [i] is set back to a positive
+ * value.
+ *
+ * On output, Nv [i] holds the number of pivots represented by super
+ * row/column i of the original matrix, or Nv [i] = 0 for non-principal
+ * rows/columns. Note that i refers to a row/column in the original
+ * matrix, not the permuted matrix.
+ *
+ * Elen: An integer array of size n. See the description of Iw above. At the
+ * start of execution, Elen [i] is set to zero for all rows i. During
+ * execution, Elen [i] is the number of elements in the list for
+ * supervariable i. When e becomes an element, Elen [e] = FLIP (esize) is
+ * set, where esize is the size of the element (the number of pivots, plus
+ * the number of nonpivotal entries). Thus Elen [e] < EMPTY.
+ * Elen (i) = EMPTY set when variable i becomes nonprincipal.
+ *
+ * For variables, Elen (i) >= EMPTY holds until just before the
+ * postordering and permutation vectors are computed. For elements,
+ * Elen [e] < EMPTY holds.
+ *
+ * On output, Elen [i] is the degree of the row/column in the Cholesky
+ * factorization of the permuted matrix, corresponding to the original row
+ * i, if i is a super row/column. It is equal to EMPTY if i is
+ * non-principal. Note that i refers to a row/column in the original
+ * matrix, not the permuted matrix.
+ *
+ * Note that the contents of Elen on output differ from the Fortran
+ * version (Elen holds the inverse permutation in the Fortran version,
+ * which is instead returned in the Next array in this C version,
+ * described below).
+ *
+ * Last: In a degree list, Last [i] is the supervariable preceding i, or EMPTY
+ * if i is the head of the list. In a hash bucket, Last [i] is the hash
+ * key for i.
+ *
+ * Last [Head [hash]] is also used as the head of a hash bucket if
+ * Head [hash] contains a degree list (see the description of Head,
+ * below).
+ *
+ * On output, Last [0..n-1] holds the permutation. That is, if
+ * i = Last [k], then row i is the kth pivot row (where k ranges from 0 to
+ * n-1). Row Last [k] of A is the kth row in the permuted matrix, PAP'.
+ *
+ * Next: Next [i] is the supervariable following i in a link list, or EMPTY if
+ * i is the last in the list. Used for two kinds of lists: degree lists
+ * and hash buckets (a supervariable can be in only one kind of list at a
+ * time).
+ *
+ * On output Next [0..n-1] holds the inverse permutation. That is, if
+ * k = Next [i], then row i is the kth pivot row. Row i of A appears as
+ * the (Next[i])-th row in the permuted matrix, PAP'.
+ *
+ * Note that the contents of Next on output differ from the Fortran
+ * version (Next is undefined on output in the Fortran version).
+
+ * ----------------------------------------------------------------------------
+ * LOCAL WORKSPACE (not input or output - used only during execution):
+ * ----------------------------------------------------------------------------
+ *
+ * Degree: An integer array of size n. If i is a supervariable, then
+ * Degree [i] holds the current approximation of the external degree of
+ * row i (an upper bound). The external degree is the number of nonzeros
+ * in row i, minus ABS (Nv [i]), the diagonal part. The bound is equal to
+ * the exact external degree if Elen [i] is less than or equal to two.
+ *
+ * We also use the term "external degree" for elements e to refer to
+ * |Le \ Lme|. If e is an element, then Degree [e] is |Le|, which is the
+ * degree of the off-diagonal part of the element e (not including the
+ * diagonal part).
+ *
+ * Head: An integer array of size n. Head is used for degree lists.
+ * Head [deg] is the first supervariable in a degree list. All
+ * supervariables i in a degree list Head [deg] have the same approximate
+ * degree, namely, deg = Degree [i]. If the list Head [deg] is empty then
+ * Head [deg] = EMPTY.
+ *
+ * During supervariable detection Head [hash] also serves as a pointer to
+ * a hash bucket. If Head [hash] >= 0, there is a degree list of degree
+ * hash. The hash bucket head pointer is Last [Head [hash]]. If
+ * Head [hash] = EMPTY, then the degree list and hash bucket are both
+ * empty. If Head [hash] < EMPTY, then the degree list is empty, and
+ * FLIP (Head [hash]) is the head of the hash bucket. After supervariable
+ * detection is complete, all hash buckets are empty, and the
+ * (Last [Head [hash]] = EMPTY) condition is restored for the non-empty
+ * degree lists.
+ *
+ * W: An integer array of size n. The flag array W determines the status of
+ * elements and variables, and the external degree of elements.
+ *
+ * for elements:
+ * if W [e] = 0, then the element e is absorbed.
+ * if W [e] >= wflg, then W [e] - wflg is the size of the set
+ * |Le \ Lme|, in terms of nonzeros (the sum of ABS (Nv [i]) for
+ * each principal variable i that is both in the pattern of
+ * element e and NOT in the pattern of the current pivot element,
+ * me).
+ * if wflg > W [e] > 0, then e is not absorbed and has not yet been
+ * seen in the scan of the element lists in the computation of
+ * |Le\Lme| in Scan 1 below.
+ *
+ * for variables:
+ * during supervariable detection, if W [j] != wflg then j is
+ * not in the pattern of variable i.
+ *
+ * The W array is initialized by setting W [i] = 1 for all i, and by
+ * setting wflg = 2. It is reinitialized if wflg becomes too large (to
+ * ensure that wflg+n does not cause integer overflow).
+
+ * ----------------------------------------------------------------------------
+ * LOCAL INTEGERS:
+ * ----------------------------------------------------------------------------
+ */
+
+ Int deg, degme, dext, lemax, e, elenme, eln, i, ilast, inext, j,
+ jlast, jnext, k, knt1, knt2, knt3, lenj, ln, me, mindeg, nel, nleft,
+ nvi, nvj, nvpiv, slenme, wbig, we, wflg, wnvi, x, ok, ndense, ncmpa,
+ dense, aggressive ;
+
+ unsigned Int hash ; /* unsigned, so that hash % n is well defined.*/
+
+/*
+ * deg: the degree of a variable or element
+ * degme: size, |Lme|, of the current element, me (= Degree [me])
+ * dext: external degree, |Le \ Lme|, of some element e
+ * lemax: largest |Le| seen so far (called dmax in Fortran version)
+ * e: an element
+ * elenme: the length, Elen [me], of element list of pivotal variable
+ * eln: the length, Elen [...], of an element list
+ * hash: the computed value of the hash function
+ * i: a supervariable
+ * ilast: the entry in a link list preceding i
+ * inext: the entry in a link list following i
+ * j: a supervariable
+ * jlast: the entry in a link list preceding j
+ * jnext: the entry in a link list, or path, following j
+ * k: the pivot order of an element or variable
+ * knt1: loop counter used during element construction
+ * knt2: loop counter used during element construction
+ * knt3: loop counter used during compression
+ * lenj: Len [j]
+ * ln: length of a supervariable list
+ * me: current supervariable being eliminated, and the current
+ * element created by eliminating that supervariable
+ * mindeg: current minimum degree
+ * nel: number of pivots selected so far
+ * nleft: n - nel, the number of nonpivotal rows/columns remaining
+ * nvi: the number of variables in a supervariable i (= Nv [i])
+ * nvj: the number of variables in a supervariable j (= Nv [j])
+ * nvpiv: number of pivots in current element
+ * slenme: number of variables in variable list of pivotal variable
+ * wbig: = INT_MAX - n for the "int" version, LONG_MAX - n for the
+ * "long" version. wflg is not allowed to be >= wbig.
+ * we: W [e]
+ * wflg: used for flagging the W array. See description of Iw.
+ * wnvi: wflg - Nv [i]
+ * x: either a supervariable or an element
+ *
+ * ok: true if supervariable j can be absorbed into i
+ * ndense: number of "dense" rows/columns
+ * dense: rows/columns with initial degree > dense are considered "dense"
+ * aggressive: true if aggressive absorption is being performed
+ * ncmpa: number of garbage collections
+
+ * ----------------------------------------------------------------------------
+ * LOCAL DOUBLES, used for statistical output only (except for alpha):
+ * ----------------------------------------------------------------------------
+ */
+
+ double f, r, ndiv, s, nms_lu, nms_ldl, dmax, alpha, lnz, lnzme ;
+
+/*
+ * f: nvpiv
+ * r: degme + nvpiv
+ * ndiv: number of divisions for LU or LDL' factorizations
+ * s: number of multiply-subtract pairs for LU factorization, for the
+ * current element me
+ * nms_lu number of multiply-subtract pairs for LU factorization
+ * nms_ldl number of multiply-subtract pairs for LDL' factorization
+ * dmax: the largest number of entries in any column of L, including the
+ * diagonal
+ * alpha: "dense" degree ratio
+ * lnz: the number of nonzeros in L (excluding the diagonal)
+ * lnzme: the number of nonzeros in L (excl. the diagonal) for the
+ * current element me
+
+ * ----------------------------------------------------------------------------
+ * LOCAL "POINTERS" (indices into the Iw array)
+ * ----------------------------------------------------------------------------
+*/
+
+ Int p, p1, p2, p3, p4, pdst, pend, pj, pme, pme1, pme2, pn, psrc ;
+
+/*
+ * Any parameter (Pe [...] or pfree) or local variable starting with "p" (for
+ * Pointer) is an index into Iw, and all indices into Iw use variables starting
+ * with "p." The only exception to this rule is the iwlen input argument.
+ *
+ * p: pointer into lots of things
+ * p1: Pe [i] for some variable i (start of element list)
+ * p2: Pe [i] + Elen [i] - 1 for some variable i
+ * p3: index of first supervariable in clean list
+ * p4:
+ * pdst: destination pointer, for compression
+ * pend: end of memory to compress
+ * pj: pointer into an element or variable
+ * pme: pointer into the current element (pme1...pme2)
+ * pme1: the current element, me, is stored in Iw [pme1...pme2]
+ * pme2: the end of the current element
+ * pn: pointer into a "clean" variable, also used to compress
+ * psrc: source pointer, for compression
+*/
+
+/* ========================================================================= */
+/* INITIALIZATIONS */
+/* ========================================================================= */
+
+ /* Note that this restriction on iwlen is slightly more restrictive than
+ * what is actually required in AMD_2. AMD_2 can operate with no elbow
+ * room at all, but it will be slow. For better performance, at least
+ * size-n elbow room is enforced. */
+ ASSERT (iwlen >= pfree + n) ;
+ ASSERT (n > 0) ;
+
+ /* initialize output statistics */
+ lnz = 0 ;
+ ndiv = 0 ;
+ nms_lu = 0 ;
+ nms_ldl = 0 ;
+ dmax = 1 ;
+ me = EMPTY ;
+
+ wflg = 2 ;
+ mindeg = 0 ;
+ ncmpa = 0 ;
+ nel = 0 ;
+ lemax = 0 ; /* this is called dmax in the Fortran version */
+
+#ifdef TEST_FOR_INTEGER_OVERFLOW
+ /* for testing only */
+ wbig = 3*n ;
+#else
+ /* normal operation */
+ wbig = Int_MAX - n ;
+#endif
+
+ /* get control parameters */
+ if (Control != (double *) NULL)
+ {
+ alpha = Control [AMD_DENSE] ;
+ aggressive = (Control [AMD_AGGRESSIVE] != 0) ;
+ }
+ else
+ {
+ alpha = AMD_DEFAULT_DENSE ;
+ aggressive = AMD_DEFAULT_AGGRESSIVE ;
+ }
+ if (alpha < 0)
+ {
+ /* no dense rows/columns */
+ dense = n ;
+ }
+ else
+ {
+ dense = alpha * sqrt ((double) n) ;
+ }
+ dense = MAX (16, dense) ;
+ dense = MIN (n, dense) ;
+ AMD_DEBUG1 (("AMD (debug), alpha %g, aggr. "ID"\n", alpha, aggressive)) ;
+
+ for (i = 0 ; i < n ; i++)
+ {
+ Last [i] = EMPTY ;
+ Head [i] = EMPTY ;
+ Next [i] = EMPTY ;
+ /* if seperate Hhead array is used for hash buckets: *
+ Hhead [i] = EMPTY ;
+ */
+ Nv [i] = 1 ;
+ W [i] = 1 ;
+ Elen [i] = 0 ;
+ Degree [i] = Len [i] ;
+ }
+
+#ifndef NDEBUG
+ AMD_DEBUG1 (("\n======Nel "ID"\n", nel)) ;
+ AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next, Last,
+ Head, Elen, Degree, W, -1) ;
+#endif
+
+ /* --------------------------------------------------------------------- */
+ /* initialize degree lists and eliminate dense and empty rows */
+ /* --------------------------------------------------------------------- */
+
+ ndense = 0 ;
+
+ /* for (i = n-1 ; i >= 0 ; i--) */
+ for (i = 0 ; i < n ; i++)
+ {
+ deg = Degree [i] ;
+ ASSERT (deg >= 0 && deg < n) ;
+ if (deg == 0)
+ {
+
+ /* -------------------------------------------------------------
+ * we have a variable that can be eliminated at once because
+ * there is no off-diagonal non-zero in its row. Note that
+ * Nv [i] = 1 for an empty variable i. It is treated just
+ * the same as an eliminated element i.
+ * ------------------------------------------------------------- */
+
+ Elen [i] = FLIP (1) ;
+ nel++ ;
+ Pe [i] = EMPTY ;
+ W [i] = 0 ;
+
+ }
+ else if (deg > dense)
+ {
+
+ /* -------------------------------------------------------------
+ * Dense variables are not treated as elements, but as unordered,
+ * non-principal variables that have no parent. They do not take
+ * part in the postorder, since Nv [i] = 0. Note that the Fortran
+ * version does not have this option.
+ * ------------------------------------------------------------- */
+
+ AMD_DEBUG1 (("Dense node "ID" degree "ID"\n", i, deg)) ;
+ ndense++ ;
+ Nv [i] = 0 ; /* do not postorder this node */
+ Elen [i] = EMPTY ;
+ nel++ ;
+ Pe [i] = EMPTY ;
+
+ }
+ else
+ {
+
+ /* -------------------------------------------------------------
+ * place i in the degree list corresponding to its degree
+ * ------------------------------------------------------------- */
+
+ inext = Head [deg] ;
+ ASSERT (inext >= EMPTY && inext < n) ;
+ if (inext != EMPTY) Last [inext] = i ;
+ Next [i] = inext ;
+ Head [deg] = i ;
+
+ }
+ }
+
+/* ========================================================================= */
+/* WHILE (selecting pivots) DO */
+/* ========================================================================= */
+
+ while (nel < n)
+ {
+
+#ifndef NDEBUG
+ AMD_DEBUG1 (("\n======Nel "ID"\n", nel)) ;
+ if (AMD_debug >= 2) AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next,
+ Last, Head, Elen, Degree, W, nel) ;
+#endif
+
+/* ========================================================================= */
+/* GET PIVOT OF MINIMUM DEGREE */
+/* ========================================================================= */
+
+ /* ----------------------------------------------------------------- */
+ /* find next supervariable for elimination */
+ /* ----------------------------------------------------------------- */
+
+ ASSERT (mindeg >= 0 && mindeg < n) ;
+ for (deg = mindeg ; deg < n ; deg++)
+ {
+ me = Head [deg] ;
+ if (me != EMPTY) break ;
+ }
+ mindeg = deg ;
+ ASSERT (me >= 0 && me < n) ;
+ AMD_DEBUG1 (("=================me: "ID"\n", me)) ;
+
+ /* ----------------------------------------------------------------- */
+ /* remove chosen variable from link list */
+ /* ----------------------------------------------------------------- */
+
+ inext = Next [me] ;
+ ASSERT (inext >= EMPTY && inext < n) ;
+ if (inext != EMPTY) Last [inext] = EMPTY ;
+ Head [deg] = inext ;
+
+ /* ----------------------------------------------------------------- */
+ /* me represents the elimination of pivots nel to nel+Nv[me]-1. */
+ /* place me itself as the first in this set. */
+ /* ----------------------------------------------------------------- */
+
+ elenme = Elen [me] ;
+ nvpiv = Nv [me] ;
+ ASSERT (nvpiv > 0) ;
+ nel += nvpiv ;
+
+/* ========================================================================= */
+/* CONSTRUCT NEW ELEMENT */
+/* ========================================================================= */
+
+ /* -----------------------------------------------------------------
+ * At this point, me is the pivotal supervariable. It will be
+ * converted into the current element. Scan list of the pivotal
+ * supervariable, me, setting tree pointers and constructing new list
+ * of supervariables for the new element, me. p is a pointer to the
+ * current position in the old list.
+ * ----------------------------------------------------------------- */
+
+ /* flag the variable "me" as being in Lme by negating Nv [me] */
+ Nv [me] = -nvpiv ;
+ degme = 0 ;
+ ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ;
+
+ if (elenme == 0)
+ {
+
+ /* ------------------------------------------------------------- */
+ /* construct the new element in place */
+ /* ------------------------------------------------------------- */
+
+ pme1 = Pe [me] ;
+ pme2 = pme1 - 1 ;
+
+ for (p = pme1 ; p <= pme1 + Len [me] - 1 ; p++)
+ {
+ i = Iw [p] ;
+ ASSERT (i >= 0 && i < n && Nv [i] >= 0) ;
+ nvi = Nv [i] ;
+ if (nvi > 0)
+ {
+
+ /* ----------------------------------------------------- */
+ /* i is a principal variable not yet placed in Lme. */
+ /* store i in new list */
+ /* ----------------------------------------------------- */
+
+ /* flag i as being in Lme by negating Nv [i] */
+ degme += nvi ;
+ Nv [i] = -nvi ;
+ Iw [++pme2] = i ;
+
+ /* ----------------------------------------------------- */
+ /* remove variable i from degree list. */
+ /* ----------------------------------------------------- */
+
+ ilast = Last [i] ;
+ inext = Next [i] ;
+ ASSERT (ilast >= EMPTY && ilast < n) ;
+ ASSERT (inext >= EMPTY && inext < n) ;
+ if (inext != EMPTY) Last [inext] = ilast ;
+ if (ilast != EMPTY)
+ {
+ Next [ilast] = inext ;
+ }
+ else
+ {
+ /* i is at the head of the degree list */
+ ASSERT (Degree [i] >= 0 && Degree [i] < n) ;
+ Head [Degree [i]] = inext ;
+ }
+ }
+ }
+ }
+ else
+ {
+
+ /* ------------------------------------------------------------- */
+ /* construct the new element in empty space, Iw [pfree ...] */
+ /* ------------------------------------------------------------- */
+
+ p = Pe [me] ;
+ pme1 = pfree ;
+ slenme = Len [me] - elenme ;
+
+ for (knt1 = 1 ; knt1 <= elenme + 1 ; knt1++)
+ {
+
+ if (knt1 > elenme)
+ {
+ /* search the supervariables in me. */
+ e = me ;
+ pj = p ;
+ ln = slenme ;
+ AMD_DEBUG2 (("Search sv: "ID" "ID" "ID"\n", me,pj,ln)) ;
+ }
+ else
+ {
+ /* search the elements in me. */
+ e = Iw [p++] ;
+ ASSERT (e >= 0 && e < n) ;
+ pj = Pe [e] ;
+ ln = Len [e] ;
+ AMD_DEBUG2 (("Search element e "ID" in me "ID"\n", e,me)) ;
+ ASSERT (Elen [e] < EMPTY && W [e] > 0 && pj >= 0) ;
+ }
+ ASSERT (ln >= 0 && (ln == 0 || (pj >= 0 && pj < iwlen))) ;
+
+ /* ---------------------------------------------------------
+ * search for different supervariables and add them to the
+ * new list, compressing when necessary. this loop is
+ * executed once for each element in the list and once for
+ * all the supervariables in the list.
+ * --------------------------------------------------------- */
+
+ for (knt2 = 1 ; knt2 <= ln ; knt2++)
+ {
+ i = Iw [pj++] ;
+ ASSERT (i >= 0 && i < n && (i == me || Elen [i] >= EMPTY));
+ nvi = Nv [i] ;
+ AMD_DEBUG2 ((": "ID" "ID" "ID" "ID"\n",
+ i, Elen [i], Nv [i], wflg)) ;
+
+ if (nvi > 0)
+ {
+
+ /* ------------------------------------------------- */
+ /* compress Iw, if necessary */
+ /* ------------------------------------------------- */
+
+ if (pfree >= iwlen)
+ {
+
+ AMD_DEBUG1 (("GARBAGE COLLECTION\n")) ;
+
+ /* prepare for compressing Iw by adjusting pointers
+ * and lengths so that the lists being searched in
+ * the inner and outer loops contain only the
+ * remaining entries. */
+
+ Pe [me] = p ;
+ Len [me] -= knt1 ;
+ /* check if nothing left of supervariable me */
+ if (Len [me] == 0) Pe [me] = EMPTY ;
+ Pe [e] = pj ;
+ Len [e] = ln - knt2 ;
+ /* nothing left of element e */
+ if (Len [e] == 0) Pe [e] = EMPTY ;
+
+ ncmpa++ ; /* one more garbage collection */
+
+ /* store first entry of each object in Pe */
+ /* FLIP the first entry in each object */
+ for (j = 0 ; j < n ; j++)
+ {
+ pn = Pe [j] ;
+ if (pn >= 0)
+ {
+ ASSERT (pn >= 0 && pn < iwlen) ;
+ Pe [j] = Iw [pn] ;
+ Iw [pn] = FLIP (j) ;
+ }
+ }
+
+ /* psrc/pdst point to source/destination */
+ psrc = 0 ;
+ pdst = 0 ;
+ pend = pme1 - 1 ;
+
+ while (psrc <= pend)
+ {
+ /* search for next FLIP'd entry */
+ j = FLIP (Iw [psrc++]) ;
+ if (j >= 0)
+ {
+ AMD_DEBUG2 (("Got object j: "ID"\n", j)) ;
+ Iw [pdst] = Pe [j] ;
+ Pe [j] = pdst++ ;
+ lenj = Len [j] ;
+ /* copy from source to destination */
+ for (knt3 = 0 ; knt3 <= lenj - 2 ; knt3++)
+ {
+ Iw [pdst++] = Iw [psrc++] ;
+ }
+ }
+ }
+
+ /* move the new partially-constructed element */
+ p1 = pdst ;
+ for (psrc = pme1 ; psrc <= pfree-1 ; psrc++)
+ {
+ Iw [pdst++] = Iw [psrc] ;
+ }
+ pme1 = p1 ;
+ pfree = pdst ;
+ pj = Pe [e] ;
+ p = Pe [me] ;
+
+ }
+
+ /* ------------------------------------------------- */
+ /* i is a principal variable not yet placed in Lme */
+ /* store i in new list */
+ /* ------------------------------------------------- */
+
+ /* flag i as being in Lme by negating Nv [i] */
+ degme += nvi ;
+ Nv [i] = -nvi ;
+ Iw [pfree++] = i ;
+ AMD_DEBUG2 ((" s: "ID" nv "ID"\n", i, Nv [i]));
+
+ /* ------------------------------------------------- */
+ /* remove variable i from degree link list */
+ /* ------------------------------------------------- */
+
+ ilast = Last [i] ;
+ inext = Next [i] ;
+ ASSERT (ilast >= EMPTY && ilast < n) ;
+ ASSERT (inext >= EMPTY && inext < n) ;
+ if (inext != EMPTY) Last [inext] = ilast ;
+ if (ilast != EMPTY)
+ {
+ Next [ilast] = inext ;
+ }
+ else
+ {
+ /* i is at the head of the degree list */
+ ASSERT (Degree [i] >= 0 && Degree [i] < n) ;
+ Head [Degree [i]] = inext ;
+ }
+ }
+ }
+
+ if (e != me)
+ {
+ /* set tree pointer and flag to indicate element e is
+ * absorbed into new element me (the parent of e is me) */
+ AMD_DEBUG1 ((" Element "ID" => "ID"\n", e, me)) ;
+ Pe [e] = FLIP (me) ;
+ W [e] = 0 ;
+ }
+ }
+
+ pme2 = pfree - 1 ;
+ }
+
+ /* ----------------------------------------------------------------- */
+ /* me has now been converted into an element in Iw [pme1..pme2] */
+ /* ----------------------------------------------------------------- */
+
+ /* degme holds the external degree of new element */
+ Degree [me] = degme ;
+ Pe [me] = pme1 ;
+ Len [me] = pme2 - pme1 + 1 ;
+ ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ;
+
+ Elen [me] = FLIP (nvpiv + degme) ;
+ /* FLIP (Elen (me)) is now the degree of pivot (including
+ * diagonal part). */
+
+#ifndef NDEBUG
+ AMD_DEBUG2 (("New element structure: length= "ID"\n", pme2-pme1+1)) ;
+ for (pme = pme1 ; pme <= pme2 ; pme++) AMD_DEBUG3 ((" "ID"", Iw[pme]));
+ AMD_DEBUG3 (("\n")) ;
+#endif
+
+ /* ----------------------------------------------------------------- */
+ /* make sure that wflg is not too large. */
+ /* ----------------------------------------------------------------- */
+
+ /* With the current value of wflg, wflg+n must not cause integer
+ * overflow */
+
+ if (wflg >= wbig)
+ {
+ for (x = 0 ; x < n ; x++)
+ {
+ if (W [x] != 0) W [x] = 1 ;
+ }
+ wflg = 2 ;
+ }
+
+/* ========================================================================= */
+/* COMPUTE (W [e] - wflg) = |Le\Lme| FOR ALL ELEMENTS */
+/* ========================================================================= */
+
+ /* -----------------------------------------------------------------
+ * Scan 1: compute the external degrees of previous elements with
+ * respect to the current element. That is:
+ * (W [e] - wflg) = |Le \ Lme|
+ * for each element e that appears in any supervariable in Lme. The
+ * notation Le refers to the pattern (list of supervariables) of a
+ * previous element e, where e is not yet absorbed, stored in
+ * Iw [Pe [e] + 1 ... Pe [e] + Iw [Pe [e]]]. The notation Lme
+ * refers to the pattern of the current element (stored in
+ * Iw [pme1..pme2]). If aggressive absorption is enabled, and
+ * (W [e] - wflg) becomes zero, then the element e will be absorbed
+ * in Scan 2.
+ * ----------------------------------------------------------------- */
+
+ AMD_DEBUG2 (("me: ")) ;
+ for (pme = pme1 ; pme <= pme2 ; pme++)
+ {
+ i = Iw [pme] ;
+ ASSERT (i >= 0 && i < n) ;
+ eln = Elen [i] ;
+ AMD_DEBUG3 ((""ID" Elen "ID": \n", i, eln)) ;
+ if (eln > 0)
+ {
+ /* note that Nv [i] has been negated to denote i in Lme: */
+ nvi = -Nv [i] ;
+ ASSERT (nvi > 0 && Pe [i] >= 0 && Pe [i] < iwlen) ;
+ wnvi = wflg - nvi ;
+ for (p = Pe [i] ; p <= Pe [i] + eln - 1 ; p++)
+ {
+ e = Iw [p] ;
+ ASSERT (e >= 0 && e < n) ;
+ we = W [e] ;
+ AMD_DEBUG4 ((" e "ID" we "ID" ", e, we)) ;
+ if (we >= wflg)
+ {
+ /* unabsorbed element e has been seen in this loop */
+ AMD_DEBUG4 ((" unabsorbed, first time seen")) ;
+ we -= nvi ;
+ }
+ else if (we != 0)
+ {
+ /* e is an unabsorbed element */
+ /* this is the first we have seen e in all of Scan 1 */
+ AMD_DEBUG4 ((" unabsorbed")) ;
+ we = Degree [e] + wnvi ;
+ }
+ AMD_DEBUG4 (("\n")) ;
+ W [e] = we ;
+ }
+ }
+ }
+ AMD_DEBUG2 (("\n")) ;
+
+/* ========================================================================= */
+/* DEGREE UPDATE AND ELEMENT ABSORPTION */
+/* ========================================================================= */
+
+ /* -----------------------------------------------------------------
+ * Scan 2: for each i in Lme, sum up the degree of Lme (which is
+ * degme), plus the sum of the external degrees of each Le for the
+ * elements e appearing within i, plus the supervariables in i.
+ * Place i in hash list.
+ * ----------------------------------------------------------------- */
+
+ for (pme = pme1 ; pme <= pme2 ; pme++)
+ {
+ i = Iw [pme] ;
+ ASSERT (i >= 0 && i < n && Nv [i] < 0 && Elen [i] >= 0) ;
+ AMD_DEBUG2 (("Updating: i "ID" "ID" "ID"\n", i, Elen[i], Len [i]));
+ p1 = Pe [i] ;
+ p2 = p1 + Elen [i] - 1 ;
+ pn = p1 ;
+ hash = 0 ;
+ deg = 0 ;
+ ASSERT (p1 >= 0 && p1 < iwlen && p2 >= -1 && p2 < iwlen) ;
+
+ /* ------------------------------------------------------------- */
+ /* scan the element list associated with supervariable i */
+ /* ------------------------------------------------------------- */
+
+ /* UMFPACK/MA38-style approximate degree: */
+ if (aggressive)
+ {
+ for (p = p1 ; p <= p2 ; p++)
+ {
+ e = Iw [p] ;
+ ASSERT (e >= 0 && e < n) ;
+ we = W [e] ;
+ if (we != 0)
+ {
+ /* e is an unabsorbed element */
+ /* dext = | Le \ Lme | */
+ dext = we - wflg ;
+ if (dext > 0)
+ {
+ deg += dext ;
+ Iw [pn++] = e ;
+ hash += e ;
+ AMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ;
+ }
+ else
+ {
+ /* external degree of e is zero, absorb e into me*/
+ AMD_DEBUG1 ((" Element "ID" =>"ID" (aggressive)\n",
+ e, me)) ;
+ ASSERT (dext == 0) ;
+ Pe [e] = FLIP (me) ;
+ W [e] = 0 ;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (p = p1 ; p <= p2 ; p++)
+ {
+ e = Iw [p] ;
+ ASSERT (e >= 0 && e < n) ;
+ we = W [e] ;
+ if (we != 0)
+ {
+ /* e is an unabsorbed element */
+ dext = we - wflg ;
+ ASSERT (dext >= 0) ;
+ deg += dext ;
+ Iw [pn++] = e ;
+ hash += e ;
+ AMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ;
+ }
+ }
+ }
+
+ /* count the number of elements in i (including me): */
+ Elen [i] = pn - p1 + 1 ;
+
+ /* ------------------------------------------------------------- */
+ /* scan the supervariables in the list associated with i */
+ /* ------------------------------------------------------------- */
+
+ /* The bulk of the AMD run time is typically spent in this loop,
+ * particularly if the matrix has many dense rows that are not
+ * removed prior to ordering. */
+ p3 = pn ;
+ p4 = p1 + Len [i] ;
+ for (p = p2 + 1 ; p < p4 ; p++)
+ {
+ j = Iw [p] ;
+ ASSERT (j >= 0 && j < n) ;
+ nvj = Nv [j] ;
+ if (nvj > 0)
+ {
+ /* j is unabsorbed, and not in Lme. */
+ /* add to degree and add to new list */
+ deg += nvj ;
+ Iw [pn++] = j ;
+ hash += j ;
+ AMD_DEBUG4 ((" s: "ID" hash "ID" Nv[j]= "ID"\n",
+ j, hash, nvj)) ;
+ }
+ }
+
+ /* ------------------------------------------------------------- */
+ /* update the degree and check for mass elimination */
+ /* ------------------------------------------------------------- */
+
+ /* with aggressive absorption, deg==0 is identical to the
+ * Elen [i] == 1 && p3 == pn test, below. */
+ ASSERT (IMPLIES (aggressive, (deg==0) == (Elen[i]==1 && p3==pn))) ;
+
+ if (Elen [i] == 1 && p3 == pn)
+ {
+
+ /* --------------------------------------------------------- */
+ /* mass elimination */
+ /* --------------------------------------------------------- */
+
+ /* There is nothing left of this node except for an edge to
+ * the current pivot element. Elen [i] is 1, and there are
+ * no variables adjacent to node i. Absorb i into the
+ * current pivot element, me. Note that if there are two or
+ * more mass eliminations, fillin due to mass elimination is
+ * possible within the nvpiv-by-nvpiv pivot block. It is this
+ * step that causes AMD's analysis to be an upper bound.
+ *
+ * The reason is that the selected pivot has a lower
+ * approximate degree than the true degree of the two mass
+ * eliminated nodes. There is no edge between the two mass
+ * eliminated nodes. They are merged with the current pivot
+ * anyway.
+ *
+ * No fillin occurs in the Schur complement, in any case,
+ * and this effect does not decrease the quality of the
+ * ordering itself, just the quality of the nonzero and
+ * flop count analysis. It also means that the post-ordering
+ * is not an exact elimination tree post-ordering. */
+
+ AMD_DEBUG1 ((" MASS i "ID" => parent e "ID"\n", i, me)) ;
+ Pe [i] = FLIP (me) ;
+ nvi = -Nv [i] ;
+ degme -= nvi ;
+ nvpiv += nvi ;
+ nel += nvi ;
+ Nv [i] = 0 ;
+ Elen [i] = EMPTY ;
+
+ }
+ else
+ {
+
+ /* --------------------------------------------------------- */
+ /* update the upper-bound degree of i */
+ /* --------------------------------------------------------- */
+
+ /* the following degree does not yet include the size
+ * of the current element, which is added later: */
+
+ Degree [i] = MIN (Degree [i], deg) ;
+
+ /* --------------------------------------------------------- */
+ /* add me to the list for i */
+ /* --------------------------------------------------------- */
+
+ /* move first supervariable to end of list */
+ Iw [pn] = Iw [p3] ;
+ /* move first element to end of element part of list */
+ Iw [p3] = Iw [p1] ;
+ /* add new element, me, to front of list. */
+ Iw [p1] = me ;
+ /* store the new length of the list in Len [i] */
+ Len [i] = pn - p1 + 1 ;
+
+ /* --------------------------------------------------------- */
+ /* place in hash bucket. Save hash key of i in Last [i]. */
+ /* --------------------------------------------------------- */
+
+ /* NOTE: this can fail if hash is negative, because the ANSI C
+ * standard does not define a % b when a and/or b are negative.
+ * That's why hash is defined as an unsigned Int, to avoid this
+ * problem. */
+ hash = hash % n ;
+ ASSERT (((Int) hash) >= 0 && ((Int) hash) < n) ;
+
+ /* if the Hhead array is not used: */
+ j = Head [hash] ;
+ if (j <= EMPTY)
+ {
+ /* degree list is empty, hash head is FLIP (j) */
+ Next [i] = FLIP (j) ;
+ Head [hash] = FLIP (i) ;
+ }
+ else
+ {
+ /* degree list is not empty, use Last [Head [hash]] as
+ * hash head. */
+ Next [i] = Last [j] ;
+ Last [j] = i ;
+ }
+
+ /* if a seperate Hhead array is used: *
+ Next [i] = Hhead [hash] ;
+ Hhead [hash] = i ;
+ */
+
+ Last [i] = hash ;
+ }
+ }
+
+ Degree [me] = degme ;
+
+ /* ----------------------------------------------------------------- */
+ /* Clear the counter array, W [...], by incrementing wflg. */
+ /* ----------------------------------------------------------------- */
+
+ /* make sure that wflg+n does not cause integer overflow */
+ lemax = MAX (lemax, degme) ;
+ wflg += lemax ;
+ if (wflg >= wbig)
+ {
+ for (x = 0 ; x < n ; x++)
+ {
+ if (W [x] != 0) W [x] = 1 ;
+ }
+ wflg = 2 ;
+ }
+ /* at this point, W [0..n-1] < wflg holds */
+
+/* ========================================================================= */
+/* SUPERVARIABLE DETECTION */
+/* ========================================================================= */
+
+ AMD_DEBUG1 (("Detecting supervariables:\n")) ;
+ for (pme = pme1 ; pme <= pme2 ; pme++)
+ {
+ i = Iw [pme] ;
+ ASSERT (i >= 0 && i < n) ;
+ AMD_DEBUG2 (("Consider i "ID" nv "ID"\n", i, Nv [i])) ;
+ if (Nv [i] < 0)
+ {
+ /* i is a principal variable in Lme */
+
+ /* ---------------------------------------------------------
+ * examine all hash buckets with 2 or more variables. We do
+ * this by examing all unique hash keys for supervariables in
+ * the pattern Lme of the current element, me
+ * --------------------------------------------------------- */
+
+ /* let i = head of hash bucket, and empty the hash bucket */
+ ASSERT (Last [i] >= 0 && Last [i] < n) ;
+ hash = Last [i] ;
+
+ /* if Hhead array is not used: */
+ j = Head [hash] ;
+ if (j == EMPTY)
+ {
+ /* hash bucket and degree list are both empty */
+ i = EMPTY ;
+ }
+ else if (j < EMPTY)
+ {
+ /* degree list is empty */
+ i = FLIP (j) ;
+ Head [hash] = EMPTY ;
+ }
+ else
+ {
+ /* degree list is not empty, restore Last [j] of head j */
+ i = Last [j] ;
+ Last [j] = EMPTY ;
+ }
+
+ /* if seperate Hhead array is used: *
+ i = Hhead [hash] ;
+ Hhead [hash] = EMPTY ;
+ */
+
+ ASSERT (i >= EMPTY && i < n) ;
+ AMD_DEBUG2 (("----i "ID" hash "ID"\n", i, hash)) ;
+
+ while (i != EMPTY && Next [i] != EMPTY)
+ {
+
+ /* -----------------------------------------------------
+ * this bucket has one or more variables following i.
+ * scan all of them to see if i can absorb any entries
+ * that follow i in hash bucket. Scatter i into w.
+ * ----------------------------------------------------- */
+
+ ln = Len [i] ;
+ eln = Elen [i] ;
+ ASSERT (ln >= 0 && eln >= 0) ;
+ ASSERT (Pe [i] >= 0 && Pe [i] < iwlen) ;
+ /* do not flag the first element in the list (me) */
+ for (p = Pe [i] + 1 ; p <= Pe [i] + ln - 1 ; p++)
+ {
+ ASSERT (Iw [p] >= 0 && Iw [p] < n) ;
+ W [Iw [p]] = wflg ;
+ }
+
+ /* ----------------------------------------------------- */
+ /* scan every other entry j following i in bucket */
+ /* ----------------------------------------------------- */
+
+ jlast = i ;
+ j = Next [i] ;
+ ASSERT (j >= EMPTY && j < n) ;
+
+ while (j != EMPTY)
+ {
+ /* ------------------------------------------------- */
+ /* check if j and i have identical nonzero pattern */
+ /* ------------------------------------------------- */
+
+ AMD_DEBUG3 (("compare i "ID" and j "ID"\n", i,j)) ;
+
+ /* check if i and j have the same Len and Elen */
+ ASSERT (Len [j] >= 0 && Elen [j] >= 0) ;
+ ASSERT (Pe [j] >= 0 && Pe [j] < iwlen) ;
+ ok = (Len [j] == ln) && (Elen [j] == eln) ;
+ /* skop the first element in the list (me) */
+ for (p = Pe [j] + 1 ; ok && p <= Pe [j] + ln - 1 ; p++)
+ {
+ ASSERT (Iw [p] >= 0 && Iw [p] < n) ;
+ if (W [Iw [p]] != wflg) ok = 0 ;
+ }
+ if (ok)
+ {
+ /* --------------------------------------------- */
+ /* found it! j can be absorbed into i */
+ /* --------------------------------------------- */
+
+ AMD_DEBUG1 (("found it! j "ID" => i "ID"\n", j,i));
+ Pe [j] = FLIP (i) ;
+ /* both Nv [i] and Nv [j] are negated since they */
+ /* are in Lme, and the absolute values of each */
+ /* are the number of variables in i and j: */
+ Nv [i] += Nv [j] ;
+ Nv [j] = 0 ;
+ Elen [j] = EMPTY ;
+ /* delete j from hash bucket */
+ ASSERT (j != Next [j]) ;
+ j = Next [j] ;
+ Next [jlast] = j ;
+
+ }
+ else
+ {
+ /* j cannot be absorbed into i */
+ jlast = j ;
+ ASSERT (j != Next [j]) ;
+ j = Next [j] ;
+ }
+ ASSERT (j >= EMPTY && j < n) ;
+ }
+
+ /* -----------------------------------------------------
+ * no more variables can be absorbed into i
+ * go to next i in bucket and clear flag array
+ * ----------------------------------------------------- */
+
+ wflg++ ;
+ i = Next [i] ;
+ ASSERT (i >= EMPTY && i < n) ;
+
+ }
+ }
+ }
+ AMD_DEBUG2 (("detect done\n")) ;
+
+/* ========================================================================= */
+/* RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVARIABLES FROM ELEMENT */
+/* ========================================================================= */
+
+ p = pme1 ;
+ nleft = n - nel ;
+ for (pme = pme1 ; pme <= pme2 ; pme++)
+ {
+ i = Iw [pme] ;
+ ASSERT (i >= 0 && i < n) ;
+ nvi = -Nv [i] ;
+ AMD_DEBUG3 (("Restore i "ID" "ID"\n", i, nvi)) ;
+ if (nvi > 0)
+ {
+ /* i is a principal variable in Lme */
+ /* restore Nv [i] to signify that i is principal */
+ Nv [i] = nvi ;
+
+ /* --------------------------------------------------------- */
+ /* compute the external degree (add size of current element) */
+ /* --------------------------------------------------------- */
+
+ deg = Degree [i] + degme - nvi ;
+ deg = MIN (deg, nleft - nvi) ;
+ ASSERT (IMPLIES (aggressive, deg > 0) && deg >= 0 && deg < n) ;
+
+ /* --------------------------------------------------------- */
+ /* place the supervariable at the head of the degree list */
+ /* --------------------------------------------------------- */
+
+ inext = Head [deg] ;
+ ASSERT (inext >= EMPTY && inext < n) ;
+ if (inext != EMPTY) Last [inext] = i ;
+ Next [i] = inext ;
+ Last [i] = EMPTY ;
+ Head [deg] = i ;
+
+ /* --------------------------------------------------------- */
+ /* save the new degree, and find the minimum degree */
+ /* --------------------------------------------------------- */
+
+ mindeg = MIN (mindeg, deg) ;
+ Degree [i] = deg ;
+
+ /* --------------------------------------------------------- */
+ /* place the supervariable in the element pattern */
+ /* --------------------------------------------------------- */
+
+ Iw [p++] = i ;
+
+ }
+ }
+ AMD_DEBUG2 (("restore done\n")) ;
+
+/* ========================================================================= */
+/* FINALIZE THE NEW ELEMENT */
+/* ========================================================================= */
+
+ AMD_DEBUG2 (("ME = "ID" DONE\n", me)) ;
+ Nv [me] = nvpiv ;
+ /* save the length of the list for the new element me */
+ Len [me] = p - pme1 ;
+ if (Len [me] == 0)
+ {
+ /* there is nothing left of the current pivot element */
+ /* it is a root of the assembly tree */
+ Pe [me] = EMPTY ;
+ W [me] = 0 ;
+ }
+ if (elenme != 0)
+ {
+ /* element was not constructed in place: deallocate part of */
+ /* it since newly nonprincipal variables may have been removed */
+ pfree = p ;
+ }
+
+ /* The new element has nvpiv pivots and the size of the contribution
+ * block for a multifrontal method is degme-by-degme, not including
+ * the "dense" rows/columns. If the "dense" rows/columns are included,
+ * the frontal matrix is no larger than
+ * (degme+ndense)-by-(degme+ndense).
+ */
+
+ if (Info != (double *) NULL)
+ {
+ f = nvpiv ;
+ r = degme + ndense ;
+ dmax = MAX (dmax, f + r) ;
+
+ /* number of nonzeros in L (excluding the diagonal) */
+ lnzme = f*r + (f-1)*f/2 ;
+ lnz += lnzme ;
+
+ /* number of divide operations for LDL' and for LU */
+ ndiv += lnzme ;
+
+ /* number of multiply-subtract pairs for LU */
+ s = f*r*r + r*(f-1)*f + (f-1)*f*(2*f-1)/6 ;
+ nms_lu += s ;
+
+ /* number of multiply-subtract pairs for LDL' */
+ nms_ldl += (s + lnzme)/2 ;
+ }
+
+#ifndef NDEBUG
+ AMD_DEBUG2 (("finalize done nel "ID" n "ID"\n ::::\n", nel, n)) ;
+ for (pme = Pe [me] ; pme <= Pe [me] + Len [me] - 1 ; pme++)
+ {
+ AMD_DEBUG3 ((" "ID"", Iw [pme])) ;
+ }
+ AMD_DEBUG3 (("\n")) ;
+#endif
+
+ }
+
+/* ========================================================================= */
+/* DONE SELECTING PIVOTS */
+/* ========================================================================= */
+
+ if (Info != (double *) NULL)
+ {
+
+ /* count the work to factorize the ndense-by-ndense submatrix */
+ f = ndense ;
+ dmax = MAX (dmax, (double) ndense) ;
+
+ /* number of nonzeros in L (excluding the diagonal) */
+ lnzme = (f-1)*f/2 ;
+ lnz += lnzme ;
+
+ /* number of divide operations for LDL' and for LU */
+ ndiv += lnzme ;
+
+ /* number of multiply-subtract pairs for LU */
+ s = (f-1)*f*(2*f-1)/6 ;
+ nms_lu += s ;
+
+ /* number of multiply-subtract pairs for LDL' */
+ nms_ldl += (s + lnzme)/2 ;
+
+ /* number of nz's in L (excl. diagonal) */
+ Info [AMD_LNZ] = lnz ;
+
+ /* number of divide ops for LU and LDL' */
+ Info [AMD_NDIV] = ndiv ;
+
+ /* number of multiply-subtract pairs for LDL' */
+ Info [AMD_NMULTSUBS_LDL] = nms_ldl ;
+
+ /* number of multiply-subtract pairs for LU */
+ Info [AMD_NMULTSUBS_LU] = nms_lu ;
+
+ /* number of "dense" rows/columns */
+ Info [AMD_NDENSE] = ndense ;
+
+ /* largest front is dmax-by-dmax */
+ Info [AMD_DMAX] = dmax ;
+
+ /* number of garbage collections in AMD */
+ Info [AMD_NCMPA] = ncmpa ;
+
+ /* successful ordering */
+ Info [AMD_STATUS] = AMD_OK ;
+ }
+
+/* -------------------------------------------------------------------------
+ * Variables at this point:
+ *
+ * Pe: holds the elimination tree. The parent of j is FLIP (Pe [j]),
+ * or EMPTY if j is a root. The tree holds both elements and
+ * non-principal (unordered) variables absorbed into them.
+ * Dense variables are non-principal and unordered.
+ *
+ * Elen: holds the size of each element, including the diagonal part.
+ * FLIP (Elen [e]) > 0 if e is an element. For unordered
+ * variables i, Elen [i] is EMPTY.
+ *
+ * Nv: Nv [e] > 0 is the number of pivots represented by the element e.
+ * For unordered variables i, Nv [i] is zero.
+ *
+ * Contents no longer needed:
+ * W, Iw, Len, Degree, Head, Next, Last.
+ *
+ * The matrix itself has been destroyed.
+ *
+ * n: the size of the matrix.
+ * No other scalars needed (pfree, iwlen, etc.)
+ * ------------------------------------------------------------------------- */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ Pe [i] = FLIP (Pe [i]) ;
+ Elen [i] = FLIP (Elen [i]) ;
+ }
+
+/* Now the parent of j is Pe [j], or EMPTY if j is a root. Elen [e] > 0
+ * is the size of element e. Elen [i] is EMPTY for unordered variable i. */
+
+#ifndef NDEBUG
+ AMD_DEBUG2 (("\nTree:\n")) ;
+ for (i = 0 ; i < n ; i++)
+ {
+ AMD_DEBUG2 ((" "ID" parent: "ID" ", i, Pe [i])) ;
+ ASSERT (Pe [i] >= EMPTY && Pe [i] < n) ;
+ if (Nv [i] > 0)
+ {
+ /* this is an element */
+ e = i ;
+ AMD_DEBUG2 ((" element, size is "ID"\n", Elen [i])) ;
+ ASSERT (Elen [e] > 0) ;
+ }
+ AMD_DEBUG2 (("\n")) ;
+ }
+ AMD_DEBUG2 (("\nelements:\n")) ;
+ for (e = 0 ; e < n ; e++)
+ {
+ if (Nv [e] > 0)
+ {
+ AMD_DEBUG3 (("Element e= "ID" size "ID" nv "ID" \n", e,
+ Elen [e], Nv [e])) ;
+ }
+ }
+ AMD_DEBUG2 (("\nvariables:\n")) ;
+ for (i = 0 ; i < n ; i++)
+ {
+ Int cnt ;
+ if (Nv [i] == 0)
+ {
+ AMD_DEBUG3 (("i unordered: "ID"\n", i)) ;
+ j = Pe [i] ;
+ cnt = 0 ;
+ AMD_DEBUG3 ((" j: "ID"\n", j)) ;
+ if (j == EMPTY)
+ {
+ AMD_DEBUG3 ((" i is a dense variable\n")) ;
+ }
+ else
+ {
+ ASSERT (j >= 0 && j < n) ;
+ while (Nv [j] == 0)
+ {
+ AMD_DEBUG3 ((" j : "ID"\n", j)) ;
+ j = Pe [j] ;
+ AMD_DEBUG3 ((" j:: "ID"\n", j)) ;
+ cnt++ ;
+ if (cnt > n) break ;
+ }
+ e = j ;
+ AMD_DEBUG3 ((" got to e: "ID"\n", e)) ;
+ }
+ }
+ }
+#endif
+
+/* ========================================================================= */
+/* compress the paths of the variables */
+/* ========================================================================= */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ if (Nv [i] == 0)
+ {
+
+ /* -------------------------------------------------------------
+ * i is an un-ordered row. Traverse the tree from i until
+ * reaching an element, e. The element, e, was the principal
+ * supervariable of i and all nodes in the path from i to when e
+ * was selected as pivot.
+ * ------------------------------------------------------------- */
+
+ AMD_DEBUG1 (("Path compression, i unordered: "ID"\n", i)) ;
+ j = Pe [i] ;
+ ASSERT (j >= EMPTY && j < n) ;
+ AMD_DEBUG3 ((" j: "ID"\n", j)) ;
+ if (j == EMPTY)
+ {
+ /* Skip a dense variable. It has no parent. */
+ AMD_DEBUG3 ((" i is a dense variable\n")) ;
+ continue ;
+ }
+
+ /* while (j is a variable) */
+ while (Nv [j] == 0)
+ {
+ AMD_DEBUG3 ((" j : "ID"\n", j)) ;
+ j = Pe [j] ;
+ AMD_DEBUG3 ((" j:: "ID"\n", j)) ;
+ ASSERT (j >= 0 && j < n) ;
+ }
+ /* got to an element e */
+ e = j ;
+ AMD_DEBUG3 (("got to e: "ID"\n", e)) ;
+
+ /* -------------------------------------------------------------
+ * traverse the path again from i to e, and compress the path
+ * (all nodes point to e). Path compression allows this code to
+ * compute in O(n) time.
+ * ------------------------------------------------------------- */
+
+ j = i ;
+ /* while (j is a variable) */
+ while (Nv [j] == 0)
+ {
+ jnext = Pe [j] ;
+ AMD_DEBUG3 (("j "ID" jnext "ID"\n", j, jnext)) ;
+ Pe [j] = e ;
+ j = jnext ;
+ ASSERT (j >= 0 && j < n) ;
+ }
+ }
+ }
+
+/* ========================================================================= */
+/* postorder the assembly tree */
+/* ========================================================================= */
+
+ AMD_postorder (n, Pe, Nv, Elen,
+ W, /* output order */
+ Head, Next, Last) ; /* workspace */
+
+/* ========================================================================= */
+/* compute output permutation and inverse permutation */
+/* ========================================================================= */
+
+ /* W [e] = k means that element e is the kth element in the new
+ * order. e is in the range 0 to n-1, and k is in the range 0 to
+ * the number of elements. Use Head for inverse order. */
+
+ for (k = 0 ; k < n ; k++)
+ {
+ Head [k] = EMPTY ;
+ Next [k] = EMPTY ;
+ }
+ for (e = 0 ; e < n ; e++)
+ {
+ k = W [e] ;
+ ASSERT ((k == EMPTY) == (Nv [e] == 0)) ;
+ if (k != EMPTY)
+ {
+ ASSERT (k >= 0 && k < n) ;
+ Head [k] = e ;
+ }
+ }
+
+ /* construct output inverse permutation in Next,
+ * and permutation in Last */
+ nel = 0 ;
+ for (k = 0 ; k < n ; k++)
+ {
+ e = Head [k] ;
+ if (e == EMPTY) break ;
+ ASSERT (e >= 0 && e < n && Nv [e] > 0) ;
+ Next [e] = nel ;
+ nel += Nv [e] ;
+ }
+ ASSERT (nel == n - ndense) ;
+
+ /* order non-principal variables (dense, & those merged into supervar's) */
+ for (i = 0 ; i < n ; i++)
+ {
+ if (Nv [i] == 0)
+ {
+ e = Pe [i] ;
+ ASSERT (e >= EMPTY && e < n) ;
+ if (e != EMPTY)
+ {
+ /* This is an unordered variable that was merged
+ * into element e via supernode detection or mass
+ * elimination of i when e became the pivot element.
+ * Place i in order just before e. */
+ ASSERT (Next [i] == EMPTY && Nv [e] > 0) ;
+ Next [i] = Next [e] ;
+ Next [e]++ ;
+ }
+ else
+ {
+ /* This is a dense unordered variable, with no parent.
+ * Place it last in the output order. */
+ Next [i] = nel++ ;
+ }
+ }
+ }
+ ASSERT (nel == n) ;
+
+ AMD_DEBUG2 (("\n\nPerm:\n")) ;
+ for (i = 0 ; i < n ; i++)
+ {
+ k = Next [i] ;
+ ASSERT (k >= 0 && k < n) ;
+ Last [k] = i ;
+ AMD_DEBUG2 ((" perm ["ID"] = "ID"\n", k, i)) ;
+ }
+}
--- /dev/null
+/* ========================================================================= */
+/* === AMD_aat ============================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* AMD_aat: compute the symmetry of the pattern of A, and count the number of
+ * nonzeros each column of A+A' (excluding the diagonal). Assume the input
+ * matrix has no errors.
+ */
+
+#include "amd_internal.h"
+
+GLOBAL Int AMD_aat /* returns nz in A+A' */
+(
+ Int n,
+ const Int Ap [ ],
+ const Int Ai [ ],
+ Int Len [ ], /* Len [j]: length of column j of A+A', excl diagonal*/
+ Int Tp [ ], /* workspace of size n */
+ double Info [ ]
+)
+{
+ Int p1, p2, p, i, j, pj, pj2, k, nzdiag, nzboth, nz, nzaat ;
+ double sym ;
+
+#ifndef NDEBUG
+ AMD_debug_init ("AMD AAT") ;
+ for (k = 0 ; k < n ; k++) Tp [k] = EMPTY ;
+ ASSERT (AMD_valid (n, n, Ap, Ai)) ;
+#endif
+
+ if (Info != (double *) NULL)
+ {
+ /* clear the Info array, if it exists */
+ for (i = 0 ; i < AMD_INFO ; i++)
+ {
+ Info [i] = EMPTY ;
+ }
+ Info [AMD_STATUS] = AMD_OK ;
+ }
+
+ for (k = 0 ; k < n ; k++)
+ {
+ Len [k] = 0 ;
+ }
+
+ nzdiag = 0 ;
+ nzboth = 0 ;
+ nz = Ap [n] ;
+
+ for (k = 0 ; k < n ; k++)
+ {
+ p1 = Ap [k] ;
+ p2 = Ap [k+1] ;
+ AMD_DEBUG2 (("\nAAT Column: "ID" p1: "ID" p2: "ID"\n", k, p1, p2)) ;
+
+ /* construct A+A' */
+ for (p = p1 ; p < p2 ; )
+ {
+ /* scan the upper triangular part of A */
+ j = Ai [p] ;
+ if (j < k)
+ {
+ /* entry A (j,k) is in the strictly upper triangular part,
+ * add both A (j,k) and A (k,j) to the matrix A+A' */
+ Len [j]++ ;
+ Len [k]++ ;
+ AMD_DEBUG3 ((" upper ("ID","ID") ("ID","ID")\n", j,k, k,j));
+ p++ ;
+ }
+ else if (j == k)
+ {
+ /* skip the diagonal */
+ p++ ;
+ nzdiag++ ;
+ break ;
+ }
+ else /* j > k */
+ {
+ /* first entry below the diagonal */
+ break ;
+ }
+ /* scan lower triangular part of A, in column j until reaching
+ * row k. Start where last scan left off. */
+ ASSERT (Tp [j] != EMPTY) ;
+ ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
+ pj2 = Ap [j+1] ;
+ for (pj = Tp [j] ; pj < pj2 ; )
+ {
+ i = Ai [pj] ;
+ if (i < k)
+ {
+ /* A (i,j) is only in the lower part, not in upper.
+ * add both A (i,j) and A (j,i) to the matrix A+A' */
+ Len [i]++ ;
+ Len [j]++ ;
+ AMD_DEBUG3 ((" lower ("ID","ID") ("ID","ID")\n",
+ i,j, j,i)) ;
+ pj++ ;
+ }
+ else if (i == k)
+ {
+ /* entry A (k,j) in lower part and A (j,k) in upper */
+ pj++ ;
+ nzboth++ ;
+ break ;
+ }
+ else /* i > k */
+ {
+ /* consider this entry later, when k advances to i */
+ break ;
+ }
+ }
+ Tp [j] = pj ;
+ }
+ /* Tp [k] points to the entry just below the diagonal in column k */
+ Tp [k] = p ;
+ }
+
+ /* clean up, for remaining mismatched entries */
+ for (j = 0 ; j < n ; j++)
+ {
+ for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
+ {
+ i = Ai [pj] ;
+ /* A (i,j) is only in the lower part, not in upper.
+ * add both A (i,j) and A (j,i) to the matrix A+A' */
+ Len [i]++ ;
+ Len [j]++ ;
+ AMD_DEBUG3 ((" lower cleanup ("ID","ID") ("ID","ID")\n",
+ i,j, j,i)) ;
+ }
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* compute the symmetry of the nonzero pattern of A */
+ /* --------------------------------------------------------------------- */
+
+ /* Given a matrix A, the symmetry of A is:
+ * B = tril (spones (A), -1) + triu (spones (A), 1) ;
+ * sym = nnz (B & B') / nnz (B) ;
+ * or 1 if nnz (B) is zero.
+ */
+
+ if (nz == nzdiag)
+ {
+ sym = 1 ;
+ }
+ else
+ {
+ sym = ((double) (2 * nzboth)) / ((double) (nz - nzdiag)) ;
+ }
+
+ nzaat = 0 ;
+ for (k = 0 ; k < n ; k++)
+ {
+ nzaat += Len [k] ;
+ }
+ AMD_DEBUG1 (("AMD nz in A+A', excluding diagonal (nzaat) = "ID"\n",nzaat));
+ AMD_DEBUG1 ((" nzboth: "ID" nz: "ID" nzdiag: "ID" symmetry: %g\n",
+ nzboth, nz, nzdiag, sym)) ;
+
+ if (Info != (double *) NULL)
+ {
+ Info [AMD_STATUS] = AMD_OK ;
+ Info [AMD_N] = n ;
+ Info [AMD_NZ] = nz ;
+ Info [AMD_SYMMETRY] = sym ; /* symmetry of pattern of A */
+ Info [AMD_NZDIAG] = nzdiag ; /* nonzeros on diagonal of A */
+ Info [AMD_NZ_A_PLUS_AT] = nzaat ; /* nonzeros in A+A' */
+ }
+
+ return (nzaat) ;
+}
--- /dev/null
+/* ========================================================================= */
+/* === AMD_control ========================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable. Prints the control parameters for AMD. See amd.h
+ * for details. If the Control array is not present, the defaults are
+ * printed instead.
+ */
+
+#include "amd_internal.h"
+
+GLOBAL void AMD_control
+(
+ double Control [ ]
+)
+{
+ double alpha ;
+ Int aggressive ;
+
+ if (Control != (double *) NULL)
+ {
+ alpha = Control [AMD_DENSE] ;
+ aggressive = Control [AMD_AGGRESSIVE] != 0 ;
+ }
+ else
+ {
+ alpha = AMD_DEFAULT_DENSE ;
+ aggressive = AMD_DEFAULT_AGGRESSIVE ;
+ }
+
+ PRINTF (("\namd: approximate minimum degree ordering, parameters:\n"
+ " dense row parameter: %g\n", alpha)) ;
+
+ if (alpha < 0)
+ {
+ PRINTF ((" no rows treated as dense\n")) ;
+ }
+ else
+ {
+ PRINTF ((
+ " (rows with more than max (%g * sqrt (n), 16) entries are\n"
+ " considered \"dense\", and placed last in output permutation)\n",
+ alpha)) ;
+ }
+
+ if (aggressive)
+ {
+ PRINTF ((" aggressive absorption: yes\n\n")) ;
+ }
+ else
+ {
+ PRINTF ((" aggressive absorption: no\n\n")) ;
+ }
+}
--- /dev/null
+/* ========================================================================= */
+/* === AMD_defaults ======================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable. Sets default control parameters for AMD. See amd.h
+ * for details.
+ */
+
+#include "amd_internal.h"
+
+GLOBAL void AMD_defaults
+(
+ double Control [ ]
+)
+{
+ Int i ;
+ if (Control != (double *) NULL)
+ {
+ for (i = 0 ; i < AMD_CONTROL ; i++)
+ {
+ Control [i] = 0 ;
+ }
+ Control [AMD_DENSE] = AMD_DEFAULT_DENSE ;
+ Control [AMD_AGGRESSIVE] = AMD_DEFAULT_AGGRESSIVE ;
+ }
+}
--- /dev/null
+/* ========================================================================= */
+/* === AMD_dump ============================================================ */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* Debugging routines for AMD. Not used if NDEBUG is not defined at compile-
+ * time (the default). See comments in amd_internal.h on how to enable
+ * debugging. Not user-callable.
+ */
+
+#include "amd_internal.h"
+
+#ifndef NDEBUG
+
+/* This global variable is present only when debugging */
+GLOBAL Int AMD_debug = -999 ; /* default is no debug printing */
+
+/* ========================================================================= */
+/* === AMD_debug_init ====================================================== */
+/* ========================================================================= */
+
+/* Sets the debug print level, by reading the file debug.amd (if it exists) */
+
+GLOBAL void AMD_debug_init ( char *s )
+{
+ FILE *f ;
+ f = fopen ("debug.amd", "r") ;
+ if (f == (FILE *) NULL)
+ {
+ AMD_debug = -999 ;
+ }
+ else
+ {
+ fscanf (f, ID, &AMD_debug) ;
+ fclose (f) ;
+ }
+ if (AMD_debug >= 0) printf ("%s: AMD_debug_init, D= "ID"\n", s, AMD_debug);
+}
+
+/* ========================================================================= */
+/* === AMD_dump ============================================================ */
+/* ========================================================================= */
+
+/* Dump AMD's data structure, except for the hash buckets. This routine
+ * cannot be called when the hash buckets are non-empty.
+ */
+
+GLOBAL void AMD_dump (
+ Int n, /* A is n-by-n */
+ Int Pe [ ], /* pe [0..n-1]: index in iw of start of row i */
+ Int Iw [ ], /* workspace of size iwlen, iwlen [0..pfree-1]
+ * holds the matrix on input */
+ Int Len [ ], /* len [0..n-1]: length for row i */
+ Int iwlen, /* length of iw */
+ Int pfree, /* iw [pfree ... iwlen-1] is empty on input */
+ Int Nv [ ], /* nv [0..n-1] */
+ Int Next [ ], /* next [0..n-1] */
+ Int Last [ ], /* last [0..n-1] */
+ Int Head [ ], /* head [0..n-1] */
+ Int Elen [ ], /* size n */
+ Int Degree [ ], /* size n */
+ Int W [ ], /* size n */
+ Int nel
+)
+{
+ Int i, pe, elen, nv, len, e, p, k, j, deg, w, cnt, ilast ;
+
+ if (AMD_debug < 0) return ;
+ ASSERT (pfree <= iwlen) ;
+ for (i = 0 ; i < n ; i++)
+ {
+ pe = Pe [i] ;
+ elen = Elen [i] ;
+ nv = Nv [i] ;
+ len = Len [i] ;
+ w = W [i] ;
+
+ if (elen >= EMPTY)
+ {
+ if (nv == 0)
+ {
+ AMD_DEBUG3 (("\nI "ID": nonprincipal: ", i)) ;
+ ASSERT (elen == EMPTY) ;
+ if (pe == EMPTY)
+ {
+ AMD_DEBUG3 ((" dense node\n")) ;
+ ASSERT (w == 1) ;
+ }
+ else
+ {
+ ASSERT (pe < EMPTY) ;
+ AMD_DEBUG3 ((" i "ID" -> parent "ID"\n", i, FLIP (Pe[i])));
+ }
+ }
+ else
+ {
+ AMD_DEBUG3 (("\nI "ID": active principal supervariable:\n",i));
+ AMD_DEBUG3 ((" nv(i): "ID" Flag: %d\n", nv, (nv < 0))) ;
+ ASSERT (elen >= 0) ;
+ ASSERT (nv > 0 && pe >= 0) ;
+ p = pe ;
+ AMD_DEBUG3 ((" e/s: ")) ;
+ if (elen == 0) AMD_DEBUG3 ((" : ")) ;
+ ASSERT (pe < pfree) ;
+ for (k = 0 ; k < len ; k++)
+ {
+ j = Iw [p] ;
+ AMD_DEBUG3 ((" "ID"", j)) ;
+ ASSERT (j >= 0 && j < n) ;
+ if (k == elen-1) AMD_DEBUG3 ((" : ")) ;
+ p++ ;
+ }
+ AMD_DEBUG3 (("\n")) ;
+ }
+ }
+ else
+ {
+ e = i ;
+ if (w == 0)
+ {
+ AMD_DEBUG3 (("\nE "ID": absorbed element: w "ID"\n", e, w)) ;
+ ASSERT (nv > 0 && pe < 0) ;
+ AMD_DEBUG3 ((" e "ID" -> parent "ID"\n", e, FLIP (Pe [e]))) ;
+ }
+ else
+ {
+ AMD_DEBUG3 (("\nE "ID": unabsorbed element: w "ID"\n", e, w)) ;
+ ASSERT (nv > 0 && pe >= 0) ;
+ p = pe ;
+ AMD_DEBUG3 ((" : ")) ;
+ ASSERT (pe < pfree) ;
+ for (k = 0 ; k < len ; k++)
+ {
+ j = Iw [p] ;
+ AMD_DEBUG3 ((" "ID"", j)) ;
+ ASSERT (j >= 0 && j < n) ;
+ p++ ;
+ }
+ AMD_DEBUG3 (("\n")) ;
+ }
+ }
+ }
+
+ /* this routine cannot be called when the hash buckets are non-empty */
+ AMD_DEBUG3 (("\nDegree lists:\n")) ;
+ if (nel >= 0)
+ {
+ cnt = 0 ;
+ for (deg = 0 ; deg < n ; deg++)
+ {
+ if (Head [deg] == EMPTY) continue ;
+ ilast = EMPTY ;
+ AMD_DEBUG3 ((ID": ", deg)) ;
+ for (i = Head [deg] ; i != EMPTY ; i = Next [i])
+ {
+ AMD_DEBUG3 ((" "ID" : next "ID" last "ID" deg "ID"\n",
+ i, Next [i], Last [i], Degree [i])) ;
+ ASSERT (i >= 0 && i < n && ilast == Last [i] &&
+ deg == Degree [i]) ;
+ cnt += Nv [i] ;
+ ilast = i ;
+ }
+ AMD_DEBUG3 (("\n")) ;
+ }
+ ASSERT (cnt == n - nel) ;
+ }
+
+}
+
+#endif
--- /dev/null
+/* ========================================================================= */
+/* === AMD_info ============================================================ */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable. Prints the output statistics for AMD. See amd.h
+ * for details. If the Info array is not present, nothing is printed.
+ */
+
+#include "amd_internal.h"
+
+#define PRI(format,x) { if (x >= 0) { PRINTF ((format, x)) ; }}
+
+GLOBAL void AMD_info
+(
+ double Info [ ]
+)
+{
+ double n, ndiv, nmultsubs_ldl, nmultsubs_lu, lnz, lnzd ;
+
+ if (!Info)
+ {
+ return ;
+ }
+
+ n = Info [AMD_N] ;
+ ndiv = Info [AMD_NDIV] ;
+ nmultsubs_ldl = Info [AMD_NMULTSUBS_LDL] ;
+ nmultsubs_lu = Info [AMD_NMULTSUBS_LU] ;
+ lnz = Info [AMD_LNZ] ;
+ lnzd = (n >= 0 && lnz >= 0) ? (n + lnz) : (-1) ;
+
+ /* AMD return status */
+ PRINTF ((
+ "\namd: approximate minimum degree ordering, results:\n"
+ " status: ")) ;
+ if (Info [AMD_STATUS] == AMD_OK)
+ {
+ PRINTF (("OK\n")) ;
+ }
+ else if (Info [AMD_STATUS] == AMD_OUT_OF_MEMORY)
+ {
+ PRINTF (("out of memory\n")) ;
+ }
+ else if (Info [AMD_STATUS] == AMD_INVALID)
+ {
+ PRINTF (("invalid matrix\n")) ;
+ }
+ else
+ {
+ PRINTF (("unknown\n")) ;
+ }
+
+ /* statistics about the input matrix */
+ PRI (" n, dimension of A: %.20g\n", n);
+ PRI (" nz, number of nonzeros in A: %.20g\n",
+ Info [AMD_NZ]) ;
+ PRI (" symmetry of A: %.4f\n",
+ Info [AMD_SYMMETRY]) ;
+ PRI (" number of nonzeros on diagonal: %.20g\n",
+ Info [AMD_NZDIAG]) ;
+ PRI (" nonzeros in pattern of A+A' (excl. diagonal): %.20g\n",
+ Info [AMD_NZ_A_PLUS_AT]) ;
+ PRI (" # dense rows/columns of A+A': %.20g\n",
+ Info [AMD_NDENSE]) ;
+
+ /* statistics about AMD's behavior */
+ PRI (" memory used, in bytes: %.20g\n",
+ Info [AMD_MEMORY]) ;
+ PRI (" # of memory compactions: %.20g\n",
+ Info [AMD_NCMPA]) ;
+
+ /* statistics about the ordering quality */
+ PRINTF (("\n"
+ " The following approximate statistics are for a subsequent\n"
+ " factorization of A(P,P) + A(P,P)'. They are slight upper\n"
+ " bounds if there are no dense rows/columns in A+A', and become\n"
+ " looser if dense rows/columns exist.\n\n")) ;
+
+ PRI (" nonzeros in L (excluding diagonal): %.20g\n",
+ lnz) ;
+ PRI (" nonzeros in L (including diagonal): %.20g\n",
+ lnzd) ;
+ PRI (" # divide operations for LDL' or LU: %.20g\n",
+ ndiv) ;
+ PRI (" # multiply-subtract operations for LDL': %.20g\n",
+ nmultsubs_ldl) ;
+ PRI (" # multiply-subtract operations for LU: %.20g\n",
+ nmultsubs_lu) ;
+ PRI (" max nz. in any column of L (incl. diagonal): %.20g\n",
+ Info [AMD_DMAX]) ;
+
+ /* total flop counts for various factorizations */
+
+ if (n >= 0 && ndiv >= 0 && nmultsubs_ldl >= 0 && nmultsubs_lu >= 0)
+ {
+ PRINTF (("\n"
+ " chol flop count for real A, sqrt counted as 1 flop: %.20g\n"
+ " LDL' flop count for real A: %.20g\n"
+ " LDL' flop count for complex A: %.20g\n"
+ " LU flop count for real A (with no pivoting): %.20g\n"
+ " LU flop count for complex A (with no pivoting): %.20g\n\n",
+ n + ndiv + 2*nmultsubs_ldl,
+ ndiv + 2*nmultsubs_ldl,
+ 9*ndiv + 8*nmultsubs_ldl,
+ ndiv + 2*nmultsubs_lu,
+ 9*ndiv + 8*nmultsubs_lu)) ;
+ }
+}
--- /dev/null
+/* ========================================================================= */
+/* === amd_internal.h ====================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* This file is for internal use in AMD itself, and does not normally need to
+ * be included in user code. Use amd.h instead.
+ *
+ * The following compile-time definitions affect how AMD is compiled.
+ *
+ * -DMATLAB_MEX_FILE
+ *
+ * This flag is turned on when compiling the amd mexFunction for
+ * use in MATLAB.
+ *
+ * -DMATHWORKS
+ *
+ * This flag is turned on when compiling amd as a built-in routine
+ * in MATLAB. Internal routines utMalloc, utFree, utRealloc, and
+ * utPrintf are used, and the MathWorks "util.h" file is included.
+ * This option is intended for use by The MathWorks, Inc., only.
+ *
+ * -DNDEBUG
+ *
+ * Debugging mode (if NDEBUG is not defined). The default, of course,
+ * is no debugging. Turning on debugging takes some work (see below).
+ * If you do not edit this file, then debugging is turned off anyway,
+ * regardless of whether or not -DNDEBUG is specified in your compiler
+ * options.
+ *
+ * -DALLOCATE=allocation_routine
+ * -DFREE=free_routine
+ *
+ * If you do not wish to use malloc or free, you can define the
+ * routines to be used here. You must specify both of them, or
+ * neither.
+ *
+ * -DPRINTF=printf_routine
+ *
+ * If you wish to use a routine other than printf, you can define it
+ * with -DPRINTF= followed by the name of the printf replacement.
+ */
+
+/* ========================================================================= */
+/* === NDEBUG ============================================================== */
+/* ========================================================================= */
+
+/*
+ AMD will be exceedingly slow when running in debug mode. The next three
+ lines ensure that debugging is turned off.
+*/
+#ifndef NDEBUG
+#define NDEBUG
+#endif
+
+/*
+ To enable debugging, uncomment the following line:
+#undef NDEBUG
+*/
+
+/* ------------------------------------------------------------------------- */
+/* ANSI include files */
+/* ------------------------------------------------------------------------- */
+
+/* from stdlib.h: malloc, free, realloc (when not compiling for MATLAB) */
+#include <stdlib.h>
+
+/* from stdio.h: printf. When in debug mode: fopen, fscanf */
+#include <stdio.h>
+
+/* from limits.h: INT_MAX and LONG_MAX */
+#include <limits.h>
+
+/* from math.h: sqrt */
+#include <math.h>
+
+/* ------------------------------------------------------------------------- */
+/* MATLAB include files (only if being used in or via MATLAB) */
+/* ------------------------------------------------------------------------- */
+
+#ifdef MATHWORKS
+#include "util.h"
+#endif
+
+#ifdef MATLAB_MEX_FILE
+#include "matrix.h"
+#include "mex.h"
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* basic definitions */
+/* ------------------------------------------------------------------------- */
+
+#ifdef FLIP
+#undef FLIP
+#endif
+
+#ifdef MAX
+#undef MAX
+#endif
+
+#ifdef MIN
+#undef MIN
+#endif
+
+#ifdef EMPTY
+#undef EMPTY
+#endif
+
+#ifdef GLOBAL
+#undef GLOBAL
+#endif
+
+#ifdef PRIVATE
+#undef PRIVATE
+#endif
+
+/* FLIP is a "negation about -1", and is used to mark an integer i that is
+ * normally non-negative. FLIP (EMPTY) is EMPTY. FLIP of a number > EMPTY
+ * is negative, and FLIP of a number < EMTPY is positive. FLIP (FLIP (i)) = i
+ * for all integers i. UNFLIP (i) is >= EMPTY. */
+#define EMPTY (-1)
+#define FLIP(i) (-(i)-2)
+#define UNFLIP(i) ((i < EMPTY) ? FLIP (i) : (i))
+
+/* for integer MAX/MIN, or for doubles when we don't care how NaN's behave: */
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+/* logical expression of p implies q: */
+#define IMPLIES(p,q) (!(p) || (q))
+
+/* Note that the IBM RS 6000 xlc predefines TRUE and FALSE in <types.h>. */
+/* The Compaq Alpha also predefines TRUE and FALSE. */
+#ifdef TRUE
+#undef TRUE
+#endif
+#ifdef FALSE
+#undef FALSE
+#endif
+
+#define TRUE (1)
+#define FALSE (0)
+#define PRIVATE static
+#define GLOBAL
+#define EMPTY (-1)
+
+/* Note that Linux's gcc 2.96 defines NULL as ((void *) 0), but other */
+/* compilers (even gcc 2.95.2 on Solaris) define NULL as 0 or (0). We */
+/* need to use the ANSI standard value of 0. */
+#ifdef NULL
+#undef NULL
+#endif
+
+#define NULL 0
+
+/* ------------------------------------------------------------------------- */
+/* integer type for AMD: int or long */
+/* ------------------------------------------------------------------------- */
+
+#if defined (DLONG) || defined (ZLONG)
+
+#define Int long
+#define ID "%ld"
+#define Int_MAX LONG_MAX
+#define Int_MIN LONG_MIN
+
+#define AMD_order amd_l_order
+#define AMD_defaults amd_l_defaults
+#define AMD_control amd_l_control
+#define AMD_info amd_l_info
+#define AMD_1 amd_l1
+#define AMD_2 amd_l2
+#define AMD_valid amd_l_valid
+#define AMD_aat amd_l_aat
+#define AMD_postorder amd_l_postorder
+#define AMD_post_tree amd_l_post_tree
+#define AMD_dump amd_l_dump
+#define AMD_debug amd_l_debug
+#define AMD_debug_init amd_l_debug_init
+#define AMD_wpreprocess amd_l_wpreprocess
+#define AMD_preprocess amd_l_preprocess
+#define AMD_preprocess_valid amd_l_preprocess_valid
+
+#else
+
+#define Int int
+#define ID "%d"
+#define Int_MAX INT_MAX
+#define Int_MIN INT_MIN
+
+#define AMD_order amd_order
+#define AMD_defaults amd_defaults
+#define AMD_control amd_control
+#define AMD_info amd_info
+#define AMD_1 amd_1
+#define AMD_2 amd_2
+#define AMD_valid amd_valid
+#define AMD_aat amd_aat
+#define AMD_postorder amd_postorder
+#define AMD_post_tree amd_post_tree
+#define AMD_dump amd_dump
+#define AMD_debug amd_debug
+#define AMD_debug_init amd_debug_init
+#define AMD_wpreprocess amd_wpreprocess
+#define AMD_preprocess amd_preprocess
+#define AMD_preprocess_valid amd_preprocess_valid
+
+#endif
+
+/* ========================================================================= */
+/* === Memory allocator ==================================================== */
+/* ========================================================================= */
+
+/* The MATLAB mexFunction uses MATLAB's memory manager, while the C-callable */
+/* AMD routine uses the ANSI C malloc, free, and realloc routines. */
+
+#ifndef ALLOCATE
+#ifdef MATLAB_MEX_FILE
+#define ALLOCATE mxMalloc
+#define FREE mxFree
+#else
+#ifdef MATHWORKS
+/* Compiling as a built-in routine. Since out-of-memory conditions are checked
+ * after every allocation, we can use ut* routines here. */
+#define ALLOCATE utMalloc
+#define FREE utFree
+#else
+/* use the ANSI C memory allocation routines */
+#define ALLOCATE malloc
+#define FREE free
+#endif
+#endif
+#endif
+
+
+/* ========================================================================= */
+/* === PRINTF macro ======================================================== */
+/* ========================================================================= */
+
+/* All output goes through the PRINTF macro. */
+
+#ifndef PRINTF
+#ifdef MATLAB_MEX_FILE
+#define PRINTF(params) { (void) mexPrintf params ; }
+#else
+#ifdef MATHWORKS
+#define PRINTF(params) { (void) utPrintf params ; }
+#else
+#define PRINTF(params) { (void) printf params ; }
+#endif
+#endif
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* AMD routine definitions (user-callable) */
+/* ------------------------------------------------------------------------- */
+
+#include "amd.h"
+
+/* ------------------------------------------------------------------------- */
+/* AMD routine definitions (not user-callable) */
+/* ------------------------------------------------------------------------- */
+
+GLOBAL Int AMD_valid
+(
+ Int n_row,
+ Int n_col,
+ const Int Ap [ ],
+ const Int Ai [ ]
+) ;
+
+GLOBAL Int AMD_aat
+(
+ Int n,
+ const Int Ap [ ],
+ const Int Ai [ ],
+ Int Len [ ],
+ Int Tp [ ],
+ double Info [ ]
+) ;
+
+GLOBAL void AMD_1
+(
+ Int n,
+ const Int Ap [ ],
+ const Int Ai [ ],
+ Int P [ ],
+ Int Pinv [ ],
+ Int Len [ ],
+ Int slen,
+ Int S [ ],
+ double Control [ ],
+ double Info [ ]
+) ;
+
+GLOBAL void AMD_2 (
+ Int n,
+ Int Pe [ ],
+ Int Iw [ ],
+ Int Len [ ],
+ Int iwlen,
+ Int pfree,
+ Int Nv [ ],
+ Int Next [ ],
+ Int Last [ ],
+ Int Head [ ],
+ Int Elen [ ],
+ Int Degree [ ],
+ Int W [ ],
+ double Control [ ],
+ double Info [ ]
+) ;
+
+GLOBAL void AMD_postorder
+(
+ Int nn,
+ Int Parent [ ],
+ Int Npiv [ ],
+ Int Fsize [ ],
+ Int Order [ ],
+ Int Child [ ],
+ Int Sibling [ ],
+ Int Stack [ ]
+) ;
+
+GLOBAL Int AMD_post_tree
+(
+ Int root,
+ Int k,
+ Int Child [ ],
+ const Int Sibling [ ],
+ Int Order [ ],
+ Int Stack [ ]
+#ifndef NDEBUG
+ , Int nn
+#endif
+) ;
+
+GLOBAL void AMD_wpreprocess
+(
+ Int n,
+ const Int Ap [ ],
+ const Int Ai [ ],
+ Int Rp [ ],
+ Int Ri [ ],
+ Int W [ ],
+ Int Flag [ ]
+) ;
+
+GLOBAL Int AMD_preprocess_valid
+(
+ Int n,
+ const Int Ap [ ],
+ const Int Ai [ ]
+) ;
+
+/* ------------------------------------------------------------------------- */
+/* debugging definitions */
+/* ------------------------------------------------------------------------- */
+
+/* from assert.h: assert macro */
+#if !defined (MATHWORKS) && !defined (MATLAB_MEX_FILE)
+#include <assert.h>
+#endif
+
+#ifndef NDEBUG
+
+GLOBAL Int AMD_debug ;
+
+GLOBAL void AMD_debug_init ( char *s ) ;
+
+GLOBAL void AMD_dump (
+ Int n,
+ Int Pe [ ],
+ Int Iw [ ],
+ Int Len [ ],
+ Int iwlen,
+ Int pfree,
+ Int Nv [ ],
+ Int Next [ ],
+ Int Last [ ],
+ Int Head [ ],
+ Int Elen [ ],
+ Int Degree [ ],
+ Int W [ ],
+ Int nel
+) ;
+
+#ifdef ASSERT
+#undef ASSERT
+#endif
+
+#ifdef MATLAB_MEX_FILE
+#define ASSERT(expression) (mxAssert ((expression), ""))
+#else
+#ifdef MATHWORKS
+#define ASSERT(expression) (utAssert (expression))
+#else
+#define ASSERT(expression) (assert (expression))
+#endif
+#endif /* MATLAB_MEX_FILE */
+
+#define AMD_DEBUG0(params) { PRINTF (params) ; }
+#define AMD_DEBUG1(params) { if (AMD_debug >= 1) PRINTF (params) ; }
+#define AMD_DEBUG2(params) { if (AMD_debug >= 2) PRINTF (params) ; }
+#define AMD_DEBUG3(params) { if (AMD_debug >= 3) PRINTF (params) ; }
+#define AMD_DEBUG4(params) { if (AMD_debug >= 4) PRINTF (params) ; }
+
+#else
+
+#define AMD_DEBUG0(params)
+#define AMD_DEBUG1(params)
+#define AMD_DEBUG2(params)
+#define AMD_DEBUG3(params)
+#define AMD_DEBUG4(params)
+
+#define ASSERT(expression)
+
+#endif
--- /dev/null
+/* ========================================================================= */
+/* === AMD_order =========================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable AMD minimum degree ordering routine. See amd.h for
+ * documentation.
+ */
+
+#include "amd_internal.h"
+
+GLOBAL Int AMD_order
+(
+ Int n,
+ const Int Ap [ ],
+ const Int Ai [ ],
+ Int P [ ],
+ double Control [ ],
+ double Info [ ]
+)
+{
+ Int slen, *Len, *S, nz, nzaat, i, *Pinv, info ;
+
+#ifndef NDEBUG
+ AMD_debug_init ("amd") ;
+#endif
+
+ /* clear the Info array, if it exists */
+ info = Info != (double *) NULL ;
+ if (info)
+ {
+ for (i = 0 ; i < AMD_INFO ; i++)
+ {
+ Info [i] = EMPTY ;
+ }
+ Info [AMD_N] = n ;
+ Info [AMD_STATUS] = AMD_OK ;
+ }
+
+ /* make sure inputs exist and n is >= 0 */
+ if (Ai == (Int *) NULL || Ap == (Int *) NULL || P == (Int *) NULL || n < 0)
+ {
+ if (info) Info [AMD_STATUS] = AMD_INVALID ;
+ return (AMD_INVALID) ; /* arguments are invalid */
+ }
+
+ if (n == 0)
+ {
+ return (AMD_OK) ; /* n is 0 so there's nothing to do */
+ }
+
+ nz = Ap [n] ;
+ if (info)
+ {
+ Info [AMD_NZ] = nz ;
+ }
+ if (nz < 0)
+ {
+ if (info) Info [AMD_STATUS] = AMD_INVALID ;
+ return (AMD_INVALID) ;
+ }
+
+ /* Avoid integer overflow in memory size calculations. The space required
+ * by AMD is at most 2.4nz + 8n for S, and n for Len.
+ * Note nz - n <= nzaat <= 2*nz, below. */
+ if ((2.4 * (double) nz + 8 * (double) n) > (double) Int_MAX / sizeof (Int))
+ {
+ /* :: int overflow :: */
+ if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+ return (AMD_OUT_OF_MEMORY) ;
+ }
+
+ if (!AMD_valid (n, n, Ap, Ai))
+ {
+ if (info) Info [AMD_STATUS] = AMD_INVALID ;
+ return (AMD_INVALID) ; /* matrix is invalid */
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* determine the symmetry and count off-diagonal nonzeros in A+A' */
+ /* --------------------------------------------------------------------- */
+
+ /* allocate size-n integer workspace */
+ Len = (Int *) ALLOCATE (n * sizeof (Int)) ;
+ if (!Len)
+ {
+ /* :: out of memory :: */
+ if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+ return (AMD_OUT_OF_MEMORY) ;
+ }
+ nzaat = AMD_aat (n, Ap, Ai, Len, P, Info) ;
+ AMD_DEBUG1 (("nzaat: "ID"\n", nzaat)) ;
+ ASSERT (nz-n <= nzaat && nzaat <= 2*nz) ;
+
+ /* --------------------------------------------------------------------- */
+ /* allocate workspace for matrix, elbow room, and 7 size-n vectors */
+ /* --------------------------------------------------------------------- */
+
+ slen = (nzaat + nzaat/5 + n) + 7*n ;
+ if (info)
+ {
+ /* memory usage (Len and S), in bytes. */
+ Info [AMD_MEMORY] = ((double) slen + n) * sizeof (Int) ;
+ }
+ S = (Int *) ALLOCATE (slen * sizeof (Int)) ;
+ AMD_DEBUG1 ((" S "ID" Len "ID" n "ID" nzaat "ID" slen "ID"\n",
+ (Int) S, (Int) Len, n, nzaat, slen)) ;
+ if (S == (Int *) NULL)
+ {
+ /* :: out of memory :: */
+ FREE (Len) ;
+ if (Info != (double *) NULL) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+ return (AMD_OUT_OF_MEMORY) ;
+ }
+
+ /* allocate space from S for Pinv */
+ Pinv = S + slen - n ;
+ slen -= n ;
+
+ /* --------------------------------------------------------------------- */
+ /* order the matrix */
+ /* --------------------------------------------------------------------- */
+
+ AMD_1 (n, Ap, Ai, P, Pinv, Len, slen, S, Control, Info) ;
+
+ /* --------------------------------------------------------------------- */
+ /* free the workspace */
+ /* --------------------------------------------------------------------- */
+
+ FREE (Len) ;
+ FREE (S) ;
+ return (AMD_OK) ; /* successful ordering */
+}
--- /dev/null
+/* ========================================================================= */
+/* === AMD_post_tree ======================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* Post-ordering of a supernodal elimination tree. */
+
+#include "amd_internal.h"
+
+GLOBAL Int AMD_post_tree
+(
+ Int root, /* root of the tree */
+ Int k, /* start numbering at k */
+ Int Child [ ], /* input argument of size nn, undefined on
+ * output. Child [i] is the head of a link
+ * list of all nodes that are children of node
+ * i in the tree. */
+ const Int Sibling [ ], /* input argument of size nn, not modified.
+ * If f is a node in the link list of the
+ * children of node i, then Sibling [f] is the
+ * next child of node i.
+ */
+ Int Order [ ], /* output order, of size nn. Order [i] = k
+ * if node i is the kth node of the reordered
+ * tree. */
+ Int Stack [ ] /* workspace of size nn */
+#ifndef NDEBUG
+ , Int nn /* nodes are in the range 0..nn-1. */
+#endif
+)
+{
+ Int f, head, h, i ;
+
+#if 0
+ /* --------------------------------------------------------------------- */
+ /* recursive version (Stack [ ] is not used): */
+ /* --------------------------------------------------------------------- */
+
+ /* this is simple, but can caouse stack overflow if nn is large */
+ i = root ;
+ for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+ {
+ k = AMD_post_tree (f, k, Child, Sibling, Order, Stack, nn) ;
+ }
+ Order [i] = k++ ;
+ return (k) ;
+#endif
+
+ /* --------------------------------------------------------------------- */
+ /* non-recursive version, using an explicit stack */
+ /* --------------------------------------------------------------------- */
+
+ /* push root on the stack */
+ head = 0 ;
+ Stack [0] = root ;
+
+ while (head >= 0)
+ {
+ /* get head of stack */
+ ASSERT (head < nn) ;
+ i = Stack [head] ;
+ AMD_DEBUG1 (("head of stack "ID" \n", i)) ;
+ ASSERT (i >= 0 && i < nn) ;
+
+ if (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 = Child [i] ; f != EMPTY ; f = Sibling [f])
+ {
+ head++ ;
+ ASSERT (head < nn) ;
+ ASSERT (f >= 0 && f < nn) ;
+ }
+ h = head ;
+ ASSERT (head < nn) ;
+ for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+ {
+ ASSERT (h > 0) ;
+ Stack [h--] = f ;
+ AMD_DEBUG1 (("push "ID" on stack\n", f)) ;
+ ASSERT (f >= 0 && f < nn) ;
+ }
+ ASSERT (Stack [h] == i) ;
+
+ /* delete child list so that i gets ordered next time we see it */
+ 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-- ;
+ AMD_DEBUG1 (("pop "ID" order "ID"\n", i, k)) ;
+ Order [i] = k++ ;
+ ASSERT (k <= nn) ;
+ }
+
+#ifndef NDEBUG
+ AMD_DEBUG1 (("\nStack:")) ;
+ for (h = head ; h >= 0 ; h--)
+ {
+ Int j = Stack [h] ;
+ AMD_DEBUG1 ((" "ID, j)) ;
+ ASSERT (j >= 0 && j < nn) ;
+ }
+ AMD_DEBUG1 (("\n\n")) ;
+ ASSERT (head < nn) ;
+#endif
+
+ }
+ return (k) ;
+}
--- /dev/null
+/* ========================================================================= */
+/* === AMD_postorder ======================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* Perform a postordering (via depth-first search) of an assembly tree. */
+
+#include "amd_internal.h"
+
+GLOBAL void AMD_postorder
+(
+ /* inputs, not modified on output: */
+ Int nn, /* nodes are in the range 0..nn-1 */
+ Int Parent [ ], /* Parent [j] is the parent of j, or EMPTY if root */
+ Int Nv [ ], /* Nv [j] > 0 number of pivots represented by node j,
+ * or zero if j is not a node. */
+ Int Fsize [ ], /* Fsize [j]: size of node j */
+
+ /* output, not defined on input: */
+ Int Order [ ], /* output post-order */
+
+ /* workspaces of size nn: */
+ Int Child [ ],
+ Int Sibling [ ],
+ Int Stack [ ]
+)
+{
+ Int i, j, k, parent, frsize, f, fprev, maxfrsize, bigfprev, bigf, fnext ;
+
+ for (j = 0 ; j < nn ; j++)
+ {
+ Child [j] = EMPTY ;
+ Sibling [j] = EMPTY ;
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* place the children in link lists - bigger elements tend to be last */
+ /* --------------------------------------------------------------------- */
+
+ for (j = nn-1 ; j >= 0 ; j--)
+ {
+ if (Nv [j] > 0)
+ {
+ /* this is an element */
+ parent = Parent [j] ;
+ if (parent != EMPTY)
+ {
+ /* place the element in link list of the children its parent */
+ /* bigger elements will tend to be at the end of the list */
+ Sibling [j] = Child [parent] ;
+ Child [parent] = j ;
+ }
+ }
+ }
+
+#ifndef NDEBUG
+ {
+ Int nels, ff, nchild ;
+ AMD_DEBUG1 (("\n\n================================ AMD_postorder:\n"));
+ nels = 0 ;
+ for (j = 0 ; j < nn ; j++)
+ {
+ if (Nv [j] > 0)
+ {
+ AMD_DEBUG1 (( ""ID" : nels "ID" npiv "ID" size "ID
+ " parent "ID" maxfr "ID"\n", j, nels,
+ Nv [j], Fsize [j], Parent [j], Fsize [j])) ;
+ /* this is an element */
+ /* dump the link list of children */
+ nchild = 0 ;
+ AMD_DEBUG1 ((" Children: ")) ;
+ for (ff = Child [j] ; ff != EMPTY ; ff = Sibling [ff])
+ {
+ AMD_DEBUG1 ((ID" ", ff)) ;
+ ASSERT (Parent [ff] == j) ;
+ nchild++ ;
+ ASSERT (nchild < nn) ;
+ }
+ AMD_DEBUG1 (("\n")) ;
+ parent = Parent [j] ;
+ if (parent != EMPTY)
+ {
+ ASSERT (Nv [parent] > 0) ;
+ }
+ nels++ ;
+ }
+ }
+ }
+ AMD_DEBUG1 (("\n\nGo through the children of each node, and put\n"
+ "the biggest child last in each list:\n")) ;
+#endif
+
+ /* --------------------------------------------------------------------- */
+ /* place the largest child last in the list of children for each node */
+ /* --------------------------------------------------------------------- */
+
+ for (i = 0 ; i < nn ; i++)
+ {
+ if (Nv [i] > 0 && Child [i] != EMPTY)
+ {
+
+#ifndef NDEBUG
+ Int nchild ;
+ AMD_DEBUG1 (("Before partial sort, element "ID"\n", i)) ;
+ nchild = 0 ;
+ for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+ {
+ ASSERT (f >= 0 && f < nn) ;
+ AMD_DEBUG1 ((" f: "ID" size: "ID"\n", f, Fsize [f])) ;
+ nchild++ ;
+ ASSERT (nchild <= nn) ;
+ }
+#endif
+
+ /* find the biggest element in the child list */
+ fprev = EMPTY ;
+ maxfrsize = EMPTY ;
+ bigfprev = EMPTY ;
+ bigf = EMPTY ;
+ for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+ {
+ ASSERT (f >= 0 && f < nn) ;
+ frsize = Fsize [f] ;
+ if (frsize >= maxfrsize)
+ {
+ /* this is the biggest seen so far */
+ maxfrsize = frsize ;
+ bigfprev = fprev ;
+ bigf = f ;
+ }
+ fprev = f ;
+ }
+ ASSERT (bigf != EMPTY) ;
+
+ fnext = Sibling [bigf] ;
+
+ AMD_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 element of the list */
+ Child [i] = fnext ;
+ }
+ else
+ {
+ /* delete bigf from the middle of the list */
+ Sibling [bigfprev] = fnext ;
+ }
+
+ /* put bigf at the end of the list */
+ Sibling [bigf] = EMPTY ;
+ ASSERT (Child [i] != EMPTY) ;
+ ASSERT (fprev != bigf) ;
+ ASSERT (fprev != EMPTY) ;
+ Sibling [fprev] = bigf ;
+ }
+
+#ifndef NDEBUG
+ AMD_DEBUG1 (("After partial sort, element "ID"\n", i)) ;
+ for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+ {
+ ASSERT (f >= 0 && f < nn) ;
+ AMD_DEBUG1 ((" "ID" "ID"\n", f, Fsize [f])) ;
+ ASSERT (Nv [f] > 0) ;
+ nchild-- ;
+ }
+ ASSERT (nchild == 0) ;
+#endif
+
+ }
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* postorder the assembly tree */
+ /* --------------------------------------------------------------------- */
+
+ for (i = 0 ; i < nn ; i++)
+ {
+ Order [i] = EMPTY ;
+ }
+
+ k = 0 ;
+
+ for (i = 0 ; i < nn ; i++)
+ {
+ if (Parent [i] == EMPTY && Nv [i] > 0)
+ {
+ AMD_DEBUG1 (("Root of assembly tree "ID"\n", i)) ;
+ k = AMD_post_tree (i, k, Child, Sibling, Order, Stack
+#ifndef NDEBUG
+ , nn
+#endif
+ ) ;
+ }
+ }
+}
--- /dev/null
+/* ========================================================================= */
+/* === AMD_preprocess ====================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* Sorts, removes duplicate entries, and transposes from the nonzero pattern of
+ * a column-form matrix A, to obtain the matrix R.
+ * See amd.h for a complete description of AMD_preprocess
+ */
+
+#include "amd_internal.h"
+
+GLOBAL Int AMD_preprocess /* returns AMD_OK if input is OK, AMD_INVALID
+ * if the matrix is invalid, or AMD_OUT_OF_MEMORY
+ * if out of memory for the 2n workspace. */
+(
+ Int n, /* input matrix: A is n-by-n */
+ const Int Ap [ ], /* size n+1 */
+ const Int Ai [ ], /* size nz = Ap [n] */
+
+ /* output matrix R: */
+ Int Rp [ ], /* size n+1 */
+ Int Ri [ ] /* size nz (or less, if duplicates present) */
+)
+{
+ /* --------------------------------------------------------------------- */
+ /* local variables */
+ /* --------------------------------------------------------------------- */
+
+ Int *Flag, *W ;
+
+ /* --------------------------------------------------------------------- */
+ /* check inputs (note: fewer restrictions than AMD_order) */
+ /* --------------------------------------------------------------------- */
+
+ if (!AMD_preprocess_valid (n, Ap, Ai) || !Ri || !Rp)
+ {
+ return (AMD_INVALID) ;
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* allocate workspace */
+ /* --------------------------------------------------------------------- */
+
+ W = (Int *) ALLOCATE (MAX (n,1) * sizeof (Int)) ;
+ if (!W)
+ {
+ return (AMD_OUT_OF_MEMORY) ;
+ }
+ Flag = (Int *) ALLOCATE (MAX (n,1) * sizeof (Int)) ;
+ if (!Flag)
+ {
+ FREE (W) ;
+ return (AMD_OUT_OF_MEMORY) ;
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* preprocess the matrix: sort, remove duplicates, and transpose */
+ /* --------------------------------------------------------------------- */
+
+ AMD_wpreprocess (n, Ap, Ai, Rp, Ri, W, Flag) ;
+
+ /* --------------------------------------------------------------------- */
+ /* free the workspace */
+ /* --------------------------------------------------------------------- */
+
+ FREE (W) ;
+ FREE (Flag) ;
+ return (AMD_OK) ;
+}
+
+
+/* ========================================================================= */
+/* === AMD_wpreprocess ===================================================== */
+/* ========================================================================= */
+
+/* The AMD_wpreprocess routine is not user-callable. It does not check its
+ * input for errors or allocate workspace (that is done by the user-callable
+ * AMD_preprocess routine). It does handle the n=0 case. */
+
+GLOBAL void AMD_wpreprocess
+(
+ Int n, /* input matrix: A is n-by-n */
+ const Int Ap [ ], /* size n+1 */
+ const Int Ai [ ], /* size nz = Ap [n] */
+
+ /* output matrix R: */
+ Int Rp [ ], /* size n+1 */
+ Int Ri [ ], /* size nz (or less, if duplicates present) */
+
+ Int W [ ], /* workspace of size n */
+ Int Flag [ ] /* workspace of size n */
+)
+{
+
+ /* --------------------------------------------------------------------- */
+ /* local variables */
+ /* --------------------------------------------------------------------- */
+
+ Int i, j, p, p2 ;
+
+ /* --------------------------------------------------------------------- */
+ /* count the entries in each row of A (excluding duplicates) */
+ /* --------------------------------------------------------------------- */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ W [i] = 0 ; /* # of nonzeros in row i (excl duplicates) */
+ Flag [i] = EMPTY ; /* Flag [i] = j if i appears in column j */
+ }
+ for (j = 0 ; j < n ; j++)
+ {
+ p2 = Ap [j+1] ;
+ for (p = Ap [j] ; p < p2 ; p++)
+ {
+ i = Ai [p] ;
+ if (Flag [i] != j)
+ {
+ /* row index i has not yet appeared in column j */
+ W [i]++ ; /* one more entry in row i */
+ Flag [i] = j ; /* flag row index i as appearing in col j*/
+ }
+ }
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* compute the row pointers for R */
+ /* --------------------------------------------------------------------- */
+
+ Rp [0] = 0 ;
+ for (i = 0 ; i < n ; i++)
+ {
+ Rp [i+1] = Rp [i] + W [i] ;
+ }
+ for (i = 0 ; i < n ; i++)
+ {
+ W [i] = Rp [i] ;
+ Flag [i] = EMPTY ;
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* construct the row form matrix R */
+ /* --------------------------------------------------------------------- */
+
+ /* R = row form of pattern of A */
+ for (j = 0 ; j < n ; j++)
+ {
+ p2 = Ap [j+1] ;
+ for (p = Ap [j] ; p < p2 ; p++)
+ {
+ i = Ai [p] ;
+ if (Flag [i] != j)
+ {
+ /* row index i has not yet appeared in column j */
+ Ri [W [i]++] = j ; /* put col j in row i */
+ Flag [i] = j ; /* flag row index i as appearing in col j*/
+ }
+ }
+ }
+
+#ifndef NDEBUG
+ for (j = 0 ; j < n ; j++)
+ {
+ ASSERT (W [j] == Rp [j+1]) ;
+ }
+ ASSERT (AMD_valid (n, n, Rp, Ri)) ;
+#endif
+}
+
+
+/* ========================================================================= */
+/* === AMD_preprocess_valid ================================================ */
+/* ========================================================================= */
+
+/* Not user-callable. Checks a matrix and returns TRUE if it is valid as input
+ * to AMD_wpreprocess, FALSE otherwise. */
+
+GLOBAL Int AMD_preprocess_valid
+(
+ Int n,
+ const Int Ap [ ],
+ const Int Ai [ ]
+)
+{
+ Int i, j, p, nz ;
+
+ if (n < 0 || !Ai || !Ap)
+ {
+ return (FALSE) ;
+ }
+ nz = Ap [n] ;
+ if (Ap [0] != 0 || nz < 0)
+ {
+ /* column pointers must start at Ap [0] = 0, and Ap [n] must be >= 0 */
+ AMD_DEBUG0 (("column 0 pointer bad or nz < 0\n")) ;
+ return (FALSE) ;
+ }
+ for (j = 0 ; j < n ; j++)
+ {
+ if (Ap [j] > Ap [j+1])
+ {
+ /* column pointers must be ascending */
+ AMD_DEBUG0 (("column "ID" pointer bad\n", j)) ;
+ return (FALSE) ;
+ }
+ }
+ for (p = 0 ; p < nz ; p++)
+ {
+ i = Ai [p] ;
+ AMD_DEBUG3 (("row: "ID"\n", i)) ;
+ if (i < 0 || i >= n)
+ {
+ /* row index out of range */
+ AMD_DEBUG0 (("index out of range, col "ID" row "ID"\n", j, i)) ;
+ return (FALSE) ;
+ }
+ }
+ return (TRUE) ;
+}
--- /dev/null
+/* ========================================================================= */
+/* === AMD_valid =========================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 1.1 (Jan. 21, 2004), Copyright (c) 2004 by Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */
+/* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* Check if a column-form matrix is valid or not. The matrix A is
+ * n_row-by-n_col. The row indices of entries in column j are in
+ * Ai [Ap [j] ... Ap [j+1]-1]. Required conditions are:
+ *
+ * n_row >= 0
+ * n_col >= 0
+ * nz = Ap [n_col] >= 0 number of entries in the matrix
+ * Ap [0] == 0
+ * Ap [j] <= Ap [j+1] for all j in the range 0 to n_col.
+ * row indices in Ai [Ap [j] ... Ap [j+1]-1] must be sorted in ascending
+ * order, must be in the range 0 to n_row-1, and no duplicate entries
+ * can exist.
+ *
+ * Not user-callable.
+ */
+
+#include "amd_internal.h"
+
+GLOBAL Int AMD_valid
+(
+ /* inputs, not modified on output: */
+ Int n_row, /* A is n_row-by-n_col */
+ Int n_col,
+ const Int Ap [ ], /* column pointers of A, of size n_col+1 */
+ const Int Ai [ ] /* row indices of A, of size nz = Ap [n_col] */
+)
+{
+ Int nz, j, p1, p2, ilast, i, p ;
+ if (n_row < 0 || n_col < 0)
+ {
+ AMD_DEBUG0 (("n must be >= 0: "ID" "ID"\n", n_row, n_col)) ;
+ return (FALSE) ;
+ }
+ nz = Ap [n_col] ;
+ if (Ap [0] != 0 || nz < 0)
+ {
+ /* column pointers must start at Ap [0] = 0, and Ap [n] must be >= 0 */
+ AMD_DEBUG0 (("column 0 pointer bad or nz < 0\n")) ;
+ return (FALSE) ;
+ }
+ for (j = 0 ; j < n_col ; j++)
+ {
+ p1 = Ap [j] ;
+ p2 = Ap [j+1] ;
+ AMD_DEBUG2 (("\nColumn: "ID" p1: "ID" p2: "ID"\n", j, p1, p2)) ;
+ if (p1 > p2)
+ {
+ /* column pointers must be ascending */
+ AMD_DEBUG0 (("column "ID" pointer bad\n", j)) ;
+ return (FALSE) ;
+ }
+ ilast = EMPTY ;
+ for (p = p1 ; p < p2 ; p++)
+ {
+ i = Ai [p] ;
+ AMD_DEBUG3 (("row: "ID"\n", i)) ;
+ if (i <= ilast || i >= n_row)
+ {
+ /* row index out of range, or unsorted */
+ AMD_DEBUG0 (("index out of range, col "ID" row "ID"\n", j, i));
+ return (FALSE) ;
+ }
+ ilast = i ;
+ }
+ }
+ return (TRUE) ;
+}
--- /dev/null
+C-----------------------------------------------------------------------
+C AMDBAR: approximate minimum degree, without aggressive absorption
+C-----------------------------------------------------------------------
+
+ SUBROUTINE AMDBAR
+ $ (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT,
+ $ LAST, HEAD, ELEN, DEGREE, NCMPA, W)
+
+ INTEGER N, IWLEN, PFREE, NCMPA, IW (IWLEN), PE (N),
+ $ DEGREE (N), NV (N), NEXT (N), LAST (N), HEAD (N),
+ $ ELEN (N), W (N), LEN (N)
+
+C Given a representation of the nonzero pattern of a symmetric matrix,
+C A, (excluding the diagonal) perform an approximate minimum
+C (UMFPACK/MA38-style) degree ordering to compute a pivot order
+C such that the introduction of nonzeros (fill-in) in the Cholesky
+C factors A = LL^T are kept low. At each step, the pivot
+C selected is the one with the minimum UMFPACK/MA38-style
+C upper-bound on the external degree.
+C
+C This routine does not do aggresive absorption (as done by AMD).
+
+C **********************************************************************
+C ***** CAUTION: ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT. ******
+C **********************************************************************
+
+C References:
+C
+C [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern
+C multifrontal method for sparse LU factorization", SIAM J.
+C Matrix Analysis and Applications, vol. 18, no. 1, pp.
+C 140-158. Discusses UMFPACK / MA38, which first introduced
+C the approximate minimum degree used by this routine.
+C
+C [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An
+C approximate degree ordering algorithm," SIAM J. Matrix
+C Analysis and Applications, vol. 17, no. 4, pp. 886-905,
+C 1996. Discusses AMD, AMDBAR, and MC47B.
+C
+C [3] Alan George and Joseph Liu, "The evolution of the minimum
+C degree ordering algorithm," SIAM Review, vol. 31, no. 1,
+C pp. 1-19, 1989. We list below the features mentioned in
+C that paper that this code includes:
+C
+C mass elimination:
+C Yes. MA27 relied on supervariable detection for mass
+C elimination.
+C indistinguishable nodes:
+C Yes (we call these "supervariables"). This was also in
+C the MA27 code - although we modified the method of
+C detecting them (the previous hash was the true degree,
+C which we no longer keep track of). A supervariable is
+C a set of rows with identical nonzero pattern. All
+C variables in a supervariable are eliminated together.
+C Each supervariable has as its numerical name that of
+C one of its variables (its principal variable).
+C quotient graph representation:
+C Yes. We use the term "element" for the cliques formed
+C during elimination. This was also in the MA27 code.
+C The algorithm can operate in place, but it will work
+C more efficiently if given some "elbow room."
+C element absorption:
+C Yes. This was also in the MA27 code.
+C external degree:
+C Yes. The MA27 code was based on the true degree.
+C incomplete degree update and multiple elimination:
+C No. This was not in MA27, either. Our method of
+C degree update within MC47B/BD is element-based, not
+C variable-based. It is thus not well-suited for use
+C with incomplete degree update or multiple elimination.
+
+C-----------------------------------------------------------------------
+C Authors, and Copyright (C) 1995 by:
+C Timothy A. Davis, Patrick Amestoy, Iain S. Duff, & John K. Reid.
+C
+C Acknowledgements:
+C This work (and the UMFPACK package) was supported by the
+C National Science Foundation (ASC-9111263 and DMS-9223088).
+C The UMFPACK/MA38 approximate degree update algorithm, the
+C unsymmetric analog which forms the basis of MC47B/BD, was
+C developed while Tim Davis was supported by CERFACS (Toulouse,
+C France) in a post-doctoral position.
+C
+C Date: September, 1995
+C-----------------------------------------------------------------------
+
+C-----------------------------------------------------------------------
+C INPUT ARGUMENTS (unaltered):
+C-----------------------------------------------------------------------
+
+C n: The matrix order.
+C
+C Restriction: 1 .le. n .lt. (iovflo/2)-2, where iovflo is
+C the largest positive integer that your computer can represent.
+
+C iwlen: The length of iw (1..iwlen). On input, the matrix is
+C stored in iw (1..pfree-1). However, iw (1..iwlen) should be
+C slightly larger than what is required to hold the matrix, at
+C least iwlen .ge. pfree + n is recommended. Otherwise,
+C excessive compressions will take place.
+C *** We do not recommend running this algorithm with ***
+C *** iwlen .lt. pfree + n. ***
+C *** Better performance will be obtained if ***
+C *** iwlen .ge. pfree + n ***
+C *** or better yet ***
+C *** iwlen .gt. 1.2 * pfree ***
+C *** (where pfree is its value on input). ***
+C The algorithm will not run at all if iwlen .lt. pfree-1.
+C
+C Restriction: iwlen .ge. pfree-1
+
+C-----------------------------------------------------------------------
+C INPUT/OUPUT ARGUMENTS:
+C-----------------------------------------------------------------------
+
+C pe: On input, pe (i) is the index in iw of the start of row i, or
+C zero if row i has no off-diagonal non-zeros.
+C
+C During execution, it is used for both supervariables and
+C elements:
+C
+C * Principal supervariable i: index into iw of the
+C description of supervariable i. A supervariable
+C represents one or more rows of the matrix
+C with identical nonzero pattern.
+C * Non-principal supervariable i: if i has been absorbed
+C into another supervariable j, then pe (i) = -j.
+C That is, j has the same pattern as i.
+C Note that j might later be absorbed into another
+C supervariable j2, in which case pe (i) is still -j,
+C and pe (j) = -j2.
+C * Unabsorbed element e: the index into iw of the description
+C of element e, if e has not yet been absorbed by a
+C subsequent element. Element e is created when
+C the supervariable of the same name is selected as
+C the pivot.
+C * Absorbed element e: if element e is absorbed into element
+C e2, then pe (e) = -e2. This occurs when the pattern of
+C e (that is, Le) is found to be a subset of the pattern
+C of e2 (that is, Le2). If element e is "null" (it has
+C no nonzeros outside its pivot block), then pe (e) = 0.
+C
+C On output, pe holds the assembly tree/forest, which implicitly
+C represents a pivot order with identical fill-in as the actual
+C order (via a depth-first search of the tree).
+C
+C On output:
+C If nv (i) .gt. 0, then i represents a node in the assembly tree,
+C and the parent of i is -pe (i), or zero if i is a root.
+C If nv (i) = 0, then (i,-pe (i)) represents an edge in a
+C subtree, the root of which is a node in the assembly tree.
+
+C pfree: On input the tail end of the array, iw (pfree..iwlen),
+C is empty, and the matrix is stored in iw (1..pfree-1).
+C During execution, additional data is placed in iw, and pfree
+C is modified so that iw (pfree..iwlen) is always the unused part
+C of iw. On output, pfree is set equal to the size of iw that
+C would have been needed for no compressions to occur. If
+C ncmpa is zero, then pfree (on output) is less than or equal to
+C iwlen, and the space iw (pfree+1 ... iwlen) was not used.
+C Otherwise, pfree (on output) is greater than iwlen, and all the
+C memory in iw was used.
+
+C-----------------------------------------------------------------------
+C INPUT/MODIFIED (undefined on output):
+C-----------------------------------------------------------------------
+
+C len: On input, len (i) holds the number of entries in row i of the
+C matrix, excluding the diagonal. The contents of len (1..n)
+C are undefined on output.
+
+C iw: On input, iw (1..pfree-1) holds the description of each row i
+C in the matrix. The matrix must be symmetric, and both upper
+C and lower triangular parts must be present. The diagonal must
+C not be present. Row i is held as follows:
+C
+C len (i): the length of the row i data structure
+C iw (pe (i) ... pe (i) + len (i) - 1):
+C the list of column indices for nonzeros
+C in row i (simple supervariables), excluding
+C the diagonal. All supervariables start with
+C one row/column each (supervariable i is just
+C row i).
+C if len (i) is zero on input, then pe (i) is ignored
+C on input.
+C
+C Note that the rows need not be in any particular order,
+C and there may be empty space between the rows.
+C
+C During execution, the supervariable i experiences fill-in.
+C This is represented by placing in i a list of the elements
+C that cause fill-in in supervariable i:
+C
+C len (i): the length of supervariable i
+C iw (pe (i) ... pe (i) + elen (i) - 1):
+C the list of elements that contain i. This list
+C is kept short by removing absorbed elements.
+C iw (pe (i) + elen (i) ... pe (i) + len (i) - 1):
+C the list of supervariables in i. This list
+C is kept short by removing nonprincipal
+C variables, and any entry j that is also
+C contained in at least one of the elements
+C (j in Le) in the list for i (e in row i).
+C
+C When supervariable i is selected as pivot, we create an
+C element e of the same name (e=i):
+C
+C len (e): the length of element e
+C iw (pe (e) ... pe (e) + len (e) - 1):
+C the list of supervariables in element e.
+C
+C An element represents the fill-in that occurs when supervariable
+C i is selected as pivot (which represents the selection of row i
+C and all non-principal variables whose principal variable is i).
+C We use the term Le to denote the set of all supervariables
+C in element e. Absorbed supervariables and elements are pruned
+C from these lists when computationally convenient.
+C
+C CAUTION: THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
+C The contents of iw are undefined on output.
+
+C-----------------------------------------------------------------------
+C OUTPUT (need not be set on input):
+C-----------------------------------------------------------------------
+
+C nv: During execution, abs (nv (i)) is equal to the number of rows
+C that are represented by the principal supervariable i. If i is
+C a nonprincipal variable, then nv (i) = 0. Initially,
+C nv (i) = 1 for all i. nv (i) .lt. 0 signifies that i is a
+C principal variable in the pattern Lme of the current pivot
+C element me. On output, nv (e) holds the true degree of element
+C e at the time it was created (including the diagonal part).
+
+C ncmpa: The number of times iw was compressed. If this is
+C excessive, then the execution took longer than what could have
+C been. To reduce ncmpa, try increasing iwlen to be 10% or 20%
+C larger than the value of pfree on input (or at least
+C iwlen .ge. pfree + n). The fastest performance will be
+C obtained when ncmpa is returned as zero. If iwlen is set to
+C the value returned by pfree on *output*, then no compressions
+C will occur.
+
+C elen: See the description of iw above. At the start of execution,
+C elen (i) is set to zero. During execution, elen (i) is the
+C number of elements in the list for supervariable i. When e
+C becomes an element, elen (e) = -nel is set, where nel is the
+C current step of factorization. elen (i) = 0 is done when i
+C becomes nonprincipal.
+C
+C For variables, elen (i) .ge. 0 holds until just before the
+C permutation vectors are computed. For elements,
+C elen (e) .lt. 0 holds.
+C
+C On output elen (1..n) holds the inverse permutation (the same
+C as the 'INVP' argument in Sparspak). That is, if k = elen (i),
+C then row i is the kth pivot row. Row i of A appears as the
+C (elen(i))-th row in the permuted matrix, PAP^T.
+
+C last: In a degree list, last (i) is the supervariable preceding i,
+C or zero if i is the head of the list. In a hash bucket,
+C last (i) is the hash key for i. last (head (hash)) is also
+C used as the head of a hash bucket if head (hash) contains a
+C degree list (see head, below).
+C
+C On output, last (1..n) holds the permutation (the same as the
+C 'PERM' argument in Sparspak). That is, if i = last (k), then
+C row i is the kth pivot row. Row last (k) of A is the k-th row
+C in the permuted matrix, PAP^T.
+
+C-----------------------------------------------------------------------
+C LOCAL (not input or output - used only during execution):
+C-----------------------------------------------------------------------
+
+C degree: If i is a supervariable, then degree (i) holds the
+C current approximation of the external degree of row i (an upper
+C bound). The external degree is the number of nonzeros in row i,
+C minus abs (nv (i)) (the diagonal part). The bound is equal to
+C the external degree if elen (i) is less than or equal to two.
+C
+C We also use the term "external degree" for elements e to refer
+C to |Le \ Lme|. If e is an element, then degree (e) holds |Le|,
+C which is the degree of the off-diagonal part of the element e
+C (not including the diagonal part).
+
+C head: head is used for degree lists. head (deg) is the first
+C supervariable in a degree list (all supervariables i in a
+C degree list deg have the same approximate degree, namely,
+C deg = degree (i)). If the list deg is empty then
+C head (deg) = 0.
+C
+C During supervariable detection head (hash) also serves as a
+C pointer to a hash bucket.
+C If head (hash) .gt. 0, there is a degree list of degree hash.
+C The hash bucket head pointer is last (head (hash)).
+C If head (hash) = 0, then the degree list and hash bucket are
+C both empty.
+C If head (hash) .lt. 0, then the degree list is empty, and
+C -head (hash) is the head of the hash bucket.
+C After supervariable detection is complete, all hash buckets
+C are empty, and the (last (head (hash)) = 0) condition is
+C restored for the non-empty degree lists.
+
+C next: next (i) is the supervariable following i in a link list, or
+C zero if i is the last in the list. Used for two kinds of
+C lists: degree lists and hash buckets (a supervariable can be
+C in only one kind of list at a time).
+
+C w: The flag array w determines the status of elements and
+C variables, and the external degree of elements.
+C
+C for elements:
+C if w (e) = 0, then the element e is absorbed
+C if w (e) .ge. wflg, then w (e) - wflg is the size of
+C the set |Le \ Lme|, in terms of nonzeros (the
+C sum of abs (nv (i)) for each principal variable i that
+C is both in the pattern of element e and NOT in the
+C pattern of the current pivot element, me).
+C if wflg .gt. w (e) .gt. 0, then e is not absorbed and has
+C not yet been seen in the scan of the element lists in
+C the computation of |Le\Lme| in loop 150 below.
+C
+C for variables:
+C during supervariable detection, if w (j) .ne. wflg then j is
+C not in the pattern of variable i
+C
+C The w array is initialized by setting w (i) = 1 for all i,
+C and by setting wflg = 2. It is reinitialized if wflg becomes
+C too large (to ensure that wflg+n does not cause integer
+C overflow).
+
+C-----------------------------------------------------------------------
+C LOCAL INTEGERS:
+C-----------------------------------------------------------------------
+
+ INTEGER DEG, DEGME, DMAX, E, ELENME, ELN, HASH, HMOD, I,
+ $ ILAST, INEXT, J, JLAST, JNEXT, K, KNT1, KNT2, KNT3,
+ $ LENJ, LN, MAXMEM, ME, MEM, MINDEG, NEL, NEWMEM,
+ $ NLEFT, NVI, NVJ, NVPIV, SLENME, WE, WFLG, WNVI, X
+
+C deg: the degree of a variable or element
+C degme: size, |Lme|, of the current element, me (= degree (me))
+C dext: external degree, |Le \ Lme|, of some element e
+C dmax: largest |Le| seen so far
+C e: an element
+C elenme: the length, elen (me), of element list of pivotal var.
+C eln: the length, elen (...), of an element list
+C hash: the computed value of the hash function
+C hmod: the hash function is computed modulo hmod = max (1,n-1)
+C i: a supervariable
+C ilast: the entry in a link list preceding i
+C inext: the entry in a link list following i
+C j: a supervariable
+C jlast: the entry in a link list preceding j
+C jnext: the entry in a link list, or path, following j
+C k: the pivot order of an element or variable
+C knt1: loop counter used during element construction
+C knt2: loop counter used during element construction
+C knt3: loop counter used during compression
+C lenj: len (j)
+C ln: length of a supervariable list
+C maxmem: amount of memory needed for no compressions
+C me: current supervariable being eliminated, and the
+C current element created by eliminating that
+C supervariable
+C mem: memory in use assuming no compressions have occurred
+C mindeg: current minimum degree
+C nel: number of pivots selected so far
+C newmem: amount of new memory needed for current pivot element
+C nleft: n - nel, the number of nonpivotal rows/columns remaining
+C nvi: the number of variables in a supervariable i (= nv (i))
+C nvj: the number of variables in a supervariable j (= nv (j))
+C nvpiv: number of pivots in current element
+C slenme: number of variables in variable list of pivotal variable
+C we: w (e)
+C wflg: used for flagging the w array. See description of iw.
+C wnvi: wflg - nv (i)
+C x: either a supervariable or an element
+
+C-----------------------------------------------------------------------
+C LOCAL POINTERS:
+C-----------------------------------------------------------------------
+
+ INTEGER P, P1, P2, P3, PDST, PEND, PJ, PME, PME1, PME2, PN, PSRC
+
+C Any parameter (pe (...) or pfree) or local variable
+C starting with "p" (for Pointer) is an index into iw,
+C and all indices into iw use variables starting with
+C "p." The only exception to this rule is the iwlen
+C input argument.
+
+C p: pointer into lots of things
+C p1: pe (i) for some variable i (start of element list)
+C p2: pe (i) + elen (i) - 1 for some var. i (end of el. list)
+C p3: index of first supervariable in clean list
+C pdst: destination pointer, for compression
+C pend: end of memory to compress
+C pj: pointer into an element or variable
+C pme: pointer into the current element (pme1...pme2)
+C pme1: the current element, me, is stored in iw (pme1...pme2)
+C pme2: the end of the current element
+C pn: pointer into a "clean" variable, also used to compress
+C psrc: source pointer, for compression
+
+C-----------------------------------------------------------------------
+C FUNCTIONS CALLED:
+C-----------------------------------------------------------------------
+
+ INTRINSIC MAX, MIN, MOD
+
+C=======================================================================
+C INITIALIZATIONS
+C=======================================================================
+
+ WFLG = 2
+ MINDEG = 1
+ NCMPA = 0
+ NEL = 0
+ HMOD = MAX (1, N-1)
+ DMAX = 0
+ MEM = PFREE - 1
+ MAXMEM = MEM
+ ME = 0
+
+ DO 10 I = 1, N
+ LAST (I) = 0
+ HEAD (I) = 0
+ NV (I) = 1
+ W (I) = 1
+ ELEN (I) = 0
+ DEGREE (I) = LEN (I)
+10 CONTINUE
+
+C ----------------------------------------------------------------
+C initialize degree lists and eliminate rows with no off-diag. nz.
+C ----------------------------------------------------------------
+
+ DO 20 I = 1, N
+
+ DEG = DEGREE (I)
+
+ IF (DEG .GT. 0) THEN
+
+C ----------------------------------------------------------
+C place i in the degree list corresponding to its degree
+C ----------------------------------------------------------
+
+ INEXT = HEAD (DEG)
+ IF (INEXT .NE. 0) LAST (INEXT) = I
+ NEXT (I) = INEXT
+ HEAD (DEG) = I
+
+ ELSE
+
+C ----------------------------------------------------------
+C we have a variable that can be eliminated at once because
+C there is no off-diagonal non-zero in its row.
+C ----------------------------------------------------------
+
+ NEL = NEL + 1
+ ELEN (I) = -NEL
+ PE (I) = 0
+ W (I) = 0
+
+ ENDIF
+
+20 CONTINUE
+
+C=======================================================================
+C WHILE (selecting pivots) DO
+C=======================================================================
+
+30 CONTINUE
+ IF (NEL .LT. N) THEN
+
+C=======================================================================
+C GET PIVOT OF MINIMUM DEGREE
+C=======================================================================
+
+C -------------------------------------------------------------
+C find next supervariable for elimination
+C -------------------------------------------------------------
+
+ DO 40 DEG = MINDEG, N
+ ME = HEAD (DEG)
+ IF (ME .GT. 0) GOTO 50
+40 CONTINUE
+50 CONTINUE
+ MINDEG = DEG
+
+C -------------------------------------------------------------
+C remove chosen variable from link list
+C -------------------------------------------------------------
+
+ INEXT = NEXT (ME)
+ IF (INEXT .NE. 0) LAST (INEXT) = 0
+ HEAD (DEG) = INEXT
+
+C -------------------------------------------------------------
+C me represents the elimination of pivots nel+1 to nel+nv(me).
+C place me itself as the first in this set. It will be moved
+C to the nel+nv(me) position when the permutation vectors are
+C computed.
+C -------------------------------------------------------------
+
+ ELENME = ELEN (ME)
+ ELEN (ME) = - (NEL + 1)
+ NVPIV = NV (ME)
+ NEL = NEL + NVPIV
+
+C=======================================================================
+C CONSTRUCT NEW ELEMENT
+C=======================================================================
+
+C -------------------------------------------------------------
+C At this point, me is the pivotal supervariable. It will be
+C converted into the current element. Scan list of the
+C pivotal supervariable, me, setting tree pointers and
+C constructing new list of supervariables for the new element,
+C me. p is a pointer to the current position in the old list.
+C -------------------------------------------------------------
+
+C flag the variable "me" as being in Lme by negating nv (me)
+ NV (ME) = -NVPIV
+ DEGME = 0
+
+ IF (ELENME .EQ. 0) THEN
+
+C ----------------------------------------------------------
+C construct the new element in place
+C ----------------------------------------------------------
+
+ PME1 = PE (ME)
+ PME2 = PME1 - 1
+
+ DO 60 P = PME1, PME1 + LEN (ME) - 1
+ I = IW (P)
+ NVI = NV (I)
+ IF (NVI .GT. 0) THEN
+
+C ----------------------------------------------------
+C i is a principal variable not yet placed in Lme.
+C store i in new list
+C ----------------------------------------------------
+
+ DEGME = DEGME + NVI
+C flag i as being in Lme by negating nv (i)
+ NV (I) = -NVI
+ PME2 = PME2 + 1
+ IW (PME2) = I
+
+C ----------------------------------------------------
+C remove variable i from degree list.
+C ----------------------------------------------------
+
+ ILAST = LAST (I)
+ INEXT = NEXT (I)
+ IF (INEXT .NE. 0) LAST (INEXT) = ILAST
+ IF (ILAST .NE. 0) THEN
+ NEXT (ILAST) = INEXT
+ ELSE
+C i is at the head of the degree list
+ HEAD (DEGREE (I)) = INEXT
+ ENDIF
+
+ ENDIF
+60 CONTINUE
+C this element takes no new memory in iw:
+ NEWMEM = 0
+
+ ELSE
+
+C ----------------------------------------------------------
+C construct the new element in empty space, iw (pfree ...)
+C ----------------------------------------------------------
+
+ P = PE (ME)
+ PME1 = PFREE
+ SLENME = LEN (ME) - ELENME
+
+ DO 120 KNT1 = 1, ELENME + 1
+
+ IF (KNT1 .GT. ELENME) THEN
+C search the supervariables in me.
+ E = ME
+ PJ = P
+ LN = SLENME
+ ELSE
+C search the elements in me.
+ E = IW (P)
+ P = P + 1
+ PJ = PE (E)
+ LN = LEN (E)
+ ENDIF
+
+C -------------------------------------------------------
+C search for different supervariables and add them to the
+C new list, compressing when necessary. this loop is
+C executed once for each element in the list and once for
+C all the supervariables in the list.
+C -------------------------------------------------------
+
+ DO 110 KNT2 = 1, LN
+ I = IW (PJ)
+ PJ = PJ + 1
+ NVI = NV (I)
+ IF (NVI .GT. 0) THEN
+
+C -------------------------------------------------
+C compress iw, if necessary
+C -------------------------------------------------
+
+ IF (PFREE .GT. IWLEN) THEN
+C prepare for compressing iw by adjusting
+C pointers and lengths so that the lists being
+C searched in the inner and outer loops contain
+C only the remaining entries.
+
+ PE (ME) = P
+ LEN (ME) = LEN (ME) - KNT1
+ IF (LEN (ME) .EQ. 0) THEN
+C nothing left of supervariable me
+ PE (ME) = 0
+ ENDIF
+ PE (E) = PJ
+ LEN (E) = LN - KNT2
+ IF (LEN (E) .EQ. 0) THEN
+C nothing left of element e
+ PE (E) = 0
+ ENDIF
+
+ NCMPA = NCMPA + 1
+C store first item in pe
+C set first entry to -item
+ DO 70 J = 1, N
+ PN = PE (J)
+ IF (PN .GT. 0) THEN
+ PE (J) = IW (PN)
+ IW (PN) = -J
+ ENDIF
+70 CONTINUE
+
+C psrc/pdst point to source/destination
+ PDST = 1
+ PSRC = 1
+ PEND = PME1 - 1
+
+C while loop:
+80 CONTINUE
+ IF (PSRC .LE. PEND) THEN
+C search for next negative entry
+ J = -IW (PSRC)
+ PSRC = PSRC + 1
+ IF (J .GT. 0) THEN
+ IW (PDST) = PE (J)
+ PE (J) = PDST
+ PDST = PDST + 1
+C copy from source to destination
+ LENJ = LEN (J)
+ DO 90 KNT3 = 0, LENJ - 2
+ IW (PDST + KNT3) = IW (PSRC + KNT3)
+90 CONTINUE
+ PDST = PDST + LENJ - 1
+ PSRC = PSRC + LENJ - 1
+ ENDIF
+ GOTO 80
+ ENDIF
+
+C move the new partially-constructed element
+ P1 = PDST
+ DO 100 PSRC = PME1, PFREE - 1
+ IW (PDST) = IW (PSRC)
+ PDST = PDST + 1
+100 CONTINUE
+ PME1 = P1
+ PFREE = PDST
+ PJ = PE (E)
+ P = PE (ME)
+ ENDIF
+
+C -------------------------------------------------
+C i is a principal variable not yet placed in Lme
+C store i in new list
+C -------------------------------------------------
+
+ DEGME = DEGME + NVI
+C flag i as being in Lme by negating nv (i)
+ NV (I) = -NVI
+ IW (PFREE) = I
+ PFREE = PFREE + 1
+
+C -------------------------------------------------
+C remove variable i from degree link list
+C -------------------------------------------------
+
+ ILAST = LAST (I)
+ INEXT = NEXT (I)
+ IF (INEXT .NE. 0) LAST (INEXT) = ILAST
+ IF (ILAST .NE. 0) THEN
+ NEXT (ILAST) = INEXT
+ ELSE
+C i is at the head of the degree list
+ HEAD (DEGREE (I)) = INEXT
+ ENDIF
+
+ ENDIF
+110 CONTINUE
+
+ IF (E .NE. ME) THEN
+C set tree pointer and flag to indicate element e is
+C absorbed into new element me (the parent of e is me)
+ PE (E) = -ME
+ W (E) = 0
+ ENDIF
+120 CONTINUE
+
+ PME2 = PFREE - 1
+C this element takes newmem new memory in iw (possibly zero)
+ NEWMEM = PFREE - PME1
+ MEM = MEM + NEWMEM
+ MAXMEM = MAX (MAXMEM, MEM)
+ ENDIF
+
+C -------------------------------------------------------------
+C me has now been converted into an element in iw (pme1..pme2)
+C -------------------------------------------------------------
+
+C degme holds the external degree of new element
+ DEGREE (ME) = DEGME
+ PE (ME) = PME1
+ LEN (ME) = PME2 - PME1 + 1
+
+C -------------------------------------------------------------
+C make sure that wflg is not too large. With the current
+C value of wflg, wflg+n must not cause integer overflow
+C -------------------------------------------------------------
+
+ IF (WFLG + N .LE. WFLG) THEN
+ DO 130 X = 1, N
+ IF (W (X) .NE. 0) W (X) = 1
+130 CONTINUE
+ WFLG = 2
+ ENDIF
+
+C=======================================================================
+C COMPUTE (w (e) - wflg) = |Le\Lme| FOR ALL ELEMENTS
+C=======================================================================
+
+C -------------------------------------------------------------
+C Scan 1: compute the external degrees of previous elements
+C with respect to the current element. That is:
+C (w (e) - wflg) = |Le \ Lme|
+C for each element e that appears in any supervariable in Lme.
+C The notation Le refers to the pattern (list of
+C supervariables) of a previous element e, where e is not yet
+C absorbed, stored in iw (pe (e) + 1 ... pe (e) + iw (pe (e))).
+C The notation Lme refers to the pattern of the current element
+C (stored in iw (pme1..pme2)). If (w (e) - wflg) becomes
+C zero, then the element e will be absorbed in scan 2.
+C -------------------------------------------------------------
+
+ DO 150 PME = PME1, PME2
+ I = IW (PME)
+ ELN = ELEN (I)
+ IF (ELN .GT. 0) THEN
+C note that nv (i) has been negated to denote i in Lme:
+ NVI = -NV (I)
+ WNVI = WFLG - NVI
+ DO 140 P = PE (I), PE (I) + ELN - 1
+ E = IW (P)
+ WE = W (E)
+ IF (WE .GE. WFLG) THEN
+C unabsorbed element e has been seen in this loop
+ WE = WE - NVI
+ ELSE IF (WE .NE. 0) THEN
+C e is an unabsorbed element
+C this is the first we have seen e in all of Scan 1
+ WE = DEGREE (E) + WNVI
+ ENDIF
+ W (E) = WE
+140 CONTINUE
+ ENDIF
+150 CONTINUE
+
+C=======================================================================
+C DEGREE UPDATE AND ELEMENT ABSORPTION
+C=======================================================================
+
+C -------------------------------------------------------------
+C Scan 2: for each i in Lme, sum up the degree of Lme (which
+C is degme), plus the sum of the external degrees of each Le
+C for the elements e appearing within i, plus the
+C supervariables in i. Place i in hash list.
+C -------------------------------------------------------------
+
+ DO 180 PME = PME1, PME2
+ I = IW (PME)
+ P1 = PE (I)
+ P2 = P1 + ELEN (I) - 1
+ PN = P1
+ HASH = 0
+ DEG = 0
+
+C ----------------------------------------------------------
+C scan the element list associated with supervariable i
+C ----------------------------------------------------------
+
+C UMFPACK/MA38-style approximate degree:
+ DO 160 P = P1, P2
+ E = IW (P)
+ WE = W (E)
+ IF (WE .NE. 0) THEN
+C e is an unabsorbed element
+ DEG = DEG + WE - WFLG
+ IW (PN) = E
+ PN = PN + 1
+ HASH = HASH + E
+ ENDIF
+160 CONTINUE
+
+C count the number of elements in i (including me):
+ ELEN (I) = PN - P1 + 1
+
+C ----------------------------------------------------------
+C scan the supervariables in the list associated with i
+C ----------------------------------------------------------
+
+ P3 = PN
+ DO 170 P = P2 + 1, P1 + LEN (I) - 1
+ J = IW (P)
+ NVJ = NV (J)
+ IF (NVJ .GT. 0) THEN
+C j is unabsorbed, and not in Lme.
+C add to degree and add to new list
+ DEG = DEG + NVJ
+ IW (PN) = J
+ PN = PN + 1
+ HASH = HASH + J
+ ENDIF
+170 CONTINUE
+
+C ----------------------------------------------------------
+C update the degree and check for mass elimination
+C ----------------------------------------------------------
+
+ IF (ELEN (I) .EQ. 1 .AND. P3 .EQ. PN) THEN
+
+C -------------------------------------------------------
+C mass elimination
+C -------------------------------------------------------
+
+C There is nothing left of this node except for an
+C edge to the current pivot element. elen (i) is 1,
+C and there are no variables adjacent to node i.
+C Absorb i into the current pivot element, me.
+
+ PE (I) = -ME
+ NVI = -NV (I)
+ DEGME = DEGME - NVI
+ NVPIV = NVPIV + NVI
+ NEL = NEL + NVI
+ NV (I) = 0
+ ELEN (I) = 0
+
+ ELSE
+
+C -------------------------------------------------------
+C update the upper-bound degree of i
+C -------------------------------------------------------
+
+C the following degree does not yet include the size
+C of the current element, which is added later:
+ DEGREE (I) = MIN (DEGREE (I), DEG)
+
+C -------------------------------------------------------
+C add me to the list for i
+C -------------------------------------------------------
+
+C move first supervariable to end of list
+ IW (PN) = IW (P3)
+C move first element to end of element part of list
+ IW (P3) = IW (P1)
+C add new element to front of list.
+ IW (P1) = ME
+C store the new length of the list in len (i)
+ LEN (I) = PN - P1 + 1
+
+C -------------------------------------------------------
+C place in hash bucket. Save hash key of i in last (i).
+C -------------------------------------------------------
+
+ HASH = MOD (HASH, HMOD) + 1
+ J = HEAD (HASH)
+ IF (J .LE. 0) THEN
+C the degree list is empty, hash head is -j
+ NEXT (I) = -J
+ HEAD (HASH) = -I
+ ELSE
+C degree list is not empty
+C use last (head (hash)) as hash head
+ NEXT (I) = LAST (J)
+ LAST (J) = I
+ ENDIF
+ LAST (I) = HASH
+ ENDIF
+180 CONTINUE
+
+ DEGREE (ME) = DEGME
+
+C -------------------------------------------------------------
+C Clear the counter array, w (...), by incrementing wflg.
+C -------------------------------------------------------------
+
+ DMAX = MAX (DMAX, DEGME)
+ WFLG = WFLG + DMAX
+
+C make sure that wflg+n does not cause integer overflow
+ IF (WFLG + N .LE. WFLG) THEN
+ DO 190 X = 1, N
+ IF (W (X) .NE. 0) W (X) = 1
+190 CONTINUE
+ WFLG = 2
+ ENDIF
+C at this point, w (1..n) .lt. wflg holds
+
+C=======================================================================
+C SUPERVARIABLE DETECTION
+C=======================================================================
+
+ DO 250 PME = PME1, PME2
+ I = IW (PME)
+ IF (NV (I) .LT. 0) THEN
+C i is a principal variable in Lme
+
+C -------------------------------------------------------
+C examine all hash buckets with 2 or more variables. We
+C do this by examing all unique hash keys for super-
+C variables in the pattern Lme of the current element, me
+C -------------------------------------------------------
+
+ HASH = LAST (I)
+C let i = head of hash bucket, and empty the hash bucket
+ J = HEAD (HASH)
+ IF (J .EQ. 0) GOTO 250
+ IF (J .LT. 0) THEN
+C degree list is empty
+ I = -J
+ HEAD (HASH) = 0
+ ELSE
+C degree list is not empty, restore last () of head
+ I = LAST (J)
+ LAST (J) = 0
+ ENDIF
+ IF (I .EQ. 0) GOTO 250
+
+C while loop:
+200 CONTINUE
+ IF (NEXT (I) .NE. 0) THEN
+
+C ----------------------------------------------------
+C this bucket has one or more variables following i.
+C scan all of them to see if i can absorb any entries
+C that follow i in hash bucket. Scatter i into w.
+C ----------------------------------------------------
+
+ LN = LEN (I)
+ ELN = ELEN (I)
+C do not flag the first element in the list (me)
+ DO 210 P = PE (I) + 1, PE (I) + LN - 1
+ W (IW (P)) = WFLG
+210 CONTINUE
+
+C ----------------------------------------------------
+C scan every other entry j following i in bucket
+C ----------------------------------------------------
+
+ JLAST = I
+ J = NEXT (I)
+
+C while loop:
+220 CONTINUE
+ IF (J .NE. 0) THEN
+
+C -------------------------------------------------
+C check if j and i have identical nonzero pattern
+C -------------------------------------------------
+
+ IF (LEN (J) .NE. LN) THEN
+C i and j do not have same size data structure
+ GOTO 240
+ ENDIF
+ IF (ELEN (J) .NE. ELN) THEN
+C i and j do not have same number of adjacent el
+ GOTO 240
+ ENDIF
+C do not flag the first element in the list (me)
+ DO 230 P = PE (J) + 1, PE (J) + LN - 1
+ IF (W (IW (P)) .NE. WFLG) THEN
+C an entry (iw(p)) is in j but not in i
+ GOTO 240
+ ENDIF
+230 CONTINUE
+
+C -------------------------------------------------
+C found it! j can be absorbed into i
+C -------------------------------------------------
+
+ PE (J) = -I
+C both nv (i) and nv (j) are negated since they
+C are in Lme, and the absolute values of each
+C are the number of variables in i and j:
+ NV (I) = NV (I) + NV (J)
+ NV (J) = 0
+ ELEN (J) = 0
+C delete j from hash bucket
+ J = NEXT (J)
+ NEXT (JLAST) = J
+ GOTO 220
+
+C -------------------------------------------------
+240 CONTINUE
+C j cannot be absorbed into i
+C -------------------------------------------------
+
+ JLAST = J
+ J = NEXT (J)
+ GOTO 220
+ ENDIF
+
+C ----------------------------------------------------
+C no more variables can be absorbed into i
+C go to next i in bucket and clear flag array
+C ----------------------------------------------------
+
+ WFLG = WFLG + 1
+ I = NEXT (I)
+ IF (I .NE. 0) GOTO 200
+ ENDIF
+ ENDIF
+250 CONTINUE
+
+C=======================================================================
+C RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVAR. FROM ELEMENT
+C=======================================================================
+
+ P = PME1
+ NLEFT = N - NEL
+ DO 260 PME = PME1, PME2
+ I = IW (PME)
+ NVI = -NV (I)
+ IF (NVI .GT. 0) THEN
+C i is a principal variable in Lme
+C restore nv (i) to signify that i is principal
+ NV (I) = NVI
+
+C -------------------------------------------------------
+C compute the external degree (add size of current elem)
+C -------------------------------------------------------
+
+ DEG = MAX (1, MIN (DEGREE (I) + DEGME-NVI, NLEFT-NVI))
+
+C -------------------------------------------------------
+C place the supervariable at the head of the degree list
+C -------------------------------------------------------
+
+ INEXT = HEAD (DEG)
+ IF (INEXT .NE. 0) LAST (INEXT) = I
+ NEXT (I) = INEXT
+ LAST (I) = 0
+ HEAD (DEG) = I
+
+C -------------------------------------------------------
+C save the new degree, and find the minimum degree
+C -------------------------------------------------------
+
+ MINDEG = MIN (MINDEG, DEG)
+ DEGREE (I) = DEG
+
+C -------------------------------------------------------
+C place the supervariable in the element pattern
+C -------------------------------------------------------
+
+ IW (P) = I
+ P = P + 1
+ ENDIF
+260 CONTINUE
+
+C=======================================================================
+C FINALIZE THE NEW ELEMENT
+C=======================================================================
+
+ NV (ME) = NVPIV + DEGME
+C nv (me) is now the degree of pivot (including diagonal part)
+C save the length of the list for the new element me
+ LEN (ME) = P - PME1
+ IF (LEN (ME) .EQ. 0) THEN
+C there is nothing left of the current pivot element
+ PE (ME) = 0
+ W (ME) = 0
+ ENDIF
+ IF (NEWMEM .NE. 0) THEN
+C element was not constructed in place: deallocate part
+C of it (final size is less than or equal to newmem,
+C since newly nonprincipal variables have been removed).
+ PFREE = P
+ MEM = MEM - NEWMEM + LEN (ME)
+ ENDIF
+
+C=======================================================================
+C END WHILE (selecting pivots)
+ GOTO 30
+ ENDIF
+C=======================================================================
+
+C=======================================================================
+C COMPUTE THE PERMUTATION VECTORS
+C=======================================================================
+
+C ----------------------------------------------------------------
+C The time taken by the following code is O(n). At this
+C point, elen (e) = -k has been done for all elements e,
+C and elen (i) = 0 has been done for all nonprincipal
+C variables i. At this point, there are no principal
+C supervariables left, and all elements are absorbed.
+C ----------------------------------------------------------------
+
+C ----------------------------------------------------------------
+C compute the ordering of unordered nonprincipal variables
+C ----------------------------------------------------------------
+
+ DO 290 I = 1, N
+ IF (ELEN (I) .EQ. 0) THEN
+
+C ----------------------------------------------------------
+C i is an un-ordered row. Traverse the tree from i until
+C reaching an element, e. The element, e, was the
+C principal supervariable of i and all nodes in the path
+C from i to when e was selected as pivot.
+C ----------------------------------------------------------
+
+ J = -PE (I)
+C while (j is a variable) do:
+270 CONTINUE
+ IF (ELEN (J) .GE. 0) THEN
+ J = -PE (J)
+ GOTO 270
+ ENDIF
+ E = J
+
+C ----------------------------------------------------------
+C get the current pivot ordering of e
+C ----------------------------------------------------------
+
+ K = -ELEN (E)
+
+C ----------------------------------------------------------
+C traverse the path again from i to e, and compress the
+C path (all nodes point to e). Path compression allows
+C this code to compute in O(n) time. Order the unordered
+C nodes in the path, and place the element e at the end.
+C ----------------------------------------------------------
+
+ J = I
+C while (j is a variable) do:
+280 CONTINUE
+ IF (ELEN (J) .GE. 0) THEN
+ JNEXT = -PE (J)
+ PE (J) = -E
+ IF (ELEN (J) .EQ. 0) THEN
+C j is an unordered row
+ ELEN (J) = K
+ K = K + 1
+ ENDIF
+ J = JNEXT
+ GOTO 280
+ ENDIF
+C leave elen (e) negative, so we know it is an element
+ ELEN (E) = -K
+ ENDIF
+290 CONTINUE
+
+C ----------------------------------------------------------------
+C reset the inverse permutation (elen (1..n)) to be positive,
+C and compute the permutation (last (1..n)).
+C ----------------------------------------------------------------
+
+ DO 300 I = 1, N
+ K = ABS (ELEN (I))
+ LAST (K) = I
+ ELEN (I) = K
+300 CONTINUE
+
+C=======================================================================
+C RETURN THE MEMORY USAGE IN IW
+C=======================================================================
+
+C If maxmem is less than or equal to iwlen, then no compressions
+C occurred, and iw (maxmem+1 ... iwlen) was unused. Otherwise
+C compressions did occur, and iwlen would have had to have been
+C greater than or equal to maxmem for no compressions to occur.
+C Return the value of maxmem in the pfree argument.
+
+ PFREE = MAXMEM
+
+ RETURN
+ END
+
--- /dev/null
+include ../../common/Make.global_options
+
+# rules
+ifeq ($(enable-shared),yes)
+ lib: $(LIBDIR)/liblac_umfpack.so
+else
+ lib: $(LIBDIR)/liblac_umfpack.a
+endif
+
+
+AMD:
+ cd AMD/Source ; $(MAKE) all
+
+UMFPACK:
+ cd UMFPACK/Source ; $(MAKE) all
+
+
+$(LIBDIR)/liblac_umfpack.so: AMD UMFPACK
+ @echo "=====umfpack==========optimized==$(MT)== Linking library: $(@F)"
+ @$(SHLIBLD) $(LDFLAGS) -shared -o $@ $D/lib/umfpack/*.o
+
+
+$(LIBDIR)/liblac_umfpack.a: AMD UMFPACK
+ @echo "=====umfpack==========optimized==$(MT)== Linking library: $(@F)"
+ @$(AR) ru $@ $D/lib/umfpack/*.o
+ @$(RANLIB) $@
+
+
+clean:
+
+
+.PHONY: AMD UMFPACK clean lib
--- /dev/null
+UMFPACK v4.3 and AMD v1.1.
+
+See UMFPACK/README and AMD/README for details. Documention is in
+UMFPACK/Doc and AMD/Doc.
+
--- /dev/null
+This directory is an almost identical copy of the UMFPACK 4.3
+release. The only things I have changed are the Makefiles: they build
+shared libraries instead of static ones if deal.II is so configured,
+and they put the object files somewhere else. This also allowed us to
+get rid of the AMD/Make and UMFPACK/Make subdirectories, since they
+did by hand what we do more elegantly using autoconf and friends.
+Finally, I removed the UMFPACK/Demo directory, since it is rather
+big. I assume that people using UMFPACK from inside deal.II are not
+interested in this, but they can of course download the full UMFPACK
+distribution if they want these files.
+
+UMFPACK is copyrighted by others than the deal.II authors, but
+included by permission. See the AMD/Doc/License and
+UMFPACK/Doc/License files for licensing information.
\ No newline at end of file
--- /dev/null
+Jan. 16, 2004: v4.3 released.
+
+ * user interface of v4.3 is upwardly-compatible with v4.2 and v4.1.
+ No bugs found in v4.1 (except for one workaround for an old compiler).
+ These changes add features only.
+
+ * Note that v4.0 has a bug in umf_scale_column.c. The bug was patched
+ in that version on Jan. 12, 2004. The bug does not appear in v4.1
+ and later. The bug is thus present in MATLAB 6.5, but it occurs
+ very rarely, fortunately. It can occur when dividing a nonzero entry
+ in the pivot column by the pivot value results in an underflow.
+
+ * <float.h> added to umfpackmex.c, for DBL_EPSILON. Some non-standard
+ compilers (Microsoft Visual C++) require this.
+
+ * #pragma added to umf_analyze.c, as a workaround around a bug in an
+ old Intel compiler.
+
+ * mexFunction interface to MATLAB modified. Call to mexCallMATLAB removed,
+ which can be slow. In V4.1 it was used only to get MATLAB's
+ spparms ('spumoni') value.
+
+ * The AMD mexFunction was also modified in the same way (v1.1), with
+ the call to mexCallMATLAB removed. Note that UMFPACK v4.1 through
+ v4.3 can use either AMD v1.0 or AMD v1.1.
+
+ * -DNO_DIVIDE_BY_ZERO option added. If this non-default option is enabled
+ at compile time, and if the pivot value is zero, then no division
+ occurs (zeros on the diagonal of U are treated as if they were equal
+ to one). By default, the division by zero does occur.
+
+ * -DNO_TIMER option added. If this non-default option is enabled at
+ compile time, then no timers (times ( ), clock ( ), getrusage ( ))
+ are used.
+
+V4.2: A special release for COMSOL, Inc., only (FEMLAB)
+
+ * drop tolerance added. A few new parameters in the Control array are used,
+ and a few new Info entries.
+
+May 6, 2003: V4.1 released.
+
+ * No bugs were found in the prior version, Version 4.0. New features
+ added only. Major changes throughout the code. User interface
+ nearly unchanged, however.
+
+ * Version 4.1 is upward-compatible with Version 4.0. The calling
+ sequence of some user-callable routines in Version 4.0 have changed
+ in this version. The routines umfpack_*_symbolic, umfpack_*_qsymbolic,
+ umfpack_*_get_symbolic, and umfpack_*_get_numeric have new arguments
+ added to them. The new arguments are optional. If you want to use
+ a calling sequence similar to v4.0, simply pass NULL pointers in
+ place of the new arguments. There are two new timing routines,
+ umfpack_tic and umfpack_toc. A new user-callable routine,
+ umfpack_*_scale, has been added.
+
+ * "auto", "unsymmetric", "symmetric", and "2-by-2" strategies added.
+ The symmetric strategy uses AMD on A+A' as the column preordering,
+ followed by a postorder of the assembly tree of A+A'. Column ordering
+ refinement is turned off, and diagonal entries are prefered as pivots.
+ V4.0 only had the unsymmetric strategy. The 2-by-2 strategy does row
+ permutations and attempts to find a zero-free diagonal while at the
+ same time maintaining structural symmetry, and then uses the
+ symmetric strategy on the permuted matrix.
+
+ * row-scaling added. The default is to divide each row by the sum of
+ the absolute values of each row. Other options are no scaling,
+ and to divide each row by the max abs value in each row.
+
+ * Matrices with upper bound memory usage greater than the maximum integer
+ (2GB for 32-bit int's) can now be factorized (assuming the actual
+ memory usage is still less than the maximum integer). With this change,
+ the UMFPACK_ERROR_problem_too_large error code is no longer returned.
+
+ * The current frontal matrix (Work->Fx) is no longer allocated as a
+ static size, via malloc. It can grow and shrink, and is allocated
+ from Numeric->Memory.
+
+ * The AMD (Version 1.0) package is now required. It is available
+ separately. To compile UMFPACK, it must appear as ../AMD if you are
+ in the main UMFPACK directory.
+
+ * The UMFPACK mexFunction now uses the internal utMalloc, utRealloc,
+ and utFree routines, by default (except on Windows).
+
+ * Three control parameters for modifying relaxed amalgamation removed.
+ These values are now fixed at compile-time.
+
+ * Many new statistics added to Info, and new control parameters added.
+
+ * The umfpack mexFunction now returns permutation matrices for P and Q,
+ not permutation vectors. It also returns the scale factors as a
+ diagonal matrix. The factorization is now L*U = P*(R\A)*Q.
+
+ * Option added for controlling the initial allocation of the workspace for
+ the current frontal matrix.
+
+ * pivot tolerance of zero treated differently. symmetric pivot tolerance
+ added.
+
+ * Makefile and GNUmakefile changed. umf_* routines with no double or
+ complex values are now compiled just twice (int and long versions)
+ rather than 4 times.
+
+ * New routines added to save and load the Numeric and Symbolic objects
+ to/from binary files.
+
+ * Simple Fortran interface added.
+
+Apr 11, 2002:
+
+ * Version 4.0 released.
+
+ * bug fix: the Microsoft compiler doesn't handle NaN's properly.
+ utIsNaN, and other ut* routines, added for MathWorks version
+ to handle this properly.
+
+Apr 1, 2002:
+
+ * bug fix: if a column was all NaN's, then UMFPACK would fail
+ to find a pivot row. umf_row_search.c and umf_internal.h
+ modified to fix this problem.
+
+Mar 9, 2002: V4.0beta released
+
+ * Map argument added to umfpack_*_triplet_to_col. New files
+ (umf_triplet.[ch]) added.
+ * minor changes made so that UMFPACK can be compiled with g++
+ * additional error checking added to umfpack_*_numeric, for
+ detecting more changes in pattern (Ap, Ai) since last
+ call to umfpack_*_symbolic
+
+Feb 21, 2002:
+
+ * User Guide explains the Makefile vs. GNUmakefile
+
+ * umf_config.h modified, so that the complex SCSL C-BLAS uses
+ (void *) arguments instead of (scsl_zomplex *). gcc generates
+ some spurious warnings (cc doesn't complain). Affects the SGI
+ IRIX only.
+
+ * ported to Compaq Alpha
+
+Feb 20, 2002: V4.0 (alpha) released.
+
+ * V4.0 not yet ported to the Compaq Alpha (V3.2 was ported).
+
+Feb 6 to Feb 19, 2002:
+
+ * Relaxed restrictions on sizes of arrays for umfpack_*_transpose and
+ umfpack_*_triplet_to_col. Size of "max(n,nz)" now just size nz.
+
+ * workspace for umfpack_*_wsolve increased in size.
+
+ * two user arrays for umfpack_*_get_symbolic increased in size,
+ by 1 (Chain_maxrows, Chain_maxcols).
+
+ * lu_normest.m added.
+
+Jan 18 to Feb 5, 2002:
+
+ * The matrix A can be complex, singular, and/or rectangular.
+ The solve step that uses the LU factors can only handle
+ matrices that are complex or real, singuluar or non-singular,
+ and *** square ***, however.
+
+ * Estimate of the condition number computed:
+ (min (abs (diag (U))) / (max (abs (diag (U)))))
+
+ * Forward/backsolves can solve with A.' as well as A'.
+
+ * char * arguments removed from user-callable routines to make it
+ easier for Fortran to call UMFPACK. No Fortran interface is (yet)
+ provided, however.
+
+ The solve codes for umfpack_*_*solve changed to #define'd
+ integers:
+
+ UMFPACK_A Ax=b
+ UMFPACK_At A'x=b
+ UMFPACK_Aat A.'x=b
+ UMFPACK_Pt_L P'Lx=b
+ UMFPACK_L Lx=b
+ UMFPACK_Lt_P L'Px=b
+ UMFPACK_Lat_P L.'Px=b
+ UMFPACK_Lt L'x=b
+ UMFPACK_U_Qt UQ'x=b
+ UMFPACK_U Ux=b
+ UMFPACK_Q_Ut QU'x=b
+ UMFPACK_Q_Uat QU.'x=b
+ UMFPACK_Ut U'x=b
+ UMFPACK_Uat U.'x=b
+
+ All arguments are now either int, long scalars (pass by value),
+ or int, long, double arrays (pass by reference), or void * pointers
+ (pass by value or reference). A void * pointer is of size 32 or 64
+ bits on most machines. There is no need for the caller (C or Fortran)
+ to dereference the void * pointers, so these can be treated as
+ integer*4 or integer*8 in Fortran. A Fortran interface would have to
+ have all arguments passed by reference.
+
+ * All user-callable routine names changed. The four sets are now:
+ umfpack_di_* real (double precision), int's as integers
+ umfpack_dl_* real (double precision), longs's as integers
+ umfpack_zi_* real (double precision), int's as integers
+ umfpack_zl_* real (double precision), longs's as integers
+
+ * Ptree (row preordering) and info on pivotal rows for each front
+ added to Symbolic object (extracted by umfpack_*_get_symbolic).
+ Ptree added as output argument to "umfpack (A, 'symbolic')"
+ mexFunction.
+
+ * umfpack_*_transpose can do A' or A.'
+
+ * umfpack_wsolve.c file removed (now generated from umfpack_solve.c).
+
+ * Can now extract just the diagonal of U with umfpack_*_get_numeric,
+ without having to extract the entire matrix U.
+
+ * UMFPACK_ERROR_singular_matrix (-2) removed.
+
+ * UMFPACK_WARNING_singular_matrix (1) added.
+
+ * Control [UMFPACK_PIVOT_OPTION] removed. No longer any symmetric
+ pivot option (conflicts with the handling of singular and
+ rectangular matrices).
+
+ * Iterative refinement can do Ax=b, A'x=b, or A.'x=b.
+
+ * Most floating-point operations done in macros, to support the complex
+ versions.
+
+ * Info [UMFPACK_N] is now Info [UMFPACK_NROW]
+
+ * Info [UMFPACK_NCOL], Info [UMFPACK_UDIAG_NZ], Info [UMFPACK_UDIAG_NZ]
+ added.
+
+ * umfpack_* routines with "n" as input now use two arguments,
+ n_row and n_col.
+
+ * umfpack mexFunction now explicitly transposes A for b/A. It computes
+ it using the array transpose as (A.'\b.').'
+
+January 1, 2002: UMFPACK Version 3.2 released. Submitted to ACM Trans.
+ on Mathematical Software.
+
+ * The umfpack mexFunction now returns the Info array when the matrix
+ is singular. Returned an empty array prior to this change.
+
+ * Renamed variable that conflicted with system library routines
+ (system and j1).
+
+ * Added a #ifdef MATHWORKS definition, so the built-in UMFPACK routine
+ (in a future release of MATLAB) can use the internal ut* memory
+ allocation routines, ut* assertion routine, and utPrintf.
+
+ * MAX and MIN are not defined if they are already defined.
+
+ * A bug fix in umf_kernel_init (a variable was not properly initialized).
+
+ * Removed unused variables.
+
+October 8, 2001: UMFPACK Version 3.1 released.
+
+August-October, 2001:
+
+ * added umfpack_btf M-file.
+
+ * modified the BLAS update in the frontal matrix. If there are only
+ a few pivots in remaining in the current front, then the BLAS3 update
+ is delayed to include pivots in the next front.
+
+ * Removed the special-case handling of dense columns from the numerical
+ factorization (kept it in the colamd preordering). This improves the
+ performance of UMFPACK on dense matrices by a factor of 5 or so, and
+ simplifies the code.
+
+ * Added a symmetric-preference pivoting option. The option slightly
+ (but uniformly) improves the ordering when factorizing matrices with
+ symmetric nonzero pattern. That class of matrix is better handled by
+ the symmetric-pattern multifrontal method (MA41 in the Harwell
+ Subroutine Library), however.
+
+ * Fixed the detection of integer overflow. The 32-bit version cannot
+ make use of more than 2GB of main memory (use the 64-bit version
+ in that case, instead). The 32-bit version did not correctly detect
+ when it was trying to factorize too large of a matrix.
+
+May 4, 2001:
+
+ * SGI port extended. It can now call the SCSL Scientific Library, with
+ 64-bit BLAS. Make.sgi and umf_config.h modified.
+
+April 30, 2001: UMFPACK Version 3.0 released. Changes since 3.0Beta release:
+
+ * Long integer version added (umfpack_l_* user-callable routines).
+
+ * Peak memory usage in the numerical factorization reduced by a total of
+ 12n integers (8n temporary workspace used during numerical
+ factorization, and 4n for the permanent LU factors which was allocated
+ at the beginning of factorization).
+
+ * Ported to the IBM RS 6000 and Compaq Alpha, with help from Anshul Gupta
+ and Friedrich Grund, respectively.
+
+ * 64-bit version added. Uses dgemm_64, dgemv_64, and dger_64 in the Sun
+ Performance Library. 64-bit versions with the BLAS might not work on
+ any other platform, because they take int's as their integer input
+ arguments instead of long's. Unfortunately, the proposed ANSI
+ definition of the C-BLAS also uses int's as input integer arguments.
+ It ought to use long's, or include a version that uses long's, just
+ like the Sun Performance Library BLAS.
+
+ * Additional statistics returned in Info:
+ Info [UMFPACK_SIZE_OF_INT] sizeof (int)
+ Info [UMFPACK_SIZE_OF_LONG] sizeof (long)
+ Info [UMFPACK_SIZE_OF_POINTER] sizeof (void *)
+ Info [UMFPACK_SIZE_OF_ENTRY] (was Info [UMFPACK_WORD])
+ Info [UMFPACK_MAX_FRONT_SIZE_ESTIMATE] est. front matrix size
+ Info [UMFPACK_MAX_FRONT_SIZE] actual max frontal matrix size.
+ Contents of Info rearranged.
+
+ * UMFPACK_ERROR_bad_configurution error code replaced with
+ UMFPACK_ERROR_problem_too_large error code. The "bad configuration"
+ error occured when sizeof (int) < sizeof (size_t). Now, the int
+ version of UMFPACK can use 32-bit int's and 64-bit pointers, and the
+ long version can use 64-bit long's and 64-bit pointers. Both versions
+ check to see if the array sizes allocated are larger than what can be
+ accessed by an integer index variable (int or long, depending on the
+ version), and returns UMFPACK_ERROR_problem_too_large if they become
+ too large.
+
+March 15, 2001: UMFPACK Version 3.0Beta released.
+
--- /dev/null
+UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+Davis. All Rights Reserved.
+
+UMFPACK License:
+
+ Your use or distribution of UMFPACK or any modified version of
+ UMFPACK implies that you agree to this License.
+
+ THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+ EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+
+ Permission is hereby granted to use or copy this program, provided
+ that the Copyright, this License, and the Availability of the original
+ version is retained on all copies. User documentation of any code that
+ uses UMFPACK or any modified version of UMFPACK code must cite the
+ Copyright, this License, the Availability note, and "Used by permission."
+ Permission to modify the code and to distribute modified code is granted,
+ provided the Copyright, this License, and the Availability note are
+ retained, and a notice that the code was modified is included. This
+ software was developed with support from the National Science Foundation,
+ and is provided to you free of charge.
+
+Availability:
+
+ http://www.cise.ufl.edu/research/sparse/umfpack
+
+--------------------------------------------------------------------------------
+
+AMD Version 1.1 (Jan. 10, 2004), Copyright (c) 2004 by Timothy A.
+Davis, Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved.
+
+AMD License:
+
+ Your use or distribution of AMD or any modified version of
+ AMD implies that you agree to this License.
+
+ THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+ EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+
+ Permission is hereby granted to use or copy this program, provided
+ that the Copyright, this License, and the Availability of the original
+ version is retained on all copies. User documentation of any code that
+ uses AMD or any modified version of AMD code must cite the
+ Copyright, this License, the Availability note, and "Used by permission."
+ Permission to modify the code and to distribute modified code is granted,
+ provided the Copyright, this License, and the Availability note are
+ retained, and a notice that the code was modified is included. This
+ software was developed with support from the National Science Foundation,
+ and is provided to you free of charge.
+
+Availability:
+
+ http://www.cise.ufl.edu/research/sparse/amd
--- /dev/null
+#-------------------------------------------------------------------------------
+# UMFPACK Makefile for compiling on Unix systems (for GNU or original make)
+#-------------------------------------------------------------------------------
+
+all: dist
+
+include ../Make/Make.include
+
+#-------------------------------------------------------------------------------
+# Remove all but the files in the original distribution
+#-------------------------------------------------------------------------------
+
+# Note that UserGuide.tex is created from UserGuide.stex, the files in
+# the ../Include directory, and the ../Demo/umfpack_simple.c file.
+purge: clean
+ - $(RM) *.aux *.bbl *.blg *.log *.toc
+ - $(RM) UserGuide.tex
+
+#-------------------------------------------------------------------------------
+# Create the User Guide and Quick Start Guide
+#-------------------------------------------------------------------------------
+
+UMFPACK = umfpack_col_to_triplet umfpack_defaults umfpack_free_numeric \
+ umfpack_free_symbolic umfpack_get_numeric umfpack_get_lunz \
+ umfpack_get_symbolic umfpack_numeric umfpack_qsymbolic \
+ umfpack_report_control umfpack_report_info umfpack_report_matrix \
+ umfpack_report_numeric umfpack_report_perm umfpack_report_status \
+ umfpack_report_symbolic umfpack_report_triplet \
+ umfpack_report_vector umfpack_solve umfpack_symbolic \
+ umfpack_transpose umfpack_triplet_to_col umfpack_scale
+
+UMFPACKW = umfpack_wsolve
+
+USER = $(UMFPACKW) $(UMFPACK)
+
+SRC = $(addprefix ../Include/, $(addsuffix .h,$(USER))) ../Demo/umfpack_simple.c
+
+UserGuide.pdf: UserGuide.stex UserGuide.sed1 UserGuide.sed2 $(SRC)
+ sed -f UserGuide.sed1 < UserGuide.stex | sed -f UserGuide.sed2 \
+ | expand -8 > UserGuide.tex
+ pdflatex UserGuide
+ bibtex UserGuide
+ pdflatex UserGuide
+ pdflatex UserGuide
+
+QuickStart.pdf: QuickStart.tex
+ pdflatex QuickStart
+ pdflatex QuickStart
+
+dist: QuickStart.pdf UserGuide.pdf
+ - $(RM) *.aux *.bbl *.blg *.log *.toc
+ - $(RM) UserGuide.tex
--- /dev/null
+%-------------------------------------------------------------------------------
+% The QuickStart.tex file.
+%-------------------------------------------------------------------------------
+
+\documentclass[11pt]{article}
+
+\newcommand{\m}[1]{{\bf{#1}}} % for matrices and vectors
+\newcommand{\tr}{^{\sf T}} % transpose
+
+\topmargin 0in
+\textheight 9in
+\oddsidemargin 0pt
+\evensidemargin 0pt
+\textwidth 6.5in
+
+\begin{document}
+
+\author{Timothy A. Davis \\
+Dept. of Computer and Information Science and Engineering \\
+Univ. of Florida, Gainesville, FL}
+\title{UMFPACK Version 4.3 Quick Start Guide}
+\date{Jan. 16, 2004}
+\maketitle
+
+%-------------------------------------------------------------------------------
+\begin{abstract}
+ UMFPACK is a set of routines for solving unsymmetric sparse linear
+ systems, $\m{Ax}=\m{b}$, using the Unsymmetric-pattern MultiFrontal method
+ and direct sparse LU factorization. It is written in ANSI/ISO C, with a
+ MATLAB interface. UMFPACK relies on the Level-3
+ Basic Linear Algebra Subprograms (dense matrix multiply) for its
+ performance. This code works on Windows and many versions of Unix (Sun
+ Solaris, Red Hat Linux, IBM AIX, SGI IRIX, and Compaq Alpha).
+ This is a ``quick start'' guide for Unix users of the C interface.
+\end{abstract}
+%-------------------------------------------------------------------------------
+
+Technical Report TR-04-003
+
+UMFPACK Version 4.3 (Jan. 16, 2004), Copyright\copyright 2004 by Timothy A.
+Davis. All Rights Reserved. Refer to the UMFPACK User Guide
+for the License. See \newline
+http://www.cise.ufl.edu/research/sparse/umfpack
+for the code and full documentation.
+
+%-------------------------------------------------------------------------------
+\section{Overview}
+%-------------------------------------------------------------------------------
+
+UMFPACK is a set of routines for solving systems of linear
+equations, $\m{Ax}=\m{b}$, when $\m{A}$ is sparse and unsymmetric.
+The sparse matrix $\m{A}$ can be square or rectangular, singular
+or non-singular, and real or complex (or any combination). Only square
+matrices $\m{A}$ can be used to solve $\m{Ax}=\m{b}$ or related systems.
+Rectangular matrices can only be factorized.
+
+UMFPACK Version 4.0 is a built-in routine in MATLAB 6.5, used by the forward and
+backslash operator, and the {\tt lu} routine. The following is a short
+introduction to Unix users of the C interface of UMFPACK.
+
+%-------------------------------------------------------------------------------
+
+The C-callable UMFPACK library consists of 31 user-callable routines and one
+include file. Twenty-seven of the routines come in four versions, with
+different sizes of integers and for real or complex floating-point numbers.
+This Quick Start Guide assumes you are working with real matrices
+(not complex) and with {\tt int}'s as integers (not {\tt long}'s).
+Refer to the User Guide for information about the complex and
+long integer versions. The include file {\tt umfpack.h}
+must be included in any C program that uses UMFPACK.
+
+%-------------------------------------------------------------------------------
+\section{Primary routines, and a simple example}
+%-------------------------------------------------------------------------------
+
+Five primary UMFPACK routines are required to factorize $\m{A}$ or
+solve $\m{Ax}=\m{b}$. An overview of the primary features of the routines
+is given in Section~\ref{Primary}.
+Additional routines are available for passing a different column ordering
+to UMFPACK, changing default parameters, manipulating sparse matrices,
+getting the LU factors, save and loading the LU factors from a file,
+and reporting results. See the User Guide for more information.
+
+\begin{itemize}
+\item {\tt umfpack\_di\_symbolic}:
+
+ Pre-orders the columns of $\m{A}$ to reduce fill-in and performs a
+ symbolic analysis.
+ Returns an opaque {\tt Symbolic} object as a {\tt void *}
+ pointer. The object contains the symbolic analysis and is needed for the
+ numerical factorization.
+
+\item {\tt umfpack\_di\_numeric}:
+
+ Numerically scales and then factorizes a sparse matrix
+ $\m{PAQ}$, $\m{PRAQ}$, or $\m{PR}^{-1}\m{AQ}$ into the product $\m{LU}$,
+ where
+ $\m{P}$ and $\m{Q}$ are permutation matrices, $\m{R}$ is a diagonal
+ matrix of scale factors, $\m{L}$ is lower triangular with unit diagonal,
+ and $\m{U}$ is upper triangular. Requires the
+ symbolic ordering and analysis computed by {\tt umfpack\_di\_symbolic}.
+ Returns an opaque {\tt Numeric} object as a
+ {\tt void *} pointer. The object contains the numerical factorization and
+ is used by {\tt umfpack\_di\_solve}.
+
+\item {\tt umfpack\_di\_solve}:
+
+ Solves a sparse linear system ($\m{Ax}=\m{b}$, $\m{A}\tr\m{x}=\m{b}$, or
+ systems involving just $\m{L}$ or $\m{U}$), using the numeric factorization
+ computed by {\tt umfpack\_di\_numeric}.
+
+\item {\tt umfpack\_di\_free\_symbolic}:
+
+ Frees the {\tt Symbolic} object created by {\tt umfpack\_di\_symbolic}.
+
+\item {\tt umfpack\_di\_free\_numeric}:
+
+ Frees the {\tt Numeric} object created by {\tt umfpack\_di\_numeric}.
+
+\end{itemize}
+
+The matrix $\m{A}$ is represented in compressed column form, which is
+identical to the sparse matrix representation used by MATLAB. It consists
+of three arrays, where the matrix is {\tt m}-by-{\tt n},
+with {\tt nz} entries:
+
+{\footnotesize
+\begin{verbatim}
+ int Ap [n+1] ;
+ int Ai [nz] ;
+ double Ax [nz] ;
+\end{verbatim}
+}
+
+All nonzeros are entries, but an entry may be numerically zero. The row indices
+of entries in column {\tt j} are stored in
+ {\tt Ai[Ap[j]} ... {\tt Ap[j+1]-1]}.
+The corresponding numerical values are stored in
+ {\tt Ax[Ap[j]} ... {\tt Ap[j+1]-1]}.
+
+No duplicate row indices may be present, and the row indices in any given
+column must be sorted in ascending order. The first entry {\tt Ap[0]} must be
+zero. The total number of entries in the matrix is thus {\tt nz = Ap[n]}.
+Except for the fact that extra zero entries can be included, there is thus a
+unique compressed column representation of any given matrix $\m{A}$.
+
+Here is a simple main program, {\tt umfpack\_simple.c}, that illustrates the
+basic usage of UMFPACK.
+
+{\footnotesize
+\begin{verbatim}
+ #include <stdio.h>
+ #include "umfpack.h"
+
+ int n = 5 ;
+ int Ap [ ] = {0, 2, 5, 9, 10, 12} ;
+ int Ai [ ] = { 0, 1, 0, 2, 4, 1, 2, 3, 4, 2, 1, 4} ;
+ double Ax [ ] = {2., 3., 3., -1., 4., 4., -3., 1., 2., 2., 6., 1.} ;
+ double b [ ] = {8., 45., -3., 3., 19.} ;
+ double x [5] ;
+
+ int main (void)
+ {
+ double *null = (double *) NULL ;
+ int i ;
+ void *Symbolic, *Numeric ;
+ (void) umfpack_di_symbolic (n, n, Ap, Ai, Ax, &Symbolic, null, null) ;
+ (void) umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric, null, null) ;
+ umfpack_di_free_symbolic (&Symbolic) ;
+ (void) umfpack_di_solve (UMFPACK_A, Ap, Ai, Ax, x, b, Numeric, null, null) ;
+ umfpack_di_free_numeric (&Numeric) ;
+ for (i = 0 ; i < n ; i++) printf ("x [%d] = %g\n", i, x [i]) ;
+ return (0) ;
+ }
+\end{verbatim}
+}
+
+The {\tt Ap}, {\tt Ai}, and {\tt Ax} arrays represent the matrix
+\[
+\m{A} = \left[
+\begin{array}{rrrrr}
+ 2 & 3 & 0 & 0 & 0 \\
+ 3 & 0 & 4 & 0 & 6 \\
+ 0 & -1 & -3 & 2 & 0 \\
+ 0 & 0 & 1 & 0 & 0 \\
+ 0 & 4 & 2 & 0 & 1 \\
+\end{array}
+\right].
+\]
+and the solution is $\m{x} = [1 \, 2 \, 3 \, 4 \, 5]\tr$. The program uses
+default control settings and does not return any statistics about the ordering,
+factorization, or solution ({\tt Control} and {\tt Info} are both
+{\tt (double *) NULL}).
+
+For routines to manipulate a simpler ``triplet-form'' data structure for your
+sparse matrix $\m{A}$, refer to the UMFPACK User Guide.
+
+%-------------------------------------------------------------------------------
+\section{Synopsis of primary C-callable routines}
+\label{Synopsis}
+%-------------------------------------------------------------------------------
+
+The matrix $\m{A}$ is {\tt m}-by-{\tt n} with {\tt nz} entries.
+The optional {\tt umfpack\_di\_defaults} routine loads the default control
+parameters into the {\tt Control} array. The settings can then be modified
+before passing the array to the other routines. Refer to Section~\ref{Primary}
+for more details.
+
+{\footnotesize
+\begin{verbatim}
+ #include "umfpack.h"
+ int status, sys, n, m, nz, Ap [n+1], Ai [nz] ;
+ double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], Ax [nz], X [n], B [n] ;
+ void *Symbolic, *Numeric ;
+
+ status = umfpack_di_symbolic (m, n, Ap, Ai, Ax, &Symbolic, Control, Info) ;
+ status = umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric, Control, Info) ;
+ status = umfpack_di_solve (sys, Ap, Ai, Ax, X, B, Numeric, Control, Info) ;
+ umfpack_di_free_symbolic (&Symbolic) ;
+ umfpack_di_free_numeric (&Numeric) ;
+ umfpack_di_defaults (Control) ;
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\section{Installation}
+\label{Install}
+%-------------------------------------------------------------------------------
+
+You will need to install both UMFPACK v4.3 and AMD v1.1 (or AMD v1.0) to use UMFPACK.
+The {\tt UMFPACK} and {\tt AMD} subdirectories must be placed side-by-side
+within the same parent directory. AMD is a stand-alone package that
+is required by UMFPACK. UMFPACK can be compiled without the
+BLAS but your performance will be much less than what it should be.
+
+System-dependent configurations are in the {\tt AMD/Make}
+and {\tt UMFPACK/Make} directories. You can edit the {\tt Make.include}
+files in those directories to customize the compilation. The default
+settings will work on most systems, except that UMFPACK will be compiled so
+that it does not use the BLAS. Sample configuration files are provided
+for Linux, Sun Solaris, SGI IRIX, IBM AIX, and the DEC/Compaq Alpha.
+
+To compile and install both packages,
+go to the UMFPACK directory and type {\tt make}. This will compile the
+libraries ({\tt AMD/Lib/libamd.a} and {\tt UMFPACK/Lib/libumfpack.a}).
+A demo of the AMD ordering routine will be compiled and tested in
+the {\tt AMD/Demo} directory, and five demo programs will then be
+compiled and tested in the {\tt UMFPACK/Demo} directory.
+The outputs of these demo programs will then be compared with output
+files in the distribution. Expect to see a few differences, such as
+residual norms, compile-time control settings, and perhaps memory usage
+differences. The AMD and MATLAB mexFunctions for
+use in MATLAB will also be compiled. If you do not have MATLAB,
+type {\tt make lib} instead.
+
+If you compile UMFPACK and AMD and then later change the {\tt Make.include}
+file or your system-specific configuration file such as {\tt Make.linux},
+then you should type {\tt make purge} and then {\tt make} to recompile.
+
+Here are the various parameters that you can control in your
+{\tt Make.include} file:
+
+\begin{itemize}
+\item {\tt CC = } your C compiler, such as {\tt cc}.
+\item {\tt RANLIB = } your system's {\tt ranlib} program, if needed.
+\item {\tt CFLAGS = } optimization flags, such as {\tt -O}.
+\item {\tt CONFIG = } configuration settings, for the BLAS, memory allocation
+ routines, and timing routines.
+\item {\tt LIB = } your libraries, such as {\tt -lm} or {\tt -lblas}.
+\item {\tt RM =} the command to delete a file.
+\item {\tt MV =} the command to rename a file.
+\item {\tt MEX =} the command to compile a MATLAB mexFunction.
+\item {\tt F77 =} the command to compile a Fortran program (optional).
+\item {\tt F77FLAGS =} the Fortran compiler flags (optional).
+\item {\tt F77LIB =} the Fortran libraries (optional).
+\end{itemize}
+
+The {\tt CONFIG} string can include combinations of the following;
+most deal with how the BLAS are called:
+\begin{itemize}
+\item {\tt -DNBLAS} if you do not have any BLAS at all.
+\item {\tt -DCBLAS} if you have the C-BLAS.
+\item {\tt -DNSUNPERF} if you are on Solaris but do not have the Sun
+ Performance Library.
+\item {\tt -DNSCSL} if you on SGI IRIX but do not have the SCSL BLAS library.
+\item {\tt -DLONGBLAS} if your BLAS can take {\tt long} integer input
+ arguments.
+\item Options for controlling how C calls the Fortran BLAS:
+ {\tt -DBLAS\_BY\_VALUE}, {\tt -DBLAS\_NO\_UNDERSCORE},
+ and {\tt -DBLAS\_CHAR\_ARG}. These are set automatically for Windows,
+ Sun Solaris, SGI Irix, Red Hat Linux, Compaq Alpha, and
+ AIX (the IBM RS 6000).
+\item {\tt -DGETRUSAGE} if you have the {\tt getrusage} function.
+\item {\tt -DLP64} if you are compiling in the LP64 model (32 bit {\tt int}'s,
+ 64 bit {\tt long}'s, and 64 bit pointers).
+\item {\tt -DNUTIL} if you wish to compile the MATLAB-callable
+ UMFPACK mexFunction with the {\tt mxMalloc}, {\tt mxRealloc}
+ and {\tt mxFree} routines, instead of the undocumented (but
+ superior) {\tt utMalloc}, {\tt utRealloc}, and {\tt utFree}
+ routines.
+\item {\tt -DNPOSIX} if you do not have the POSIX-compliant
+ {\tt sysconf} and {\tt times} routines.
+\item {\tt -DNRECIPROCAL} controls a trade-off between speed and accuracy.
+ This is normally off by default, except when the {\tt gcc}
+ compiler is used.
+\end{itemize}
+
+When you compile your program that uses the C-callable UMFPACK library,
+you need to add the both {\tt UMFPACK/Lib/libumfpack.a} and
+{\tt AMD/Lib/libamd.a}
+libraries, and you need to tell your compiler to look in the
+directories {\tt UMFPACK/Include} and {\tt AMD/Include} for include
+files. See {\tt UMFPACK/Demo/Makefile} for an example.
+You do not need to directly include any AMD include files in your
+program, unless you directly call AMD routines. You only need the
+\begin{verbatim}
+#include "umfpack.h"
+\end{verbatim}
+statement, as described in Section~\ref{Synopsis}.
+
+%-------------------------------------------------------------------------------
+\newpage
+\section{The primary UMFPACK routines}
+\label{Primary}
+%-------------------------------------------------------------------------------
+
+\subsection{umfpack\_di\_symbolic}
+
+{\footnotesize
+\begin{verbatim}
+int umfpack_di_symbolic
+(
+ int n_row,
+ int n_col,
+ const int Ap [ ],
+ const int Ai [ ],
+ const double Ax [ ],
+ void **Symbolic,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO]
+) ;
+
+Purpose:
+
+ Given nonzero pattern of a sparse matrix A in column-oriented form,
+ umfpack_di_symbolic performs a column pre-ordering to reduce fill-in
+ (using COLAMD or AMD) and a symbolic factorization. This is required
+ before the matrix can be numerically factorized with umfpack_di_numeric.
+
+ For the following discussion, let S be the submatrix of A obtained after
+ eliminating all pivots of zero Markowitz cost. S has dimension
+ (n_row-n1-nempty_row) -by- (n_col-n1-nempty_col), where
+ n1 = Info [UMFPACK_COL_SINGLETONS] + Info [UMFPACK_ROW_SINGLETONS],
+ nempty_row = Info [UMFPACK_NEMPTY_ROW] and
+ nempty_col = Info [UMFPACK_NEMPTY_COL].
+
+Returns:
+
+ The status code is returned. See Info [UMFPACK_STATUS], below.
+
+Arguments:
+
+ Int n_row ; Input argument, not modified.
+ Int n_col ; Input argument, not modified.
+
+ A is an n_row-by-n_col matrix. Restriction: n_row > 0 and n_col > 0.
+
+ Int Ap [n_col+1] ; Input argument, not modified.
+
+ Ap is an integer array of size n_col+1. On input, it holds the
+ "pointers" for the column form of the sparse matrix A. Column j of
+ the matrix A is held in Ai [(Ap [j]) ... (Ap [j+1]-1)]. The first
+ entry, Ap [0], must be zero, and Ap [j] <= Ap [j+1] must hold for all
+ j in the range 0 to n_col-1. The value nz = Ap [n_col] is thus the
+ total number of entries in the pattern of the matrix A. nz must be
+ greater than or equal to zero.
+
+ Int Ai [nz] ; Input argument, not modified, of size nz = Ap [n_col].
+
+ The nonzero pattern (row indices) for column j is stored in
+ Ai [(Ap [j]) ... (Ap [j+1]-1)]. The row indices in a given column j
+ must be in ascending order, and no duplicate row indices may be present.
+ Row indices must be in the range 0 to n_row-1 (the matrix is 0-based).
+
+ double Ax [nz] ; Optional input argument, not modified.
+
+ The numerical values of the sparse matrix A. The nonzero pattern (row
+ indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and
+ the corresponding numerical values are stored in
+ Ax [(Ap [j]) ... (Ap [j+1]-1)]. Used only by the 2-by-2 strategy to
+ determine whether entries are "large" or "small". You do not have to
+ pass the same numerical values to umfpack_di_numeric. If Ax is not
+ present (a (double *) NULL pointer), then any entry in A is assumed to
+ be "large".
+
+ void **Symbolic ; Output argument.
+
+ **Symbolic is the address of a (void *) pointer variable in the user's
+ calling routine (see Syntax, above). On input, the contents of this
+ variable are not defined. On output, this variable holds a (void *)
+ pointer to the Symbolic object (if successful), or (void *) NULL if
+ a failure occurred.
+
+ double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+ If a (double *) NULL pointer is passed, then the default control
+ settings are used. Only the primary parameters are listed below:
+
+ Control [UMFPACK_STRATEGY]: This is the most important control
+ parameter. It determines what kind of ordering and pivoting
+ strategy that UMFPACK should use. It is new to Version 4.1
+ There are 4 options:
+
+ UMFPACK_STRATEGY_AUTO: This is the default. The input matrix is
+ analyzed to determine how symmetric the nonzero pattern is, and
+ how many entries there are on the diagonal. It then selects one
+ of the following strategies. Refer to the User Guide for a
+ description of how the strategy is automatically selected.
+
+ UMFPACK_STRATEGY_UNSYMMETRIC: Use the unsymmetric strategy. COLAMD
+ is used to order the columns of A, followed by a postorder of
+ the column elimination tree. No attempt is made to perform
+ diagonal pivoting. The column ordering is refined during
+ factorization. This strategy was the only one provided with
+ UMFPACK V4.0.
+
+ In the numerical factorization, the
+ Control [UMFPACK_SYM_PIVOT_TOLERANCE] parameter is ignored. A
+ pivot is selected if its magnitude is >=
+ Control [UMFPACK_PIVOT_TOLERANCE] (default 0.1) times the
+ largest entry in its column.
+
+ UMFPACK_STRATEGY_SYMMETRIC: Use the symmetric strategy (new to
+ Version 4.1). In this method, the approximate minimum degree
+ ordering (AMD) is applied to A+A', followed by a postorder of
+ the elimination tree of A+A'. UMFPACK attempts to perform
+ diagonal pivoting during numerical factorization. No refinement
+ of the column preordering is performed during factorization.
+
+ In the numerical factorization, a nonzero entry on the diagonal
+ is selected as the pivot if its magnitude is >= Control
+ [UMFPACK_SYM_PIVOT_TOLERANCE] (default 0.001) times the largest
+ entry in its column. If this is not acceptable, then an
+ off-diagonal pivot is selected with magnitude >= Control
+ [UMFPACK_PIVOT_TOLERANCE] (default 0.1) times the largest entry
+ in its column.
+
+ UMFPACK_STRATEGY_2BY2: a row permutation P2 is found that places
+ large entries on the diagonal. The matrix P2*A is then
+ factorized using the symmetric strategy, described above.
+ Refer to the User Guide for more information.
+
+ Control [UMFPACK_2BY2_TOLERANCE]: a diagonal entry S (k,k) is
+ considered "small" if it is < tol * max (abs (S (:,k))), where S a
+ submatrix of the scaled input matrix, with pivots of zero Markowitz
+ cost removed.
+
+ Control [UMFPACK_SCALE]: This parameter is new to V4.1. See
+ umfpack_numeric.h for a description. Only affects the 2-by-2
+ strategy. Default: UMFPACK_SCALE_SUM.
+
+ double Info [UMFPACK_INFO] ; Output argument, not defined on input.
+
+ Contains statistics about the symbolic analysis. If a (double *) NULL
+ pointer is passed, then no statistics are returned in Info (this is not
+ an error condition). The entire Info array is cleared (all entries set
+ to -1) and then the following statistics are computed (only the
+ primary statistics are listed):
+
+ Info [UMFPACK_STATUS]: status code. This is also the return value,
+ whether or not Info is present.
+
+ UMFPACK_OK
+
+ Each column of the input matrix contained row indices
+ in increasing order, with no duplicates. Only in this case
+ does umfpack_di_symbolic compute a valid symbolic factorization.
+ For the other cases below, no Symbolic object is created
+ (*Symbolic is (void *) NULL).
+
+ UMFPACK_ERROR_n_nonpositive
+
+ n is less than or equal to zero.
+
+ UMFPACK_ERROR_invalid_matrix
+
+ Number of entries in the matrix is negative, Ap [0] is nonzero,
+ a column has a negative number of entries, a row index is out of
+ bounds, or the columns of input matrix were jumbled (unsorted
+ columns or duplicate entries).
+
+ UMFPACK_ERROR_out_of_memory
+
+ Insufficient memory to perform the symbolic analysis. If the
+ analysis requires more than 2GB of memory and you are using
+ the 32-bit ("int") version of UMFPACK, then you are guaranteed
+ to run out of memory. Try using the 64-bit version of UMFPACK.
+
+ UMFPACK_ERROR_argument_missing
+
+ One or more required arguments is missing.
+
+ UMFPACK_ERROR_internal_error
+
+ Something very serious went wrong. This is a bug.
+ Please contact the author (davis@cise.ufl.edu).
+
+ Info [UMFPACK_SIZE_OF_UNIT]: the number of bytes in a Unit,
+ for memory usage statistics below.
+
+ Info [UMFPACK_SYMBOLIC_PEAK_MEMORY]: the amount of memory (in Units)
+ required for umfpack_di_symbolic to complete. This count includes
+ the size of the Symbolic object itself, which is also reported in
+ Info [UMFPACK_SYMBOLIC_SIZE].
+
+ Info [UMFPACK_NUMERIC_SIZE_ESTIMATE]: an estimate of the final size (in
+ Units) of the entire Numeric object (both fixed-size and variable-
+ sized parts), which holds the LU factorization (including the L, U,
+ P and Q matrices).
+
+ Info [UMFPACK_PEAK_MEMORY_ESTIMATE]: an estimate of the total amount of
+ memory (in Units) required by umfpack_di_symbolic and
+ umfpack_di_numeric to perform both the symbolic and numeric
+ factorization. This is the larger of the amount of memory needed
+ in umfpack_di_numeric itself, and the amount of memory needed in
+ umfpack_di_symbolic (Info [UMFPACK_SYMBOLIC_PEAK_MEMORY]). The
+ count includes the size of both the Symbolic and Numeric objects
+ themselves. It can be a very loose upper bound, particularly when
+ the symmetric or 2-by-2 strategies are used.
+
+ Info [UMFPACK_FLOPS_ESTIMATE]: an estimate of the total floating-point
+ operations required to factorize the matrix. This is a "true"
+ theoretical estimate of the number of flops that would be performed
+ by a flop-parsimonious sparse LU algorithm. It assumes that no
+ extra flops are performed except for what is strictly required to
+ compute the LU factorization. It ignores, for example, the flops
+ performed by umfpack_di_numeric to add contribution blocks of
+ frontal matrices together. If L and U are the upper bound on the
+ pattern of the factors, then this flop count estimate can be
+ represented in MATLAB (for real matrices, not complex) as:
+
+ Lnz = full (sum (spones (L))) - 1 ; % nz in each col of L
+ Unz = full (sum (spones (U')))' - 1 ; % nz in each row of U
+ flops = 2*Lnz*Unz + sum (Lnz) ;
+
+ The actual "true flop" count found by umfpack_di_numeric will be
+ less than this estimate.
+
+ Info [UMFPACK_LNZ_ESTIMATE]: an estimate of the number of nonzeros in
+ L, including the diagonal. Since L is unit-diagonal, the diagonal
+ of L is not stored. This estimate is a strict upper bound on the
+ actual nonzeros in L to be computed by umfpack_di_numeric.
+
+ Info [UMFPACK_UNZ_ESTIMATE]: an estimate of the number of nonzeros in
+ U, including the diagonal. This estimate is a strict upper bound on
+ the actual nonzeros in U to be computed by umfpack_di_numeric.
+
+ Info [UMFPACK_SYMBOLIC_TIME]: The CPU time taken, in seconds.
+
+ Info [UMFPACK_STRATEGY_USED]: The ordering strategy used:
+ UMFPACK_STRATEGY_SYMMETRIC, UMFPACK_STRATEGY_UNSYMMETRIC, or
+ UMFPACK_STRATEGY_2BY2.
+\end{verbatim}
+}
+
+
+%-------------------------------------------------------------------------------
+\newpage
+\subsection{umfpack\_di\_numeric}
+
+{\footnotesize
+\begin{verbatim}
+int umfpack_di_numeric
+(
+ const int Ap [ ],
+ const int Ai [ ],
+ const double Ax [ ],
+ void *Symbolic,
+ void **Numeric,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO]
+) ;
+
+Purpose:
+
+ Given a sparse matrix A in column-oriented form, and a symbolic analysis
+ computed by umfpack_di_symbolic, the umfpack_di_numeric routine performs the
+ numerical factorization, PAQ=LU, PRAQ=LU, or P(R\A)Q=LU, where P and Q are
+ permutation matrices (represented as permutation vectors), R is the row
+ scaling, L is unit-lower triangular, and U is upper triangular. This is
+ required before the system Ax=b (or other related linear systems) can be
+ solved. umfpack_di_numeric can be called multiple times for each call to
+ umfpack_di_symbolic, to factorize a sequence of matrices with identical
+ nonzero pattern. Simply compute the Symbolic object once, with
+ umfpack_di_symbolic, and reuse it for subsequent matrices.
+ umfpack_di_numeric safely detects if the pattern changes, and sets an
+ appropriate error code.
+
+Returns:
+
+ The status code is returned. See Info [UMFPACK_STATUS], below.
+
+Arguments:
+
+ Int Ap [n_col+1] ; Input argument, not modified.
+
+ This must be identical to the Ap array passed to umfpack_di_symbolic.
+ The value of n_col is what was passed to umfpack_di_symbolic (this is
+ held in the Symbolic object).
+
+ Int Ai [nz] ; Input argument, not modified, of size nz = Ap [n_col].
+
+ This must be identical to the Ai array passed to umfpack_di_symbolic.
+
+ double Ax [nz] ; Input argument, not modified, of size nz = Ap [n_col].
+
+ The numerical values of the sparse matrix A. The nonzero pattern (row
+ indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and
+ the corresponding numerical values are stored in
+ Ax [(Ap [j]) ... (Ap [j+1]-1)].
+
+ void *Symbolic ; Input argument, not modified.
+
+ The Symbolic object, which holds the symbolic factorization computed by
+ umfpack_di_symbolic. The Symbolic object is not modified by
+ umfpack_di_numeric.
+
+ void **Numeric ; Output argument.
+
+ **Numeric is the address of a (void *) pointer variable in the user's
+ calling routine (see Syntax, above). On input, the contents of this
+ variable are not defined. On output, this variable holds a (void *)
+ pointer to the Numeric object (if successful), or (void *) NULL if
+ a failure occurred.
+
+ double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+ If a (double *) NULL pointer is passed, then the default control
+ settings are used. Only the primary parameters are listed below:
+
+ Control [UMFPACK_PIVOT_TOLERANCE]: relative pivot tolerance for
+ threshold partial pivoting with row interchanges. In any given
+ column, an entry is numerically acceptable if its absolute value is
+ greater than or equal to Control [UMFPACK_PIVOT_TOLERANCE] times
+ the largest absolute value in the column. A value of 1.0 gives true
+ partial pivoting. If less than or equal to zero, then any nonzero
+ entry is numerically acceptable as a pivot (this is changed from
+ Version 4.0). Default: 0.1.
+
+ Smaller values tend to lead to sparser LU factors, but the solution
+ to the linear system can become inaccurate. Larger values can lead
+ to a more accurate solution (but not always), and usually an
+ increase in the total work.
+
+ Control [UMFPACK_SYM_PIVOT_TOLERANCE]: This parameter is new to V4.1.
+ If diagonal pivoting is attempted (the symmetric or symmetric-2by2
+ strategies are used) then this parameter is used to control when the
+ diagonal entry is selected in a given pivot column. The absolute
+ value of the entry must be >= Control [UMFPACK_SYM_PIVOT_TOLERANCE]
+ times the largest absolute value in the column. A value of zero
+ will ensure that no off-diagonal pivoting is performed, except that
+ zero diagonal entries are not selected if there are any off-diagonal
+ nonzero entries.
+
+ If an off-diagonal pivot is selected, an attempt is made to restore
+ symmetry later on. Suppose A (i,j) is selected, where i != j.
+ If column i has not yet been selected as a pivot column, then
+ the entry A (j,i) is redefined as a "diagonal" entry, except that
+ the tighter tolerance (Control [UMFPACK_PIVOT_TOLERANCE]) is
+ applied. This strategy has an effect similar to 2-by-2 pivoting
+ for symmetric indefinite matrices. If a 2-by-2 block pivot with
+ nonzero structure
+
+ i j
+ i: 0 x
+ j: x 0
+
+ is selected in a symmetric indefinite factorization method, the
+ 2-by-2 block is inverted and a rank-2 update is applied. In
+ UMFPACK, this 2-by-2 block would be reordered as
+
+ j i
+ i: x 0
+ j: 0 x
+
+ In both cases, the symmetry of the Schur complement is preserved.
+
+ Control [UMFPACK_SCALE]: This parameter is new to V4.1. Version 4.0
+ did not scale the matrix. Note that the user's input matrix is
+ never modified, only an internal copy is scaled.
+
+ There are three valid settings for this parameter. If any other
+ value is provided, the default is used.
+
+ UMFPACK_SCALE_NONE: no scaling is performed.
+
+ UMFPACK_SCALE_SUM: each row of the input matrix A is divided by
+ the sum of the absolute values of the entries in that row.
+ The scaled matrix has an infinity norm of 1.
+
+ UMFPACK_SCALE_MAX: each row of the input matrix A is divided by
+ the maximum the absolute values of the entries in that row.
+ In the scaled matrix the largest entry in each row has
+ a magnitude exactly equal to 1.
+
+ Scaling is very important for the "symmetric" strategy when
+ diagonal pivoting is attempted. It also improves the performance
+ of the "unsymmetric" strategy.
+
+ Default: UMFPACK_SCALE_SUM.
+
+ double Info [UMFPACK_INFO] ; Output argument.
+
+ Contains statistics about the numeric factorization. If a
+ (double *) NULL pointer is passed, then no statistics are returned in
+ Info (this is not an error condition). The following statistics are
+ computed in umfpack_di_numeric (only the primary statistics are listed):
+
+ Info [UMFPACK_STATUS]: status code. This is also the return value,
+ whether or not Info is present.
+
+ UMFPACK_OK
+
+ Numeric factorization was successful. umfpack_di_numeric
+ computed a valid numeric factorization.
+
+ UMFPACK_WARNING_singular_matrix
+
+ Numeric factorization was successful, but the matrix is
+ singular. umfpack_di_numeric computed a valid numeric
+ factorization, but you will get a divide by zero in
+ umfpack_di_solve. For the other cases below, no Numeric object
+ is created (*Numeric is (void *) NULL).
+
+ UMFPACK_ERROR_out_of_memory
+
+ Insufficient memory to complete the numeric factorization.
+
+ UMFPACK_ERROR_argument_missing
+
+ One or more required arguments are missing.
+
+ UMFPACK_ERROR_invalid_Symbolic_object
+
+ Symbolic object provided as input is invalid.
+
+ UMFPACK_ERROR_different_pattern
+
+ The pattern (Ap and/or Ai) has changed since the call to
+ umfpack_di_symbolic which produced the Symbolic object.
+
+ Info [UMFPACK_NUMERIC_SIZE]: the actual final size (in Units) of the
+ entire Numeric object, including the final size of the variable
+ part of the object. Info [UMFPACK_NUMERIC_SIZE_ESTIMATE],
+ an estimate, was computed by umfpack_di_symbolic. The estimate is
+ normally an upper bound on the actual final size, but this is not
+ guaranteed.
+
+ Info [UMFPACK_PEAK_MEMORY]: the actual peak memory usage (in Units) of
+ both umfpack_di_symbolic and umfpack_di_numeric. An estimate,
+ Info [UMFPACK_PEAK_MEMORY_ESTIMATE], was computed by
+ umfpack_di_symbolic. The estimate is normally an upper bound on the
+ actual peak usage, but this is not guaranteed. With testing on
+ hundreds of matrix arising in real applications, I have never
+ observed a matrix where this estimate or the Numeric size estimate
+ was less than the actual result, but this is theoretically possible.
+ Please send me one if you find such a matrix.
+
+ Info [UMFPACK_FLOPS]: the actual count of the (useful) floating-point
+ operations performed. An estimate, Info [UMFPACK_FLOPS_ESTIMATE],
+ was computed by umfpack_di_symbolic. The estimate is guaranteed to
+ be an upper bound on this flop count. The flop count excludes
+ "useless" flops on zero values, flops performed during the pivot
+ search (for tentative updates and assembly of candidate columns),
+ and flops performed to add frontal matrices together.
+
+ Info [UMFPACK_LNZ]: the actual nonzero entries in final factor L,
+ including the diagonal. This excludes any zero entries in L,
+ although some of these are stored in the Numeric object. The
+ Info [UMFPACK_LU_ENTRIES] statistic does account for all
+ explicitly stored zeros, however. Info [UMFPACK_LNZ_ESTIMATE],
+ an estimate, was computed by umfpack_di_symbolic. The estimate is
+ guaranteed to be an upper bound on Info [UMFPACK_LNZ].
+
+ Info [UMFPACK_UNZ]: the actual nonzero entries in final factor U,
+ including the diagonal. This excludes any zero entries in U,
+ although some of these are stored in the Numeric object. The
+ Info [UMFPACK_LU_ENTRIES] statistic does account for all
+ explicitly stored zeros, however. Info [UMFPACK_UNZ_ESTIMATE],
+ an estimate, was computed by umfpack_di_symbolic. The estimate is
+ guaranteed to be an upper bound on Info [UMFPACK_UNZ].
+
+ Info [UMFPACK_NUMERIC_TIME]: The CPU time taken, in seconds.
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\newpage
+\subsection{umfpack\_di\_solve}
+
+{\footnotesize
+\begin{verbatim}
+int umfpack_di_solve
+(
+ int sys,
+ const int Ap [ ],
+ const int Ai [ ],
+ const double Ax [ ],
+ double X [ ],
+ const double B [ ],
+ void *Numeric,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO]
+) ;
+
+Purpose:
+
+ Given LU factors computed by umfpack_di_numeric (PAQ=LU, PRAQ=LU, or
+ P(R\A)Q=LU) and the right-hand-side, B, solve a linear system for the
+ solution X. Iterative refinement is optionally performed. Only square
+ systems are handled. Singular matrices result in a divide-by-zero for all
+ systems except those involving just the matrix L. Iterative refinement is
+ not performed for singular matrices.
+
+ In the discussion below, n is equal to n_row and n_col, because only
+ square systems are handled.
+
+Returns:
+
+ The status code is returned. See Info [UMFPACK_STATUS], below.
+
+Arguments:
+
+ Int sys ; Input argument, not modified.
+
+ Defines which system to solve. (') is the linear algebraic transpose.
+
+ sys value system solved
+
+ UMFPACK_A Ax=b
+ UMFPACK_At A'x=b
+ UMFPACK_Pt_L P'Lx=b
+ UMFPACK_L Lx=b
+ UMFPACK_Lt_P L'Px=b
+ UMFPACK_Lt L'x=b
+ UMFPACK_U_Qt UQ'x=b
+ UMFPACK_U Ux=b
+ UMFPACK_Q_Ut QU'x=b
+ UMFPACK_Ut U'x=b
+
+ Iterative refinement can be optionally performed when sys is any of
+ the following:
+
+ UMFPACK_A Ax=b
+ UMFPACK_At A'x=b
+
+ For the other values of the sys argument, iterative refinement is not
+ performed (Control [UMFPACK_IRSTEP], Ap, Ai, and Ax are ignored).
+
+ Int Ap [n+1] ; Input argument, not modified.
+ Int Ai [nz] ; Input argument, not modified.
+ double Ax [nz] ; Input argument, not modified.
+
+ If iterative refinement is requested (Control [UMFPACK_IRSTEP] >= 1,
+ Ax=b or A'x=b is being solved, and A is nonsingular), then
+ these arrays must be identical to the same ones passed to
+ umfpack_di_numeric. The umfpack_di_solve routine does not check the
+ contents of these arguments, so the results are undefined if Ap, Ai, Ax,
+ are modified between the calls the umfpack_di_numeric and
+ umfpack_di_solve. These three arrays do not need to be present (NULL
+ pointers can be passed) if Control [UMFPACK_IRSTEP] is zero, or if a
+ system other than Ax=b or A'x=b is being solved, or if A is
+ singular, since in each of these cases A is not accessed.
+
+ double X [n] ; Output argument.
+
+ The solution to the linear system, where n = n_row = n_col is the
+ dimension of the matrices A, L, and U.
+
+ double B [n] ; Input argument, not modified.
+
+ The right-hand side vector, b, stored as a conventional array of size n
+ (or two arrays of size n for complex versions). This routine does not
+ solve for multiple right-hand-sides, nor does it allow b to be stored in
+ a sparse-column form.
+
+ void *Numeric ; Input argument, not modified.
+
+ Numeric must point to a valid Numeric object, computed by
+ umfpack_di_numeric.
+
+ double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+ If a (double *) NULL pointer is passed, then the default control
+ settings are used.
+
+ Control [UMFPACK_IRSTEP]: The maximum number of iterative refinement
+ steps to attempt. A value less than zero is treated as zero. If
+ less than 1, or if Ax=b or A'x=b is not being solved, or
+ if A is singular, then the Ap, Ai, and Ax arguments are not
+ accessed. Default: 2.
+
+ double Info [UMFPACK_INFO] ; Output argument.
+
+ Contains statistics about the solution factorization. If a
+ (double *) NULL pointer is passed, then no statistics are returned in
+ Info (this is not an error condition). The following statistics are
+ computed in umfpack_di_solve (only the primary statistics are listed):
+
+ Info [UMFPACK_STATUS]: status code. This is also the return value,
+ whether or not Info is present.
+
+ UMFPACK_OK
+
+ The linear system was successfully solved.
+
+ UMFPACK_WARNING_singular_matrix
+
+ A divide-by-zero occured. Your solution will contain Inf's
+ and/or NaN's. Some parts of the solution may be valid. For
+ example, solving Ax=b with
+
+ A = [2 0] b = [ 1 ] returns x = [ 0.5 ]
+ [0 0] [ 0 ] [ Inf ]
+
+ UMFPACK_ERROR_out_of_memory
+
+ Insufficient memory to solve the linear system.
+
+ UMFPACK_ERROR_argument_missing
+
+ One or more required arguments are missing. The B and X
+ arguments are always required. Info and Control are not
+ required. Ap, Ai and Ax are required if Ax=b or
+ A'x=b is to be solved, the (default) iterative
+ refinement is requested, and the matrix A is nonsingular.
+
+ UMFPACK_ERROR_invalid_system
+
+ The sys argument is not valid, or the matrix A is not square.
+
+ UMFPACK_ERROR_invalid_Numeric_object
+
+ The Numeric object is not valid.
+
+ Info [UMFPACK_SOLVE_FLOPS]: the number of floating point operations
+ performed to solve the linear system. This includes the work
+ taken for all iterative refinement steps, including the backtrack
+ (if any).
+
+ Info [UMFPACK_SOLVE_TIME]: The time taken, in seconds.
+\end{verbatim}
+}
+
+
+%-------------------------------------------------------------------------------
+\newpage
+
+\subsection{umfpack\_di\_free\_symbolic}
+{\footnotesize
+\begin{verbatim}
+void umfpack_di_free_symbolic
+(
+ void **Symbolic
+) ;
+
+Purpose:
+
+ Deallocates the Symbolic object and sets the Symbolic handle to NULL.
+
+Arguments:
+
+ void **Symbolic ; Input argument, deallocated and Symbolic is
+ set to (void *) NULL on output.
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\subsection{umfpack\_di\_free\_numeric}
+
+{\footnotesize
+\begin{verbatim}
+void umfpack_di_free_numeric
+(
+ void **Numeric
+) ;
+
+Purpose:
+
+ Deallocates the Numeric object and sets the Numeric handle to NULL.
+
+Arguments:
+
+ void **Numeric ; Input argument, deallocated and Numeric is
+ set to (void *) NULL on output.
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\subsection{umfpack\_di\_defaults}
+
+{\footnotesize
+\begin{verbatim}
+void umfpack_di_defaults
+(
+ double Control [UMFPACK_CONTROL]
+) ;
+
+Purpose:
+
+ Sets the default control parameter settings.
+
+Arguments:
+
+ double Control [UMFPACK_CONTROL] ; Output argument.
+
+ Control is set to the default control parameter settings.
+\end{verbatim}
+}
+\end{document}
--- /dev/null
+@string{TOMS = "ACM Trans. Math. Softw."}
+@string{SIMAX = "SIAM J. Matrix Anal. Applic."}
+@string{SINUM = "SIAM J. Numer. Anal."}
+@string{SIAMJSC = "SIAM J. Sci. Comput."}
+@string{SIAMJSSC = "SIAM J. Sci. Statist. Comput."}
+@string{IJNME = "Internat. J. Numer. Methods Eng."}
+@string{SIAMJADM = "SIAM J. Alg. Disc. Meth."}
+
+@article{AmestoyDavisDuff96,
+ author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.},
+ title={An approximate minimum degree ordering algorithm},
+ journal=SIMAX,
+ year={1996}
+ ,volume={17}
+ ,number={4}
+ ,pages={886-905}}
+
+@article{AmestoyDavisDuff03,
+ author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.},
+ title={Algorithm 8xx: {AMD}, an approximate minimum degree ordering algorithm},
+ journal=TOMS,
+ year={2003 (under submission)},
+ note={Also TR-03-010 at www.cise.ufl.edu/tech-reports.}
+ }
+
+@techreport{AmestoyDavisDuff03_user,
+ author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.},
+ title={{AMD} Version 1.0 User Guide},
+ institution={CISE Dept., Univ. of Florida},
+ year={2003}
+ ,number={TR-03-011}
+ ,address={Gainesville, FL}
+ ,note={www.cise.ufl.edu/tech-reports.}
+ }
+
+@article{Davis03,
+ author={Davis, T. A.},
+ title={A column pre-ordering strategy for the unsymmetric-pattern multifrontal method},
+ journal=TOMS,
+ year={2003 (under submission)}
+ ,note={Also TR-03-006 at www.cise.ufl.edu/tech-reports.}
+ }
+
+@article{Davis03_algo,
+ author={Davis, T. A.},
+ title={Algorithm 8xx: {UMFPACK V4.3}, an unsymmetric-pattern multifrontal method},
+ journal=TOMS,
+ year={2004 (under submission)}
+ ,note={Also TR-04-004 at www.cise.ufl.edu/tech-reports.}
+ }
+
+@techreport{Davis03_umf,
+ author={Davis, T. A.},
+ title={{UMFPACK} Version 4.3 User Guide},
+ institution={Univ. of Florida, CISE Dept.},
+ year={2004}
+ ,number={TR-04-003}
+ ,address={Gainesville, FL}
+ ,note={(www.cise.ufl.edu/tech-reports)}
+ }
+
+@techreport{Davis03_umfquick,
+ author={Davis, T. A.},
+ title={{UMFPACK} Version 4.3 Quick Start Guide},
+ institution={Univ. of Florida, CISE Dept.},
+ year={2004}
+ ,number={TR-04-005}
+ ,address={Gainesville, FL}
+ ,note={(www.cise.ufl.edu/tech-reports)}
+ }
+
+@article{DavisDuff97,
+ author={Davis, T. A. and Duff, I. S.},
+ title={An unsymmetric-pattern multifrontal method for sparse {LU} factorization},
+ journal=SIMAX,
+ year={1997}
+ ,volume={18}
+ ,number={1}
+ ,pages={140-158}}
+
+@article{DavisDuff99,
+ author={Davis, T. A. and Duff, I. S.},
+ title={A combined unifrontal/multifrontal method for unsymmetric sparse matrices},
+ journal=TOMS,
+ volume={25},
+ number={1},
+ pages={1-19},
+ year={1999}}
+
+@article{SuperLU99,
+ author={Demmel, J. W. and Eisenstat, S. C. and Gilbert, J. R. and Li, X. S. and Liu, J. W. H.},
+ title={A supernodal approach to sparse partial pivoting},
+ journal=SIMAX,
+ year={1999}
+ ,volume={20}
+ ,number={3}
+ ,pages={720-755}
+ ,note={www.netlib.org}
+ }
+
+@article{ACM679a,
+ author={Dongarra, J. J. and Du Croz, J. and Duff, I. S. and Hammarling, S.},
+ title={A set of level-3 basic linear algebra subprograms},
+ journal=TOMS,
+ year={1990}
+ ,volume={16}
+ ,number={1}
+ ,pages={1--17}}
+
+@article{netlib,
+ author={Dongarra, J. J. and Grosse, E.},
+ title={Distribution of mathematical software via electronic mail},
+ journal={Comm. ACM},
+ year={1987}
+ ,volume={30}
+ ,pages={403-407}
+ ,note={www.netlib.org}
+ }
+
+@article{Duff78b,
+ author={Duff, I. S. and Reid, J. K.},
+ year={1978},
+ title={Algorithm 529: Permutations to Block Triangular Form},
+ journal=TOMS,
+ volume={4},
+ annote={f},
+ number={2},
+ pages={189-192},
+ keywords={102 ordering block triangular form}}
+
+@article{Duff81b,
+ author={Duff, I. S.},
+ year={1981},
+ title={Algorithm 575: Permutations for a Zero-Free Diagonal},
+ journal=TOMS,
+ annote={f},
+ volume={7},
+ pages={387-390},
+ keywords={ordering, zero-free diagonal}}
+
+@techreport{GotoVandeGeijn02,
+ author = {Goto, K. and van de Geijn, R.},
+ title = {On Reducing {TLB} Misses in Matrix Multiplication, {FLAME} Working Note 9},
+ institution={The University of Texas at Austin, Department of Computer Sciences},
+ number={TR-2002-55},
+ month={Nov.},
+ year={2002}}
+
+@article{GeorgeNg85,
+ author={George, A. and Ng, E. G.},
+ year={1985},
+ title={An Implementation of {G}aussian Elimination with
+ Partial Pivoting for Sparse Systems},
+ journal=SIAMJSSC,
+ volume={6},
+ number={2},
+ pages={390-409}}
+
+@article{GeorgeNg87,
+ author={George, A. and Ng, E. G.},
+ year={1987},
+ title={Symbolic Factorization for Sparse {G}aussian Elimination
+ with Partial Pivoting},
+ journal={SIAM J. Sci. Statist. Comput.},
+ volume={8},
+ number={6},
+ pages={877-898}}
+
+@article{GilbertMolerSchreiber,
+ author={Gilbert, J. R. and Moler, C. and Schreiber, R.},
+ title={Sparse matrices in {MATLAB}: design and implementation},
+ journal=SIMAX,
+ year={1992}
+ ,volume={13}
+ ,number={1}
+ ,pages={333-356}}
+
+@article{GilbertPeierls88,
+ author={Gilbert, J. R. and Peierls, T.},
+ year={1988},
+ title={Sparse Partial Pivoting in Time Proportional to Arithmetic Operations},
+ journal={SIAM J. Sci. Statist. Comput.},
+ volume={9},
+ pages={862-874}}
+
+@article{Gustavson78,
+ author={Gustavson, F. G.},
+ year={1978},
+ title={Two Fast Algorithms for Sparse Matrices: Multiplication and Permuted Transposition},
+ journal=TOMS,
+ volume={4},
+ number={3},
+ pages={250-269}}
+
+@techreport{Larimore98,
+ author={Larimore, S. I.},
+ title={An approximate minimum degree column ordering algorithm},
+ institution={Univ. of Florida, CISE Dept.},
+ year={1998}
+ ,number={TR-98-016}
+ ,address={Gainesville, FL}
+ ,note={www.cise.ufl.edu/tech-reports}}
+
+@techreport{DavisGilbertLarimoreNg00,
+ author={Davis, T. A. and Gilbert, J. R. and Larimore, S. I. and Ng, E. G.},
+ title={A column approximate minimum degree ordering algorithm},
+ institution={Univ. of Florida, CISE Dept.},
+ year={2000}
+ ,number={TR-00-005}
+ ,address={Gainesville, FL}
+ ,month={October}
+ ,note={(www.cise.ufl.edu/tech-reports. Submitted to ACM Trans. Math. Softw.)}
+ }
+
+@techreport{DavisGilbertLarimoreNg00_algo,
+ author={Davis, T. A. and Gilbert, J. R. and Larimore, S. I. and Ng, E. G.},
+ title={Algorithm 8xx: {COLAMD}, a column approximate minimum degree ordering algorithm},
+ institution={Univ. of Florida, CISE Dept.},
+ year={2000}
+ ,number={TR-00-006}
+ ,address={Gainesville, FL}
+ ,month={October}
+ ,note={(www.cise.ufl.edu/tech-reports. Submitted to ACM Trans. Math. Softw.)}
+ }
+
+
+@INCOLLECTION{GilbertNg93,
+ author = {J. R. Gilbert and E. G. Ng},
+ editor = {A. George and J. R. Gilbert and J. W.H. Liu},
+ year = 1993,
+ title = {Predicting Structure in Nonsymmetric Sparse Matrix Factorizations},
+ booktitle = {Graph Theory and Sparse Matrix Computation},
+ series = {Volume 56 of the {IMA} Volumes in Mathematics and its Applications},
+ pages = {107-139},
+ publisher = {Springer-Verlag}
+}
+
+
+@techreport{ATLAS,
+ author={Whaley, R. C and Petitet, A. and Dongarra, J. J.},
+ title={Automated Emperical Optimization of Software and the {ATLAS} Project},
+ institution={Computer Science Department, The University of Tennessee},
+ year={2000}
+ ,number={LAPACK Working Note 147}
+ ,month={September}
+ ,note={www.netlib.org/atlas}
+ }
+
+@article{DaydeDuff99,
+ author = "M. J. Dayd\'{e} and I. S. Duff",
+ title = "The {RISC} {BLAS}: A Blocked Implementation of Level 3 {BLAS} for {RISC} Processors",
+ journal = TOMS,
+ volume = "25",
+ number = "3",
+ month = {Sept.},
+ year ="1999"
+ }
+
+
+@article{ardd:89,
+ author = {M. Arioli and J. W. Demmel and I. S. Duff},
+ year = "1989",
+ title = {Solving sparse linear systems with sparse backward error},
+ journal = SIMAX,
+ volume = {10},
+ pages = {165-190}
+}
+
+
+@article{DavisHager99,
+ author={Davis, T. A. and Hager, W. W.},
+ title={Modifying a sparse {C}holesky factorization},
+ journal=SIMAX,
+ year={1999}
+ ,volume={20}
+ ,number={3}
+ ,pages={606-627}
+ }
+
+
+@article{dusc:96,
+ author = {I. S. Duff and J. A. Scott},
+ title = {The design of a new frontal code for solving sparse unsymmetric systems},
+ journal = TOMS,
+ year = "1996",
+ volume = "22",
+ number = "1",
+ pages = "30-45"
+ }
+
+
+@article{Duff78a,
+ author={Duff, I. S. and Reid, J. K.},
+ year={1978},
+ title={An Implementation of {T}arjan's Algorithm for the Block Triangularization of a Matrix},
+ journal=TOMS,
+ volume={4},
+ number={2},
+ pages={137-147}
+ }
+
+@book{GeorgeLiu,
+ author={George, A. and Liu, J. W. H.},
+ year={1981},
+ title={Computer Solution of Large Sparse Positive Definite Systems},
+ publisher={Englewood Cliffs, New Jersey: Prentice-Hall}
+ }
+
+@article{GilbertNgPeyton94,
+ author={Gilbert, J. R. and Ng, E. G. and Peyton, B. W.},
+ title={An efficient algorithm to compute row and column counts for sparse {C}holesky factorization},
+ journal=SIMAX,
+ year={1994}
+ ,volume={15}
+ ,number={4}
+ ,pages={1075-1091}
+ }
+
+@techreport{DuffGrimesLewis87b,
+ author={Duff, I. S. and Grimes, R. G. and Lewis, J. G.},
+ year={1987},
+ title={Users' Guide for the Harwell-Boeing Sparse Matrix Test Collection},
+ institution={AERE Harwell Laboratory, United Kingdom Atomic Energy Authority}}
+
--- /dev/null
+/INCLUDE umfpack_col_to_triplet.h/r ../Include/umfpack_col_to_triplet.h
+/INCLUDE umfpack_defaults.h/r ../Include/umfpack_defaults.h
+/INCLUDE umfpack_free_numeric.h/r ../Include/umfpack_free_numeric.h
+/INCLUDE umfpack_free_symbolic.h/r ../Include/umfpack_free_symbolic.h
+/INCLUDE umfpack_get_lunz.h/r ../Include/umfpack_get_lunz.h
+/INCLUDE umfpack_get_numeric.h/r ../Include/umfpack_get_numeric.h
+/INCLUDE umfpack_get_symbolic.h/r ../Include/umfpack_get_symbolic.h
+/INCLUDE umfpack_get_scale.h/r ../Include/umfpack_get_scale.h
+/INCLUDE umfpack_numeric.h/r ../Include/umfpack_numeric.h
+/INCLUDE umfpack_qsymbolic.h/r ../Include/umfpack_qsymbolic.h
+/INCLUDE umfpack_report_control.h/r ../Include/umfpack_report_control.h
+/INCLUDE umfpack_report_info.h/r ../Include/umfpack_report_info.h
+/INCLUDE umfpack_report_matrix.h/r ../Include/umfpack_report_matrix.h
+/INCLUDE umfpack_report_numeric.h/r ../Include/umfpack_report_numeric.h
+/INCLUDE umfpack_report_perm.h/r ../Include/umfpack_report_perm.h
+/INCLUDE umfpack_report_status.h/r ../Include/umfpack_report_status.h
+/INCLUDE umfpack_report_symbolic.h/r ../Include/umfpack_report_symbolic.h
+/INCLUDE umfpack_report_triplet.h/r ../Include/umfpack_report_triplet.h
+/INCLUDE umfpack_report_vector.h/r ../Include/umfpack_report_vector.h
+/INCLUDE umfpack_simple.c/r ../Demo/umfpack_simple.c
+/INCLUDE umfpack_solve.h/r ../Include/umfpack_solve.h
+/INCLUDE umfpack_scale.h/r ../Include/umfpack_scale.h
+/INCLUDE umfpack_symbolic.h/r ../Include/umfpack_symbolic.h
+/INCLUDE umfpack_timer.h/r ../Include/umfpack_timer.h
+/INCLUDE umfpack_tictoc.h/r ../Include/umfpack_tictoc.h
+/INCLUDE umfpack_transpose.h/r ../Include/umfpack_transpose.h
+/INCLUDE umfpack_triplet_to_col.h/r ../Include/umfpack_triplet_to_col.h
+/INCLUDE umfpack_wsolve.h/r ../Include/umfpack_wsolve.h
+/INCLUDE umfpack_load_numeric.h/r ../Include/umfpack_load_numeric.h
+/INCLUDE umfpack_load_symbolic.h/r ../Include/umfpack_load_symbolic.h
+/INCLUDE umfpack_save_numeric.h/r ../Include/umfpack_save_numeric.h
+/INCLUDE umfpack_save_symbolic.h/r ../Include/umfpack_save_symbolic.h
--- /dev/null
+/[/][*]/d
+/[*][/]/d
+/INCLUDE umfpack/d
--- /dev/null
+%-------------------------------------------------------------------------------
+% The UserGuide.stex file. Processed into UserGuide.tex via sed.
+%-------------------------------------------------------------------------------
+
+\documentclass[11pt]{article}
+
+\newcommand{\m}[1]{{\bf{#1}}} % for matrices and vectors
+\newcommand{\tr}{^{\sf T}} % transpose
+\newcommand{\he}{^{\sf H}} % complex conjugate transpose
+\newcommand{\implies}{\rightarrow}
+
+\topmargin 0in
+\textheight 9in
+\oddsidemargin 0pt
+\evensidemargin 0pt
+\textwidth 6.5in
+
+\begin{document}
+
+\author{Timothy A. Davis \\
+Dept. of Computer and Information Science and Engineering \\
+Univ. of Florida, Gainesville, FL}
+\title{UMFPACK Version 4.3 User Guide}
+\date{Jan. 16, 2004}
+\maketitle
+
+%-------------------------------------------------------------------------------
+\begin{abstract}
+ UMFPACK is a set of routines for solving unsymmetric sparse linear
+ systems, $\m{Ax}=\m{b}$, using the Unsymmetric MultiFrontal method
+ and direct sparse LU factorization. It is written in ANSI/ISO C, with a
+ MATLAB interface. UMFPACK relies on the Level-3 Basic
+ Linear Algebra Subprograms (dense matrix multiply) for its performance.
+ This code works on Windows and many versions of Unix (Sun Solaris,
+ Red Hat Linux, IBM AIX, SGI IRIX, and Compaq Alpha).
+\end{abstract}
+%-------------------------------------------------------------------------------
+
+Technical Report TR-04-003.
+
+UMFPACK Version 4.3 (Jan. 16, 2004), Copyright\copyright 2004 by Timothy A.
+Davis. All Rights Reserved.
+
+{\bf UMFPACK License:}
+ Your use or distribution of UMFPACK or any modified version of
+ UMFPACK implies that you agree to this License.
+
+ THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+ EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+
+ Permission is hereby granted to use or copy this program, provided
+ that the Copyright, this License, and the Availability of the original
+ version is retained on all copies. User documentation of any code that
+ uses UMFPACK or any modified version of UMFPACK code must cite the
+ Copyright, this License, the Availability note, and ``Used by permission.''
+ Permission to modify the code and to distribute modified code is granted,
+ provided the Copyright, this License, and the Availability note are
+ retained, and a notice that the code was modified is included. This
+ software was developed with support from the National Science Foundation,
+ and is provided to you free of charge.
+
+{\bf Availability:}
+ http://www.cise.ufl.edu/research/sparse/umfpack
+
+{\bf Acknowledgments:}
+
+ This work was supported by the National Science Foundation, under
+ grants DMS-9504974, DMS-9803599, and CCR-0203270.
+ The upgrade to Version 4.1 and the inclusion of the
+ symmetric and 2-by-2 pivoting strategies
+ were done while the author was on sabbatical at
+ Stanford University and Lawrence Berkeley National Laboratory.
+
+%-------------------------------------------------------------------------------
+\newpage
+%-------------------------------------------------------------------------------
+
+\tableofcontents
+
+%-------------------------------------------------------------------------------
+\newpage
+\section{Overview}
+%-------------------------------------------------------------------------------
+
+UMFPACK\footnote{Pronounced with two syllables: umph-pack}
+Version 4.3 is a set of routines for solving systems of linear
+equations, $\m{Ax}=\m{b}$, when $\m{A}$ is sparse and unsymmetric. It is based
+on the Unsymmetric-pattern MultiFrontal method \cite{DavisDuff97,DavisDuff99}.
+UMFPACK factorizes
+$\m{PAQ}$, $\m{PRAQ}$, or $\m{PR}^{-1}\m{AQ}$ into the product $\m{LU}$,
+where $\m{L}$ and $\m{U}$
+are lower and upper triangular, respectively, $\m{P}$ and $\m{Q}$ are
+permutation matrices, and $\m{R}$ is a diagonal matrix of row scaling factors
+(or $\m{R}=\m{I}$ if row-scaling is not used). Both $\m{P}$ and $\m{Q}$ are
+chosen to reduce fill-in (new nonzeros in $\m{L}$ and $\m{U}$ that are not
+present in $\m{A}$). The permutation $\m{P}$ has the dual role of reducing
+fill-in and maintaining numerical accuracy (via relaxed partial pivoting
+and row interchanges).
+
+The sparse matrix $\m{A}$ can be square or rectangular, singular
+or non-singular, and real or complex (or any combination). Only square
+matrices $\m{A}$ can be used to solve $\m{Ax}=\m{b}$ or related systems.
+Rectangular matrices can only be factorized.
+
+UMFPACK first finds a column pre-ordering that reduces fill-in, without regard
+to numerical values. It scales and analyzes the matrix, and then automatically
+selects one of three strategies for pre-ordering the rows and columns:
+{\em unsymmetric},
+{\em 2-by-2}, and
+{\em symmetric}. These strategies are described below.
+
+First, all pivots with zero Markowitz cost are eliminated and placed in the
+LU factors. The remaining submatrix $\m{S}$ is then analyzed.
+The following rules are applied, and the first one that matches defines
+the strategy.
+
+\begin{itemize}
+\item Rule 1: $\m{A}$ rectangular $\implies$ unsymmetric.
+\item Rule 2:
+ If the zero-Markowitz elimination results in a rectangular $\m{S}$,
+ or an $\m{S}$ whose diagonal has not been preserved, the
+ unsymmetric strategy is used.
+\item The symmetry $\sigma_1$ of $\m{S}$ is computed. It is defined as
+ the number of {\em matched} off-diagonal entries, divided by the
+ total number of off-diagonal entries. An entry $s_{ij}$ is matched
+ if $s_{ji}$ is also an entry. They need not be numerically equal.
+ An {\em entry} is a value in $\m{A}$ which is present
+ in the input data structure. All nonzeros are entries, but some entries
+ may be numerically zero.
+ Rule 3: $\sigma_1 < 0.1 \implies$ unsymmetric.
+ The matrix is very unsymmetric.
+\item Let $d$ be the number of nonzero entries on the diagonal of $\m{S}$.
+ Let $\m{S}$ be $\nu$-by-$\nu$.
+ Rule 4: $(\sigma_1 \ge 0.7) \:\wedge\: (d = \nu) \implies$ symmetric.
+ The matrix has a nearly symmetric nonzero pattern, and a zero-free
+ diagonal.
+\end{itemize}
+
+If the strategy has not yet been determined,
+the 2-by-2 strategy is attempted. A row permutation $\m{P}_2$
+is found which attempts to reduce the number of small
+diagonal entries of $\m{P}_2 \m{S}$.
+An entry $s_{ij}$ is determined to be small if
+$|s_{ij}| < 0.01 \max |s_{*j}|$, or large otherwise.
+If $s_{ii}$ is numerically small, the method attempts to swap
+two rows $i$ and $j$, such that both $s_{ij}$ and $s_{ji}$ are large.
+Once these rows are swapped,
+they remain in place. Let $\sigma_2$ be the symmetry of $\m{P}_2 \m{S}$,
+and let $d_2$ be the number of nonzero entries (either small or large)
+on the diagonal of $\m{P}_2 \m{S}$.
+
+\begin{itemize}
+\item Rule 5:
+ ($\sigma_2 > 1.1 \sigma_1) \:\wedge\: (d_2 > 0.9 \nu) \implies$ 2-by-2.
+ The 2-by-2 permutation has made the matrix significantly more symmetric.
+\item Rule 6: $\sigma_2 < 0.7 \sigma_1 \implies$ unsymmetric.
+ The 2-by-2 strategy has significantly deteriorated the symmetry,
+\item Rule 7: $\sigma_2 < 0.25 \implies$ unsymmetric.
+ The matrix is still very unsymmetric.
+\item Rule 8: $\sigma_2 \ge 0.51 \implies$ 2-by-2.
+ The matrix is roughly symmetric.
+\item Rule 9: $\sigma_2 \ge 0.999 \sigma_1 \implies$ 2-by-2.
+ The 2-by-2 permutation has preserved symmetry, or made it only
+ slightly worse.
+\item Rule 10: if no rule has yet triggered, use the unsymmetric strategy.
+\end{itemize}
+
+Each strategy is described below:
+\begin{itemize}
+\item {\em unsymmetric}:
+The column pre-ordering of $\m{S}$ is computed by a modified version of COLAMD
+\cite{DavisGilbertLarimoreNg00_algo,DavisGilbertLarimoreNg00,Larimore98}.
+The method finds a symmetric permutation $\m{Q}$ of the matrix $\m{S}\tr\m{S}$
+(without forming $\m{S}\tr\m{S}$ explicitly). This is a good choice for
+$\m{Q}$, since the Cholesky factors of $\m{(SQ)\tr(SQ)}$ are an upper bound (in
+terms of nonzero pattern) of the factor $\m{U}$ for the unsymmetric LU
+factorization ($\m{PSQ}=\m{LU}$) regardless of the choice of $\m{P}$
+\cite{GeorgeNg85,GeorgeNg87,GilbertNg93}. This modified version of
+COLAMD also computes the column elimination tree and post-orders the
+tree. It finds the upper bound on the number of nonzeros in L and U.
+It also has a different threshold for determining dense rows and columns.
+During factorization, the column pre-ordering can be modified.
+Columns within a single super-column can be reshuffled, to reduce fill-in.
+Threshold partial pivoting is used with no preference given to the diagonal
+entry. Within a given pivot column $j$, an entry $a_{ij}$ can be chosen if
+$|a_{ij}| \ge 0.1 \max |a_{*j}|$. Among those numerically acceptable
+entries, the sparsest row $i$ is chosen as the pivot row.
+
+\item {\em 2-by-2}:
+The symmetric strategy (see below) is applied to the matrix $\m{P}_2 \m{S}$,
+rather than $\m{S}$.
+
+\item {\em symmetric}:
+The column ordering is computed from AMD
+\cite{AmestoyDavisDuff96,AmestoyDavisDuff03},
+applied to the pattern of $\m{S}+\m{S}\tr$
+followed by a post-ordering of the supernodal elimination
+tree of $\m{S}+\m{S}\tr$.
+No modification of the column pre-ordering is made during numerical
+factorization. Threshold partial pivoting is used, with a strong
+preference given to the diagonal entry. The diagonal entry is chosen if
+$a_{jj} \ge 0.001 \max |a_{*j}|$. Otherwise, a sparse row is selected,
+using the same method used by the unsymmetric strategy.
+
+\end{itemize}
+
+The symmetric and 2-by-2 strategies, and their automatic selection,
+are new to Version 4.1. Version 4.0 only used the unsymmetric strategy.
+
+Once the strategy is selected,
+the factorization of the matrix $\m{A}$ is broken down into the factorization
+of a sequence of dense rectangular frontal matrices. The frontal matrices are
+related to each other by a supernodal column elimination tree, in which each
+node in the tree represents one frontal matrix. This analysis phase also
+determines upper bounds on the memory usage, the floating-point operation count,
+and the number of nonzeros in the LU factors.
+
+UMFPACK factorizes each {\em chain} of frontal matrices in a single working
+array, similar to how the unifrontal method \cite{dusc:96} factorizes the whole
+matrix. A chain of frontal matrices is a sequence of fronts where the parent
+of front $i$ is $i$+1 in the supernodal column elimination tree. For the
+nonsingular matrices factorized with the unsymmetric strategy, there are
+exactly the same number of chains as there are leaves in the supernodal
+column elimination tree. UMFPACK is an
+outer-product based, right-looking method. At the $k$-th step of Gaussian
+elimination, it represents the updated submatrix $\m{A}_k$ as an implicit
+summation of a set of dense sub-matrices (referred to as {\em elements},
+borrowing a phrase from finite-element methods) that arise when the frontal
+matrices are factorized and their pivot rows and columns eliminated.
+
+Each frontal matrix represents the elimination of one or more columns;
+each column of $\m{A}$ will be eliminated in a specific frontal matrix,
+and which frontal matrix will be used for which column is determined by
+the pre-analysis phase. The pre-analysis phase also determines the worst-case
+size of each frontal matrix so that they can hold any candidate pivot column
+and any candidate pivot row. From the perspective of the analysis phase, any
+candidate pivot column in the frontal matrix is identical (in terms of nonzero
+pattern), and so is any row. However, the numeric factorization phase has
+more information than the analysis phase. It uses this information to reorder
+the columns within each frontal matrix to reduce fill-in. Similarly, since
+the number of nonzeros in each row and column are maintained (more precisely,
+COLMMD-style approximate degrees \cite{GilbertMolerSchreiber}), a pivot row can
+be selected based on sparsity-preserving criteria (low degree) as well as
+numerical considerations (relaxed threshold partial pivoting).
+
+When the symmetric or 2-by-2 strategies are used,
+the column preordering is not refined during numeric factorization.
+Row pivoting for sparsity and numerical accuracy is performed if the
+diagonal entry is too small.
+
+More details of the method, including experimental results, are
+described in \cite{Davis03,Davis03}, available at
+http://www.cise.ufl.edu/tech-reports.
+
+%-------------------------------------------------------------------------------
+\section{Availability}
+%-------------------------------------------------------------------------------
+
+In addition to appearing as a Collected Algorithm of the ACM,
+UMFPACK Version 4.3 is available at http://www.cise.ufl.edu/research/sparse.
+An earlier version (Version 4.0) is included as a built-in routine in MATLAB
+6.5. Version 4.0 does not have the symmetric or 2-by-2 strategies and it takes
+less advantage of the level-3
+BLAS \cite{DaydeDuff99,ACM679a,ATLAS,GotoVandeGeijn02}.
+Version 4.3 (and v4.2 and v4.1) tend to be much faster than Version 4.0,
+particularly on unsymmetric matrices with mostly symmetric
+nonzero pattern (such as finite element and circuit simulation matrices).
+Version 3.0 and following make
+use of a modified version of COLAMD V2.0 by Timothy A.~Davis, Stefan
+Larimore, John Gilbert, and Esmond Ng. The original COLAMD V2.1 is available in
+as a built-in routine in MATLAB V6.0 (or later), and at
+http://www.cise.ufl.edu/research/sparse.
+These codes are also available in Netlib \cite{netlib} at
+http://www.netlib.org.
+UMFPACK Versions 2.2.1 and earlier, co-authored with Iain Duff,
+are available at http://www.cise.ufl.edu/research/sparse and as
+MA38 (functionally equivalent to Version 2.2.1) in the Harwell
+Subroutine Library.
+
+%-------------------------------------------------------------------------------
+\section{Primary changes since Version 4.1}
+%-------------------------------------------------------------------------------
+
+No changes are visible to the C or MATLAB user, except the presence of
+one new control parameter in the {\tt Control} array,
+and three new statistics in the {\tt Info} array.
+The primary change is the addition of an (optional) drop tolerance.
+
+%-------------------------------------------------------------------------------
+\section{Primary changes in Version 4.1 (since Version 4.0)}
+%-------------------------------------------------------------------------------
+
+A detailed list of changes is in the {\tt ChangeLog} file. The following
+is a summary of the main changes that are visible to the C or MATLAB user:
+
+\begin{enumerate}
+
+\item New ordering strategies added. No changes are required in user code
+ (either C or MATLAB) to use the new default strategy, which is an automatic
+ selection of the unsymmetric, symmetric, or 2-by-2 strategies.
+
+\item Row scaling added. This is only visible to the MATLAB caller when using
+ the form {\tt [L,U,P,Q,R] = umfpack (A)}, to retrieve the LU factors.
+ Likewise, it is only visible to the C caller when the LU factors are
+ retrieved, or when solving systems with just $\m{L}$ or $\m{U}$.
+ New C-callable and MATLAB-callable routines are included to get and to
+ apply the scale factors computed by UMFPACK. Row scaling is enabled by
+ default, but can be disabled. Row scaling usually leads to a better
+ factorization, particularly when the symmetric strategy is used.
+
+\item Error code {\tt UMFPACK\_ERROR\_problem\_to\_large} removed.
+ Version 4.0 would generate this error when the upper bound memory usage
+ exceeded 2GB (for the {\tt int} version), even when the actual memory
+ usage was less than this. The new version properly handles this case,
+ and can successfully factorize the matrix if sufficient memory is
+ available.
+
+\item New control parameters and statistics provided.
+
+\item The AMD symmetric approximate minimum degree ordering routine added
+ \cite{AmestoyDavisDuff96,AmestoyDavisDuff03}.
+ It is used by UMFPACK, and can also be called independently from C or
+ MATLAB.
+
+\item The {\tt umfpack} mexFunction now returns permutation matrices, not
+ permutation vectors, when using the form {\tt [L,U,P,Q] = umfpack (A)}
+ or the new form {\tt [L,U,P,Q,R] = umfpack (A)}.
+
+\item New arguments added to the user-callable routines
+ {\tt umfpack\_*\_symbolic},
+ {\tt umfpack\_*\_qsymbolic},
+ {\tt umfpack\_*\_get\_numeric}, and
+ {\tt umfpack\_*\_get\_symbolic}.
+ The symbolic analysis now makes use of the numerical values of the matrix
+ $\m{A}$, to guide the 2-by-2 strategy. The subsequent matrix passed to
+ the numeric factorization step does not have to have the same numerical
+ values. All of the new arguments are optional. If you do not wish to
+ include them, simply pass {\tt NULL} pointers instead. The 2-by-2 strategy
+ will assume all entries are numerically large, for example.
+
+\item New routines added to save and load the {\tt Numeric} and {\tt Symbolic}
+ objects to and from a binary file.
+
+\item A Fortran interface added. It provides access to a subset of
+ UMFPACK's features.
+
+\item You can compute an incomplete LU factorization, by dropping small
+ entries from $\m{L}$ and $\m{U}$. By default, no nonzero entry is
+ dropped, no matter how small in absolute value. This feature is new
+ to Version 4.3.
+
+\end{enumerate}
+
+%-------------------------------------------------------------------------------
+\section{Using UMFPACK in MATLAB}
+%-------------------------------------------------------------------------------
+
+The easiest way to use UMFPACK is within MATLAB. Version 4.0 is a built-in
+routine in MATLAB 6.5, and is used in {\tt x = A}$\backslash${\tt b} when
+{\tt A} is sparse, square, unsymmetric (or symmetric but not positive definite),
+and with nonzero entries that are not confined in a narrow band.
+It is also used for the {\tt [L,U,P,Q] = lu (A)} usage of {\tt lu}.
+Type {\tt help lu} in MATLAB 6.5 or later for more details.
+
+To use the UMFPACK mexFunction, you must download and compile it,
+since the mexFunction itself is not part of MATLAB.
+The following discussion assumes that
+you have MATLAB Version 6.0 or later (which includes the BLAS, and the
+{\tt colamd} ordering routine). To compile both the UMFPACK and AMD
+mexFunctions, just type {\tt make} in the Unix system shell,
+while in the {\tt UMFPACK} directory.
+You can also type {\tt umfpack\_make} in MATLAB, if you are in the
+{\tt UMFPACK/MATLAB} directory, or if that directory is in your MATLAB path.
+This works on any system with MATLAB, including Windows.
+See Section~\ref{Install} for more details on how to install UMFPACK.
+Once installed, the UMFPACK mexFunction can analyze, factor, and solve linear
+systems. Table~\ref{matlab} summarizes some of the more common uses
+of the UMFPACK mexFunction within MATLAB.
+
+An optional input argument can be used to modify the control parameters for
+UMFPACK, and an optional output argument provides statistics on the
+factorization. UMFPACK will print these statistics if you turn
+on the sparse matrix monitor flag with {\tt spparms ('spumoni', 1)}.
+The UMFPACK printing level parameter described in Section~\ref{Reporting}
+is set to {\tt spumoni} plus 1. Type {\tt help umfpack} for more information.
+
+Refer to the AMD User Guide for more details about the AMD mexFunction.
+
+\begin{table}
+\caption{Using UMFPACK's MATLAB interface}
+\label{matlab}
+\vspace{0.1in}
+{\footnotesize
+\begin{tabular}{l|l|l}
+\hline
+Function & Using UMFPACK & MATLAB 6.0 equivalent \\
+\hline
+ & & \\
+\begin{minipage}[t]{1.5in}
+Solve $\m{Ax}=\m{b}$.
+\end{minipage}
+&
+\begin{minipage}[t]{2.2in}
+\begin{verbatim}
+x = umfpack (A,'\',b) ;
+\end{verbatim}
+\end{minipage}
+&
+\begin{minipage}[t]{2.2in}
+\begin{verbatim}
+x = A \ b ;
+\end{verbatim}
+\end{minipage}
+ \\
+ & & \\
+\hline
+ & & \\
+\begin{minipage}[t]{1.5in}
+Solve $\m{Ax}=\m{b}$ using a different column pre-ordering.
+\end{minipage}
+&
+\begin{minipage}[t]{2.2in}
+\begin{verbatim}
+S = spones (A) ;
+Q = symamd (S+S') ;
+x = umfpack (A,Q,'\',b) ;
+\end{verbatim}
+\end{minipage}
+&
+\begin{minipage}[t]{2.2in}
+\begin{verbatim}
+spparms ('autommd',0) ;
+S = spones (A) ;
+Q = symamd (S+S') ;
+x = A (:,Q) \ b ;
+x (Q) = x ;
+spparms ('autommd',1) ;
+\end{verbatim}
+\end{minipage}
+ \\
+ & & \\
+\hline
+ & & \\
+\begin{minipage}[t]{1.5in}
+Solve $\m{A}\tr\m{x}\tr = \m{b}\tr$.
+\end{minipage}
+&
+\begin{minipage}[t]{2.2in}
+\begin{verbatim}
+x = umfpack (b,'/',A) ;
+\end{verbatim}
+\end{minipage}
+&
+\begin{minipage}[t]{2.2in}
+\begin{verbatim}
+x = b / A ;
+\end{verbatim}
+\end{minipage}
+ \\
+ & & \\
+\hline
+ & & \\
+\begin{minipage}[t]{1.5in}
+Scale and factorize $\m{A}$, then solve $\m{Ax}=\m{b}$.
+\end{minipage}
+&
+\begin{minipage}[t]{2.2in}
+\begin{verbatim}
+[L,U,P,Q,R] = umfpack (A) ;
+c = P * (R \ b) ;
+x = Q * (U \ (L \ c)) ;
+\end{verbatim}
+\end{minipage}
+&
+\begin{minipage}[t]{2.2in}
+\begin{verbatim}
+[m n] = size (A) ;
+r = full (sum (abs (A), 2)) ;
+r (find (r == 0)) = 1 ;
+R = spdiags (r, 0, m, m) ;
+I = speye (n) ;
+Q = I (:, colamd (A)) ;
+[L,U,P] = lu ((R\A)*Q) ;
+c = P * (R \ b) ;
+x = Q * (U \ (L \ c)) ;
+\end{verbatim}
+\end{minipage}
+ \\
+ & & \\
+\hline
+\end{tabular}
+}
+\end{table}
+
+Note: in MATLAB 6.5, use {\tt spparms ('autoamd',0)} in addition to
+{\tt spparms ('autommd',0)}, in Table~\ref{matlab}, to turn off MATLAB's
+default reordering.
+
+UMFPACK requires
+{\tt b} to be a dense vector (real or complex) of the appropriate dimension.
+This is more restrictive than what you can do with MATLAB's
+backslash or forward slash. See {\tt umfpack\_solve} for an M-file that
+removes this restriction.
+This restriction does not apply to the built-in backslash operator
+in MATLAB 6.5, which uses UMFPACK v4.0 to factorize the matrix.
+You can do this yourself in MATLAB:
+
+{\footnotesize
+\begin{verbatim}
+ [L,U,P,Q,R] = umfpack (A) ;
+ x = Q * (U \ (L \ (P * (R \ b)))) ;
+\end{verbatim}
+}
+
+or, with no row scaling:
+
+{\footnotesize
+\begin{verbatim}
+ [L,U,P,Q] = umfpack (A) ;
+ x = Q * (U \ (L \ (P * b))) ;
+\end{verbatim}
+}
+
+The above examples do not make use of the iterative refinement
+that is built into
+{\tt x = }{\tt umfpack (A,'}$\backslash${\tt ',b)}
+however.
+
+MATLAB's {\tt [L,U,P] = lu(A)} returns a lower triangular {\tt L}, an upper
+triangular {\tt U}, and a permutation matrix {\tt P} such that {\tt P*A} is
+equal to {\tt L*U}. UMFPACK behaves differently. By default, it scales
+the rows of {\tt A} and reorders the columns of {\tt A} prior to
+factorization, so that {\tt L*U} is equal to {\tt P*(R}$\backslash${\tt A)*Q},
+where {\tt R} is a diagonal sparse matrix of scale factors for the rows
+of {\tt A}. The scale factors {\tt R} are applied to {\tt A} via the MATLAB
+expression {\tt R}$\backslash${\tt A} to avoid multiplying by
+the reciprocal, which can be numerically inaccurate.
+
+There are more options; you can provide your own column pre-ordering (in which
+case UMFPACK does not call COLAMD or AMD), you can modify other control settings
+(similar to the {\tt spparms} in MATLAB), and you can get various statistics on
+the analysis, factorization, and solution of the linear system. Type
+{\tt umfpack\_details} and {\tt umfpack\_report} in MATLAB for more
+information. Two demo M-files are provided. Just type {\tt umfpack\_simple}
+and {\tt umfpack\_demo} to run them.
+The output of these two programs should be about the same
+as the files {\tt umfpack\_simple.m.out} and {\tt umfpack\_demo.m.out}
+that are provided.
+
+Factorizing {\tt A'} (or {\tt A.'}) and using the transposed factors can
+sometimes be faster than factorizing {\tt A}. It can also be preferable to
+factorize {\tt A'} if {\tt A} is rectangular. UMFPACK pre-orders the columns
+to maintain sparsity; the row ordering is not determined until the matrix
+is factorized. Thus, if {\tt A} is {\tt m} by {\tt n} with rank {\tt m}
+and {\tt m} $<$ {\tt n}, then {\tt umfpack} might not find a factor
+{\tt U} with a zero-free diagonal. Unless the matrix ill-conditioned or
+poorly scaled, factorizing {\tt A'} in this case will guarantee that both
+factors will have zero-free diagonals. Here's how you can factorize {\tt A'}
+and get the factors of {\tt A} instead:
+
+\begin{verbatim}
+ [l,u,p,q] = umfpack (A') ;
+ L = u' ;
+ U = l' ;
+ P = q ;
+ Q = p ;
+ clear l u p q
+\end{verbatim}
+
+This is an alternative to {\tt [L,U,P,Q]=umfpack(A)}.
+
+A simple M-file ({\tt umfpack\_btf}) is provided that first permutes the matrix
+to upper block triangular form, using MATLAB's {\tt dmperm} routine, and then
+solves each block. The LU factors are not returned. Its usage is simple:
+{\tt x = umfpack\_btf(A,b)}. Type {\tt help umfpack\_btf} for more options.
+An estimate of the 1-norm of {\tt L*U-P*A*Q} can be computed in MATLAB
+as {\tt lu\_normest(P*A*Q,L,U)}, using the {\tt lu\_normest.m} M-file
+by Hager and Davis \cite{DavisHager99} that is included with the
+UMFPACK distribution. With row scaling enabled, use
+{\tt lu\_normest(P*(R}$\backslash${\tt A)*Q,L,U)} instead.
+
+One issue you may encounter is how UMFPACK allocates its memory when being used
+in a mexFunction. One part of its working space is of variable size. The
+symbolic analysis phase determines an upper bound on the size of this memory,
+but not all of this memory will typically be used in the numerical
+factorization. UMFPACK tries to allocate a decent amount of working space.
+This is 70\% of the upper bound, by default, for the unsymmetric strategy.
+For the symmetric strategy, the fraction of the upper bound is computed
+automatically (assuming a best-case scenario with no numerical pivoting
+required during numeric factorization).
+If this initial allocation fails, it reduces its request
+and uses less memory. If the space is not large enough during factorization,
+it is increased via {\tt mxRealloc}.
+
+However, {\tt mxMalloc} and {\tt mxRealloc} abort the {\tt umfpack} mexFunction
+if they fail, so this strategy does not work in MATLAB. The strategy works fine
+when {\tt malloc} or the internal memory allocator {\tt utMalloc} are used
+instead, since those routines return {\tt NULL} on failure, and do not terminate
+the mexFunction. The {\tt umfpack} mexFunction can be compiled to use
+{\tt utMalloc}, but this is an internal undocumented utility routine in MATLAB,
+and thus using {\tt utMalloc} might not always be successful.
+To use the documented {\tt mxMalloc} routine instead, compile the
+mexFunction with the {\tt -DNUTIL} flag enabled.
+
+%-------------------------------------------------------------------------------
+\section{Using UMFPACK in a C program}
+\label{C}
+%-------------------------------------------------------------------------------
+
+The C-callable UMFPACK library consists of 31 user-callable routines and one
+include file. Twenty-seven of the routines come in four versions, with
+different sizes of integers and for real or complex floating-point numbers:
+\begin{enumerate}
+\item {\tt umfpack\_di\_*}: real double precision, {\tt int} integers.
+\item {\tt umfpack\_dl\_*}: real double precision, {\tt long} integers.
+\item {\tt umfpack\_zi\_*}: complex double precision, {\tt int} integers.
+\item {\tt umfpack\_zl\_*}: complex double precision, {\tt long} integers.
+\end{enumerate}
+where {\tt *} denotes the specific name of one of the 27 routines.
+Routine names beginning with {\tt umf\_} are internal to the package,
+and should not be called by the user. The include file {\tt umfpack.h}
+must be included in any C program that uses UMFPACK.
+The other three routines are the same for all four versions.
+
+In addition, the C-callable AMD library distributed with UMFPACK
+includes 4 user-callable routines (in two versions with {\tt int} and
+{\tt long} integers) and one include file. Refer to the AMD documentation
+for more details.
+
+Use only one version for any one problem; do not attempt to use one version
+to analyze the matrix and another version to factorize the matrix, for example.
+
+The notation {\tt umfpack\_di\_*} refers to all 27 user-callable routines
+for the real double precision and {\tt int} integer case. The notation
+{\tt umfpack\_*\_numeric}, for example, refers all four versions
+(real/complex, int/long) of a single operation
+(in this case numeric factorization).
+
+%-------------------------------------------------------------------------------
+\subsection{The size of an integer}
+%-------------------------------------------------------------------------------
+
+The {\tt umfpack\_di\_*} and {\tt umfpack\_zi\_*} routines use {\tt int} integer
+arguments; those starting with {\tt umfpack\_dl\_} or {\tt umfpack\_zl\_}
+use {\tt long} integer arguments. If you compile UMFPACK in the standard
+ILP32 mode (32-bit {\tt int}'s, {\tt long}'s, and pointers) then the versions
+are essentially identical. You will be able to solve problems using up to 2GB
+of memory. If you compile UMFPACK in the standard LP64 mode, the size of an
+{\tt int} remains 32-bits, but the size of a {\tt long} and a pointer both get
+promoted to 64-bits. In the LP64 mode, the {\tt umfpack\_dl\_*}
+and {\tt umfpack\_zl\_*} routines can solve huge
+problems (not limited to 2GB), limited of course by the amount of available
+memory. The only drawback to the 64-bit mode is that not all BLAS libraries
+support 64-bit integers. This limits the performance you will obtain.
+Those that do support 64-bit integers are specific to particular
+architectures, and are not portable. UMFPACK and AMD should be compiled
+in the same mode.
+If you compile UMFPACK and AMD in the LP64 mode,
+be sure to add {\tt -DLP64} to the compilation command. See the examples in
+{\tt Make.alpha}, {\tt Make.sgi}, and {\tt Make.solaris}.
+
+%-------------------------------------------------------------------------------
+\subsection{Real and complex floating-point}
+%-------------------------------------------------------------------------------
+
+The {\tt umfpack\_di\_*} and {\tt umfpack\_dl\_*} routines take (real) double
+precision arguments, and return double precision arguments. In the
+{\tt umfpack\_zi\_*} and {\tt umfpack\_zl\_*} routines, these same arguments
+hold the real part of the matrices; and second double precision arrays hold
+the imaginary part of the input and output matrices. Internally, complex
+numbers are stored in arrays with their real and imaginary parts interleaved,
+as required by the BLAS.
+
+%-------------------------------------------------------------------------------
+\subsection{Primary routines, and a simple example}
+%-------------------------------------------------------------------------------
+
+Five primary UMFPACK routines are required to factorize $\m{A}$ or
+solve $\m{Ax}=\m{b}$. They are fully described in Section~\ref{Primary}:
+
+\begin{itemize}
+\item {\tt umfpack\_*\_symbolic}:
+
+ Pre-orders the columns of $\m{A}$ to reduce fill-in.
+ Returns an opaque {\tt Symbolic} object as a {\tt void *}
+ pointer. The object contains the symbolic analysis and is needed for the
+ numeric factorization. This routine requires only $O(|\m{A}|)$ space,
+ where $|\m{A}|$ is the number of nonzero entries in the matrix. It computes
+ upper bounds on the nonzeros in $\m{L}$ and $\m{U}$, the floating-point
+ operations required, and the memory usage of {\tt umfpack\_*\_numeric}. The
+ {\tt Symbolic} object is small; it contains just the column pre-ordering,
+ the supernodal column elimination tree, and information about each frontal
+ matrix. It is no larger than about $13n$ integers if $\m{A}$ is
+ $n$-by-$n$.
+
+\item {\tt umfpack\_*\_numeric}:
+
+ Numerically scales and then factorizes a sparse matrix into
+ $\m{PAQ}$, $\m{PRAQ}$, or $\m{PR}^{-1}\m{AQ}$ into the product $\m{LU}$,
+ where
+ $\m{P}$ and $\m{Q}$ are permutation matrices, $\m{R}$ is a diagonal
+ matrix of scale factors, $\m{L}$ is lower triangular with unit diagonal,
+ and $\m{U}$ is upper triangular. Requires the
+ symbolic ordering and analysis computed by {\tt umfpack\_*\_symbolic}
+ or {\tt umfpack\_*\_qsymbolic}.
+ Returns an opaque {\tt Numeric} object as a
+ {\tt void *} pointer. The object contains the numerical factorization and
+ is used by {\tt umfpack\_*\_solve}. You can factorize a new matrix with a
+ different values (but identical pattern) as the matrix analyzed by
+ {\tt umfpack\_*\_symbolic} or {\tt umfpack\_*\_qsymbolic} by re-using the
+ {\tt Symbolic} object (this feature is available when using UMFPACK in a
+ C or Fortran program, but not in MATLAB).
+ The matrix
+ $\m{U}$ will have zeros on the diagonal if $\m{A}$ is singular; this
+ produces a warning, but the factorization is still valid.
+
+\item {\tt umfpack\_*\_solve}:
+
+ Solves a sparse linear system ($\m{Ax}=\m{b}$, $\m{A}\tr\m{x}=\m{b}$, or
+ systems involving just $\m{L}$ or $\m{U}$), using the numeric factorization
+ computed by {\tt umfpack\_*\_numeric}. Iterative refinement with sparse
+ backward error \cite{ardd:89} is used by default. The matrix $\m{A}$ must
+ be square. If it is singular, then a divide-by-zero will occur, and your
+ solution with contain IEEE Inf's or NaN's in the appropriate places.
+
+\item {\tt umfpack\_*\_free\_symbolic}:
+
+ Frees the {\tt Symbolic} object created by {\tt umfpack\_*\_symbolic}
+ or {\tt umfpack\_*\_qsymbolic}.
+
+\item {\tt umfpack\_*\_free\_numeric}:
+
+ Frees the {\tt Numeric} object created by {\tt umfpack\_*\_numeric}.
+
+\end{itemize}
+
+Be careful not to free a {\tt Symbolic} object with
+{\tt umfpack\_*\_free\_numeric}. Nor should you attempt to free a {\tt Numeric}
+object with {\tt umfpack\_*\_free\_symbolic}.
+Failure to free these objects will lead to memory leaks.
+
+The matrix $\m{A}$ is represented in compressed column form, which is
+identical to the sparse matrix representation used by MATLAB. It consists
+of three or four arrays, where the matrix is {\tt m}-by-{\tt n},
+with {\tt nz} entries. For the {\tt int} version of UMFPACK:
+
+{\footnotesize
+\begin{verbatim}
+ int Ap [n+1] ;
+ int Ai [nz] ;
+ double Ax [nz] ;
+\end{verbatim}
+}
+
+For the {\tt long} version of UMFPACK:
+
+{\footnotesize
+\begin{verbatim}
+ long Ap [n+1] ;
+ long Ai [nz] ;
+ double Ax [nz] ;
+\end{verbatim}
+}
+
+The complex versions add another array for the imaginary part:
+
+{\footnotesize
+\begin{verbatim}
+ double Az [nz] ;
+\end{verbatim}
+}
+
+All nonzeros are entries, but an entry may be numerically zero. The row indices
+of entries in column {\tt j} are stored in
+ {\tt Ai[Ap[j]} \ldots {\tt Ap[j+1]-1]}.
+The corresponding numerical values are stored in
+ {\tt Ax[Ap[j]} \ldots {\tt Ap[j+1]-1]}.
+The imaginary part, for the complex versions, is stored in
+ {\tt Az[Ap[j]} \ldots {\tt Ap[j+1]-1]}.
+
+No duplicate row indices may be present, and the row indices in any given
+column must be sorted in ascending order. The first entry {\tt Ap[0]} must be
+zero. The total number of entries in the matrix is thus {\tt nz = Ap[n]}.
+Except for the fact that extra zero entries can be included, there is thus a
+unique compressed column representation of any given matrix $\m{A}$.
+For a more flexible method for providing an input matrix to UMFPACK,
+see Section~\ref{triplet}.
+
+Here is a simple main program, {\tt umfpack\_simple.c}, that illustrates the
+basic usage of UMFPACK. See Section~\ref{Synopsis} for a short description
+of each calling sequence, including a list of options for the first
+argument of {\tt umfpack\_di\_solve}.
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_simple.c via sed
+\end{verbatim}
+}
+
+The {\tt Ap}, {\tt Ai}, and {\tt Ax} arrays represent the matrix
+\[
+\m{A} = \left[
+\begin{array}{rrrrr}
+ 2 & 3 & 0 & 0 & 0 \\
+ 3 & 0 & 4 & 0 & 6 \\
+ 0 & -1 & -3 & 2 & 0 \\
+ 0 & 0 & 1 & 0 & 0 \\
+ 0 & 4 & 2 & 0 & 1 \\
+\end{array}
+\right].
+\]
+and the solution to $\m{Ax}=\m{b}$ is $\m{x} = [1 \, 2 \, 3 \, 4 \, 5]\tr$.
+The program uses default control settings and does not return any statistics
+about the ordering, factorization, or solution ({\tt Control} and {\tt Info}
+are both {\tt (double *) NULL}). It also ignores the status value returned by
+most user-callable UMFPACK routines.
+
+%-------------------------------------------------------------------------------
+\subsection{A note about zero-sized arrays}
+%-------------------------------------------------------------------------------
+
+UMFPACK uses many user-provided arrays of
+size {\tt m} or {\tt n} (the order of the matrix), and of size
+{\tt nz} (the number of nonzeros in a matrix). UMFPACK does not handle
+zero-dimensioned arrays;
+it returns an error code if {\tt m} or {\tt n}
+are zero. However, {\tt nz} can be zero, since all singular matrices are
+handled correctly. If you attempt to {\tt malloc} an array of size {\tt nz}
+= 0, however, {\tt malloc} will return a null pointer which UMFPACK will report
+as a missing argument. If you {\tt malloc} an array of
+size {\tt nz} to pass to UMFPACK, make sure that you handle the {\tt nz} = 0
+case correctly (use a size equal to the maximum of {\tt nz} and 1, or use a
+size of {\tt nz+1}).
+
+%-------------------------------------------------------------------------------
+\subsection{Alternative routines}
+%-------------------------------------------------------------------------------
+
+Three alternative routines are provided that modify UMFPACK's default
+behavior. They are fully described in Section~\ref{Alternative}:
+
+\begin{itemize}
+\item {\tt umfpack\_*\_defaults}:
+
+ Sets the default control parameters in the {\tt Control} array. These can
+ then be modified as desired before passing the array to the other UMFPACK
+ routines. Control parameters are summarized in Section~\ref{control_param}.
+ Three particular parameters deserve special notice.
+ UMFPACK uses relaxed partial pivoting, where a candidate pivot entry is
+ numerically acceptable if its magnitude is greater than or equal to a
+ tolerance parameter times the magnitude of the largest entry in the same
+ column. The parameter {\tt Control [UMFPACK\_PIVOT\_TOLERANCE]} has a
+ default value of 0.1, and is used for the unsymmetric strategy.
+ For complex matrices, a cheap approximation of the absolute value is
+ used for the threshold pivoting test
+ ($|a| \approx |a_{\mbox{real}}|+|a_{\mbox{imag}}|$).
+
+ For the symmetric strategy, a second tolerance is used for diagonal
+ entries: \newline {\tt Control [UMFPACK\_SYM\_PIVOT\_TOLERANCE]}, with
+ a default value of 0.001. The first parameter (with a default of 0.1)
+ is used for any off-diagonal candidate pivot entries.
+
+ These two parameters may be too small for some matrices, particularly for
+ ill-conditioned or poorly scaled ones. With the default pivot tolerances
+ and default iterative refinement,
+ {\tt x = umfpack (A,'}$\backslash${\tt ',b)}
+ is just as accurate as (or more accurate) than
+ {\tt x = A}$\backslash${\tt b}
+ in MATLAB 6.1 for nearly all matrices.
+
+ If {\tt Control [UMFPACK\_PIVOT\_TOLERANCE]} is zero, than any
+ nonzero entry is acceptable as a pivot (this is changed from Version 4.0,
+ which treated a value of 0.0 the same as 1.0). If the symmetric strategy is
+ used, and {\tt Control [UMFPACK\_SYM\_PIVOT\_TOLERANCE]} is zero, then any
+ nonzero entry on the diagonal is accepted as a pivot. Off-diagonal pivoting
+ will still occur if the diagonal entry is exactly zero. The
+ {\tt Control [UMFPACK\_SYM\_PIVOT\_TOLERANCE]} parameter is new to Version
+ 4.1. It is similar in function to the pivot tolerance for left-looking
+ methods (the MATLAB {\tt THRESH} option in {\tt [L,U,P] = lu (A, THRESH)},
+ and the pivot tolerance parameter in SuperLU).
+
+ The parameter {\tt Control [UMFPACK\_STRATEGY]} can be used to bypass
+ UMFPACK's automatic strategy selection. The automatic strategy nearly
+ always selects the best method. When it does not, the different methods
+ nearly always give about the same quality of results. There may be
+ cases where the automatic strategy fails to pick a good strategy. Also,
+ you can save some computing time if you know the right strategy for your
+ set of matrix problems.
+
+\item {\tt umfpack\_*\_qsymbolic}:
+
+ An alternative to {\tt umfpack\_*\_symbolic}. Allows the user to specify
+ his or her own column pre-ordering, rather than using the default COLAMD
+ or AMD pre-orderings. For example, a graph partitioning-based order
+ of $\m{A}\tr\m{A}$ would be suitable for UMFPACK's unsymmetric strategy.
+ A partitioning of $\m{A}+\m{A}\tr$ would be suitable for UMFPACK's
+ symmetric or 2-by-2 strategies.
+
+\item {\tt umfpack\_*\_wsolve}:
+
+ An alternative to {\tt umfpack\_*\_solve} which does not dynamically
+ allocate any memory. Requires the user to pass two additional work
+ arrays.
+
+\end{itemize}
+
+%-------------------------------------------------------------------------------
+\subsection{Matrix manipulation routines}
+\label{triplet}
+%-------------------------------------------------------------------------------
+
+The compressed column data structure is compact, and simplifies the UMFPACK
+routines that operate on the sparse matrix $\m{A}$. However, it can be
+inconvenient for the user to generate. Section~\ref{Manipulate} presents the
+details of routines for manipulating sparse matrices in {\em triplet} form,
+compressed column form, and compressed row form (the transpose of the
+compressed column form). The triplet form of a matrix consists of three or
+four arrays. For the {\tt int} version of UMFPACK:
+
+{\footnotesize
+\begin{verbatim}
+ int Ti [nz] ;
+ int Tj [nz] ;
+ double Tx [nz] ;
+\end{verbatim}
+}
+
+For the {\tt long} version:
+
+{\footnotesize
+\begin{verbatim}
+ long Ti [nz] ;
+ long Tj [nz] ;
+ double Tx [nz] ;
+\end{verbatim}
+}
+
+The complex versions use another array to hold the imaginary part:
+
+{\footnotesize
+\begin{verbatim}
+ double Tz [nz] ;
+\end{verbatim}
+}
+
+The {\tt k}-th triplet is $(i,j,a_{ij})$, where $i =$ {\tt Ti[k]},
+$j =$ {\tt Tj[k]}, and $a_{ij} =$ {\tt Tx[k]}. For the complex versions,
+{\tt Tx[k]} is the real part of $a_{ij}$ and
+{\tt Tz[k]} is the imaginary part.
+The triplets can be in any
+order in the {\tt Ti}, {\tt Tj}, and {\tt Tx} arrays (and {\tt Tz} for
+the complex versions), and duplicate entries may
+exist. Any duplicate entries are summed when the triplet form is converted to
+compressed column form. This is a convenient way to create a matrix arising in
+finite-element methods, for example.
+
+Four routines are provided for manipulating sparse matrices:
+
+\begin{itemize}
+\item {\tt umfpack\_*\_triplet\_to\_col}:
+
+ Converts a triplet form of a matrix to compressed column form (ready for
+ input to \newline
+ {\tt umfpack\_*\_symbolic}, {\tt umfpack\_*\_qsymbolic}, and
+ {\tt umfpack\_*\_numeric}). Identical to {\tt A = spconvert(i,j,x)} in
+ MATLAB, except that zero entries are not removed, so that the pattern of
+ entries in the compressed column form of $\m{A}$ are fully under user
+ control. This is important if you want to factorize a new matrix with the
+ {\tt Symbolic} object from a prior matrix with the same pattern as the new
+ one.
+
+\item {\tt umfpack\_*\_col\_to\_triplet}:
+
+ The opposite of {\tt umfpack\_*\_triplet\_to\_col}. Identical to
+ {\tt [i,j,x] = find(A)} in MATLAB, except that numerically zero entries
+ may be included.
+
+\item {\tt umfpack\_*\_transpose}:
+
+ Transposes and optionally permutes a column form matrix \cite{Gustavson78}.
+ Identical to
+ {\tt R = A(P,Q)'} (linear algebraic transpose, using the complex conjugate)
+ or {\tt R = A(P,Q).'} (the array transpose)
+ in MATLAB, except for the presence of numerically zero entries.
+
+ Factorizing $\m{A}\tr$ and then solving $\m{Ax}=\m{b}$ with the transposed
+ factors can sometimes be much faster or much slower than factorizing
+ $\m{A}$. It is highly dependent on your particular matrix.
+
+\item {\tt umfpack\_*\_scale}:
+
+ Applies the row scale factors to a user-provided vector. This is not
+ required to solve the sparse linear system $\m{Ax}=\m{b}$ or
+ $\m{A}\tr\m{x}=\m{b}$, since {\tt umfpack\_*\_solve} applies the scale
+ factors for those systems. This routine is new to Version 4.1.
+
+\end{itemize}
+
+It is quite easy to add matrices in triplet form, subtract them, transpose
+them, permute them, construct a submatrix, and multiply a triplet-form matrix
+times a vector. UMFPACK does not provide code for these basic operations,
+however. Refer to the discussion of
+{\tt umfpack\_*\_triplet\_to\_col} in Section~\ref{Manipulate} for more details
+on how to compute these operations in your own code.
+The only primary matrix operation not provided by UMFPACK is the
+multiplication of two sparse matrices \cite{Gustavson78}.
+
+%-------------------------------------------------------------------------------
+\subsection{Getting the contents of opaque objects}
+%-------------------------------------------------------------------------------
+
+There are cases where you may wish to do more with the LU factorization
+of a matrix than solve a linear system. The opaque {\tt Symbolic} and
+{\tt Numeric} objects are just that - opaque. You cannot do anything with them
+except to pass them back to subsequent calls to UMFPACK. Three routines
+are provided for copying their contents into user-provided arrays using simpler
+data structures. Four routines are provided for saving and loading the
+{\tt Numeric} and {\tt Symbolic} objects to/from binary files.
+They are fully described in Section~\ref{Get}:
+
+\begin{itemize}
+\item {\tt umfpack\_*\_get\_lunz}:
+
+ Returns the number of nonzeros in $\m{L}$ and $\m{U}$.
+
+\item {\tt umfpack\_*\_get\_numeric}:
+
+ Copies $\m{L}$, $\m{U}$, $\m{P}$, $\m{Q}$, and $\m{R}$
+ from the {\tt Numeric} object
+ into arrays provided by the user. The matrix $\m{L}$ is returned in
+ compressed row form (with the column indices in each row sorted in ascending
+ order). The matrix $\m{U}$ is returned in compressed column form (with
+ sorted columns). There are no explicit zero entries in $\m{L}$ and $\m{U}$,
+ but such entries may exist in the {\tt Numeric} object. The permutations
+ $\m{P}$ and $\m{Q}$ are represented as permutation vectors, where
+ {\tt P[k] = i} means that row {\tt i} of the original matrix is the
+ the {\tt k}-th row of $\m{PAQ}$, and where
+ {\tt Q[k] = j} means that column {\tt j} of the original matrix is the
+ {\tt k}-th column of $\m{PAQ}$. This is identical to how MATLAB uses
+ permutation vectors (type {\tt help colamd} in MATLAB 6.1 or later).
+
+\item {\tt umfpack\_*\_get\_symbolic}:
+
+ Copies the contents of the {\tt Symbolic} object (the initial row and column
+ preordering, supernodal column elimination tree, and information
+ about each frontal matrix) into arrays provided by the user.
+
+\item {\tt umfpack\_*\_save\_numeric}:
+
+ Saves a copy of the {\tt Numeric} object to a file, in binary format.
+
+\item {\tt umfpack\_*\_load\_numeric}:
+
+ Creates a {\tt Numeric} object by loading it from a file created
+ by {\tt umfpack\_*\_save\_numeric}.
+
+\item {\tt umfpack\_*\_save\_symbolic}:
+
+ Saves a copy of the {\tt Symbolic} object to a file, in binary format.
+
+\item {\tt umfpack\_*\_load\_symbolic}:
+
+ Creates a {\tt Symbolic} object by loading it from a file created
+ by {\tt umfpack\_*\_save\_symbolic}.
+
+\end{itemize}
+
+UMFPACK itself does not make use of these routines;
+they are provided solely for returning the contents of the opaque
+{\tt Symbolic} and {\tt Numeric} objects to the user, and saving/loading
+them to/from a binary file.
+
+%-------------------------------------------------------------------------------
+\subsection{Reporting routines}
+\label{Reporting}
+%-------------------------------------------------------------------------------
+
+None of the UMFPACK routines discussed so far prints anything, even when an
+error occurs. UMFPACK provides you with nine routines for printing the input
+and output arguments (including the {\tt Control} settings and {\tt Info}
+statistics) of UMFPACK routines discussed above. They are fully described in
+Section~\ref{Report}:
+
+\begin{itemize}
+\item {\tt umfpack\_*\_report\_status}:
+
+ Prints the status (return value) of other {\tt umfpack\_*} routines.
+
+\item {\tt umfpack\_*\_report\_info}:
+
+ Prints the statistics returned in the {\tt Info} array by
+ {\tt umfpack\_*\_*symbolic},
+ {\tt umfpack\_*\_numeric}, and {\tt umfpack\_*\_*solve}.
+
+\item {\tt umfpack\_*\_report\_control}:
+
+ Prints the {\tt Control} settings.
+
+\item {\tt umfpack\_*\_report\_matrix}:
+
+ Verifies and prints a compressed column-form or compressed row-form sparse
+ matrix.
+
+\item {\tt umfpack\_*\_report\_triplet}:
+
+ Verifies and prints a matrix in triplet form.
+
+\item {\tt umfpack\_*\_report\_symbolic}:
+
+ Verifies and prints a {\tt Symbolic} object.
+
+\item {\tt umfpack\_*\_report\_numeric}:
+
+ Verifies and prints a {\tt Numeric} object.
+
+\item {\tt umfpack\_*\_report\_perm}:
+
+ Verifies and prints a permutation vector.
+
+\item {\tt umfpack\_*\_report\_vector}:
+
+ Verifies and prints a real or complex vector.
+
+\end{itemize}
+
+The {\tt umfpack\_*\_report\_*} routines behave slightly differently when
+compiled
+into the C-callable UMFPACK library than when used in the MATLAB mexFunction.
+MATLAB stores its sparse matrices using the same compressed column data
+structure discussed above, where row and column indices of an $m$-by-$n$
+matrix are in the range 0 to $m-1$ or $n-1$, respectively.
+It prints them as if they are in the range 1 to $m$ or $n$.
+The UMFPACK mexFunction behaves the same way.
+
+You can control how much the {\tt umfpack\_*\_report\_*} routines print by
+modifying the {\tt Control [UMFPACK\_PRL]} parameter. Its default value is 1.
+Here is a summary of how the routines use this print level parameter:
+
+\begin{itemize}
+\item {\tt umfpack\_*\_report\_status}:
+
+ No output if the print level is 0 or less, even when an error occurs.
+ If 1, then error messages are printed, and nothing is printed if
+ the status is {\tt UMFPACK\_OK}. A warning message is printed if
+ the matrix is singular. If 2 or more, then the status is always
+ printed. If 4 or more, then the UMFPACK Copyright is printed.
+ If 6 or more, then the UMFPACK License is printed. See also the first page
+ of this User Guide for the Copyright and License.
+
+\item {\tt umfpack\_*\_report\_control}:
+
+ No output if the print level is 1 or less. If 2 or more, all of
+ {\tt Control} is printed.
+
+\item {\tt umfpack\_*\_report\_info}:
+
+ No output if the print level is 1 or less. If 2 or more, all of
+ {\tt Info} is printed.
+
+\item all other {\tt umfpack\_*\_report\_*} routines:
+
+ If the print level is 2 or less, then these routines return silently without
+ checking their inputs. If 3 or more, the inputs are fully verified and a
+ short status summary is printed. If 4, then the first few entries of the
+ input arguments are printed. If 5, then all of the input arguments are
+ printed.
+
+\end{itemize}
+
+This print level parameter has an additional effect on the MATLAB mexFunction.
+If zero, then no warnings of singular or nearly singular matrices are
+printed (similar to the MATLAB commands
+{\tt warning off MATLAB:singularMatrix} and
+{\tt warning off MATLAB:nearlySingularMatrix}).
+
+%-------------------------------------------------------------------------------
+\subsection{Utility routines}
+%-------------------------------------------------------------------------------
+
+UMFPACK v4.0 included a routine that returns the time used by the process,
+{\tt umfpack\_timer}. The routine uses either {\tt getrusage} (which is
+preferred), or the ANSI C {\tt clock} routine if that is not available.
+It is fully described in Section~\ref{Utility}. It is still available in
+UMFPACK v4.1 and following, but not used internally.
+Two new timing routines are provided in UMFPACK Version 4.1 and following,
+{\tt umfpack\_tic} and {\tt umfpack\_toc}. They use POSIX-compliant
+{\tt sysconf} and {\tt times} routines to find both the CPU time
+and wallclock time.
+These three routines are the only user-callable
+routine that is identical in all four {\tt int}/{\tt long}, real/complex
+versions (there is no {\tt umfpack\_di\_timer} routine, for example).
+
+%-------------------------------------------------------------------------------
+\subsection{Control parameters}
+\label{control_param}
+%-------------------------------------------------------------------------------
+
+UMFPACK uses an optional {\tt double} array (currently of size 20)
+to modify its control parameters. If you pass {\tt (double *) NULL} instead
+of a {\tt Control} array, then defaults are used.
+This array will almost certainly grow in size in future releases,
+so be sure to dimension your {\tt Control} array to be of size
+{\tt UMFPACK\_CONTROL}. That constant is currently defined to be 20,
+but will increase in future versions.
+
+The contents of this array may be modified by the user
+(see {\tt umfpack\_*\_defaults}). Each
+user-callable routine includes a complete description of how each control
+setting modifies its behavior. Table~\ref{control} summarizes the entire
+contents of the {\tt Control} array.
+Note that ANSI C uses 0-based indexing, while MATLAB uses 1-based
+indexing. Thus, {\tt Control(1)} in MATLAB is the same as
+{\tt Control[0]} or {\tt Control[UMFPACK\_PRL]} in ANSI C.
+
+\begin{table}
+\caption{UMFPACK Control parameters}
+\label{control}
+{\footnotesize
+\begin{tabular}{llll}
+\hline
+
+MATLAB & ANSI C & default & description \\
+\hline
+{\tt Control(1)} & {\tt Control[UMFPACK\_PRL]} & 1 & printing level \\
+{\tt Control(2)} & {\tt Control[UMFPACK\_DENSE\_ROW]} & 0.2 & dense row parameter \\
+{\tt Control(3)} & {\tt Control[UMFPACK\_DENSE\_COL]} & 0.2 & dense column parameter \\
+{\tt Control(4)} & {\tt Control[UMFPACK\_PIVOT\_TOLERANCE]} & 0.1 & partial pivoting tolerance \\
+{\tt Control(5)} & {\tt Control[UMFPACK\_BLOCK\_SIZE]} & 32 & BLAS block size \\
+{\tt Control(6)} & {\tt Control[UMFPACK\_STRATEGY]} & 0 (auto) & select strategy \\
+{\tt Control(7)} & {\tt Control[UMFPACK\_ALLOC\_INIT]} & 0.7 & initial memory allocation \\
+{\tt Control(8)} & {\tt Control[UMFPACK\_IRSTEP]} & 2 & max iter. refinement steps \\
+{\tt Control(13)} & {\tt Control[UMFPACK\_2BY2\_TOLERANCE]} & 0.01 & defines ``large'' entries \\
+{\tt Control(14)} & {\tt Control[UMFPACK\_FIXQ]} & 0 (auto) & fix or modify Q \\
+{\tt Control(15)} & {\tt Control[UMFPACK\_AMD\_DENSE]} & 10 & AMD dense row/column parameter \\
+{\tt Control(16)} & {\tt Control[UMFPACK\_SYM\_PIVOT\_TOLERANCE]} & 0.001 & for diagonal entries \\
+{\tt Control(17)} & {\tt Control[UMFPACK\_SCALE]} & 1 (sum) & row scaling (none, sum, or max) \\
+{\tt Control(18)} & {\tt Control[UMFPACK\_FRONT\_ALLOC\_INIT]} & 0.5 & frontal matrix allocation ratio \\
+{\tt Control(19)} & {\tt Control[UMFPACK\_DROPTOL]} & 0 & drop tolerance \\
+{\tt Control(20)} & {\tt Control[UMFPACK\_AGGRESSIVE]} & 1 (yes) & aggressive absorption \\
+ & & & in AMD and COLAMD \\
+%
+\hline
+\multicolumn{4}{l}{Can only be changed at compile time:} \\
+{\tt Control(9)} & {\tt Control[UMFPACK\_COMPILED\_WITH\_BLAS]} & - & true if BLAS is used \\
+{\tt Control(10)} & {\tt Control[UMFPACK\_COMPILED\_FOR\_MATLAB]} & - & true for mexFunction \\
+{\tt Control(11)} & {\tt Control[UMFPACK\_COMPILED\_WITH\_GETRUSAGE]} & - & 1 if {\tt getrusage} used \\
+{\tt Control(12)} & {\tt Control[UMFPACK\_COMPILED\_IN\_DEBUG\_MODE]} & - & true if debug mode enabled \\
+\hline
+\end{tabular}
+}
+\end{table}
+
+Let $\alpha_r = ${\tt Control [UMFPACK\_DENSE\_ROW]},
+ $\alpha_c = ${\tt Control [UMFPACK\_DENSE\_COL]}, and
+ $\alpha = ${\tt Control [UMFPACK\_AMD\_DENSE]}.
+Suppose the submatrix $\m{S}$, obtained after eliminating pivots with
+zero Markowitz cost, is $m$-by-$n$.
+Then a row is considered ``dense'' if it has more than
+$\max (16, 16 \alpha_r \sqrt{n})$ entries.
+A column is considered ``dense'' if it has more than
+$\max (16, 16 \alpha_c \sqrt{m})$ entries.
+These rows and columns are treated different in COLAMD and during numerical
+factorization. In COLAMD, dense columns are placed last in their natural
+order, and dense rows are ignored. During numerical factorization, dense
+rows are stored differently.
+In AMD, a row/column of the square matrix $\m{S}+\m{S}\tr$ is
+considered ``dense'' if it has more than $\max (16, \alpha \sqrt{n})$ entries.
+These rows/columns are placed last in AMD's output ordering.
+For more details on the control parameters, refer to the documentation of
+{\tt umfpack\_*\_qsymbolic}, {\tt umfpack\_*\_numeric}, {\tt umfpack\_*\_solve},
+and the {\tt umfpack\_*\_report\_*} routines,
+in Sections~\ref{Primary}~through~\ref{Report}, below.
+
+%-------------------------------------------------------------------------------
+\subsection{Error codes}
+\label{error_codes}
+%-------------------------------------------------------------------------------
+
+Many of the routines return a {\tt status} value.
+This is also returned as the first entry in the {\tt Info} array, for
+those routines with that argument. The following list summarizes
+all of the error codes in UMFPACK v4.3. Each error code is given a
+specific name in the {\tt umfpack.h} include file, so you can use
+those constants instead of hard-coded values in your program.
+Future versions may report additional error codes.
+
+A value of zero means everything was successful, and the matrix is
+non-singular. A value greater than zero means the routine was successful,
+but a warning occurred. Currently, the only warning code is when the
+matrix is singular. A negative value means the routine was not successful.
+In this case, no {\tt Symbolic} or {\tt Numeric} object was created.
+
+\begin{itemize}
+\item {\tt UMFPACK\_OK}, (0): UMFPACK was successful.
+
+\item {\tt UMFPACK\_WARNING\_singular\_matrix}, (1): Matrix is singular.
+ There are exact zeros on the diagonal of $\m{U}$.
+
+\item {\tt UMFPACK\_ERROR\_out\_of\_memory}, (-1): Not enough memory.
+ The ANSI C {\tt malloc} or {\tt realloc} routine failed.
+
+\item {\tt UMFPACK\_ERROR\_invalid\_Numeric\_object}, (-3):
+ Routines that take a {\tt Numeric} object as input (or load it
+ from a file) check this object and return this error code if it is
+ invalid. This can be caused by a memory leak or overrun in your
+ program, which can overwrite part of the Numeric object. It can also
+ be caused by passing a Symbolic object by mistake, or some other pointer.
+ If you try to factorize a matrix using one version of UMFPACK and
+ then use the factors in another version, this error code will trigger as
+ well. You cannot factor your matrix using
+ version 4.0 and then solve with version 4.1.
+ You cannot use different precisions of the same version
+ (real and complex, for example).
+ It is possible for the {\tt Numeric} object to be corrupted by your
+ program in subtle ways that are not detectable by this quick check.
+ In this case, you may see an
+ {\tt UMFPACK\_ERROR\_different\_pattern} error code, or even an
+ {\tt UMFPACK\_ERROR\_internal\_error}.
+
+\item {\tt UMFPACK\_ERROR\_invalid\_Symbolic\_object}, (-4):
+ Routines that take a {\tt Symbolic} object as input (or load it
+ from a file) check this object and return this error code if it is
+ invalid. The causes of this error are analogous to the
+ {\tt UMFPACK\_ERROR\_invalid\_Numeric\_object} error described above.
+
+\item {\tt UMFPACK\_ERROR\_argument\_missing}, (-5):
+ Some arguments of some are optional (you can pass a {\tt NULL} pointer
+ instead of an array). This error code occurs if you pass a {\tt NULL}
+ pointer when that argument is required to be present.
+ \item {\tt UMFPACK\_ERROR\_n\_nonpositive} (-6):
+ The number of rows or columns of the matrix must be greater than zero.
+ \item {\tt UMFPACK\_ERROR\_invalid\_matrix} (-8):
+ The matrix is invalid. For the column-oriented input, this error
+ code will occur if the contents of {\tt Ap} and/or {\tt Ai} are invalid.
+
+ {\tt Ap} is an integer array of size {\tt n\_col+1}.
+ On input, it holds the
+ ``pointers'' for the column form of the sparse matrix $\m{A}$.
+ Column {\tt j} of
+ the matrix A is held in {\tt Ai [(Ap [j])} \ldots {\tt (Ap [j+1]-1)]}.
+ The first entry, {\tt Ap [0]}, must be zero,
+ and {\tt Ap [j]} $\le$ {\tt Ap [j+1]} must hold for all
+ {\tt j} in the range 0 to {\tt n\_col-1}.
+ The value {\tt nz = Ap [n\_col]} is thus the
+ total number of entries in the pattern of the matrix A.
+ {\tt nz} must be greater than or equal to zero.
+
+ The nonzero pattern (row indices) for column {\tt j} is stored in
+ {\tt Ai [(Ap [j])} \ldots {\tt (Ap [j+1]-1)]}. The row indices in a given
+ column {\tt j}
+ must be in ascending order, and no duplicate row indices may be present.
+ Row indices must be in the range 0 to {\tt n\_row-1}
+ (the matrix is 0-based).
+
+ Some routines take a triplet-form input, with arguments
+ {\tt nz}, {\tt Ti}, and {\tt Tj}. This error code is returned
+ if {\tt nz} is less than zero,
+ if any row index in {\tt Ti} is outside the range 0 to {\tt n\_col-1}, or
+ if any column index in {\tt Tj} is outside the range 0 to {\tt n\_row-1}.
+
+\item {\tt UMFPACK\_ERROR\_different\_pattern}, (-11):
+ The most common cause of this error is that the pattern of the
+ matrix has changed between the symbolic and numeric factorization.
+ It can also occur if the {\tt Numeric} or {\tt Symbolic} object has
+ been subtly corrupted by your program.
+
+\item {\tt UMFPACK\_ERROR\_invalid\_system}, (-13):
+ The {\tt sys} argument provided to one of the solve routines is invalid.
+
+\item {\tt UMFPACK\_ERROR\_invalid\_permutation}, (-15):
+ The permutation vector provided as input is invalid.
+
+\item {\tt UMFPACK\_ERROR\_file\_IO}, (-17):
+ This error code is returned by the routines that save and load
+ the {\tt Numeric} or {\tt Symbolic} objects to/from a file, if a
+ file I/O error has occurred. The file may not exist or may not be readable,
+ you may be trying to create a file that you don't have permission to create,
+ or you may be out of disk space. The file you are trying to read might
+ be the wrong one, and an earlier end-of-file condition would then result
+ in this error.
+
+\item {\tt UMFPACK\_ERROR\_internal\_error}, (-911):
+ An internal error has occurred, of unknown cause. This is either a bug
+ in UMFPACK, or the result of a memory overrun from your program.
+ Try modifying the file {\tt AMD/Source/amd\_internal.h} and adding
+ the statement {\tt \#undef NDEBUG}, to enable the debugging mode.
+ Recompile UMFPACK and rerun your program.
+ A failed assertion might occur which
+ can give you a better indication as to what is going wrong. Be aware that
+ UMFPACK will be extraordinarily slow when running in debug mode.
+ If all else fails, contact the developer (davis@cise.ufl.edu) with
+ as many details as possible.
+
+\end{itemize}
+
+%-------------------------------------------------------------------------------
+\subsection{Larger examples}
+%-------------------------------------------------------------------------------
+
+Full examples of all user-callable UMFPACK routines
+are available in four stand-alone C main programs, {\tt umfpack\_*\_demo.c}.
+Another example is
+the UMFPACK mexFunction, {\tt umfpackmex.c}. The mexFunction accesses only the
+user-callable C interface to UMFPACK. The only features that it does not use
+are the support for the triplet form (MATLAB's sparse arrays are already in the
+compressed column form) and the ability to reuse the {\tt Symbolic} object to
+numerically factorize a matrix whose pattern is the same as a prior matrix
+analyzed by {\tt umfpack\_*\_symbolic} or {\tt umfpack\_*\_qsymbolic}. The
+latter is an important feature, but the mexFunction does not return its opaque
+{\tt Symbolic} and {\tt Numeric} objects to MATLAB. Instead, it gets the
+contents of these objects after extracting them via the {\tt umfpack\_*\_get\_*}
+routines, and returns them as MATLAB sparse matrices.
+
+The {\tt umf4.c} program for reading matrices in Harwell/Boeing format
+\cite{DuffGrimesLewis87b} is provided. It requires three Fortran 77 programs
+({\tt readhb.f}, {\tt readhb\_nozeros.f}, and {\tt readhb\_size.f})
+for reading in the sample Harwell/Boeing files in the {\tt UMFPACK/Demo/HB}
+directory. More matrices are available at
+http://www.cise.ufl.edu/research/sparse/matrices.
+Type {\tt make hb} in the {\tt UMFPACK/Demo/HB} directory
+to compile and run this demo. This program was used for the experimental
+results in \cite{Davis03}.
+
+%-------------------------------------------------------------------------------
+\section{Synopsis of C-callable routines}
+\label{Synopsis}
+%-------------------------------------------------------------------------------
+
+Each subsection, below, summarizes the input variables, output variables, return
+values, and calling sequences of the routines in one category. Variables with
+the same name as those already listed in a prior category have the same size
+and type.
+
+The real, {\tt long} integer {\tt umfpack\_dl\_*} routines are
+identical to the real, {\tt int} routines, except that {\tt \_di\_} is replaced
+with {\tt \_dl\_} in the name, and all {\tt int} arguments become {\tt long}.
+Similarly, the complex, {\tt long} integer {\tt umfpack\_zl\_*} routines are
+identical to the complex, {\tt int} routines, except that {\tt \_zi\_} is
+replaced
+with {\tt \_zl\_} in the name, and all {\tt int} arguments become {\tt long}.
+Only the real and complex {\tt int} versions are listed in the synopsis below.
+
+The matrix $\m{A}$ is {\tt m}-by-{\tt n} with {\tt nz} entries.
+
+The {\tt sys} argument of {\tt umfpack\_*\_solve}
+is an integer in the range 0 to 14 which defines which linear system is
+to be solved. Valid values are listed in Table~\ref{sys}.
+The notation $\m{A}\he$ refers to the matrix transpose, which is the
+complex conjugate transpose for complex matrices ({\tt A'} in MATLAB).
+The array transpose is $\m{A}\tr$, which is {\tt A.'} in MATLAB.
+
+\begin{table}
+\begin{center}
+\caption{UMFPACK {\tt sys} parameter}
+\label{sys}
+{\footnotesize
+\begin{tabular}{ll|l}
+\hline
+Value & & system \\
+\hline
+{\tt UMFPACK\_A} & (0) & $\m{Ax}=\m{b}$ \\
+{\tt UMFPACK\_At} & (1) & $\m{A}\he\m{x}=\m{b}$ \\
+{\tt UMFPACK\_Aat} & (2) & $\m{A}\tr\m{x}=\m{b}$ \\
+\hline
+{\tt UMFPACK\_Pt\_L} & (3) & $\m{P}\tr\m{Lx}=\m{b}$ \\
+{\tt UMFPACK\_L} & (4) & $\m{Lx}=\m{b}$ \\
+{\tt UMFPACK\_Lt\_P} & (5) & $\m{L}\he\m{Px}=\m{b}$ \\
+{\tt UMFPACK\_Lat\_P} & (6) & $\m{L}\tr\m{Px}=\m{b}$ \\
+{\tt UMFPACK\_Lt} & (7) & $\m{L}\he\m{x}=\m{b}$ \\
+{\tt UMFPACK\_Lat} & (8) & $\m{L}\tr\m{x}=\m{b}$ \\
+\hline
+{\tt UMFPACK\_U\_Qt} & (9) & $\m{UQ}\tr\m{x}=\m{b}$ \\
+{\tt UMFPACK\_U} & (10) & $\m{Ux}=\m{b}$ \\
+{\tt UMFPACK\_Q\_Ut} & (11) & $\m{QU}\he\m{x}=\m{b}$ \\
+{\tt UMFPACK\_Q\_Uat} & (12) & $\m{QU}\tr\m{x}=\m{b}$ \\
+{\tt UMFPACK\_Ut} & (13) & $\m{U}\he\m{x}=\m{b}$ \\
+{\tt UMFPACK\_Uat} & (14) & $\m{U}\tr\m{x}=\m{b}$ \\
+\hline
+\end{tabular}
+}
+\end{center}
+\end{table}
+
+%-------------------------------------------------------------------------------
+\subsection{Primary routines: real/{\tt int}}
+%-------------------------------------------------------------------------------
+
+{\footnotesize
+\begin{verbatim}
+#include "umfpack.h"
+int status, sys, n, m, nz, Ap [n+1], Ai [nz] ;
+double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], Ax [nz], X [n], B [n] ;
+void *Symbolic, *Numeric ;
+
+status = umfpack_di_symbolic (m, n, Ap, Ai, Ax, &Symbolic, Control, Info) ;
+status = umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric, Control, Info) ;
+status = umfpack_di_solve (sys, Ap, Ai, Ax, X, B, Numeric, Control, Info) ;
+umfpack_di_free_symbolic (&Symbolic) ;
+umfpack_di_free_numeric (&Numeric) ;
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\subsection{Alternative routines: real/{\tt int}}
+%-------------------------------------------------------------------------------
+
+{\footnotesize
+\begin{verbatim}
+int Qinit [n], Wi [n] ;
+double W [5*n] ;
+
+umfpack_di_defaults (Control) ;
+status = umfpack_di_qsymbolic (m, n, Ap, Ai, Ax, Qinit, &Symbolic, Control, Info) ;
+status = umfpack_di_wsolve (sys, Ap, Ai, Ax, X, B, Numeric, Control, Info, Wi, W) ;
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\subsection{Matrix manipulation routines: real/{\tt int}}
+%-------------------------------------------------------------------------------
+
+{\footnotesize
+\begin{verbatim}
+int Ti [nz], Tj [nz], P [m], Q [n], Rp [m+1], Ri [nz], Map [nz] ;
+double Tx [nz], Rx [nz], Y [m], Z [m] ;
+
+status = umfpack_di_col_to_triplet (n, Ap, Tj) ;
+status = umfpack_di_triplet_to_col (m, n, nz, Ti, Tj, Tx, Ap, Ai, Ax, Map) ;
+status = umfpack_di_transpose (m, n, Ap, Ai, Ax, P, Q, Rp, Ri, Rx) ;
+status = umfpack_di_scale (Y, Z, Numeric) ;
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\subsection{Getting the contents of opaque objects: real/{\tt int}}
+%-------------------------------------------------------------------------------
+
+The {\tt filename} string should be large enough to hold the name of a file.
+
+{\footnotesize
+\begin{verbatim}
+int lnz, unz, Lp [m+1], Lj [lnz], Up [n+1], Ui [unz], do_recip ;
+double Lx [lnz], Ux [unz], D [min (m,n)], Rs [m] ;
+int nfr, nchains, P1 [m], Q1 [n], Front_npivcol [n+1], Front_parent [n+1], Front_1strow [n+1],
+ Front_leftmostdesc [n+1], Chain_start [n+1], Chain_maxrows [n+1], Chain_maxcols [n+1] ;
+char filename [100] ;
+
+status = umfpack_di_get_lunz (&lnz, &unz, &m, &n, &nz_udiag, Numeric) ;
+status = umfpack_di_get_numeric (Lp, Lj, Lx, Up, Ui, Ux, P, Q, D, &do_recip, Rs, Numeric) ;
+status = umfpack_di_get_symbolic (&m, &n, &n1, &nz, &nfr, &nchains, P1, Q1,
+ Front_npivcol, Front_parent, Front_1strow, Front_leftmostdesc,
+ Chain_start, Chain_maxrows, Chain_maxcols, Symbolic) ;
+status = umfpack_di_load_numeric (&Numeric, filename) ;
+status = umfpack_di_save_numeric (Numeric, filename) ;
+status = umfpack_di_load_symbolic (&Symbolic, filename) ;
+status = umfpack_di_save_symbolic (Symbolic, filename) ;
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\subsection{Reporting routines: real/{\tt int}}
+%-------------------------------------------------------------------------------
+
+{\footnotesize
+\begin{verbatim}
+
+umfpack_di_report_status (Control, status) ;
+umfpack_di_report_control (Control) ;
+umfpack_di_report_info (Control, Info) ;
+status = umfpack_di_report_matrix (m, n, Ap, Ai, Ax, 1, Control) ;
+status = umfpack_di_report_matrix (m, n, Rp, Ri, Rx, 0, Control) ;
+status = umfpack_di_report_numeric (Numeric, Control) ;
+status = umfpack_di_report_perm (m, P, Control) ;
+status = umfpack_di_report_perm (n, Q, Control) ;
+status = umfpack_di_report_symbolic (Symbolic, Control) ;
+status = umfpack_di_report_triplet (m, n, nz, Ti, Tj, Tx, Control) ;
+status = umfpack_di_report_vector (n, X, Control) ;
+\end{verbatim}
+}
+
+
+
+
+
+
+%-------------------------------------------------------------------------------
+\subsection{Primary routines: complex/{\tt int}}
+%-------------------------------------------------------------------------------
+
+{\footnotesize
+\begin{verbatim}
+double Az [nz], Xx [n], Xz [n], Bx [n], Bz [n] ;
+
+status = umfpack_zi_symbolic (m, n, Ap, Ai, Ax, Az, &Symbolic, Control, Info) ;
+status = umfpack_zi_numeric (Ap, Ai, Ax, Az, Symbolic, &Numeric, Control, Info) ;
+status = umfpack_zi_solve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric, Control, Info) ;
+umfpack_zi_free_symbolic (&Symbolic) ;
+umfpack_zi_free_numeric (&Numeric) ;
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\subsection{Alternative routines: complex/{\tt int}}
+%-------------------------------------------------------------------------------
+
+{\footnotesize
+\begin{verbatim}
+double Wz [10*n] ;
+
+umfpack_zi_defaults (Control) ;
+status = umfpack_zi_qsymbolic (m, n, Ap, Ai, Ax, Az, Qinit, &Symbolic, Control, Info) ;
+status = umfpack_zi_wsolve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric, Control, Info, Wi, Wz) ;
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\subsection{Matrix manipulation routines: complex/{\tt int}}
+%-------------------------------------------------------------------------------
+
+{\footnotesize
+\begin{verbatim}
+double Tz [nz], Rz [nz], Yx [m], Yz [m], Zx [m], Zz [m] ;
+
+status = umfpack_zi_col_to_triplet (n, Ap, Tj) ;
+status = umfpack_zi_triplet_to_col (m, n, nz, Ti, Tj, Tx, Tz, Ap, Ai, Ax, Az, Map) ;
+status = umfpack_zi_transpose (m, n, Ap, Ai, Ax, Az, P, Q, Rp, Ri, Rx, Rz, 1) ;
+status = umfpack_zi_transpose (m, n, Ap, Ai, Ax, Az, P, Q, Rp, Ri, Rx, Rz, 0) ;
+status = umfpack_zi_scale (Yx, Yz, Zx, Zz, Numeric) ;
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\subsection{Getting the contents of opaque objects: complex/{\tt int}}
+%-------------------------------------------------------------------------------
+
+{\footnotesize
+\begin{verbatim}
+double Lz [lnz], Uz [unz], Dx [min (m,n)], Dz [min (m,n)] ;
+
+status = umfpack_zi_get_lunz (&lnz, &unz, &m, &n, &nz_udiag, Numeric) ;
+status = umfpack_zi_get_numeric (Lp, Lj, Lx, Lz, Up, Ui, Ux, Uz, P, Q, Dx, Dz,
+ &do_recip, Rs, Numeric) ;
+status = umfpack_zi_get_symbolic (&m, &n, &n1, &nz, &nfr, &nchains, P1, Q1,
+ Front_npivcol, Front_parent, Front_1strow, Front_leftmostdesc,
+ Chain_start, Chain_maxrows, Chain_maxcols, Symbolic) ;
+status = umfpack_zi_load_numeric (&Numeric, filename) ;
+status = umfpack_zi_save_numeric (Numeric, filename) ;
+status = umfpack_zi_load_symbolic (&Symbolic, filename) ;
+status = umfpack_zi_save_symbolic (Symbolic, filename) ;
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\subsection{Reporting routines: complex/{\tt int}}
+%-------------------------------------------------------------------------------
+
+{\footnotesize
+\begin{verbatim}
+
+umfpack_zi_report_status (Control, status) ;
+umfpack_zi_report_control (Control) ;
+umfpack_zi_report_info (Control, Info) ;
+status = umfpack_zi_report_matrix (m, n, Ap, Ai, Ax, Az, 1, Control) ;
+status = umfpack_zi_report_matrix (m, n, Rp, Ri, Rx, Rz, 0, Control) ;
+status = umfpack_zi_report_numeric (Numeric, Control) ;
+status = umfpack_zi_report_perm (m, P, Control) ;
+status = umfpack_zi_report_perm (n, Q, Control) ;
+status = umfpack_zi_report_symbolic (Symbolic, Control) ;
+status = umfpack_zi_report_triplet (m, n, nz, Ti, Tj, Tx, Tz, Control) ;
+status = umfpack_zi_report_vector (n, Xx, Xz, Control) ;
+\end{verbatim}
+}
+
+
+
+
+
+%-------------------------------------------------------------------------------
+\section{Synopsis of utility routines}
+%-------------------------------------------------------------------------------
+
+These routines are the same in all four versions of UMFPACK.
+
+{\footnotesize
+\begin{verbatim}
+double t, s [2] ;
+
+t = umfpack_timer ( ) ;
+umfpack_tic (s) ;
+umfpack_toc (s) ;
+
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\section{Synopsis of AMD ordering routines}
+%-------------------------------------------------------------------------------
+
+UMFPACK makes use of the AMD ordering package for its symmetric ordering
+strategy. You may also use these four user-callable routines in your own C
+programs. You need to include the {\tt amd.h} file only if you make direct
+calls to the AMD routines themselves. The {\tt int} versions are summarized
+below; {\tt long} versions are also available. Refer to the AMD User Guide
+for more information, or to the file {\tt amd.h} which documents these routines.
+
+{\footnotesize
+\begin{verbatim}
+#include "amd.h"
+double amd_control [AMD_CONTROL], amd_info [AMD_INFO] ;
+
+amd_defaults (amd_control) ;
+status = amd_order (n, Ap, Ai, P, amd_control, amd_info) ;
+amd_control (amd_control) ;
+amd_info (amd_info) ;
+
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\section{Using UMFPACK in a Fortran program}
+%-------------------------------------------------------------------------------
+
+UMFPACK v4.3 includes a basic Fortran 77 interface to some of the C-callable
+UMFPACK routines.
+Since interfacing C and Fortran programs is not portable, this interface might
+not work with all C and Fortran compilers. Refer to Section~\ref{Install} for
+more details. The following Fortran routines are provided.
+The list includes the C-callable routines that the Fortran interface
+routine calls. Refer to the corresponding C routines in Section~\ref{C} for
+more details on what the Fortran routine does.
+
+\begin{itemize}
+\item {\tt umf4def}: sets the default control parameters
+ ({\tt umfpack\_di\_defaults}).
+
+\item {\tt umf4sym}: pre-ordering and symbolic factorization
+ ({\tt umfpack\_di\_symbolic}).
+
+\item {\tt umf4num}: numeric factorization
+ ({\tt umfpack\_di\_numeric}).
+
+\item {\tt umf4solr}: solve a linear system with iterative refinement
+ ({\tt umfpack\_di\_solve}).
+
+\item {\tt umf4sol}: solve a linear system without iterative refinement
+ ({\tt umfpack\_di\_solve}). Sets {\tt Control [UMFPACK\_IRSTEP]}
+ to zero, and does not require the matrix $\m{A}$.
+
+\item {\tt umf4scal}: scales a vector using UMFPACK's scale factors
+ ({\tt umfpack\_di\_scale}).
+
+\item {\tt umf4fnum}: free the {\tt Numeric} object
+ ({\tt umfpack\_di\_free\_numeric}).
+
+\item {\tt umf4fsym}: free the {\tt Symbolic} object
+ ({\tt umfpack\_di\_free\_symbolic}).
+
+\item {\tt umf4pcon}: prints the control parameters
+ ({\tt umfpack\_di\_report\_control}).
+
+\item {\tt umf4pinf}: print statistics
+ ({\tt umfpack\_di\_report\_info}).
+
+\item {\tt umf4snum}: save the {\tt Numeric} object to a file
+ ({\tt umfpack\_di\_save\_numeric}).
+
+\item {\tt umf4ssym}: save the {\tt Symbolic} object to a file
+ ({\tt umfpack\_di\_save\_symbolic}).
+
+\item {\tt umf4lnum}: load the {\tt Numeric} object from a file
+ ({\tt umfpack\_di\_load\_numeric}).
+
+\item {\tt umf4lsym}: load the {\tt Symbolic} object from a file
+ ({\tt umfpack\_di\_load\_symbolic}).
+\end{itemize}
+
+The matrix $\m{A}$ is passed to UMFPACK in compressed column form, with 0-based
+indices. In Fortran, for an {\tt m}-by-{\tt n} matrix $\m{A}$ with {\tt nz}
+entries, the row indices of the first column (column 1) are in
+{\tt Ai (Ap(1)+1} \ldots {\tt Ap(2))}, with values in
+{\tt Ax (Ap(1)+1} \ldots {\tt Ap(2))}. The last column (column {\tt n}) is in
+{\tt Ai (Ap(n)+1} \ldots {\tt Ap(n+1))} and
+{\tt Ax (Ap(n)+1} \ldots {\tt Ap(n+1))}.
+The number of entries in the matrix is thus {\tt nz = Ap (n+1)}.
+The row indices in {\tt Ai} are in the range 0 to {\tt m}-1. They must be
+sorted, with no duplicate entries allowed. None of the UMFPACK routines
+modify the input matrix $\m{A}$.
+The following definitions apply for the Fortran routines:
+
+{\footnotesize
+\begin{verbatim}
+ integer m, n, Ap (n+1), Ai (nz), symbolic, numeric, filenum, status
+ double precision Ax (nz), control (20), info (90), x (n), b (n)
+\end{verbatim}
+}
+
+UMFPACK's status is returned in either a {\tt status} argument, or in
+{\tt info (1)}.
+It is zero if UMFPACK was successful, 1 if the matrix is singular (this is a
+warning, not an error), and negative if an error occurred.
+Section~\ref{error_codes} summarizes the possible values of {\tt status}
+and {\tt info (1)}.
+See Table~\ref{sys} for a list of the values of the {\tt sys} argument.
+See Table~\ref{control} for a list of the control parameters (the
+Fortran usage is the same as the MATLAB usage for this array).
+
+For the {\tt Numeric} and {\tt Symbolic} handles, it is probably safe to
+assume that a Fortran {\tt integer} is sufficient to store a C pointer. If
+that does not work, try defining {\tt numeric} and {\tt symbolic} in your
+Fortran program as integer arrays of size 2. You will need to define them
+as {\tt integer*8} if you compile UMFPACK in the 64-bit mode.
+
+To avoid passing strings between C and Fortran in the load/save routines,
+a file number is passed instead, and the C interface constructs a file name
+(if {\tt filenum} is 42, the {\tt Numeric} file name is {\tt n42.umf}, and
+the {\tt Symbolic} file name is {\tt s42.umf}).
+
+The following is a summary of the calling sequence of each Fortran
+interface routine. An example of their use is in the {\tt Demo/umf4hb.f}
+file. That routine also includes an example of how to convert a 1-based
+sparse matrix into 0-based form. For more details on the arguments of each
+routine, refer to the arguments of the same name in the corresponding
+C-callable routine, in Sections~\ref{Primary}~through~\ref{Utility}.
+The only exception is the {\tt control} argument of {\tt umf4sol},
+which sets {\tt control (8)} to zero to disable iterative refinement.
+Note that the solve routines do not overwrite {\tt b} with the solution,
+but return their solution in a different array, {\tt x}.
+
+{\footnotesize
+\begin{verbatim}
+ call umf4def (control)
+ call umf4sym (m, n, Ap, Ai, Ax, symbolic, control, info)
+ call umf4num (Ap, Ai, Ax, symbolic, numeric, control, info)
+ call umf4solr (sys, Ap, Ai, Ax, x, b, numeric, control, info)
+ call umf4sol (sys, x, b, numeric, control, info)
+ call umf4scal (x, b, numeric, status)
+ call umf4fnum (numeric)
+ call umf4fsym (symbolic)
+ call umf4pcon (control)
+ call umf4pinf (control)
+ call umf4snum (numeric, filenum, status)
+ call umf4ssym (symbolic, filenum, status)
+ call umf4lnum (numeric, filenum, status)
+ call umf4lsym (symbolic, filenum, status)
+\end{verbatim}
+}
+
+Access to the complex routines in UMFPACK is provided by the interface
+routines in {\tt umf4\_f77zwrapper.c}. The following is a synopsis
+of each routine. All the arguments are the same as the real versions,
+except {\tt Az}, {\tt xz}, and {\tt bz} are the imaginary parts of
+the matrix, solution, and right-hand-side, respectively. The
+{\tt Ax}, {\tt x}, and {\tt b} are the real parts.
+
+{\footnotesize
+\begin{verbatim}
+ call umf4zdef (control)
+ call umf4zsym (m, n, Ap, Ai, Ax, Az, symbolic, control, info)
+ call umf4znum (Ap, Ai, Ax, Az, symbolic, numeric, control, info)
+ call umf4zsolr (sys, Ap, Ai, Ax, Az, x, xz, b, bz, numeric, control, info)
+ call umf4zsol (sys, x, xz, b, bz, numeric, control, info)
+ call umf4zscal (x, xz, b, bz, numeric, status)
+ call umf4zfnum (numeric)
+ call umf4zfsym (symbolic)
+ call umf4zpcon (control)
+ call umf4zpinf (control)
+ call umf4zsnum (numeric, filenum, status)
+ call umf4zssym (symbolic, filenum, status)
+ call umf4zlnum (numeric, filenum, status)
+ call umf4zlsym (symbolic, filenum, status)
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\section{Installing the C library}
+\label{Install}
+%-------------------------------------------------------------------------------
+
+The following discussion assumes you have the {\tt make} program, either in
+Unix, or in Windows with Cygwin\footnote{www.cygwin.com}.
+You can skip this section and go to next one if all you want to use is
+the UMFPACK and AMD mexFunctions in MATLAB.
+
+You will need to install both UMFPACK v4.3 and AMD v1.1 (or AMD v1.0) to use UMFPACK.
+The {\tt UMFPACK} and {\tt AMD} subdirectories must be placed side-by-side
+within the same directory. AMD is a stand-alone package that
+is required by UMFPACK. UMFPACK can be compiled without the
+BLAS \cite{DaydeDuff99,ACM679a,ATLAS,GotoVandeGeijn02},
+but your performance will be much less than what it should be.
+
+System-dependent configurations are in the {\tt AMD/Make}
+and {\tt UMFPACK/Make} directories (the \newline
+{\tt UMFPACK/Make} directory is actually
+just a symbolic link to {\tt AMD/Make}\footnote{Windows might not extract
+the symbolic link {\tt UMFPACK/Make} correctly. If it doesn't, simply
+create the {\tt UMFPACK/Make} folder by copying it from {\tt AMD/Make}.}).
+You can edit the {\tt Make.include}
+files in either of those directories to customize the compilation. The default
+settings will work on most systems, except that UMFPACK will be compiled so
+that it does not use the BLAS. Sample configuration files are provided
+for Linux, Sun Solaris, SGI IRIX, IBM AIX, and the DEC/Compaq Alpha.
+
+To compile and install both packages,
+go to the {\tt UMFPACK} directory and type {\tt make}. This will compile the
+libraries ({\tt AMD/Lib/libamd.a} and {\tt UMFPACK/Lib/libumfpack.a}).
+A demo of the AMD ordering routine will be compiled and tested in
+the {\tt AMD/Demo} directory, and five demo programs will then be
+compiled and tested in the {\tt UMFPACK/Demo} directory.
+The outputs of these demo programs will then be compared with output
+files in the distribution. Expect to see a few differences, such as
+residual norms, compile-time control settings, and perhaps memory usage
+differences. The AMD and UMFPACK mexFunctions for
+use in MATLAB will also be compiled. If you do not have MATLAB 6.0 or
+later, type {\tt make lib} instead.
+
+If you have the GNU version of {\tt make}, the {\tt Source/GNUmakefile} and
+{\tt MATLAB/GNUmakefile} files are used. These are much more concise than
+what the ``old'' version of {\tt make} can handle. If you do not have
+GNU {\tt make}, the {\tt Source/Makefile} and {\tt MATLAB/Makefile} files
+are used instead. Each UMFPACK source file is compiled into four
+versions ({\tt double} / complex, and {\tt int} / {\tt long}). A proper
+old-style {\tt Makefile} is cumbersome in this case, so these two
+{\tt Makefile}'s have been constructed by brute force. They ignore
+dependencies, and simply compile everything. I highly recommend using GNU
+{\tt make} if you wish to modify UMFPACK.
+
+If you compile UMFPACK and AMD and then later change the {\tt Make.include}
+file or your system-specific configuration file such as {\tt Make.linux},
+then you should type {\tt make purge} and then {\tt make} to recompile.
+
+Here are the various parameters that you can control in your
+{\tt Make.include} file:
+
+\begin{itemize}
+\item {\tt CC = } your C compiler, such as {\tt cc}.
+\item {\tt RANLIB = } your system's {\tt ranlib} program, if needed.
+\item {\tt CFLAGS = } optimization flags, such as {\tt -O}.
+ Add {\tt -DLP64} if you are compiling in 64-bit mode
+ (32 bit {\tt int}'s, 64 bit {\tt long}'s, and 64 bit pointers).
+\item {\tt CONFIG = } configuration settings for the BLAS, memory allocation
+ routines, and timing routines.
+\item {\tt LIB = } your libraries, such as {\tt -lm} or {\tt -lblas}.
+\item {\tt RM =} the command to delete a file.
+\item {\tt MV =} the command to rename a file.
+\item {\tt MEX =} the command to compile a MATLAB mexFunction.
+ If you are using MATLAB 5, you need to add {\tt -DNBLAS} and
+ {\tt -DNUTIL} to this command. An example is provided in
+ the {\tt Make/Make.include} file.
+\item {\tt F77 =} the command to compile a Fortran program (optional).
+\item {\tt F77FLAGS =} the Fortran compiler flags (optional).
+\item {\tt F77LIB =} the Fortran libraries (optional).
+\end{itemize}
+
+The {\tt CONFIG} string can include combinations of the following;
+most deal with how the BLAS are called:
+\begin{itemize}
+\item {\tt -DNBLAS} if you do not have any BLAS at all.
+\item {\tt -DCBLAS} if you have the C-BLAS \cite{ATLAS}.
+\item {\tt -DNSUNPERF} if you are on Solaris but do not have the Sun
+ Performance Library (for the BLAS).
+\item {\tt -DNSCSL} if you on SGI IRIX but do not have the SCSL BLAS library.
+\item {\tt -DLONGBLAS} if your BLAS can take {\tt long} integer input
+ arguments. If not defined, then the {\tt umfpack\_*l\_*} versions of
+ UMFPACK that use {\tt long} integers do not call the BLAS.
+ This flag is set internally when using the Sun Performance BLAS
+ or SGI's SCSL BLAS (both have 64-bit versions of the BLAS).
+\item Options for controlling how C calls the Fortran BLAS:
+ {\tt -DBLAS\_BY\_VALUE}, {\tt -DBLAS\_NO\_UNDERSCORE},
+ and {\tt -DBLAS\_CHAR\_ARG}. These are set automatically for Windows,
+ Sun Solaris, SGI Irix, Red Hat Linux, Compaq Alpha, and
+ AIX (the IBM RS 6000). They are ignored if you are using
+ the C-BLAS interface to the BLAS.
+\item {\tt -DGETRUSAGE} if you have the {\tt getrusage} function.
+\item {\tt -DNUTIL} if you wish to compile the MATLAB-callable
+ UMFPACK mexFunction with the {\tt mxMalloc}, {\tt mxRealloc}
+ and {\tt mxFree} routines, instead of the undocumented (but
+ superior) {\tt utMalloc}, {\tt utRealloc}, and {\tt utFree}
+ routines. The default is to use the {\tt ut*} routines on
+ Unix, and the {\tt mx*} routines on Windows.
+\item {\tt -DNPOSIX} if you do not have the POSIX-compliant
+ {\tt sysconf} and {\tt times} routines used by
+ {\tt umfpack\_tic} and {\tt umfpack\_toc}.
+\item {\tt -DNRECIPROCAL} controls a trade-off between speed and accuracy.
+ If defined (or if the pivot value itself is less than $10^{-12}$),
+ then the pivot column is divided by the pivot value during numeric
+ factorization. Otherwise, it is multiplied by the reciprocal of the
+ pivot, which is faster but can be less accurate. The default is
+ to multiply by the reciprocal unless the pivot value is small.
+ This option also modifies how the rows of the matrix $\m{A}$ are
+ scaled. If {\tt -DNRECIPROCAL} is defined (or if any scale factor is
+ less than $10^{-12}$), entries in the rows of $\m{A}$ are divided
+ by the scale factors. Otherwise, they are multiplied by the reciprocal.
+ When compiling the complex routines with the GNU {\tt gcc} compiler, the
+ pivot column is always divided by the pivot entry, because of a
+ numerical accuracy issue encountered with {\tt gcc} version 3.2 with a
+ few complex matrices on a Pentium 4M (running Linux). You can still
+ use {\tt -DNRECIPROCAL} to control how the scale factors
+ for the rows of $\m{A}$ are applied.
+\item {\tt -DNO\_DIVIDE\_BY\_ZERO} controls how UMFPACK treats zeros
+ on the diagonal of $\m{U}$, for a singular matrix $\m{A}$.
+ If defined, then no division by
+ zero is performed (a zero entry on the diagonal of $\m{U}$ is
+ treated as if it were equal to one). By default,
+ UMFPACK will divide by zero.
+\item {\tt -DNO\_TIMER} controls whether or not timing routines
+ are to be called. If defined, no timers are used.
+ Timers are included by default.
+\end{itemize}
+
+If a Fortran BLAS package is used you may see compiler warnings. The BLAS
+routines
+{\tt dgemm}, {\tt dgemv}, {\tt dger}, {\tt dtrsm}, {\tt dtrsv}, {\tt dscal}
+and their corresponding complex versions are used.
+Header files are not provided for the Fortran
+BLAS. You may safely ignore all of these warnings.
+
+I highly recommend the recent BLAS by Goto and van de Geijn
+\cite{GotoVandeGeijn02}. Using this BLAS increased the performance
+of UMFPACK by up to 50\% on a Dell Latitude C840 laptop (2GHz Pentium 4M,
+512K L2 cache, 1GB main memory). The peak performance of
+{\tt umfpack\_di\_numeric} with Goto and van de Geijn's BLAS is 1.6 Gflops
+on this computer. In MATLAB, the peak performance of UMFPACK on
+a dense matrix (stored in sparse format) is 900 Mflops, as compared to
+1 Gflop for {\tt x = A}$\backslash${\tt b}
+when {\tt A} is stored as a regular full matrix.
+
+When you compile your program that uses the C-callable UMFPACK library,
+you need to link your program with both libraries
+({\tt UMFPACK/Lib/libumfpack.a} and {\tt AMD/Lib/libamd.a})
+and you need to tell your compiler to look in the
+directories {\tt UMFPACK/Include} and {\tt AMD/Include} for include
+files. See {\tt UMFPACK/Demo/Makefile} for an example.
+You do not need to directly include any AMD include files in your
+program, unless you directly call AMD routines. You only need the
+\begin{verbatim}
+#include "umfpack.h"
+\end{verbatim}
+statement, as described in Section~\ref{Synopsis}.
+
+If you would like to compile both 32-bit and 64-bit versions of the libraries,
+you will need to do it in two steps. Modify your {\tt Make/Make.<arch>}
+file, and select the 32-bit option. Type {\tt make} in the {\tt UMFPACK}
+directory, which creates the {\tt UMFPACK/Lib/libumfpack.a} and
+{\tt AMD/Lib/libamd.a} libraries. Rename those two files. Edit your
+{\tt Make/Make.<arch>} and select the 64-bit option. Type {\tt make purge},
+and then {\tt make}, and you will create the 64-bit libraries.
+You can use the same {\tt umfpack.h} include file for both 32-bit and
+64-bit versions. Simply link your program with the appropriate 32-bit
+or 64-bit compiled version of the UMFPACK and AMD libraries.
+
+Type {\tt make hb} in the {\tt UMFPACK/Demo/HB} directory
+to compile and run a C program that reads in and factorizes
+Harwell/Boeing matrices. Note that this uses a stand-alone Fortran
+program to read in the Fortran-formatted Harwell/Boeing matrices and
+write them to a file which can be read by a C program.
+
+%-------------------------------------------------------------------------------
+\section{Installing the MATLAB interface}
+%-------------------------------------------------------------------------------
+
+If all you want to do is use the UMFPACK mexFunction in MATLAB, you can skip
+the use of the {\tt make} command described above. Simply type
+{\tt umfpack\_make} in MATLAB while in the {\tt UMFPACK/MATLAB} directory.
+You can also type {\tt amd\_make} in the {\tt AMD/MATLAB} directory
+to compile the stand-alone AMD mexFunction (this is not required to
+compile the UMFPACK mexFunction). This works on any computer with MATLAB,
+including Windows. This method of creating the UMFPACK mexFunction
+has been tested with MATLAB 5.3, 6.1, and 6.5.
+
+You will be prompted to select several configuration options, including
+whether or not to use the BLAS.
+MATLAB 5.3 (or earlier) does not include the BLAS, so you either have to
+compile UMFPACK without the BLAS (UMFPACK will be slow), or modify your
+{\tt <matlab>/bin/mexopts.sh} by adding your BLAS library
+to the {\tt CLIBS} string,
+where {\tt <matlab>} is the directory in which MATLAB is installed.
+
+If you are using Windows and the {\tt lcc} compiler bundled with
+MATLAB 6.1, then you may need to copy the
+{\tt UMFPACK}$\backslash${\tt MATLAB}$\backslash${\tt lcc\_lib}$\backslash${\tt libmwlapack.lib}
+file into the
+{\tt <matlab>}$\backslash${\tt extern}$\backslash${\tt lib}$\backslash${\tt win32}$\backslash${\tt lcc}$\backslash$
+directory.
+Next, type {\tt mex -setup}
+at the MATLAB prompt, and ask MATLAB to select the {\tt lcc} compiler.
+MATLAB 6.1 has built-in BLAS, but in that version of MATLAB the BLAS
+cannot be accessed by a mexFunction compiled by {\tt lcc} without first copying
+this file to the location listed above.
+If you have MATLAB 6.5 or later, you can probably skip this step.
+
+%-------------------------------------------------------------------------------
+\section{Installing the Fortran interface}
+%-------------------------------------------------------------------------------
+
+Once the 32-bit C-callable UMFPACK library is compiled, you can also compile
+the Fortran interface, by typing {\tt make fortran}. This will create
+the {\tt umf4hb} program, test it, and compare the output with the
+file {\tt umf4hb.out} in the distribution.
+If you compiled UMFPACK in 64-bit mode, you need to use {\tt make fortran64}
+instead, which compiles the {\tt umf4hb64} program and compares its output
+with the file {\tt umf4hb64.out}.
+Refer to the comments in the {\tt Demo/umf4\_f77wrapper.c} file
+for more details.
+
+This interface is {\bf highly} non-portable, since it depends
+on how C and Fortran are interfaced.
+Because of this issue, the interface is included in the {\tt Demo} directory,
+and not as a primary part of the UMFPACK library. The interface routines are
+not included in the compiled {\tt UMFPACK/Lib/libumfpack.a} library, but left
+as stand-alone compiled files ({\tt umf4\_f77wrapper.o} and
+{\tt umf4\_f77wrapper64.o} in the {\tt Demo} directory).
+You may need to modify the interface routines in the file
+{\tt umf4\_f77wrapper.c} if you are using compilers for which this interface
+has not been tested.
+
+%-------------------------------------------------------------------------------
+\section{Known Issues}
+%-------------------------------------------------------------------------------
+
+The Microsoft C or C++ compilers on a Pentium badly break the IEEE 754 standard,
+and do not treat NaN's properly. According to IEEE 754, the expression
+{\tt (x != x)} is supposed to be true if and only if {\tt x} is NaN. For
+non-compliant compilers in Windows that expression is always false, and another
+test must be used: {\tt (x < x)} is true if and only if {\tt x}
+is NaN. For compliant compilers, {\tt (x < x)} is always false, for any
+value of {\tt x} (including NaN).
+To cover both cases, UMFPACK when running under Microsoft Windows
+defines the following macro, which is true if and only if {\tt x} is NaN,
+regardless of whether your compiler is compliant or not:
+
+\begin{verbatim}
+#define SCALAR_IS_NAN(x) (((x) != (x)) || ((x) < (x)))
+\end{verbatim}
+
+If your compiler breaks this test, then UMFPACK will fail catastrophically
+if it encounters a NaN. You will not just see NaN's in your output; UMFPACK
+will probably crash with a segmentation fault. In that case, you might try to
+see if the common (but non-ANSI C) routine {\tt isnan} is available, and modify
+the macro {\tt SCALAR\_IS\_NAN} in {\tt umf\_version.h} accordingly. The
+simpler (and IEEE 754-compliant) test {\tt (x != x)} is always true with Linux
+on a PC, and on every Unix compiler I have tested.
+
+Some compilers will complain about the Fortran BLAS being defined implicitly.
+C prototypes for the BLAS are not used, except the C-BLAS. Some compilers
+will complain about unrecognized {\tt \#pragma}'s. You may safely ignore
+all of these warnings.
+
+%-------------------------------------------------------------------------------
+\section{Future work}
+\label{Future}
+%-------------------------------------------------------------------------------
+
+Here are a few features that are not in UMFPACK Version 4.3, in no particular
+order. They may appear in a future release of UMFPACK. If you are interested,
+let me know and I could consider including them:
+
+\begin{enumerate}
+
+\item Future versions may have different default {\tt Control} parameters.
+ Future versions may return more statistics in the {\tt Info} array, and
+ they may use more entries in the {\tt Control} array.
+ These two arrays will probably become larger, since there are very few
+ unused entries. If they change in size, the constants
+ {\tt UMFPACK\_CONTROL} and {\tt UMFPACK\_INFO} defined in {\tt umfpack.h}
+ will be changed to reflect their new size. Your C program should use
+ these constants when declaring the size of these two arrays. Do not
+ define them as {\tt Control [20]} and {\tt Info [90]}.
+
+\item Forward/back solvers for the conventional row or column-form data
+ structure for $\m{L}$ and $\m{U}$ (the output of
+ {\tt umfpack\_*\_di\_get\_numeric}). This would enable a separate
+ solver that could be used to write a MATLAB mexFunction
+ {\tt x = lu\_refine (A, b, L, U, P, Q, R)} that gives MATLAB access
+ to the iterative refinement algorithm with sparse backward error
+ analysis. It would also be easier to handle sparse right-hand-sides
+ in this data structure, and end up with good asymptotic run-time
+ in this case
+ (particularly for $\m{Lx}=\m{b}$; see \cite{GilbertPeierls88}).
+
+\item Complex absolute value computations could be
+ based on FDLIBM (see \newline
+ http://www.netlib.org/fdlibm),
+ using the {\tt hypot(x,y)} routine.
+
+\item When using iterative refinement, the residual $\m{Ax}-\m{b}$ could be
+ returned by {\tt umfpack\_solve}.
+
+\item The solve routines could handle multiple right-hand sides, and sparse
+ right-hand sides. See {\tt umfpack\_solve} for the MATLAB version
+ of this feature.
+
+\item An option to redirect the error and diagnostic output.
+
+\item Permutation to block-triangular-form \cite{Duff78a} for the C-callable
+ interface. There are two routines in the ACM Collected
+ Algorithms (529 and 575) \cite{Duff81b,Duff78b}
+ that could be translated from Fortran
+ to C and included in UMFPACK. This would result in better performance
+ for matrices from circuit simulation and
+ chemical process engineering. See {\tt umfpack\_btf.m} for the MATLAB
+ version of this feature.
+
+\item The ability to use user-provided {\tt malloc}, {\tt free}, and
+ {\tt realloc} memory allocation routines. Note that UMFPACK makes very
+ few calls to these routines. You can do this at compile-time by
+ modifying the definitions of {\tt ALLOCATE}, {\tt FREE}, and
+ {\tt REALLOCATE} in the file {\tt umf\_internal.h}. Be sure to document
+ your changes carefully when you change UMFPACK source code.
+
+\item The ability to use user-provided work arrays, so that {\tt malloc},
+ {\tt free}, and {\tt realloc} realloc are not called. The
+ {\tt umfpack\_*\_wsolve} routine is one example.
+
+\item A method that takes time proportional to the number of nonzeros in
+ $\m{A}$ to compute the symbolic factorization \cite{GilbertNgPeyton94}.
+ This would improve the performance of the symmetric and 2-by-2 strategies,
+ and the unsymmetric strategy when dense rows are present.
+ The current method takes
+ time proportional to the number of nonzeros in the upper bound of $\m{U}$.
+ The method used in UMFPACK exploits super-columns, however, so this
+ bound is rarely reached.
+
+\item The complex versions could use ANSI C99 {\tt double \_Complex} arguments,
+ and support the use of interleaved real/imaginary parts as input and output
+ arguments. The \newline
+ {\tt umfpack\_*\_report\_vector} routine is one example.
+
+\item Other basic sparse matrix operations, such as sparse matrix
+ multiplication, could be included.
+
+\item A more complete Fortran interface.
+
+\item A C++ interface.
+
+\item A parallel version using MPI. This would require a large amount
+ of effort.
+
+\end{enumerate}
+
+
+%-------------------------------------------------------------------------------
+\newpage
+\section{The primary UMFPACK routines}
+\label{Primary}
+%-------------------------------------------------------------------------------
+
+The include files are the same for all four versions of
+UMFPACK. The generic integer type is {\tt Int}, which is an {\tt int} or
+{\tt long}, depending on which version of UMFPACK you are using.
+
+\subsection{umfpack\_*\_symbolic}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_symbolic.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_numeric}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_numeric.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_solve}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_solve.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_free\_symbolic}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_free_symbolic.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_free\_numeric}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_free_numeric.h via sed
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\newpage
+\section{Alternative routines}
+\label{Alternative}
+%-------------------------------------------------------------------------------
+
+\subsection{umfpack\_*\_defaults}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_defaults.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_qsymbolic}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_qsymbolic.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_wsolve}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_wsolve.h via sed
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\newpage
+\section{Matrix manipulation routines}
+\label{Manipulate}
+%-------------------------------------------------------------------------------
+
+\subsection{umfpack\_*\_col\_to\_triplet}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_col_to_triplet.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_triplet\_to\_col}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_triplet_to_col.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_transpose}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_transpose.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_scale}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_scale.h via sed
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\newpage
+\section{Getting the contents of opaque objects}
+\label{Get}
+%-------------------------------------------------------------------------------
+
+\subsection{umfpack\_*\_get\_lunz}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_get_lunz.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_get\_numeric}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_get_numeric.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_get\_symbolic}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_get_symbolic.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_save\_numeric}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_save_numeric.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_load\_numeric}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_load_numeric.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_save\_symbolic}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_save_symbolic.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_load\_symbolic}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_load_symbolic.h via sed
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\newpage
+\section{Reporting routines}
+\label{Report}
+%-------------------------------------------------------------------------------
+
+\subsection{umfpack\_*\_report\_status}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_report_status.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_report\_control}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_report_control.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_report\_info}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_report_info.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_report\_matrix}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_report_matrix.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_report\_numeric}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_report_numeric.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_report\_perm}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_report_perm.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_report\_symbolic}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_report_symbolic.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_report\_triplet}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_report_triplet.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_*\_report\_vector}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_report_vector.h via sed
+\end{verbatim}
+}
+
+%-------------------------------------------------------------------------------
+\newpage
+\section{Utility routines}
+\label{Utility}
+%-------------------------------------------------------------------------------
+
+\subsection{umfpack\_timer}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_timer.h via sed
+\end{verbatim}
+}
+
+\newpage
+\subsection{umfpack\_tic and umfpack\_toc}
+
+{\footnotesize
+\begin{verbatim}
+INCLUDE umfpack_tictoc.h via sed
+\end{verbatim}
+}
+
+
+%-------------------------------------------------------------------------------
+\newpage
+% References
+%-------------------------------------------------------------------------------
+
+\bibliographystyle{plain}
+\bibliography{UserGuide}
+
+\end{document}
--- /dev/null
+/* ========================================================================== */
+/* === umfpack.h ============================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+/*
+ This is the umfpack.h include file, and should be included in all user code
+ that uses UMFPACK. Do not include any of the umf_* header files in user
+ code. All routines in UMFPACK starting with "umfpack_" are user-callable.
+ All other routines are prefixed "umf_XY_", (where X is d or z, and Y is
+ i or l) and are not user-callable.
+*/
+
+#ifndef UMFPACK_H
+#define UMFPACK_H
+
+/* -------------------------------------------------------------------------- */
+/* size of Info and Control arrays */
+/* -------------------------------------------------------------------------- */
+
+#define UMFPACK_INFO 90 /* these might be larger in future versions */
+#define UMFPACK_CONTROL 20
+
+/* -------------------------------------------------------------------------- */
+/* User-callable routines */
+/* -------------------------------------------------------------------------- */
+
+/* Primary routines: */
+#include "umfpack_symbolic.h"
+#include "umfpack_numeric.h"
+#include "umfpack_solve.h"
+#include "umfpack_free_symbolic.h"
+#include "umfpack_free_numeric.h"
+
+/* Alternative routines: */
+#include "umfpack_defaults.h"
+#include "umfpack_qsymbolic.h"
+#include "umfpack_wsolve.h"
+
+/* Matrix manipulation routines: */
+#include "umfpack_triplet_to_col.h"
+#include "umfpack_col_to_triplet.h"
+#include "umfpack_transpose.h"
+#include "umfpack_scale.h"
+
+/* Getting the contents of the Symbolic and Numeric opaque objects: */
+#include "umfpack_get_lunz.h"
+#include "umfpack_get_numeric.h"
+#include "umfpack_get_symbolic.h"
+#include "umfpack_save_numeric.h"
+#include "umfpack_load_numeric.h"
+#include "umfpack_save_symbolic.h"
+#include "umfpack_load_symbolic.h"
+
+/* Reporting routines (the above 14 routines print nothing): */
+#include "umfpack_report_status.h"
+#include "umfpack_report_info.h"
+#include "umfpack_report_control.h"
+#include "umfpack_report_matrix.h"
+#include "umfpack_report_triplet.h"
+#include "umfpack_report_vector.h"
+#include "umfpack_report_symbolic.h"
+#include "umfpack_report_numeric.h"
+#include "umfpack_report_perm.h"
+
+/* Utility routines: */
+#include "umfpack_timer.h"
+#include "umfpack_tictoc.h"
+
+/* -------------------------------------------------------------------------- */
+/* Version, copyright, and license */
+/* -------------------------------------------------------------------------- */
+
+#define UMFPACK_VERSION "UMFPACK V4.3 (Jan. 16, 2004)"
+
+#define UMFPACK_COPYRIGHT \
+"UMFPACK: Copyright (c) 2004 by Timothy A. Davis. All Rights Reserved.\n"
+
+#define UMFPACK_LICENSE_PART1 \
+"\nUMFPACK License:\n" \
+"\n" \
+" Your use or distribution of UMFPACK or any modified version of\n" \
+" UMFPACK implies that you agree to this License.\n" \
+"\n" \
+" THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY\n" \
+" EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.\n"
+#define UMFPACK_LICENSE_PART2 \
+"\n" \
+" Permission is hereby granted to use or copy this program, provided\n" \
+" that the Copyright, this License, and the Availability of the original\n" \
+" version is retained on all copies. User documentation of any code that\n" \
+" uses UMFPACK or any modified version of UMFPACK code must cite the\n" \
+" Copyright, this License, the Availability note, and \"Used by permission.\"\n"
+#define UMFPACK_LICENSE_PART3 \
+" Permission to modify the code and to distribute modified code is granted,\n" \
+" provided the Copyright, this License, and the Availability note are\n" \
+" retained, and a notice that the code was modified is included. This\n" \
+" software was developed with support from the National Science Foundation,\n" \
+" and is provided to you free of charge.\n" \
+"\n" \
+"Availability: http://www.cise.ufl.edu/research/sparse/umfpack\n" \
+"\n"
+
+/* -------------------------------------------------------------------------- */
+/* contents of Info */
+/* -------------------------------------------------------------------------- */
+
+/* Note that umfpack_report.m must coincide with these definitions. */
+
+/* returned by all routines that use Info: */
+#define UMFPACK_STATUS 0 /* UMFPACK_OK, or other result */
+#define UMFPACK_NROW 1 /* n_row input value */
+#define UMFPACK_NCOL 16 /* n_col input value */
+#define UMFPACK_NZ 2 /* # of entries in A */
+
+/* computed in UMFPACK_*symbolic and UMFPACK_numeric: */
+#define UMFPACK_SIZE_OF_UNIT 3 /* sizeof (Unit) */
+
+/* computed in UMFPACK_*symbolic: */
+#define UMFPACK_SIZE_OF_INT 4 /* sizeof (int) */
+#define UMFPACK_SIZE_OF_LONG 5 /* sizeof (long) */
+#define UMFPACK_SIZE_OF_POINTER 6 /* sizeof (void *) */
+#define UMFPACK_SIZE_OF_ENTRY 7 /* sizeof (Entry), real or complex */
+#define UMFPACK_NDENSE_ROW 8 /* number of dense rows */
+#define UMFPACK_NEMPTY_ROW 9 /* number of empty rows */
+#define UMFPACK_NDENSE_COL 10 /* number of dense rows */
+#define UMFPACK_NEMPTY_COL 11 /* number of empty rows */
+#define UMFPACK_SYMBOLIC_DEFRAG 12 /* # of memory compactions */
+#define UMFPACK_SYMBOLIC_PEAK_MEMORY 13 /* memory used by symbolic analysis */
+#define UMFPACK_SYMBOLIC_SIZE 14 /* size of Symbolic object, in Units */
+#define UMFPACK_SYMBOLIC_TIME 15 /* time (sec.) for symbolic analysis */
+#define UMFPACK_SYMBOLIC_WALLTIME 17 /* wall clock time for sym. analysis */
+#define UMFPACK_STRATEGY_USED 18 /* strategy used: sym, unsym, 2by2 */
+#define UMFPACK_ORDERING_USED 19 /* ordering used: colamd, amd, given */
+#define UMFPACK_QFIXED 31 /* whether Q is fixed or refined */
+#define UMFPACK_DIAG_PREFERRED 32 /* whether diagonal pivoting attempted*/
+#define UMFPACK_PATTERN_SYMMETRY 33 /* symmetry of pattern of S */
+#define UMFPACK_NZ_A_PLUS_AT 34 /* nnz (S+S'), excl. diagonal */
+#define UMFPACK_NZDIAG 35 /* nnz (diag (S)) */
+
+/* AMD statistics, computed in UMFPACK_*symbolic: */
+#define UMFPACK_SYMMETRIC_LUNZ 36 /* nz in L+U, if AMD ordering used */
+#define UMFPACK_SYMMETRIC_FLOPS 37 /* flops for LU, if AMD ordering used */
+#define UMFPACK_SYMMETRIC_NDENSE 38 /* # of "dense" rows/cols in S+S' */
+#define UMFPACK_SYMMETRIC_DMAX 39 /* max nz in cols of L, for AMD */
+
+/* statistics for 2-by-2 strategy */
+#define UMFPACK_2BY2_NWEAK 51 /* number of weak diagonal entries*/
+#define UMFPACK_2BY2_UNMATCHED 52 /* # of weak diagonals not matched*/
+#define UMFPACK_2BY2_PATTERN_SYMMETRY 53 /* symmetry of pattern of P*S */
+#define UMFPACK_2BY2_NZ_PA_PLUS_PAT 54 /* nz in PS+(PS)' */
+#define UMFPACK_2BY2_NZDIAG 55 /* nz on diagonal of PS+(PS)' */
+
+/* statistcs for singleton pruning */
+#define UMFPACK_COL_SINGLETONS 56
+#define UMFPACK_ROW_SINGLETONS 57
+#define UMFPACK_N2 58
+#define UMFPACK_S_SYMMETRIC 59
+
+/* estimates computed in UMFPACK_*symbolic: */
+#define UMFPACK_NUMERIC_SIZE_ESTIMATE 20 /* final size of Numeric->Memory */
+#define UMFPACK_PEAK_MEMORY_ESTIMATE 21 /* for symbolic & numeric */
+#define UMFPACK_FLOPS_ESTIMATE 22 /* flop count */
+#define UMFPACK_LNZ_ESTIMATE 23 /* nz in L, incl. diagonal */
+#define UMFPACK_UNZ_ESTIMATE 24 /* nz in U, incl. diagonal */
+#define UMFPACK_VARIABLE_INIT_ESTIMATE 25 /* initial size of Numeric->Memory*/
+#define UMFPACK_VARIABLE_PEAK_ESTIMATE 26 /* peak size of Numeric->Memory */
+#define UMFPACK_VARIABLE_FINAL_ESTIMATE 27 /* final size of Numeric->Memory */
+#define UMFPACK_MAX_FRONT_SIZE_ESTIMATE 28 /* max frontal matrix size */
+#define UMFPACK_MAX_FRONT_NROWS_ESTIMATE 29 /* max # rows in any front */
+#define UMFPACK_MAX_FRONT_NCOLS_ESTIMATE 30 /* max # columns in any front */
+
+/* exact values, (estimates shown above) computed in UMFPACK_numeric: */
+#define UMFPACK_NUMERIC_SIZE 40 /* final size of Numeric->Memory */
+#define UMFPACK_PEAK_MEMORY 41 /* for symbolic & numeric */
+#define UMFPACK_FLOPS 42 /* flop count */
+#define UMFPACK_LNZ 43 /* nz in L, incl. diagonal */
+#define UMFPACK_UNZ 44 /* nz in U, incl. diagonal */
+#define UMFPACK_VARIABLE_INIT 45 /* initial size of Numeric->Memory*/
+#define UMFPACK_VARIABLE_PEAK 46 /* peak size of Numeric->Memory */
+#define UMFPACK_VARIABLE_FINAL 47 /* final size of Numeric->Memory */
+#define UMFPACK_MAX_FRONT_SIZE 48 /* max frontal matrix size */
+#define UMFPACK_MAX_FRONT_NROWS 49 /* max # rows in any front */
+#define UMFPACK_MAX_FRONT_NCOLS 50 /* max # columns in any front */
+
+/* computed in UMFPACK_numeric: */
+#define UMFPACK_NUMERIC_DEFRAG 60 /* # of garbage collections */
+#define UMFPACK_NUMERIC_REALLOC 61 /* # of memory reallocations */
+#define UMFPACK_NUMERIC_COSTLY_REALLOC 62 /* # of costlly memory realloc's */
+#define UMFPACK_COMPRESSED_PATTERN 63 /* # of integers in LU pattern */
+#define UMFPACK_LU_ENTRIES 64 /* # of reals in LU factors */
+#define UMFPACK_NUMERIC_TIME 65 /* numeric factorization time */
+#define UMFPACK_UDIAG_NZ 66 /* nz on diagonal of U */
+#define UMFPACK_RCOND 67 /* est. reciprocal condition # */
+#define UMFPACK_WAS_SCALED 68 /* none, max row, or sum row */
+#define UMFPACK_RSMIN 69 /* min (max row) or min (sum row) */
+#define UMFPACK_RSMAX 70 /* max (max row) or max (sum row) */
+#define UMFPACK_UMIN 71 /* min abs diagonal entry of U */
+#define UMFPACK_UMAX 72 /* max abs diagonal entry of U */
+#define UMFPACK_ALLOC_INIT_USED 73 /* alloc_init parameter used */
+#define UMFPACK_FORCED_UPDATES 74 /* # of forced updates */
+#define UMFPACK_NUMERIC_WALLTIME 75 /* numeric wall clock time */
+#define UMFPACK_NOFF_DIAG 76 /* number of off-diagonal pivots */
+
+#define UMFPACK_ALL_LNZ 77 /* nz in L, if no dropped entries */
+#define UMFPACK_ALL_UNZ 78 /* nz in U, if no dropped entries */
+#define UMFPACK_NZDROPPED 79 /* # of dropped small entries */
+
+/* computed in UMFPACK_solve: */
+#define UMFPACK_IR_TAKEN 80 /* # of iterative refinement steps taken */
+#define UMFPACK_IR_ATTEMPTED 81 /* # of iter. refinement steps attempted */
+#define UMFPACK_OMEGA1 82 /* omega1, sparse backward error estimate */
+#define UMFPACK_OMEGA2 83 /* omega2, sparse backward error estimate */
+#define UMFPACK_SOLVE_FLOPS 84 /* flop count for solve */
+#define UMFPACK_SOLVE_TIME 85 /* solve time (seconds) */
+#define UMFPACK_SOLVE_WALLTIME 86 /* solve time (wall clock, seconds) */
+
+/* Info [87, 88, 89] unused */
+
+/* Unused parts of Info may be used in future versions of UMFPACK. */
+
+/* -------------------------------------------------------------------------- */
+
+/* Info [UMFPACK_ORDERING_USED] is one of the following: */
+#define UMFPACK_ORDERING_COLAMD 0 /* COLAMD(A) */
+#define UMFPACK_ORDERING_AMD 1 /* AMD(A+A') */
+#define UMFPACK_ORDERING_GIVEN 2 /* Q is provided on input */
+
+/* -------------------------------------------------------------------------- */
+/* contents of Control */
+/* -------------------------------------------------------------------------- */
+
+/* used in all UMFPACK_report_* routines: */
+#define UMFPACK_PRL 0 /* print level */
+
+/* used in UMFPACK_*symbolic only: */
+#define UMFPACK_DENSE_ROW 1 /* dense row parameter */
+#define UMFPACK_DENSE_COL 2 /* dense col parameter */
+#define UMFPACK_BLOCK_SIZE 4 /* BLAS-3 block size */
+#define UMFPACK_STRATEGY 5 /* auto, symmetric, unsym., or 2by2 */
+#define UMFPACK_2BY2_TOLERANCE 12 /* 2-by-2 pivot tolerance */
+#define UMFPACK_FIXQ 13 /* -1: no fixQ, 0: default, 1: fixQ */
+#define UMFPACK_AMD_DENSE 14 /* for AMD ordering */
+#define UMFPACK_AGGRESSIVE 19 /* whether or not to use aggressive
+ * absorption in AMD and COLAMD */
+
+/* used in UMFPACK_numeric only: */
+#define UMFPACK_PIVOT_TOLERANCE 3 /* threshold partial pivoting setting */
+#define UMFPACK_ALLOC_INIT 6 /* initial allocation ratio */
+#define UMFPACK_SYM_PIVOT_TOLERANCE 15 /* threshold, only for diag. entries */
+#define UMFPACK_SCALE 16 /* what row scaling to do */
+#define UMFPACK_FRONT_ALLOC_INIT 17 /* frontal matrix allocation ratio */
+#define UMFPACK_DROPTOL 18 /* drop tolerance for entries in L,U */
+
+/* used in UMFPACK_*solve only: */
+#define UMFPACK_IRSTEP 7 /* max # of iterative refinements */
+
+/* compile-time settings - Control [8..11] cannot be changed at run time: */
+#define UMFPACK_COMPILED_WITH_BLAS 8 /* uses the BLAS */
+#define UMFPACK_COMPILED_FOR_MATLAB 9 /* 1 if MATLAB mexFunction, etc. */
+#define UMFPACK_COMPILED_WITH_GETRUSAGE 10 /* uses getrusage timer, or not */
+#define UMFPACK_COMPILED_IN_DEBUG_MODE 11 /* debugging enabled (very slow!) */
+
+#if 0
+/* No longer unused. These parameters are now used for the new symmetric and
+ * 2-by-2 ordering strategies. See 5, 12, 13, and 14, above. */
+#define UMFPACK_RELAXED_AMALGAMATION 5 /* unused (was in v4.0) */
+#define UMFPACK_PIVOT_OPTION 12 /* unused (was in v3.2) */
+#define UMFPACK_RELAXED2_AMALGAMATION 13 /* unused (was in v4.0) */
+#define UMFPACK_RELAXED3_AMALGAMATION 14 /* unused (was in v4.0) */
+#endif
+
+/* -------------------------------------------------------------------------- */
+
+/* Control [UMFPACK_STRATEGY] is one of the following: */
+#define UMFPACK_STRATEGY_AUTO 0 /* use sym. or unsym. strategy */
+#define UMFPACK_STRATEGY_UNSYMMETRIC 1 /* COLAMD(A), coletree postorder,
+ not prefer diag*/
+#define UMFPACK_STRATEGY_2BY2 2 /* AMD(PA+PA'), no coletree postorder,
+ prefer diag(PA) where P is pseudo
+ max transversal */
+#define UMFPACK_STRATEGY_SYMMETRIC 3 /* AMD(A+A'), no coletree postorder,
+ prefer diagonal */
+
+/* Control [UMFPACK_SCALE] is one of the following: */
+#define UMFPACK_SCALE_NONE 0 /* no scaling */
+#define UMFPACK_SCALE_SUM 1 /* default: divide each row by sum (abs (row))*/
+#define UMFPACK_SCALE_MAX 2 /* divide each row by max (abs (row)) */
+
+/* -------------------------------------------------------------------------- */
+/* default values of Control: */
+/* -------------------------------------------------------------------------- */
+
+/* Note that the default block sized changed for Version 3.1 and following.
+ * In Version 4.1, the relaxed amalgamation parameters were removed. These are
+ * now fixed internally (see umf_local_search.c), and cannot be changed.
+ * COLAMD aggressive absorption did not exist in v4.0. In v4.1, it is in
+ * use by default (but can be turned off). Aggressive absorption is used by
+ * default in AMD, also.
+ *
+ * Drop tolerance was added in V4.2.
+ */
+
+#define UMFPACK_DEFAULT_PRL 1
+#define UMFPACK_DEFAULT_DENSE_ROW 0.2
+#define UMFPACK_DEFAULT_DENSE_COL 0.2
+#define UMFPACK_DEFAULT_PIVOT_TOLERANCE 0.1
+#define UMFPACK_DEFAULT_2BY2_TOLERANCE 0.01
+#define UMFPACK_DEFAULT_SYM_PIVOT_TOLERANCE 0.001
+#define UMFPACK_DEFAULT_BLOCK_SIZE 32
+#define UMFPACK_DEFAULT_ALLOC_INIT 0.7
+#define UMFPACK_DEFAULT_FRONT_ALLOC_INIT 0.5
+#define UMFPACK_DEFAULT_IRSTEP 2
+#define UMFPACK_DEFAULT_SCALE UMFPACK_SCALE_SUM
+#define UMFPACK_DEFAULT_STRATEGY UMFPACK_STRATEGY_AUTO
+#define UMFPACK_DEFAULT_AMD_DENSE AMD_DEFAULT_DENSE
+#define UMFPACK_DEFAULT_FIXQ 0
+#define UMFPACK_DEFAULT_AGGRESSIVE 1
+#define UMFPACK_DEFAULT_DROPTOL 0
+
+#if 0
+/* no longer unused: for unsymmetric strategy (were used in v4.0) */
+#define UMFPACK_DEFAULT_RELAXED_AMALGAMATION 0.25 /* unused */
+#define UMFPACK_DEFAULT_RELAXED2_AMALGAMATION 0.1 /* unused */
+#define UMFPACK_DEFAULT_RELAXED3_AMALGAMATION 0.125 /* unused */
+#endif
+
+/* default values of Control may change in future versions of UMFPACK. */
+
+/* -------------------------------------------------------------------------- */
+/* status codes */
+/* -------------------------------------------------------------------------- */
+
+#define UMFPACK_OK (0)
+
+/* status > 0 means a warning, but the method was successful anyway. */
+/* A Symbolic or Numeric object was still created. */
+#define UMFPACK_WARNING_singular_matrix (1)
+
+/* status < 0 means an error, and the method was not successful. */
+/* No Symbolic of Numeric object was created. */
+#define UMFPACK_ERROR_out_of_memory (-1)
+#define UMFPACK_ERROR_invalid_Numeric_object (-3)
+#define UMFPACK_ERROR_invalid_Symbolic_object (-4)
+#define UMFPACK_ERROR_argument_missing (-5)
+#define UMFPACK_ERROR_n_nonpositive (-6)
+#define UMFPACK_ERROR_invalid_matrix (-8) /* replaces errors -[7:10,12,14] */
+#define UMFPACK_ERROR_different_pattern (-11)
+#define UMFPACK_ERROR_invalid_system (-13)
+#define UMFPACK_ERROR_invalid_permutation (-15)
+#define UMFPACK_ERROR_internal_error (-911)
+#define UMFPACK_ERROR_file_IO (-17)
+
+/* The following error codes are no longer used. They are left in for
+ * historical reasons. They appeared in Version 4.0. Most of them are combined
+ * into the single UMFPACK_ERROR_invalid_matrix error code (-8). The last one,
+ * UMFPACK_ERROR_problem_too_large, has been removed. This error can no longer
+ * occur. */
+#define UMFPACK_ERROR_nz_negative (-7) /* unused */
+#define UMFPACK_ERROR_jumbled_matrix (-8) /* unused */
+#define UMFPACK_ERROR_Ap0_nonzero (-9) /* unused */
+#define UMFPACK_ERROR_row_index_out_of_bounds (-10) /* unused */
+#define UMFPACK_ERROR_col_length_negative (-12) /* unused */
+#define UMFPACK_ERROR_invalid_triplet (-14) /* unused */
+#define UMFPACK_ERROR_problem_too_large (-16) /* unused */
+
+/* -------------------------------------------------------------------------- */
+/* solve codes */
+/* -------------------------------------------------------------------------- */
+
+/* Solve the system ( )x=b, where ( ) is defined below. "t" refers to the */
+/* linear algebraic transpose (complex conjugate if A is complex), or the (') */
+/* operator in MATLAB. "at" refers to the array transpose, or the (.') */
+/* operator in MATLAB. */
+
+#define UMFPACK_A (0) /* Ax=b */
+#define UMFPACK_At (1) /* A'x=b */
+#define UMFPACK_Aat (2) /* A.'x=b */
+
+#define UMFPACK_Pt_L (3) /* P'Lx=b */
+#define UMFPACK_L (4) /* Lx=b */
+#define UMFPACK_Lt_P (5) /* L'Px=b */
+#define UMFPACK_Lat_P (6) /* L.'Px=b */
+#define UMFPACK_Lt (7) /* L'x=b */
+#define UMFPACK_Lat (8) /* L.'x=b */
+
+#define UMFPACK_U_Qt (9) /* UQ'x=b */
+#define UMFPACK_U (10) /* Ux=b */
+#define UMFPACK_Q_Ut (11) /* QU'x=b */
+#define UMFPACK_Q_Uat (12) /* QU.'x=b */
+#define UMFPACK_Ut (13) /* U'x=b */
+#define UMFPACK_Uat (14) /* U.'x=b */
+
+/* -------------------------------------------------------------------------- */
+
+/* Integer constants are used for status and solve codes instead of enum */
+/* to make it easier for a Fortran code to call UMFPACK. */
+
+#endif /* UMFPACK_H */
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_col_to_triplet =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_col_to_triplet
+(
+ int n_col,
+ const int Ap [ ],
+ int Tj [ ]
+) ;
+
+long umfpack_dl_col_to_triplet
+(
+ long n_col,
+ const long Ap [ ],
+ long Tj [ ]
+) ;
+
+int umfpack_zi_col_to_triplet
+(
+ int n_col,
+ const int Ap [ ],
+ int Tj [ ]
+) ;
+
+long umfpack_zl_col_to_triplet
+(
+ long n_col,
+ const long Ap [ ],
+ long Tj [ ]
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ int n_col, *Tj, *Ap, status ;
+ status = umfpack_di_col_to_triplet (n_col, Ap, Tj) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ long n_col, *Tj, *Ap, status ;
+ status = umfpack_dl_col_to_triplet (n_col, Ap, Tj) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ int n_col, *Tj, *Ap, status ;
+ status = umfpack_zi_col_to_triplet (n_col, Ap, Tj) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ long n_col, *Tj, *Ap, status ;
+ status = umfpack_zl_col_to_triplet (n_col, Ap, Tj) ;
+
+Purpose:
+
+ Converts a column-oriented matrix to a triplet form. Only the column
+ pointers, Ap, are required, and only the column indices of the triplet form
+ are constructed. This routine is the opposite of umfpack_*_triplet_to_col.
+ The matrix may be singular and/or rectangular. Analogous to [i, Tj, x] =
+ find (A) in MATLAB, except that zero entries present in the column-form of
+ A are present in the output, and i and x are not created (those are just Ai
+ and Ax+Az*1i, respectively, for a column-form matrix A).
+
+Returns:
+
+ UMFPACK_OK if successful
+ UMFPACK_ERROR_argument_missing if Ap or Tj is missing
+ UMFPACK_ERROR_n_nonpositive if n_col <= 0
+ UMFPACK_ERROR_invalid_matrix if Ap [n_col] < 0, Ap [0] != 0, or
+ Ap [j] > Ap [j+1] for any j in the range 0 to n-1.
+ Unsorted columns and duplicate entries do not cause an error (these would
+ only be evident by examining Ai). Empty rows and columns are OK.
+
+Arguments:
+
+ Int n_col ; Input argument, not modified.
+
+ A is an n_row-by-n_col matrix. Restriction: n_col > 0.
+ (n_row is not required)
+
+ Int Ap [n_col+1] ; Input argument, not modified.
+
+ The column pointers of the column-oriented form of the matrix. See
+ umfpack_*_*symbolic for a description. The number of entries in
+ the matrix is nz = Ap [n_col]. Restrictions on Ap are the same as those
+ for umfpack_*_transpose. Ap [0] must be zero, nz must be >= 0, and
+ Ap [j] <= Ap [j+1] and Ap [j] <= Ap [n_col] must be true for all j in
+ the range 0 to n_col-1. Empty columns are OK (that is, Ap [j] may equal
+ Ap [j+1] for any j in the range 0 to n_col-1).
+
+ Int Tj [nz] ; Output argument.
+
+ Tj is an integer array of size nz on input, where nz = Ap [n_col].
+ Suppose the column-form of the matrix is held in Ap, Ai, Ax, and Az
+ (see umfpack_*_*symbolic for a description). Then on output, the
+ triplet form of the same matrix is held in Ai (row indices), Tj (column
+ indices), and Ax (numerical values). Note, however, that this routine
+ does not require Ai and Ax (or Az for the complex version) in order to
+ do the conversion.
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_defaults ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_di_defaults
+(
+ double Control [UMFPACK_CONTROL]
+) ;
+
+void umfpack_dl_defaults
+(
+ double Control [UMFPACK_CONTROL]
+) ;
+
+void umfpack_zi_defaults
+(
+ double Control [UMFPACK_CONTROL]
+) ;
+
+void umfpack_zl_defaults
+(
+ double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ double Control [UMFPACK_CONTROL] ;
+ umfpack_di_defaults (Control) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ double Control [UMFPACK_CONTROL] ;
+ umfpack_dl_defaults (Control) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ double Control [UMFPACK_CONTROL] ;
+ umfpack_zi_defaults (Control) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ double Control [UMFPACK_CONTROL] ;
+ umfpack_zl_defaults (Control) ;
+
+Purpose:
+
+ Sets the default control parameter settings.
+
+ NOTE: new control parameters have been added to the Control array for
+ Version 4.1. These entries were unused in Version 4.0. The default block
+ size for the BLAS has increased from 24 to 32. Some rarely used control
+ parameters have been removed (those that controlled relaxed amalgamation).
+
+Arguments:
+
+ double Control [UMFPACK_CONTROL] ; Output argument.
+
+ Control is set to the default control parameter settings. You can
+ then modify individual settings by changing specific entries in the
+ Control array. If Control is a (double *) NULL pointer, then
+ umfpack_*_defaults returns silently (no error is generated, since
+ passing a NULL pointer for Control to any UMFPACK routine is valid).
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_free_numeric ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_di_free_numeric
+(
+ void **Numeric
+) ;
+
+void umfpack_dl_free_numeric
+(
+ void **Numeric
+) ;
+
+void umfpack_zi_free_numeric
+(
+ void **Numeric
+) ;
+
+void umfpack_zl_free_numeric
+(
+ void **Numeric
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ umfpack_di_free_numeric (&Numeric) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ umfpack_dl_free_numeric (&Numeric) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ umfpack_zi_free_numeric (&Numeric) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ umfpack_zl_free_numeric (&Numeric) ;
+
+Purpose:
+
+ Deallocates the Numeric object and sets the Numeric handle to NULL. This
+ routine is the only valid way of destroying the Numeric object.
+
+Arguments:
+
+ void **Numeric ; Input argument, set to (void *) NULL on output.
+
+ Numeric points to a valid Numeric object, computed by umfpack_*_numeric.
+ No action is taken if Numeric is a (void *) NULL pointer.
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_free_symbolic ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_di_free_symbolic
+(
+ void **Symbolic
+) ;
+
+void umfpack_dl_free_symbolic
+(
+ void **Symbolic
+) ;
+
+void umfpack_zi_free_symbolic
+(
+ void **Symbolic
+) ;
+
+void umfpack_zl_free_symbolic
+(
+ void **Symbolic
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ void *Symbolic ;
+ umfpack_di_free_symbolic (&Symbolic) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ void *Symbolic ;
+ umfpack_dl_free_symbolic (&Symbolic) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ void *Symbolic ;
+ umfpack_zi_free_symbolic (&Symbolic) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ void *Symbolic ;
+ umfpack_zl_free_symbolic (&Symbolic) ;
+
+Purpose:
+
+ Deallocates the Symbolic object and sets the Symbolic handle to NULL. This
+ routine is the only valid way of destroying the Symbolic object.
+
+Arguments:
+
+ void **Symbolic ; Input argument, set to (void *) NULL on output.
+
+ Points to a valid Symbolic object computed by umfpack_*_symbolic.
+ No action is taken if Symbolic is a (void *) NULL pointer.
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_get_lunz ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_get_lunz
+(
+ int *lnz,
+ int *unz,
+ int *n_row,
+ int *n_col,
+ int *nz_udiag,
+ void *Numeric
+) ;
+
+long umfpack_dl_get_lunz
+(
+ long *lnz,
+ long *unz,
+ long *n_row,
+ long *n_col,
+ long *nz_udiag,
+ void *Numeric
+) ;
+
+int umfpack_zi_get_lunz
+(
+ int *lnz,
+ int *unz,
+ int *n_row,
+ int *n_col,
+ int *nz_udiag,
+ void *Numeric
+) ;
+
+long umfpack_zl_get_lunz
+(
+ long *lnz,
+ long *unz,
+ long *n_row,
+ long *n_col,
+ long *nz_udiag,
+ void *Numeric
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ int status, lnz, unz, n_row, n_col ;
+ status = umfpack_di_get_lunz (&lnz, &unz, &n_row, &n_col, Numeric) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ long status, lnz, unz, n_row, n_col ;
+ status = umfpack_dl_get_lunz (&lnz, &unz, &n_row, &n_col, Numeric) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ int status, lnz, unz, n_row, n_col ;
+ status = umfpack_zi_get_lunz (&lnz, &unz, &n_row, &n_col, Numeric) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ long status, lnz, unz, n_row, n_col ;
+ status = umfpack_zl_get_lunz (&lnz, &unz, &n_row, &n_col, Numeric) ;
+
+Purpose:
+
+ Determines the size and number of nonzeros in the LU factors held by the
+ Numeric object. These are also the sizes of the output arrays required
+ by umfpack_*_get_numeric.
+
+ The matrix L is n_row -by- min(n_row,n_col), with lnz nonzeros, including
+ the entries on the unit diagonal of L.
+
+ The matrix U is min(n_row,n_col) -by- n_col, with unz nonzeros, including
+ nonzeros on the diagonal of U.
+
+Returns:
+
+ UMFPACK_OK if successful.
+ UMFPACK_ERROR_invalid_Numeric_object if Numeric is not a valid object.
+ UMFPACK_ERROR_argument_missing if any other argument is (Int *) NULL.
+
+Arguments:
+
+ Int *lnz ; Output argument.
+
+ The number of nonzeros in L, including the diagonal (which is all
+ one's). This value is the required size of the Lj and Lx arrays as
+ computed by umfpack_*_get_numeric. The value of lnz is identical to
+ Info [UMFPACK_LNZ], if that value was returned by umfpack_*_numeric.
+
+ Int *unz ; Output argument.
+
+ The number of nonzeros in U, including the diagonal. This value is the
+ required size of the Ui and Ux arrays as computed by
+ umfpack_*_get_numeric. The value of unz is identical to
+ Info [UMFPACK_UNZ], if that value was returned by umfpack_*_numeric.
+
+ Int *n_row ; Output argument.
+ Int *n_col ; Output argument.
+
+ The order of the L and U matrices. L is n_row -by- min(n_row,n_col)
+ and U is min(n_row,n_col) -by- n_col.
+
+ Int *nz_udiag ; Output argument.
+
+ The number of numerically nonzero values on the diagonal of U. The
+ matrix is singular if nz_diag < min(n_row,n_col). A divide-by-zero
+ will occur if nz_diag < n_row == n_col when solving a sparse system
+ involving the matrix U in umfpack_*_*solve. The value of nz_udiag is
+ identical to Info [UMFPACK_UDIAG_NZ] if that value was returned by
+ umfpack_*_numeric.
+
+ void *Numeric ; Input argument, not modified.
+
+ Numeric must point to a valid Numeric object, computed by
+ umfpack_*_numeric.
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_get_numeric ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_get_numeric
+(
+ int Lp [ ],
+ int Lj [ ],
+ double Lx [ ],
+ int Up [ ],
+ int Ui [ ],
+ double Ux [ ],
+ int P [ ],
+ int Q [ ],
+ double Dx [ ],
+ int *do_recip,
+ double Rs [ ],
+ void *Numeric
+) ;
+
+long umfpack_dl_get_numeric
+(
+ long Lp [ ],
+ long Lj [ ],
+ double Lx [ ],
+ long Up [ ],
+ long Ui [ ],
+ double Ux [ ],
+ long P [ ],
+ long Q [ ],
+ double Dx [ ],
+ long *do_recip,
+ double Rs [ ],
+ void *Numeric
+) ;
+
+int umfpack_zi_get_numeric
+(
+ int Lp [ ],
+ int Lj [ ],
+ double Lx [ ], double Lz [ ],
+ int Up [ ],
+ int Ui [ ],
+ double Ux [ ], double Uz [ ],
+ int P [ ],
+ int Q [ ],
+ double Dx [ ], double Dz [ ],
+ int *do_recip,
+ double Rs [ ],
+ void *Numeric
+) ;
+
+long umfpack_zl_get_numeric
+(
+ long Lp [ ],
+ long Lj [ ],
+ double Lx [ ], double Lz [ ],
+ long Up [ ],
+ long Ui [ ],
+ double Ux [ ], double Uz [ ],
+ long P [ ],
+ long Q [ ],
+ double Dx [ ], double Dz [ ],
+ long *do_recip,
+ double Rs [ ],
+ void *Numeric
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ int *Lp, *Lj, *Up, *Ui, *P, *Q, status, do_recip ;
+ double *Lx, *Ux, *Dx, *Rs ;
+ status = umfpack_di_get_numeric (Lp, Lj, Lx, Up, Ui, Ux, P, Q, Dx,
+ &do_recip, Rs, Numeric) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ long *Lp, *Lj, *Up, *Ui, *P, *Q, status, do_recip ;
+ double *Lx, *Ux, *Dx, *Rs ;
+ status = umfpack_dl_get_numeric (Lp, Lj, Lx, Up, Ui, Ux, P, Q, Dx,
+ &do_recip, Rs, Numeric) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ int *Lp, *Lj, *Up, *Ui, *P, *Q, status, do_recip ;
+ double *Lx, *Lz, *Ux, *Uz, *Dx, *Dz, *Rs ;
+ status = umfpack_zi_get_numeric (Lp, Lj, Lx, Lz, Up, Ui, Ux, Uz, P, Q,
+ Dx, Dz, &do_recip, Rs, Numeric) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ long *Lp, *Lj, *Up, *Ui, *P, *Q, status, do_recip ;
+ double *Lx, *Lz, *Ux, *Uz, *Dx, *Dz, *Rs ;
+ status = umfpack_zl_get_numeric (Lp, Lj, Lx, Lz, Up, Ui, Ux, Uz, P, Q,
+ Dx, Dz, &do_recip, Rs, Numeric) ;
+
+Purpose:
+
+ This routine copies the LU factors and permutation vectors from the Numeric
+ object into user-accessible arrays. This routine is not needed to solve a
+ linear system. Note that the output arrays Lp, Lj, Lx, Up, Ui, Ux, P, Q,
+ Dx, and Rs are not allocated by umfpack_*_get_numeric; they must exist on
+ input. Similarly, Lz, Uz and Dz must exist on input for the complex
+ versions.
+
+ All output arguments are optional. If any of them are NULL
+ on input, then that part of the LU factorization is not copied. You can
+ use this routine to extract just the parts of the LU factorization that
+ you want. For example, to retrieve just the column permutation Q, use:
+
+ #define noD (double *) NULL
+ #define noI (int *) NULL
+ status = umfpack_di_get_numeric (noI, noI, noD, noI, noI, noD, noI,
+ Q, noD, noI, noD, Numeric) ;
+
+Returns:
+
+ Returns UMFPACK_OK if successful. Returns UMFPACK_ERROR_out_of_memory
+ if insufficient memory is available for the 2*max(n_row,n_col) integer
+ workspace that umfpack_*_get_numeric allocates to construct L and/or U.
+ Returns UMFPACK_ERROR_invalid_Numeric_object if the Numeric object provided
+ as input is invalid.
+
+Arguments:
+
+ Int Lp [n_row+1] ; Output argument.
+ Int Lj [lnz] ; Output argument.
+ double Lx [lnz] ; Output argument.
+ double Lz [lnz] ; Output argument for complex versions.
+
+ The n_row-by-min(n_row,n_col) matrix L is returned in compressed-row
+ form. The column indices of row i and corresponding numerical values
+ are in:
+
+ Lj [Lp [i] ... Lp [i+1]-1]
+ Lx [Lp [i] ... Lp [i+1]-1] real part
+ Lz [Lp [i] ... Lp [i+1]-1] imaginary part (complex versions)
+
+ respectively. Each row is stored in sorted order, from low column
+ indices to higher. The last entry in each row is the diagonal, which
+ is numerically equal to one. The sizes of Lp, Lj, Lx, and Lz are
+ returned by umfpack_*_get_lunz. If Lp, Lj, or Ux (or Uz for the
+ complex version) are not present, then the matrix L is not returned.
+ This is not an error condition. The L matrix can be printed if n_row,
+ Lp, Lj, Lx (and Lz for the complex versions) are passed to
+ umfpack_*_report_matrix (using the "row" form).
+
+ Future complex version: if Lx is present and Lz is NULL, then both real
+ and imaginary parts will be returned in Lx[0..2*lnz-1], with Lx[2*k]
+ and Lx[2*k+1] being the real and imaginary part of the kth entry.
+
+ Int Up [n_col+1] ; Output argument.
+ Int Ui [unz] ; Output argument.
+ double Ux [unz] ; Output argument.
+ double Uz [unz] ; Output argument for complex versions.
+
+ The min(n_row,n_col)-by-n_col matrix U is returned in compressed-column
+ form. The row indices of column j and corresponding numerical values
+ are in
+
+ Ui [Up [j] ... Up [j+1]-1]
+ Ux [Up [j] ... Up [j+1]-1] real part
+ Uz [Up [j] ... Up [j+1]-1] imaginary part (complex versions)
+
+ respectively. Each column is stored in sorted order, from low row
+ indices to higher. The last entry in each column is the diagonal
+ (assuming that it is nonzero). The sizes of Up, Ui, Ux, and Uz are
+ returned by umfpack_*_get_lunz. If Up, Ui, or Ux (or Uz for the complex
+ version) are not present, then the matrix U is not returned. This is
+ not an error condition. The U matrix can be printed if n_col, Up, Ui,
+ Ux (and Uz for the complex versions) are passed to
+ umfpack_*_report_matrix (using the "column" form).
+
+ Future complex version: if Ux is present and Uz is NULL, then both real
+ and imaginary parts will be returned in Ux[0..2*unz-1], with Ux[2*k]
+ and Ux[2*k+1] being the real and imaginary part of the kth entry.
+
+ Int P [n_row] ; Output argument.
+
+ The permutation vector P is defined as P [k] = i, where the original
+ row i of A is the kth pivot row in PAQ. If you do not want the P vector
+ to be returned, simply pass (Int *) NULL for P. This is not an error
+ condition. You can print P and Q with umfpack_*_report_perm.
+
+ Int Q [n_col] ; Output argument.
+
+ The permutation vector Q is defined as Q [k] = j, where the original
+ column j of A is the kth pivot column in PAQ. If you not want the Q
+ vector to be returned, simply pass (Int *) NULL for Q. This is not
+ an error condition. Note that Q is not necessarily identical to
+ Qtree, the column pre-ordering held in the Symbolic object. Refer to
+ the description of Qtree and Front_npivcol in umfpack_*_get_symbolic for
+ details.
+
+ double Dx [min(n_row,n_col)] ; Output argument.
+ double Dz [min(n_row,n_col)] ; Output argument for complex versions.
+
+ The diagonal of U is also returned in Dx and Dz. You can extract the
+ diagonal of U without getting all of U by passing a non-NULL Dx (and
+ Dz for the complex version) and passing Up, Ui, and Ux as NULL. Dx is
+ the real part of the diagonal, and Dz is the imaginary part.
+
+ Future complex version: if Dx is present and Dz is NULL, then both real
+ and imaginary parts will be returned in Dx[0..2*min(n_row,n_col)-1],
+ with Dx[2*k] and Dx[2*k+1] being the real and imaginary part of the kth
+ entry.
+
+ Int *do_recip ; Output argument.
+
+ If do_recip is returned as zero (false), then the scale factors Rs [i]
+ are to be used by multiplying row i by Rs [i]. Otherwise, the entries
+ in row i are to be divided by Rs [i].
+
+ If UMFPACK has been compiled with gcc, or for MATLAB as either a
+ built-in routine or as a mexFunction, then the NRECIPROCAL flag is
+ set, and do_recip will always be zero (false).
+
+ NOTE: this argument is new to version 4.1.
+
+ double Rs [n_row] ; Output argument.
+
+ The row scale factors are returned in Rs [0..n_row-1]. Row i of A is
+ scaled by dividing or multiplying its values by Rs [i]. If default
+ scaling is in use, Rs [i] is the sum of the absolute values of row i
+ (or its reciprocal). If max row scaling is in use, then Rs [i] is the
+ maximum absolute value in row i (or its reciprocal).
+ Otherwise, Rs [i] = 1. If row i is all zero, Rs [i] = 1 as well. For
+ the complex version, an approximate absolute value is used
+ (|x_real|+|x_imag|).
+
+ NOTE: this argument is new to version 4.1.
+
+ void *Numeric ; Input argument, not modified.
+
+ Numeric must point to a valid Numeric object, computed by
+ umfpack_*_numeric.
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_get_symbolic ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_get_symbolic
+(
+ int *n_row,
+ int *n_col,
+ int *n1,
+ int *nz,
+ int *nfr,
+ int *nchains,
+ int P [ ],
+ int Q [ ],
+ int Front_npivcol [ ],
+ int Front_parent [ ],
+ int Front_1strow [ ],
+ int Front_leftmostdesc [ ],
+ int Chain_start [ ],
+ int Chain_maxrows [ ],
+ int Chain_maxcols [ ],
+ void *Symbolic
+) ;
+
+long umfpack_dl_get_symbolic
+(
+ long *n_row,
+ long *n_col,
+ long *n1,
+ long *nz,
+ long *nfr,
+ long *nchains,
+ long P [ ],
+ long Q [ ],
+ long Front_npivcol [ ],
+ long Front_parent [ ],
+ long Front_1strow [ ],
+ long Front_leftmostdesc [ ],
+ long Chain_start [ ],
+ long Chain_maxrows [ ],
+ long Chain_maxcols [ ],
+ void *Symbolic
+) ;
+
+int umfpack_zi_get_symbolic
+(
+ int *n_row,
+ int *n_col,
+ int *n1,
+ int *nz,
+ int *nfr,
+ int *nchains,
+ int P [ ],
+ int Q [ ],
+ int Front_npivcol [ ],
+ int Front_parent [ ],
+ int Front_1strow [ ],
+ int Front_leftmostdesc [ ],
+ int Chain_start [ ],
+ int Chain_maxrows [ ],
+ int Chain_maxcols [ ],
+ void *Symbolic
+) ;
+
+long umfpack_zl_get_symbolic
+(
+ long *n_row,
+ long *n_col,
+ long *n1,
+ long *nz,
+ long *nfr,
+ long *nchains,
+ long P [ ],
+ long Q [ ],
+ long Front_npivcol [ ],
+ long Front_parent [ ],
+ long Front_1strow [ ],
+ long Front_leftmostdesc [ ],
+ long Chain_start [ ],
+ long Chain_maxrows [ ],
+ long Chain_maxcols [ ],
+ void *Symbolic
+) ;
+
+/*
+
+double int Syntax:
+
+ #include "umfpack.h"
+ int status, n_row, n_col, nz, nfr, nchains, *P, *Q,
+ *Front_npivcol, *Front_parent, *Front_1strow, *Front_leftmostdesc,
+ *Chain_start, *Chain_maxrows, *Chain_maxcols ;
+ void *Symbolic ;
+ status = umfpack_di_get_symbolic (&n_row, &n_col, &nz, &nfr, &nchains,
+ P, Q, Front_npivcol, Front_parent, Front_1strow,
+ Front_leftmostdesc, Chain_start, Chain_maxrows, Chain_maxcols,
+ Symbolic) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ long status, n_row, n_col, nz, nfr, nchains, *P, *Q,
+ *Front_npivcol, *Front_parent, *Front_1strow, *Front_leftmostdesc,
+ *Chain_start, *Chain_maxrows, *Chain_maxcols ;
+ void *Symbolic ;
+ status = umfpack_dl_get_symbolic (&n_row, &n_col, &nz, &nfr, &nchains,
+ P, Q, Front_npivcol, Front_parent, Front_1strow,
+ Front_leftmostdesc, Chain_start, Chain_maxrows, Chain_maxcols,
+ Symbolic) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ int status, n_row, n_col, nz, nfr, nchains, *P, *Q,
+ *Front_npivcol, *Front_parent, *Front_1strow, *Front_leftmostdesc,
+ *Chain_start, *Chain_maxrows, *Chain_maxcols ;
+ void *Symbolic ;
+ status = umfpack_zi_get_symbolic (&n_row, &n_col, &nz, &nfr, &nchains,
+ P, Q, Front_npivcol, Front_parent, Front_1strow,
+ Front_leftmostdesc, Chain_start, Chain_maxrows, Chain_maxcols,
+ Symbolic) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ long status, n_row, n_col, nz, nfr, nchains, *P, *Q,
+ *Front_npivcol, *Front_parent, *Front_1strow, *Front_leftmostdesc,
+ *Chain_start, *Chain_maxrows, *Chain_maxcols ;
+ void *Symbolic ;
+ status = umfpack_zl_get_symbolic (&n_row, &n_col, &nz, &nfr, &nchains,
+ P, Q, Front_npivcol, Front_parent, Front_1strow,
+ Front_leftmostdesc, Chain_start, Chain_maxrows, Chain_maxcols,
+ Symbolic) ;
+
+Purpose:
+
+ Copies the contents of the Symbolic object into simple integer arrays
+ accessible to the user. This routine is not needed to factorize and/or
+ solve a sparse linear system using UMFPACK. Note that the output arrays
+ P, Q, Front_npivcol, Front_parent, Front_1strow, Front_leftmostdesc,
+ Chain_start, Chain_maxrows, and Chain_maxcols are not allocated by
+ umfpack_*_get_symbolic; they must exist on input.
+
+ All output arguments are optional. If any of them are NULL
+ on input, then that part of the symbolic analysis is not copied. You can
+ use this routine to extract just the parts of the symbolic analysis that
+ you want. For example, to retrieve just the column permutation Q, use:
+
+ #define noI (int *) NULL
+ status = umfpack_di_get_symbolic (noI, noI, noI, noI, noI, noI, noI,
+ Q, noI, noI, noI, noI, noI, noI, noI, Symbolic) ;
+
+ The only required argument the last one, the pointer to the Symbolic object.
+
+ The Symbolic object is small. Its size for an n-by-n square matrix varies
+ from 4*n to 13*n, depending on the matrix. The object holds the initial
+ column permutation, the supernodal column elimination tree, and information
+ about each frontal matrix. You can print it with umfpack_*_report_symbolic.
+
+Returns:
+
+ Returns UMFPACK_OK if successful, UMFPACK_ERROR_invalid_Symbolic_object
+ if Symbolic is an invalid object.
+
+Arguments:
+
+ Int *n_row ; Output argument.
+ Int *n_col ; Output argument.
+
+ The dimensions of the matrix A analyzed by the call to
+ umfpack_*_symbolic that generated the Symbolic object.
+
+ Int *n1 ; Output argument.
+
+ The number of pivots with zero Markowitz cost (they have just one entry
+ in the pivot row, or the pivot column, or both). These appear first in
+ the output permutations P and Q.
+
+ NOTE: this argument is new to version 4.1.
+
+ Int *nz ; Output argument.
+
+ The number of nonzeros in A.
+
+ Int *nfr ; Output argument.
+
+ The number of frontal matrices that will be used by umfpack_*_numeric
+ to factorize the matrix A. It is in the range 0 to n_col.
+
+ Int *nchains ; Output argument.
+
+ The frontal matrices are related to one another by the supernodal
+ column elimination tree. Each node in this tree is one frontal matrix.
+ The tree is partitioned into a set of disjoint paths, and a frontal
+ matrix chain is one path in this tree. Each chain is factorized using
+ a unifrontal technique, with a single working array that holds each
+ frontal matrix in the chain, one at a time. nchains is in the range
+ 0 to nfr.
+
+ Int P [n_row] ; Output argument.
+
+ The initial row permutation. If P [k] = i, then this means that
+ row i is the kth row in the pre-ordered matrix. In general, this P is
+ not the same as the final row permutation computed by umfpack_*_numeric.
+
+ For the unsymmetric strategy, P defines the row-merge order. Let j be
+ the column index of the leftmost nonzero entry in row i of A*Q. Then
+ P defines a sort of the rows according to this value. A row can appear
+ earlier in this ordering if it is aggressively absorbed before it can
+ become a pivot row. If P [k] = i, row i typically will not be the kth
+ pivot row.
+
+ For the symmetric strategy, P = Q. For the 2-by-2 strategy, P is the
+ row permutation that places large entries on the diagonal of P*A*Q.
+ If no pivoting occurs during numerical factorization, P [k] = i also
+ defines the final permutation of umfpack_*_numeric, for either the
+ symmetric or 2-by-2 strategies.
+
+ Int Q [n_col] ; Output argument.
+
+ The initial column permutation. If Q [k] = j, then this means that
+ column j is the kth pivot column in the pre-ordered matrix. Q is
+ not necessarily the same as the final column permutation Q, computed by
+ umfpack_*_numeric. The numeric factorization may reorder the pivot
+ columns within each frontal matrix to reduce fill-in. If the matrix is
+ structurally singular, and if the symmetric or 2-by-2 strategies or
+ used (or if Control [UMFPACK_FIXQ] > 0), then this Q will be the same
+ as the final column permutation computed in umfpack_*_numeric.
+
+ Int Front_npivcol [n_col+1] ; Output argument.
+
+ This array should be of size at least n_col+1, in order to guarantee
+ that it will be large enough to hold the output. Only the first nfr+1
+ entries are used, however.
+
+ The kth frontal matrix holds Front_npivcol [k] pivot columns. Thus, the
+ first frontal matrix, front 0, is used to factorize the first
+ Front_npivcol [0] columns; these correspond to the original columns
+ Q [0] through Q [Front_npivcol [0]-1]. The next frontal matrix
+ is used to factorize the next Front_npivcol [1] columns, which are thus
+ the original columns Q [Front_npivcol [0]] through
+ Q [Front_npivcol [0] + Front_npivcol [1] - 1], and so on. Columns
+ with no entries at all are put in a placeholder "front",
+ Front_npivcol [nfr]. The sum of Front_npivcol [0..nfr] is equal to
+ n_col.
+
+ Any modifications that umfpack_*_numeric makes to the initial column
+ permutation are constrained to within each frontal matrix. Thus, for
+ the first frontal matrix, Q [0] through Q [Front_npivcol [0]-1] is some
+ permutation of the columns Q [0] through
+ Q [Front_npivcol [0]-1]. For second frontal matrix,
+ Q [Front_npivcol [0]] through Q [Front_npivcol [0] + Front_npivcol[1]-1]
+ is some permutation of the same portion of Q, and so on. All pivot
+ columns are numerically factorized within the frontal matrix originally
+ determined by the symbolic factorization; there is no delayed pivoting
+ across frontal matrices.
+
+ Int Front_parent [n_col+1] ; Output argument.
+
+ This array should be of size at least n_col+1, in order to guarantee
+ that it will be large enough to hold the output. Only the first nfr+1
+ entries are used, however.
+
+ Front_parent [0..nfr] holds the supernodal column elimination tree
+ (including the placeholder front nfr, which may be empty). Each node in
+ the tree corresponds to a single frontal matrix. The parent of node f
+ is Front_parent [f].
+
+ Int Front_1strow [n_col+1] ; Output argument.
+
+ This array should be of size at least n_col+1, in order to guarantee
+ that it will be large enough to hold the output. Only the first nfr+1
+ entries are used, however.
+
+ Front_1strow [k] is the row index of the first row in A (P,Q)
+ whose leftmost entry is in a pivot column for the kth front. This is
+ necessary only to properly factorize singular matrices. It is new to
+ Version 4.0. Rows in the range Front_1strow [k] to
+ Front_1strow [k+1]-1 first become pivot row candidates at the kth front.
+ Any rows not eliminated in the kth front may be selected as pivot rows
+ in the parent of k (Front_parent [k]) and so on up the tree.
+
+ Int Front_leftmostdesc [n_col+1] ; Output argument.
+
+ This array should be of size at least n_col+1, in order to guarantee
+ that it will be large enough to hold the output. Only the first nfr+1
+ entries are used, however.
+
+ Front_leftmostdesc [k] is the leftmost descendant of front k, or k
+ if the front has no children in the tree. Since the rows and columns
+ (P and Q) have been post-ordered via a depth-first-search of
+ the tree, rows in the range Front_1strow [Front_leftmostdesc [k]] to
+ Front_1strow [k+1]-1 form the entire set of candidate pivot rows for
+ the kth front (some of these will typically have already been selected
+ by fronts in the range Front_leftmostdesc [k] to front k-1, before
+ the factorization reaches front k).
+
+ Chain_start [n_col+1] ; Output argument.
+
+ This array should be of size at least n_col+1, in order to guarantee
+ that it will be large enough to hold the output. Only the first
+ nchains+1 entries are used, however.
+
+ The kth frontal matrix chain consists of frontal matrices Chain_start[k]
+ through Chain_start [k+1]-1. Thus, Chain_start [0] is always 0, and
+ Chain_start [nchains] is the total number of frontal matrices, nfr. For
+ two adjacent fronts f and f+1 within a single chain, f+1 is always the
+ parent of f (that is, Front_parent [f] = f+1).
+
+ Int Chain_maxrows [n_col+1] ; Output argument.
+ Int Chain_maxcols [n_col+1] ; Output argument.
+
+ These arrays should be of size at least n_col+1, in order to guarantee
+ that they will be large enough to hold the output. Only the first
+ nchains entries are used, however.
+
+ The kth frontal matrix chain requires a single working array of
+ dimension Chain_maxrows [k] by Chain_maxcols [k], for the unifrontal
+ technique that factorizes the frontal matrix chain. Since the symbolic
+ factorization only provides an upper bound on the size of each frontal
+ matrix, not all of the working array is necessarily used during the
+ numerical factorization.
+
+ Note that the upper bound on the number of rows and columns of each
+ frontal matrix is computed by umfpack_*_symbolic, but all that is
+ required by umfpack_*_numeric is the maximum of these two sets of
+ values for each frontal matrix chain. Thus, the size of each
+ individual frontal matrix is not preserved in the Symbolic object.
+
+ void *Symbolic ; Input argument, not modified.
+
+ The Symbolic object, which holds the symbolic factorization computed by
+ umfpack_*_symbolic. The Symbolic object is not modified by
+ umfpack_*_get_symbolic.
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_load_numeric ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_load_numeric
+(
+ void **Numeric,
+ char *filename
+) ;
+
+long umfpack_dl_load_numeric
+(
+ void **Numeric,
+ char *filename
+) ;
+
+int umfpack_zi_load_numeric
+(
+ void **Numeric,
+ char *filename
+) ;
+
+long umfpack_zl_load_numeric
+(
+ void **Numeric,
+ char *filename
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ int status ;
+ char *filename ;
+ void *Numeric ;
+ status = umfpack_di_load_numeric (&Numeric, filename) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ long status ;
+ char *filename ;
+ void *Numeric ;
+ status = umfpack_dl_load_numeric (&Numeric, filename) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ int status ;
+ char *filename ;
+ void *Numeric ;
+ status = umfpack_zi_load_numeric (&Numeric, filename) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ long status ;
+ char *filename ;
+ void *Numeric ;
+ status = umfpack_zl_load_numeric (&Numeric, filename) ;
+
+Purpose:
+
+ Loads a Numeric object from a file created by umfpack_*_save_numeric. The
+ Numeric handle passed to this routine is overwritten with the new object.
+ If that object exists prior to calling this routine, a memory leak will
+ occur. The contents of Numeric are ignored on input.
+
+Returns:
+
+ UMFPACK_OK if successful.
+ UMFPACK_ERROR_out_of_memory if not enough memory is available.
+ UMFPACK_ERROR_file_IO if an I/O error occurred.
+
+Arguments:
+
+ void **Numeric ; Output argument.
+
+ **Numeric is the address of a (void *) pointer variable in the user's
+ calling routine (see Syntax, above). On input, the contents of this
+ variable are not defined. On output, this variable holds a (void *)
+ pointer to the Numeric object (if successful), or (void *) NULL if
+ a failure occurred.
+
+ char *filename ; Input argument, not modified.
+
+ A string that contains the filename from which to read the Numeric
+ object.
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_load_symbolic ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_load_symbolic
+(
+ void **Symbolic,
+ char *filename
+) ;
+
+long umfpack_dl_load_symbolic
+(
+ void **Symbolic,
+ char *filename
+) ;
+
+int umfpack_zi_load_symbolic
+(
+ void **Symbolic,
+ char *filename
+) ;
+
+long umfpack_zl_load_symbolic
+(
+ void **Symbolic,
+ char *filename
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ int status ;
+ char *filename ;
+ void *Symbolic ;
+ status = umfpack_di_load_symbolic (&Symbolic, filename) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ long status ;
+ char *filename ;
+ void *Symbolic ;
+ status = umfpack_dl_load_symbolic (&Symbolic, filename) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ int status ;
+ char *filename ;
+ void *Symbolic ;
+ status = umfpack_zi_load_symbolic (&Symbolic, filename) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ long status ;
+ char *filename ;
+ void *Symbolic ;
+ status = umfpack_zl_load_symbolic (&Symbolic, filename) ;
+
+Purpose:
+
+ Loads a Symbolic object from a file created by umfpack_*_save_symbolic. The
+ Symbolic handle passed to this routine is overwritten with the new object.
+ If that object exists prior to calling this routine, a memory leak will
+ occur. The contents of Symbolic are ignored on input.
+
+Returns:
+
+ UMFPACK_OK if successful.
+ UMFPACK_ERROR_out_of_memory if not enough memory is available.
+ UMFPACK_ERROR_file_IO if an I/O error occurred.
+
+Arguments:
+
+ void **Symbolic ; Output argument.
+
+ **Symbolic is the address of a (void *) pointer variable in the user's
+ calling routine (see Syntax, above). On input, the contents of this
+ variable are not defined. On output, this variable holds a (void *)
+ pointer to the Symbolic object (if successful), or (void *) NULL if
+ a failure occurred.
+
+ char *filename ; Input argument, not modified.
+
+ A string that contains the filename from which to read the Symbolic
+ object.
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_numeric ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_numeric
+(
+ const int Ap [ ],
+ const int Ai [ ],
+ const double Ax [ ],
+ void *Symbolic,
+ void **Numeric,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO]
+) ;
+
+long umfpack_dl_numeric
+(
+ const long Ap [ ],
+ const long Ai [ ],
+ const double Ax [ ],
+ void *Symbolic,
+ void **Numeric,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO]
+) ;
+
+int umfpack_zi_numeric
+(
+ const int Ap [ ],
+ const int Ai [ ],
+ const double Ax [ ], const double Az [ ],
+ void *Symbolic,
+ void **Numeric,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO]
+) ;
+
+long umfpack_zl_numeric
+(
+ const long Ap [ ],
+ const long Ai [ ],
+ const double Ax [ ], const double Az [ ],
+ void *Symbolic,
+ void **Numeric,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO]
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ void *Symbolic, *Numeric ;
+ int *Ap, *Ai, status ;
+ double *Ax, Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+ status = umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric, Control, Info);
+
+double long Syntax:
+
+ #include "umfpack.h"
+ void *Symbolic, *Numeric ;
+ long *Ap, *Ai, status ;
+ double *Ax, Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+ status = umfpack_dl_numeric (Ap, Ai, Ax, Symbolic, &Numeric, Control, Info);
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ void *Symbolic, *Numeric ;
+ int *Ap, *Ai, status ;
+ double *Ax, *Az, Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+ status = umfpack_zi_numeric (Ap, Ai, Ax, Az, Symbolic, &Numeric,
+ Control, Info) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ void *Symbolic, *Numeric ;
+ long *Ap, *Ai, status ;
+ double *Ax, *Az, Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+ status = umfpack_zl_numeric (Ap, Ai, Ax, Symbolic, &Numeric,
+ Control, Info) ;
+
+Purpose:
+
+ Given a sparse matrix A in column-oriented form, and a symbolic analysis
+ computed by umfpack_*_*symbolic, the umfpack_*_numeric routine performs the
+ numerical factorization, PAQ=LU, PRAQ=LU, or P(R\A)Q=LU, where P and Q are
+ permutation matrices (represented as permutation vectors), R is the row
+ scaling, L is unit-lower triangular, and U is upper triangular. This is
+ required before the system Ax=b (or other related linear systems) can be
+ solved. umfpack_*_numeric can be called multiple times for each call to
+ umfpack_*_*symbolic, to factorize a sequence of matrices with identical
+ nonzero pattern. Simply compute the Symbolic object once, with
+ umfpack_*_*symbolic, and reuse it for subsequent matrices. This routine
+ safely detects if the pattern changes, and sets an appropriate error code.
+
+Returns:
+
+ The status code is returned. See Info [UMFPACK_STATUS], below.
+
+Arguments:
+
+ Int Ap [n_col+1] ; Input argument, not modified.
+
+ This must be identical to the Ap array passed to umfpack_*_*symbolic.
+ The value of n_col is what was passed to umfpack_*_*symbolic (this is
+ held in the Symbolic object).
+
+ Int Ai [nz] ; Input argument, not modified, of size nz = Ap [n_col].
+
+ This must be identical to the Ai array passed to umfpack_*_*symbolic.
+
+ double Ax [nz] ; Input argument, not modified, of size nz = Ap [n_col].
+
+ The numerical values of the sparse matrix A. The nonzero pattern (row
+ indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and
+ the corresponding numerical values are stored in
+ Ax [(Ap [j]) ... (Ap [j+1]-1)].
+
+ double Az [nz] ; Input argument, not modified, for complex versions.
+
+ For the complex versions, this holds the imaginary part of A. The
+ imaginary part of column j is held in Az [(Ap [j]) ... (Ap [j+1]-1)].
+
+ Future complex version: if Ax is present and Az is NULL, then both real
+ and imaginary parts will be contained in Ax[0..2*nz-1], with Ax[2*k]
+ and Ax[2*k+1] being the real and imaginary part of the kth entry.
+
+ void *Symbolic ; Input argument, not modified.
+
+ The Symbolic object, which holds the symbolic factorization computed by
+ umfpack_*_*symbolic. The Symbolic object is not modified by
+ umfpack_*_numeric.
+
+ void **Numeric ; Output argument.
+
+ **Numeric is the address of a (void *) pointer variable in the user's
+ calling routine (see Syntax, above). On input, the contents of this
+ variable are not defined. On output, this variable holds a (void *)
+ pointer to the Numeric object (if successful), or (void *) NULL if
+ a failure occurred.
+
+ double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+ If a (double *) NULL pointer is passed, then the default control
+ settings are used. Otherwise, the settings are determined from the
+ Control array. See umfpack_*_defaults on how to fill the Control
+ array with the default settings. If Control contains NaN's, the
+ defaults are used. The following Control parameters are used:
+
+ Control [UMFPACK_PIVOT_TOLERANCE]: relative pivot tolerance for
+ threshold partial pivoting with row interchanges. In any given
+ column, an entry is numerically acceptable if its absolute value is
+ greater than or equal to Control [UMFPACK_PIVOT_TOLERANCE] times
+ the largest absolute value in the column. A value of 1.0 gives true
+ partial pivoting. If less than or equal to zero, then any nonzero
+ entry is numerically acceptable as a pivot (this is changed from
+ Version 4.0). Default: 0.1.
+
+ Smaller values tend to lead to sparser LU factors, but the solution
+ to the linear system can become inaccurate. Larger values can lead
+ to a more accurate solution (but not always), and usually an
+ increase in the total work.
+
+ For complex matrices, a cheap approximate of the absolute value
+ is used for the threshold partial pivoting test (|a_real| + |a_imag|
+ instead of the more expensive-to-compute exact absolute value
+ sqrt (a_real^2 + a_imag^2)).
+
+ Control [UMFPACK_SYM_PIVOT_TOLERANCE]: This parameter is new to V4.1.
+ If diagonal pivoting is attempted (the symmetric or symmetric-2by2
+ strategies are used) then this parameter is used to control when the
+ diagonal entry is selected in a given pivot column. The absolute
+ value of the entry must be >= Control [UMFPACK_SYM_PIVOT_TOLERANCE]
+ times the largest absolute value in the column. A value of zero
+ will ensure that no off-diagonal pivoting is performed, except that
+ zero diagonal entries are not selected if there are any off-diagonal
+ nonzero entries.
+
+ If an off-diagonal pivot is selected, an attempt is made to restore
+ symmetry later on. Suppose A (i,j) is selected, where i != j.
+ If column i has not yet been selected as a pivot column, then
+ the entry A (j,i) is redefined as a "diagonal" entry, except that
+ the tighter tolerance (Control [UMFPACK_PIVOT_TOLERANCE]) is
+ applied. This strategy has an effect similar to 2-by-2 pivoting
+ for symmetric indefinite matrices. If a 2-by-2 block pivot with
+ nonzero structure
+
+ i j
+ i: 0 x
+ j: x 0
+
+ is selected in a symmetric indefinite factorization method, the
+ 2-by-2 block is inverted and a rank-2 update is applied. In
+ UMFPACK, this 2-by-2 block would be reordered as
+
+ j i
+ i: x 0
+ j: 0 x
+
+ In both cases, the symmetry of the Schur complement is preserved.
+
+ Control [UMFPACK_SCALE]: This parameter is new to V4.1. Version 4.0
+ did not scale the matrix. Note that the user's input matrix is
+ never modified, only an internal copy is scaled.
+
+ There are three valid settings for this parameter. If any other
+ value is provided, the default is used.
+
+ UMFPACK_SCALE_NONE: no scaling is performed.
+
+ UMFPACK_SCALE_SUM: each row of the input matrix A is divided by
+ the sum of the absolute values of the entries in that row.
+ The scaled matrix has an infinity norm of 1.
+
+ UMFPACK_SCALE_MAX: each row of the input matrix A is divided by
+ the maximum the absolute values of the entries in that row.
+ In the scaled matrix the largest entry in each row has
+ a magnitude exactly equal to 1.
+
+ Note that for complex matrices, a cheap approximate absolute value
+ is used, |a_real| + |a_imag|, instead of the exact absolute value
+ sqrt ((a_real)^2 + (a_imag)^2).
+
+ Scaling is very important for the "symmetric" strategy when
+ diagonal pivoting is attempted. It also improves the performance
+ of the "unsymmetric" strategy.
+
+ Default: UMFPACK_SCALE_SUM.
+
+ Control [UMFPACK_ALLOC_INIT]: This parameter has changed in V4.1.
+
+ When umfpack_*_numeric starts, it allocates memory for the Numeric
+ object. Part of this is of fixed size (approximately n double's +
+ 12*n integers). The remainder is of variable size, which grows to
+ hold the LU factors and the frontal matrices created during
+ factorization. A estimate of the upper bound is computed by
+ umfpack_*_*symbolic, and returned by umfpack_*_*symbolic in
+ Info [UMFPACK_VARIABLE_PEAK_ESTIMATE] (in Units).
+
+ If Control [UMFPACK_ALLOC_INIT] is >= 0, umfpack_*_numeric initially
+ allocates space for the variable-sized part equal to this estimate
+ times Control [UMFPACK_ALLOC_INIT]. Typically, for matrices for
+ which the "unsymmetric" strategy applies, umfpack_*_numeric needs
+ only about half the estimated memory space, so a setting of 0.5 or
+ 0.6 often provides enough memory for umfpack_*_numeric to factorize
+ the matrix with no subsequent increases in the size of this block.
+
+ If the matrix is ordered via AMD, then this non-negative parameter
+ is ignored. The initial allocation ratio computed automatically,
+ as 1.2 * (nz + Info [UMFPACK_SYMMETRIC_LUNZ]) /
+ (Info [UMFPACK_LNZ_ESTIMATE] + Info [UMFPACK_UNZ_ESTIMATE] -
+ min (n_row, n_col)).
+
+ If Control [UMFPACK_ALLOC_INIT] is negative, then umfpack_*_numeric
+ allocates a space with initial size (in Units) equal to
+ (-Control [UMFPACK_ALLOC_INIT]).
+
+ Regardless of the value of this parameter, a space equal to or
+ greater than the the bare minimum amount of memory needed to start
+ the factorization is always initially allocated. The bare initial
+ memory required is returned by umfpack_*_*symbolic in
+ Info [UMFPACK_VARIABLE_INIT_ESTIMATE] (an exact value, not an
+ estimate).
+
+ If the variable-size part of the Numeric object is found to be too
+ small sometime after numerical factorization has started, the memory
+ is increased in size by a factor of 1.2. If this fails, the
+ request is reduced by a factor of 0.95 until it succeeds, or until
+ it determines that no increase in size is possible. Garbage
+ collection then occurs.
+
+ The strategy of attempting to "malloc" a working space, and
+ re-trying with a smaller space, may not work under MATLAB, since
+ mxMalloc aborts the mexFunction if it fails. The built-in umfpack
+ routine (version 4.0) in MATLAB 6.5 uses utMalloc instead, which
+ avoids this problem. As a mexFunction, utMalloc is used unless
+ -DNUTIL is defined at compile time. The utMalloc routine, and
+ utFree and utRealloc, are not documented. If the mexFunction
+ doesn't work, then compile it with -DNUTIL instead.
+
+ If you are using the umfpack mexFunction, decrease the magnitude of
+ Control [UMFPACK_ALLOC_INIT] if you run out of memory in MATLAB.
+
+ Default initial allocation size: 0.7. Thus, with the default
+ control settings and the "unsymmetric" strategy, the upper-bound is
+ reached after two reallocations (0.7 * 1.2 * 1.2 = 1.008).
+
+ Changing this parameter has little effect on fill-in or operation
+ count. It has a small impact on run-time (the extra time required
+ to do the garbage collection and memory reallocation).
+
+ Control [UMFPACK_FRONT_ALLOC_INIT]: This parameter is new to V4.1.
+
+ When UMFPACK starts the factorization of each "chain" of frontal
+ matrices, it allocates a working array to hold the frontal matrices
+ as they are factorized. The symbolic factorization computes the
+ size of the largest possible frontal matrix that could occur during
+ the factorization of each chain.
+
+ If Control [UMFPACK_FRONT_ALLOC_INIT] is >= 0, the following
+ strategy is used. If the AMD ordering was used, this non-negative
+ parameter is ignored. A front of size (d+2)*(d+2) is allocated,
+ where d = Info [UMFPACK_SYMMETRIC_DMAX]. Otherwise, a front of
+ size Control [UMFPACK_FRONT_ALLOC_INIT] times the largest front
+ possible for this chain is allocated.
+
+ If Control [UMFPACK_FRONT_ALLOC_INIT] is negative, then a front of
+ size (-Control [UMFPACK_FRONT_ALLOC_INIT]) is allocated (where the
+ size is in terms of the number of numerical entries). This is done
+ regardless of the ordering method or ordering strategy used.
+
+ Default: 0.5.
+
+ Control [UMFPACK_DROPTOL]: This parameter is new to V4.2.
+
+ Entries in L and U with absolute value less than or equal to the
+ drop tolerance are removed from the data structures (unless leaving
+ them there reduces memory usage by reducing the space required
+ for the nonzero pattern of L and U).
+
+ Default: 0.0.
+
+ double Info [UMFPACK_INFO] ; Output argument.
+
+ Contains statistics about the numeric factorization. If a
+ (double *) NULL pointer is passed, then no statistics are returned in
+ Info (this is not an error condition). The following statistics are
+ computed in umfpack_*_numeric:
+
+ Info [UMFPACK_STATUS]: status code. This is also the return value,
+ whether or not Info is present.
+
+ UMFPACK_OK
+
+ Numeric factorization was successful. umfpack_*_numeric
+ computed a valid numeric factorization.
+
+ UMFPACK_WARNING_singular_matrix
+
+ Numeric factorization was successful, but the matrix is
+ singular. umfpack_*_numeric computed a valid numeric
+ factorization, but you will get a divide by zero in
+ umfpack_*_*solve. For the other cases below, no Numeric object
+ is created (*Numeric is (void *) NULL).
+
+ UMFPACK_ERROR_out_of_memory
+
+ Insufficient memory to complete the numeric factorization.
+
+ UMFPACK_ERROR_argument_missing
+
+ One or more required arguments are missing.
+
+ UMFPACK_ERROR_invalid_Symbolic_object
+
+ Symbolic object provided as input is invalid.
+
+ UMFPACK_ERROR_different_pattern
+
+ The pattern (Ap and/or Ai) has changed since the call to
+ umfpack_*_*symbolic which produced the Symbolic object.
+
+ Info [UMFPACK_NROW]: the value of n_row stored in the Symbolic object.
+
+ Info [UMFPACK_NCOL]: the value of n_col stored in the Symbolic object.
+
+ Info [UMFPACK_NZ]: the number of entries in the input matrix.
+ This value is obtained from the Symbolic object.
+
+ Info [UMFPACK_SIZE_OF_UNIT]: the number of bytes in a Unit, for memory
+ usage statistics below.
+
+ Info [UMFPACK_VARIABLE_INIT]: the initial size (in Units) of the
+ variable-sized part of the Numeric object. If this differs from
+ Info [UMFPACK_VARIABLE_INIT_ESTIMATE], then the pattern (Ap and/or
+ Ai) has changed since the last call to umfpack_*_*symbolic, which is
+ an error condition.
+
+ Info [UMFPACK_VARIABLE_PEAK]: the peak size (in Units) of the
+ variable-sized part of the Numeric object. This size is the amount
+ of space actually used inside the block of memory, not the space
+ allocated via UMF_malloc. You can reduce UMFPACK's memory
+ requirements by setting Control [UMFPACK_ALLOC_INIT] to the ratio
+ Info [UMFPACK_VARIABLE_PEAK] / Info[UMFPACK_VARIABLE_PEAK_ESTIMATE].
+ This will ensure that no memory reallocations occur (you may want to
+ add 0.001 to make sure that integer roundoff does not lead to a
+ memory size that is 1 Unit too small; otherwise, garbage collection
+ and reallocation will occur).
+
+ Info [UMFPACK_VARIABLE_FINAL]: the final size (in Units) of the
+ variable-sized part of the Numeric object. It holds just the
+ sparse LU factors.
+
+ Info [UMFPACK_NUMERIC_SIZE]: the actual final size (in Units) of the
+ entire Numeric object, including the final size of the variable
+ part of the object. Info [UMFPACK_NUMERIC_SIZE_ESTIMATE],
+ an estimate, was computed by umfpack_*_*symbolic. The estimate is
+ normally an upper bound on the actual final size, but this is not
+ guaranteed.
+
+ Info [UMFPACK_PEAK_MEMORY]: the actual peak memory usage (in Units) of
+ both umfpack_*_*symbolic and umfpack_*_numeric. An estimate,
+ Info [UMFPACK_PEAK_MEMORY_ESTIMATE], was computed by
+ umfpack_*_*symbolic. The estimate is normally an upper bound on the
+ actual peak usage, but this is not guaranteed. With testing on
+ hundreds of matrix arising in real applications, I have never
+ observed a matrix where this estimate or the Numeric size estimate
+ was less than the actual result, but this is theoretically possible.
+ Please send me one if you find such a matrix.
+
+ Info [UMFPACK_FLOPS]: the actual count of the (useful) floating-point
+ operations performed. An estimate, Info [UMFPACK_FLOPS_ESTIMATE],
+ was computed by umfpack_*_*symbolic. The estimate is guaranteed to
+ be an upper bound on this flop count. The flop count excludes
+ "useless" flops on zero values, flops performed during the pivot
+ search (for tentative updates and assembly of candidate columns),
+ and flops performed to add frontal matrices together.
+
+ For the real version, only (+ - * /) are counted. For the complex
+ version, the following counts are used:
+
+ operation flops
+ c = 1/b 6
+ c = a*b 6
+ c -= a*b 8
+
+ Info [UMFPACK_LNZ]: the actual nonzero entries in final factor L,
+ including the diagonal. This excludes any zero entries in L,
+ although some of these are stored in the Numeric object. The
+ Info [UMFPACK_LU_ENTRIES] statistic does account for all
+ explicitly stored zeros, however. Info [UMFPACK_LNZ_ESTIMATE],
+ an estimate, was computed by umfpack_*_*symbolic. The estimate is
+ guaranteed to be an upper bound on Info [UMFPACK_LNZ].
+
+ Info [UMFPACK_UNZ]: the actual nonzero entries in final factor U,
+ including the diagonal. This excludes any zero entries in U,
+ although some of these are stored in the Numeric object. The
+ Info [UMFPACK_LU_ENTRIES] statistic does account for all
+ explicitly stored zeros, however. Info [UMFPACK_UNZ_ESTIMATE],
+ an estimate, was computed by umfpack_*_*symbolic. The estimate is
+ guaranteed to be an upper bound on Info [UMFPACK_UNZ].
+
+ Info [UMFPACK_NUMERIC_DEFRAG]: The number of garbage collections
+ performed during umfpack_*_numeric, to compact the contents of the
+ variable-sized workspace used by umfpack_*_numeric. No estimate was
+ computed by umfpack_*_*symbolic. In the current version of UMFPACK,
+ garbage collection is performed and then the memory is reallocated,
+ so this statistic is the same as Info [UMFPACK_NUMERIC_REALLOC],
+ below. It may differ in future releases.
+
+ Info [UMFPACK_NUMERIC_REALLOC]: The number of times that the Numeric
+ object was increased in size from its initial size. A rough upper
+ bound on the peak size of the Numeric object was computed by
+ umfpack_*_*symbolic, so reallocations should be rare. However, if
+ umfpack_*_numeric is unable to allocate that much storage, it
+ reduces its request until either the allocation succeeds, or until
+ it gets too small to do anything with. If the memory that it
+ finally got was small, but usable, then the reallocation count
+ could be high. No estimate of this count was computed by
+ umfpack_*_*symbolic.
+
+ Info [UMFPACK_NUMERIC_COSTLY_REALLOC]: The number of times that the
+ system realloc library routine (or mxRealloc for the mexFunction)
+ had to move the workspace. Realloc can sometimes increase the size
+ of a block of memory without moving it, which is much faster. This
+ statistic will always be <= Info [UMFPACK_NUMERIC_REALLOC]. If your
+ memory space is fragmented, then the number of "costly" realloc's
+ will be equal to Info [UMFPACK_NUMERIC_REALLOC].
+
+ Info [UMFPACK_COMPRESSED_PATTERN]: The number of integers used to
+ represent the pattern of L and U.
+
+ Info [UMFPACK_LU_ENTRIES]: The total number of numerical values that
+ are stored for the LU factors. Some of the values may be explicitly
+ zero in order to save space (allowing for a smaller compressed
+ pattern).
+
+ Info [UMFPACK_NUMERIC_TIME]: The CPU time taken, in seconds.
+
+ Info [UMFPACK_RCOND]: A rough estimate of the condition number, equal
+ to min (abs (diag (U))) / max (abs (diag (U))), or zero if the
+ diagonal of U is all zero.
+
+ Info [UMFPACK_UDIAG_NZ]: The number of numerically nonzero values on
+ the diagonal of U.
+
+ Info [UMFPACK_UMIN]: the smallest absolute value on the diagonal of U.
+
+ Info [UMFPACK_UMAX]: the smallest absolute value on the diagonal of U.
+
+ Info [UMFPACK_MAX_FRONT_SIZE]: the size of the
+ largest frontal matrix (number of entries).
+
+ ------------------------------------------------------------------------
+ The following statistics were added to Version 4.1:
+ ------------------------------------------------------------------------
+
+ Info [UMFPACK_NUMERIC_WALLTIME]: The wallclock time taken, in seconds.
+
+ Info [UMFPACK_MAX_FRONT_NROWS]: the max number of
+ rows in any frontal matrix.
+
+ Info [UMFPACK_MAX_FRONT_NCOLS]: the max number of
+ columns in any frontal matrix.
+
+ Info [UMFPACK_WAS_SCALED]: the scaling used, either UMFPACK_SCALE_NONE,
+ UMFPACK_SCALE_SUM, or UMFPACK_SCALE_MAX.
+
+ Info [UMFPACK_RSMIN]: if scaling is performed, the smallest scale factor
+ for any row (either the smallest sum of absolute entries, or the
+ smallest maximum of absolute entries).
+
+ Info [UMFPACK_RSMAX]: if scaling is performed, the largest scale factor
+ for any row (either the largest sum of absolute entries, or the
+ largest maximum of absolute entries).
+
+ Info [UMFPACK_ALLOC_INIT_USED]: the initial allocation parameter used.
+
+ Info [UMFPACK_FORCED_UPDATES]: the number of BLAS-3 updates to the
+ frontal matrices that were required because the frontal matrix
+ grew larger than its current working array.
+
+ Info [UMFPACK_NOFF_DIAG]: number of off-diagonal pivots selected, if the
+ symmetric or 2-by-2 strategies are used.
+
+ ------------------------------------------------------------------------
+ The following statistics were added to Version 4.2:
+ ------------------------------------------------------------------------
+
+ Info [UMFPACK_NZDROPPED]: the number of entries smaller in absolute
+ value than Control [UMFPACK_DROPTOL] that were dropped from L and U.
+ Note that entries on the diagonal of U are never dropped.
+
+ Info [UMFPACK_ALL_LNZ]: the number of entries in L, including the
+ diagonal, if no small entries are dropped.
+
+ Info [UMFPACK_ALL_UNZ]: the number of entries in U, including the
+ diagonal, if no small entries are dropped.
+
+ Only the above listed Info [...] entries are accessed. The remaining
+ entries of Info are not accessed or modified by umfpack_*_numeric.
+ Future versions might modify different parts of Info.
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_qsymbolic ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_qsymbolic
+(
+ int n_row,
+ int n_col,
+ const int Ap [ ],
+ const int Ai [ ],
+ const double Ax [ ],
+ const int Qinit [ ],
+ void **Symbolic,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO]
+) ;
+
+long umfpack_dl_qsymbolic
+(
+ long n_row,
+ long n_col,
+ const long Ap [ ],
+ const long Ai [ ],
+ const double Ax [ ],
+ const long Qinit [ ],
+ void **Symbolic,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO]
+) ;
+
+int umfpack_zi_qsymbolic
+(
+ int n_row,
+ int n_col,
+ const int Ap [ ],
+ const int Ai [ ],
+ const double Ax [ ], const double Az [ ],
+ const int Qinit [ ],
+ void **Symbolic,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO]
+) ;
+
+long umfpack_zl_qsymbolic
+(
+ long n_row,
+ long n_col,
+ const long Ap [ ],
+ const long Ai [ ],
+ const double Ax [ ], const double Az [ ],
+ const long Qinit [ ],
+ void **Symbolic,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO]
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ void *Symbolic ;
+ int n_row, n_col, *Ap, *Ai, *Qinit, status ;
+ double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax ;
+ status = umfpack_di_qsymbolic (n_row, n_col, Ap, Ai, Ax, Qinit,
+ &Symbolic, Control, Info) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ void *Symbolic ;
+ long n_row, n_col, *Ap, *Ai, *Qinit, status ;
+ double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax ;
+ status = umfpack_dl_qsymbolic (n_row, n_col, Ap, Ai, Ax, Qinit,
+ &Symbolic, Control, Info) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ void *Symbolic ;
+ int n_row, n_col, *Ap, *Ai, *Qinit, status ;
+ double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax, *Az ;
+ status = umfpack_zi_qsymbolic (n_row, n_col, Ap, Ai, Ax, Az, Qinit,
+ &Symbolic, Control, Info) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ void *Symbolic ;
+ long n_row, n_col, *Ap, *Ai, *Qinit, status ;
+ double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax, *Az ;
+ status = umfpack_zl_qsymbolic (n_row, n_col, Ap, Ai, Ax, Az, Qinit,
+ &Symbolic, Control, Info) ;
+
+Purpose:
+
+ Given the nonzero pattern of a sparse matrix A in column-oriented form, and
+ a sparsity preserving column pre-ordering Qinit, umfpack_*_qsymbolic
+ performs the symbolic factorization of A*Qinit (or A (:,Qinit) in MATLAB
+ notation). This is identical to umfpack_*_symbolic, except that neither
+ COLAMD nor AMD are called and the user input column order Qinit is used
+ instead. Note that in general, the Qinit passed to umfpack_*_qsymbolic
+ can differ from the final Q found in umfpack_*_numeric. The unsymmetric
+ strategy will perform a column etree postordering done in
+ umfpack_*_qsymbolic and sparsity-preserving modifications are made within
+ each frontal matrix during umfpack_*_numeric. The symmetric and 2-by-2
+ strategies will preserve Qinit, unless the matrix is structurally singular.
+
+ See umfpack_*_symbolic for more information.
+
+ *** WARNING *** A poor choice of Qinit can easily cause umfpack_*_numeric
+ to use a huge amount of memory and do a lot of work. The "default" symbolic
+ analysis method is umfpack_*_symbolic, not this routine. If you use this
+ routine, the performance of UMFPACK is your responsibility; UMFPACK will
+ not try to second-guess a poor choice of Qinit.
+
+Returns:
+
+ The value of Info [UMFPACK_STATUS]; see umfpack_*_symbolic.
+ Also returns UMFPACK_ERROR_invalid_permuation if Qinit is not a valid
+ permutation vector.
+
+Arguments:
+
+ All arguments are the same as umfpack_*_symbolic, except for the following:
+
+ Int Qinit [n_col] ; Input argument, not modified.
+
+ The user's fill-reducing initial column pre-ordering. This must be a
+ permutation of 0..n_col-1. If Qinit [k] = j, then column j is the kth
+ column of the matrix A (:,Qinit) to be factorized. If Qinit is an
+ (Int *) NULL pointer, then COLAMD or AMD are called instead.
+
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_report_control =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_di_report_control
+(
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+void umfpack_dl_report_control
+(
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+void umfpack_zi_report_control
+(
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+void umfpack_zl_report_control
+(
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ double Control [UMFPACK_CONTROL] ;
+ umfpack_di_report_control (Control) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ double Control [UMFPACK_CONTROL] ;
+ umfpack_dl_report_control (Control) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ double Control [UMFPACK_CONTROL] ;
+ umfpack_zi_report_control (Control) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ double Control [UMFPACK_CONTROL] ;
+ umfpack_zl_report_control (Control) ;
+
+Purpose:
+
+ Prints the current control settings. Note that with the default print
+ level, nothing is printed. Does nothing if Control is (double *) NULL.
+
+Arguments:
+
+ double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+ If a (double *) NULL pointer is passed, then the default control
+ settings are used. Otherwise, the settings are determined from the
+ Control array. See umfpack_*_defaults on how to fill the Control
+ array with the default settings. If Control contains NaN's, the
+ defaults are used. The following Control parameters are used:
+
+ Control [UMFPACK_PRL]: printing level.
+
+ 1 or less: no output
+ 2 or more: print all of Control
+ Default: 1
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_report_info ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_di_report_info
+(
+ const double Control [UMFPACK_CONTROL],
+ const double Info [UMFPACK_INFO]
+) ;
+
+void umfpack_dl_report_info
+(
+ const double Control [UMFPACK_CONTROL],
+ const double Info [UMFPACK_INFO]
+) ;
+
+void umfpack_zi_report_info
+(
+ const double Control [UMFPACK_CONTROL],
+ const double Info [UMFPACK_INFO]
+) ;
+
+void umfpack_zl_report_info
+(
+ const double Control [UMFPACK_CONTROL],
+ const double Info [UMFPACK_INFO]
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+ umfpack_di_report_info (Control, Info) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+ umfpack_dl_report_info (Control, Info) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+ umfpack_zi_report_info (Control, Info) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ;
+ umfpack_zl_report_info (Control, Info) ;
+
+Purpose:
+
+ Reports statistics from the umfpack_*_*symbolic, umfpack_*_numeric, and
+ umfpack_*_*solve routines.
+
+Arguments:
+
+ double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+ If a (double *) NULL pointer is passed, then the default control
+ settings are used. Otherwise, the settings are determined from the
+ Control array. See umfpack_*_defaults on how to fill the Control
+ array with the default settings. If Control contains NaN's, the
+ defaults are used. The following Control parameters are used:
+
+ Control [UMFPACK_PRL]: printing level.
+
+ 0 or less: no output, even when an error occurs
+ 1: error messages only
+ 2 or more: error messages, and print all of Info
+ Default: 1
+
+ double Info [UMFPACK_INFO] ; Input argument, not modified.
+
+ Info is an output argument of several UMFPACK routines.
+ The contents of Info are printed on standard output.
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_report_matrix ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_report_matrix
+(
+ int n_row,
+ int n_col,
+ const int Ap [ ],
+ const int Ai [ ],
+ const double Ax [ ],
+ int col_form,
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_dl_report_matrix
+(
+ long n_row,
+ long n_col,
+ const long Ap [ ],
+ const long Ai [ ],
+ const double Ax [ ],
+ long col_form,
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+int umfpack_zi_report_matrix
+(
+ int n_row,
+ int n_col,
+ const int Ap [ ],
+ const int Ai [ ],
+ const double Ax [ ], const double Az [ ],
+ int col_form,
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_zl_report_matrix
+(
+ long n_row,
+ long n_col,
+ const long Ap [ ],
+ const long Ai [ ],
+ const double Ax [ ], const double Az [ ],
+ long col_form,
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ int n_row, n_col, *Ap, *Ai, status ;
+ double *Ax, Control [UMFPACK_CONTROL] ;
+ status = umfpack_di_report_matrix (n_row, n_col, Ap, Ai, Ax, 1, Control) ;
+or:
+ status = umfpack_di_report_matrix (n_row, n_col, Ap, Ai, Ax, 0, Control) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ long n_row, n_col, *Ap, *Ai, status ;
+ double *Ax, Control [UMFPACK_CONTROL] ;
+ status = umfpack_dl_report_matrix (n_row, n_col, Ap, Ai, Ax, 1, Control) ;
+or:
+ status = umfpack_dl_report_matrix (n_row, n_col, Ap, Ai, Ax, 0, Control) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ int n_row, n_col, *Ap, *Ai, status ;
+ double *Ax, *Az, Control [UMFPACK_CONTROL] ;
+ status = umfpack_zi_report_matrix (n_row, n_col, Ap, Ai, Ax, Az, 1,
+ Control) ;
+or:
+ status = umfpack_zi_report_matrix (n_row, n_col, Ap, Ai, Ax, Az, 0,
+ Control) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ long n_row, n_col, *Ap, *Ai, status ;
+ double *Ax, Control [UMFPACK_CONTROL] ;
+ status = umfpack_zl_report_matrix (n_row, n_col, Ap, Ai, Ax, Az, 1,
+ Control) ;
+or:
+ status = umfpack_zl_report_matrix (n_row, n_col, Ap, Ai, Ax, Az, 0,
+ Control) ;
+
+Purpose:
+
+ Verifies and prints a row or column-oriented sparse matrix.
+
+Returns:
+
+ UMFPACK_OK if Control [UMFPACK_PRL] <= 2 (the input is not checked).
+
+ Otherwise (where n is n_col for the column form and n_row for row
+ and let ni be n_row for the column form and n_col for row):
+
+ UMFPACK_OK if the matrix is valid.
+
+ UMFPACK_ERROR_n_nonpositive if n_row <= 0 or n_col <= 0.
+ UMFPACK_ERROR_argument_missing if Ap and/or Ai are missing.
+ UMFPACK_ERROR_invalid_matrix if Ap [n] < 0, if Ap [0] is not zero,
+ if Ap [j+1] < Ap [j] for any j in the range 0 to n-1,
+ if any row index in Ai is not in the range 0 to ni-1, or
+ if the row indices in any column are not in
+ ascending order, or contain duplicates.
+ UMFPACK_ERROR_out_of_memory if out of memory.
+
+Arguments:
+
+ Int n_row ; Input argument, not modified.
+ Int n_col ; Input argument, not modified.
+
+ A is an n_row-by-n_row matrix. Restriction: n_row > 0 and n_col > 0.
+
+ Int Ap [n+1] ; Input argument, not modified.
+
+ n is n_row for a row-form matrix, and n_col for a column-form matrix.
+
+ Ap is an integer array of size n+1. If col_form is true (nonzero),
+ then on input, it holds the "pointers" for the column form of the
+ sparse matrix A. The row indices of column j of the matrix A are held
+ in Ai [(Ap [j]) ... (Ap [j+1]-1)]. Otherwise, Ap holds the
+ row pointers, and the column indices of row j of the matrix are held
+ in Ai [(Ap [j]) ... (Ap [j+1]-1)].
+
+ The first entry, Ap [0], must be zero, and Ap [j] <= Ap [j+1] must hold
+ for all j in the range 0 to n-1. The value nz = Ap [n] is thus the
+ total number of entries in the pattern of the matrix A.
+
+ Int Ai [nz] ; Input argument, not modified, of size nz = Ap [n].
+
+ If col_form is true (nonzero), then the nonzero pattern (row indices)
+ for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)]. Row indices
+ must be in the range 0 to n_row-1 (the matrix is 0-based).
+
+ Otherwise, the nonzero pattern (column indices) for row j is stored in
+ Ai [(Ap [j]) ... (Ap [j+1]-1)]. Column indices must be in the range 0
+ to n_col-1 (the matrix is 0-based).
+
+ double Ax [nz] ; Input argument, not modified, of size nz = Ap [n].
+
+ The numerical values of the sparse matrix A.
+
+ If col_form is true (nonzero), then the nonzero pattern (row indices)
+ for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and the
+ corresponding (real) numerical values are stored in
+ Ax [(Ap [j]) ... (Ap [j+1]-1)]. The imaginary parts are stored in
+ Az [(Ap [j]) ... (Ap [j+1]-1)], for the complex versions.
+
+ Otherwise, the nonzero pattern (column indices) for row j
+ is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and the corresponding
+ (real) numerical values are stored in Ax [(Ap [j]) ... (Ap [j+1]-1)].
+ The imaginary parts are stored in Az [(Ap [j]) ... (Ap [j+1]-1)],
+ for the complex versions.
+
+ No numerical values are printed if Ax or Az are (double *) NULL.
+
+ double Az [nz] ; Input argument, not modified, for complex versions.
+
+ The imaginary values of the sparse matrix A. See the description
+ of Ax, above. No numerical values are printed if Az is NULL.
+
+ Future complex version: if Ax is present and Az is NULL, then both real
+ and imaginary parts will be contained in Ax[0..2*nz-1], with Ax[2*k]
+ and Ax[2*k+1] being the real and imaginary part of the kth entry.
+
+ Int col_form ; Input argument, not modified.
+
+ The matrix is in row-oriented form if form is col_form is false (0).
+ Otherwise, the matrix is in column-oriented form.
+
+ double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+ If a (double *) NULL pointer is passed, then the default control
+ settings are used. Otherwise, the settings are determined from the
+ Control array. See umfpack_*_defaults on how to fill the Control
+ array with the default settings. If Control contains NaN's, the
+ defaults are used. The following Control parameters are used:
+
+ Control [UMFPACK_PRL]: printing level.
+
+ 2 or less: no output. returns silently without checking anything.
+ 3: fully check input, and print a short summary of its status
+ 4: as 3, but print first few entries of the input
+ 5: as 3, but print all of the input
+ Default: 1
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_report_numeric =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_report_numeric
+(
+ void *Numeric,
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_dl_report_numeric
+(
+ void *Numeric,
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+int umfpack_zi_report_numeric
+(
+ void *Numeric,
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_zl_report_numeric
+(
+ void *Numeric,
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ double Control [UMFPACK_CONTROL] ;
+ int status ;
+ status = umfpack_di_report_numeric (Numeric, Control) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ double Control [UMFPACK_CONTROL] ;
+ long status ;
+ status = umfpack_dl_report_numeric (Numeric, Control) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ double Control [UMFPACK_CONTROL] ;
+ int status ;
+ status = umfpack_zi_report_numeric (Numeric, Control) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ double Control [UMFPACK_CONTROL] ;
+ long status ;
+ status = umfpack_zl_report_numeric (Numeric, Control) ;
+
+Purpose:
+
+ Verifies and prints a Numeric object (the LU factorization, both its pattern
+ numerical values, and permutation vectors P and Q). This routine checks the
+ object more carefully than the computational routines. Normally, this check
+ is not required, since umfpack_*_numeric either returns (void *) NULL, or a
+ valid Numeric object. However, if you suspect that your own code has
+ corrupted the Numeric object (by overruning memory bounds, for example),
+ then this routine might be able to detect a corrupted Numeric object. Since
+ this is a complex object, not all such user-generated errors are guaranteed
+ to be caught by this routine.
+
+Returns:
+
+ UMFPACK_OK if Control [UMFPACK_PRL] <= 2 (the input is not checked).
+
+ Otherwise:
+
+ UMFPACK_OK if the Numeric object is valid.
+ UMFPACK_ERROR_invalid_Numeric_object if the Numeric object is invalid.
+ UMFPACK_ERROR_out_of_memory if out of memory.
+
+Arguments:
+
+ void *Numeric ; Input argument, not modified.
+
+ The Numeric object, which holds the numeric factorization computed by
+ umfpack_*_numeric.
+
+ double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+ If a (double *) NULL pointer is passed, then the default control
+ settings are used. Otherwise, the settings are determined from the
+ Control array. See umfpack_*_defaults on how to fill the Control
+ array with the default settings. If Control contains NaN's, the
+ defaults are used. The following Control parameters are used:
+
+ Control [UMFPACK_PRL]: printing level.
+
+ 2 or less: no output. returns silently without checking anything.
+ 3: fully check input, and print a short summary of its status
+ 4: as 3, but print first few entries of the input
+ 5: as 3, but print all of the input
+ Default: 1
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_report_perm ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_report_perm
+(
+ int np,
+ const int Perm [ ],
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_dl_report_perm
+(
+ long np,
+ const long Perm [ ],
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+int umfpack_zi_report_perm
+(
+ int np,
+ const int Perm [ ],
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_zl_report_perm
+(
+ long np,
+ const long Perm [ ],
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ int np, *Perm, status ;
+ double Control [UMFPACK_CONTROL] ;
+ status = umfpack_di_report_perm (np, Perm, Control) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ long np, *Perm, status ;
+ double Control [UMFPACK_CONTROL] ;
+ status = umfpack_dl_report_perm (np, Perm, Control) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ int np, *Perm, status ;
+ double Control [UMFPACK_CONTROL] ;
+ status = umfpack_zi_report_perm (np, Perm, Control) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ long np, *Perm, status ;
+ double Control [UMFPACK_CONTROL] ;
+ status = umfpack_zl_report_perm (np, Perm, Control) ;
+
+Purpose:
+
+ Verifies and prints a permutation vector.
+
+Returns:
+
+ UMFPACK_OK if Control [UMFPACK_PRL] <= 2 (the input is not checked).
+
+ Otherwise:
+ UMFPACK_OK if the permutation vector is valid (this includes that case
+ when Perm is (Int *) NULL, which is not an error condition).
+ UMFPACK_ERROR_n_nonpositive if np <= 0.
+ UMFPACK_ERROR_out_of_memory if out of memory.
+ UMFPACK_ERROR_invalid_permutation if Perm is not a valid permutation vector.
+
+Arguments:
+
+ Int np ; Input argument, not modified.
+
+ Perm is an integer vector of size np. Restriction: np > 0.
+
+ Int Perm [np] ; Input argument, not modified.
+
+ A permutation vector of size np. If Perm is not present (an (Int *)
+ NULL pointer), then it is assumed to be the identity permutation. This
+ is consistent with its use as an input argument to umfpack_*_qsymbolic,
+ and is not an error condition. If Perm is present, the entries in Perm
+ must range between 0 and np-1, and no duplicates may exist.
+
+ double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+ If a (double *) NULL pointer is passed, then the default control
+ settings are used. Otherwise, the settings are determined from the
+ Control array. See umfpack_*_defaults on how to fill the Control
+ array with the default settings. If Control contains NaN's, the
+ defaults are used. The following Control parameters are used:
+
+ Control [UMFPACK_PRL]: printing level.
+
+ 2 or less: no output. returns silently without checking anything.
+ 3: fully check input, and print a short summary of its status
+ 4: as 3, but print first few entries of the input
+ 5: as 3, but print all of the input
+ Default: 1
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_report_status ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_di_report_status
+(
+ const double Control [UMFPACK_CONTROL],
+ int status
+) ;
+
+void umfpack_dl_report_status
+(
+ const double Control [UMFPACK_CONTROL],
+ long status
+) ;
+
+void umfpack_zi_report_status
+(
+ const double Control [UMFPACK_CONTROL],
+ int status
+) ;
+
+void umfpack_zl_report_status
+(
+ const double Control [UMFPACK_CONTROL],
+ long status
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ double Control [UMFPACK_CONTROL] ;
+ int status ;
+ umfpack_di_report_status (Control, status) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ double Control [UMFPACK_CONTROL] ;
+ long status ;
+ umfpack_dl_report_status (Control, status) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ double Control [UMFPACK_CONTROL] ;
+ int status ;
+ umfpack_zi_report_status (Control, status) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ double Control [UMFPACK_CONTROL] ;
+ long status ;
+ umfpack_zl_report_status (Control, status) ;
+
+Purpose:
+
+ Prints the status (return value) of other umfpack_* routines.
+
+Arguments:
+
+ double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+ If a (double *) NULL pointer is passed, then the default control
+ settings are used. Otherwise, the settings are determined from the
+ Control array. See umfpack_*_defaults on how to fill the Control
+ array with the default settings. If Control contains NaN's, the
+ defaults are used. The following Control parameters are used:
+
+ Control [UMFPACK_PRL]: printing level.
+
+ 0 or less: no output, even when an error occurs
+ 1: error messages only
+ 2 or more: print status, whether or not an error occured
+ 4 or more: also print the UMFPACK Copyright
+ 6 or more: also print the UMFPACK License
+ Default: 1
+
+ Int status ; Input argument, not modified.
+
+ The return value from another umfpack_* routine.
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_report_symbolic ============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_report_symbolic
+(
+ void *Symbolic,
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_dl_report_symbolic
+(
+ void *Symbolic,
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+int umfpack_zi_report_symbolic
+(
+ void *Symbolic,
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_zl_report_symbolic
+(
+ void *Symbolic,
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ void *Symbolic ;
+ double Control [UMFPACK_CONTROL] ;
+ int status ;
+ status = umfpack_di_report_symbolic (Symbolic, Control) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ void *Symbolic ;
+ double Control [UMFPACK_CONTROL] ;
+ long status ;
+ status = umfpack_dl_report_symbolic (Symbolic, Control) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ void *Symbolic ;
+ double Control [UMFPACK_CONTROL] ;
+ int status ;
+ status = umfpack_zi_report_symbolic (Symbolic, Control) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ void *Symbolic ;
+ double Control [UMFPACK_CONTROL] ;
+ long status ;
+ status = umfpack_zl_report_symbolic (Symbolic, Control) ;
+
+Purpose:
+
+ Verifies and prints a Symbolic object. This routine checks the object more
+ carefully than the computational routines. Normally, this check is not
+ required, since umfpack_*_*symbolic either returns (void *) NULL, or a valid
+ Symbolic object. However, if you suspect that your own code has corrupted
+ the Symbolic object (by overruning memory bounds, for example), then this
+ routine might be able to detect a corrupted Symbolic object. Since this is
+ a complex object, not all such user-generated errors are guaranteed to be
+ caught by this routine.
+
+Returns:
+
+ UMFPACK_OK if Control [UMFPACK_PRL] is <= 2 (no inputs are checked).
+
+ Otherwise:
+
+ UMFPACK_OK if the Symbolic object is valid.
+ UMFPACK_ERROR_invalid_Symbolic_object if the Symbolic object is invalid.
+ UMFPACK_ERROR_out_of_memory if out of memory.
+
+Arguments:
+
+ void *Symbolic ; Input argument, not modified.
+
+ The Symbolic object, which holds the symbolic factorization computed by
+ umfpack_*_*symbolic.
+
+ double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+ If a (double *) NULL pointer is passed, then the default control
+ settings are used. Otherwise, the settings are determined from the
+ Control array. See umfpack_*_defaults on how to fill the Control
+ array with the default settings. If Control contains NaN's, the
+ defaults are used. The following Control parameters are used:
+
+ Control [UMFPACK_PRL]: printing level.
+
+ 2 or less: no output. returns silently without checking anything.
+ 3: fully check input, and print a short summary of its status
+ 4: as 3, but print first few entries of the input
+ 5: as 3, but print all of the input
+ Default: 1
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_report_triplet =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_report_triplet
+(
+ int n_row,
+ int n_col,
+ int nz,
+ const int Ti [ ],
+ const int Tj [ ],
+ const double Tx [ ],
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_dl_report_triplet
+(
+ long n_row,
+ long n_col,
+ long nz,
+ const long Ti [ ],
+ const long Tj [ ],
+ const double Tx [ ],
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+int umfpack_zi_report_triplet
+(
+ int n_row,
+ int n_col,
+ int nz,
+ const int Ti [ ],
+ const int Tj [ ],
+ const double Tx [ ], const double Tz [ ],
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_zl_report_triplet
+(
+ long n_row,
+ long n_col,
+ long nz,
+ const long Ti [ ],
+ const long Tj [ ],
+ const double Tx [ ], const double Tz [ ],
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ int n_row, n_col, nz, *Ti, *Tj, status ;
+ double *Tx, Control [UMFPACK_CONTROL] ;
+ status = umfpack_di_report_triplet (n_row, n_col, nz, Ti, Tj, Tx, Control) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ long n_row, n_col, nz, *Ti, *Tj, status ;
+ double *Tx, Control [UMFPACK_CONTROL] ;
+ status = umfpack_dl_report_triplet (n_row, n_col, nz, Ti, Tj, Tx, Control) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ int n_row, n_col, nz, *Ti, *Tj, status ;
+ double *Tx, *Tz, Control [UMFPACK_CONTROL] ;
+ status = umfpack_zi_report_triplet (n_row, n_col, nz, Ti, Tj, Tx, Tz,
+ Control) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ long n_row, n_col, nz, *Ti, *Tj, status ;
+ double *Tx, *Tz, Control [UMFPACK_CONTROL] ;
+ status = umfpack_zl_report_triplet (n_row, n_col, nz, Ti, Tj, Tx, Tz,
+ Control) ;
+
+Purpose:
+
+ Verifies and prints a matrix in triplet form.
+
+Returns:
+
+ UMFPACK_OK if Control [UMFPACK_PRL] <= 2 (the input is not checked).
+
+ Otherwise:
+
+ UMFPACK_OK if the Triplet matrix is OK.
+ UMFPACK_ERROR_argument_missing if Ti and/or Tj are missing.
+ UMFPACK_ERROR_n_nonpositive if n_row <= 0 or n_col <= 0.
+ UMFPACK_ERROR_invalid_matrix if nz < 0, or
+ if any row or column index in Ti and/or Tj
+ is not in the range 0 to n_row-1 or 0 to n_col-1, respectively.
+
+Arguments:
+
+ Int n_row ; Input argument, not modified.
+ Int n_col ; Input argument, not modified.
+
+ A is an n_row-by-n_col matrix.
+
+ Int nz ; Input argument, not modified.
+
+ The number of entries in the triplet form of the matrix.
+
+ Int Ti [nz] ; Input argument, not modified.
+ Int Tj [nz] ; Input argument, not modified.
+ double Tx [nz] ; Input argument, not modified.
+ double Tz [nz] ; Input argument, not modified, for complex versions.
+
+ Ti, Tj, Tx (and Tz for complex versions) hold the "triplet" form of a
+ sparse matrix. The kth nonzero entry is in row i = Ti [k], column
+ j = Tj [k], the real numerical value of a_ij is Tx [k], and the
+ imaginary part of a_ij is Tz [k] (for complex versions). The row and
+ column indices i and j must be in the range 0 to n_row-1 or 0 to
+ n_col-1, respectively. Duplicate entries may be present. The
+ "triplets" may be in any order. Tx and Tz are optional; if Tx or Tz are
+ not present ((double *) NULL pointers), then the numerical values are
+ not printed.
+
+ Future complex version: if Tx is present and Tz is NULL, then both real
+ and imaginary parts will be contained in Tx[0..2*nz-1], with Tx[2*k]
+ and Tx[2*k+1] being the real and imaginary part of the kth entry.
+
+ double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+ If a (double *) NULL pointer is passed, then the default control
+ settings are used. Otherwise, the settings are determined from the
+ Control array. See umfpack_*_defaults on how to fill the Control
+ array with the default settings. If Control contains NaN's, the
+ defaults are used. The following Control parameters are used:
+
+ Control [UMFPACK_PRL]: printing level.
+
+ 2 or less: no output. returns silently without checking anything.
+ 3: fully check input, and print a short summary of its status
+ 4: as 3, but print first few entries of the input
+ 5: as 3, but print all of the input
+ Default: 1
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_report_vector ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_report_vector
+(
+ int n,
+ const double X [ ],
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_dl_report_vector
+(
+ long n,
+ const double X [ ],
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+int umfpack_zi_report_vector
+(
+ int n,
+ const double Xx [ ], const double Xz [ ],
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+long umfpack_zl_report_vector
+(
+ long n,
+ const double Xx [ ], const double Xz [ ],
+ const double Control [UMFPACK_CONTROL]
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ int n, status ;
+ double *X, Control [UMFPACK_CONTROL] ;
+ status = umfpack_di_report_vector (n, X, Control) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ long n, status ;
+ double *X, Control [UMFPACK_CONTROL] ;
+ status = umfpack_dl_report_vector (n, X, Control) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ int n, status ;
+ double *Xx, *Xz, Control [UMFPACK_CONTROL] ;
+ status = umfpack_zi_report_vector (n, Xx, Xz, Control) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ long n, status ;
+ double *Xx, *Xz, Control [UMFPACK_CONTROL] ;
+ status = umfpack_zl_report_vector (n, Xx, Xz, Control) ;
+
+Purpose:
+
+ Verifies and prints a dense vector.
+
+Returns:
+
+ UMFPACK_OK if Control [UMFPACK_PRL] <= 2 (the input is not checked).
+
+ Otherwise:
+
+ UMFPACK_OK if the vector is valid.
+ UMFPACK_ERROR_argument_missing if X or Xx is missing.
+ UMFPACK_ERROR_n_nonpositive if n <= 0.
+
+Arguments:
+
+ Int n ; Input argument, not modified.
+
+ X is a real or complex vector of size n. Restriction: n > 0.
+
+ double X [n] ; Input argument, not modified. For real versions.
+
+ A real vector of size n. X must not be (double *) NULL.
+
+ double Xx [n or 2*n] ; Input argument, not modified. For complex versions.
+ double Xz [n or 0] ; Input argument, not modified. For complex versions.
+
+ A complex vector of size n, in one of two storage formats.
+ Xx must not be (double *) NULL.
+
+ If Xz is not (double *) NULL, then Xx [i] is the real part of X (i) and
+ Xz [i] is the imaginary part of X (i). Both vectors are of length n.
+ This is the "split" form of the complex vector X.
+
+ If Xz is (double *) NULL, then Xx holds both real and imaginary parts,
+ where Xx [2*i] is the real part of X (i) and Xx [2*i+1] is the imaginary
+ part of X (i). Xx is of length 2*n doubles. If you have an ANSI C99
+ compiler with the intrinsic double _Complex type, then Xx can be of
+ type double _Complex in the calling routine and typecast to (double *)
+ when passed to umfpack_*_report_vector (this is untested, however).
+ This is the "merged" form of the complex vector X.
+
+ Future work: all complex routines in UMFPACK could use this same
+ strategy for their complex arguments. The split format is useful for
+ MATLAB, which holds its real and imaginary parts in seperate arrays.
+ The merged format is compatible with the intrinsic double _Complex
+ type in ANSI C99, and is also compatible with SuperLU's method of
+ storing complex matrices. In the current version, only
+ umfpack_*_report_vector supports both formats.
+
+ double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+ If a (double *) NULL pointer is passed, then the default control
+ settings are used. Otherwise, the settings are determined from the
+ Control array. See umfpack_*_defaults on how to fill the Control
+ array with the default settings. If Control contains NaN's, the
+ defaults are used. The following Control parameters are used:
+
+ Control [UMFPACK_PRL]: printing level.
+
+ 2 or less: no output. returns silently without checking anything.
+ 3: fully check input, and print a short summary of its status
+ 4: as 3, but print first few entries of the input
+ 5: as 3, but print all of the input
+ Default: 1
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_save_numeric ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_save_numeric
+(
+ void *Numeric,
+ char *filename
+) ;
+
+long umfpack_dl_save_numeric
+(
+ void *Numeric,
+ char *filename
+) ;
+
+int umfpack_zi_save_numeric
+(
+ void *Numeric,
+ char *filename
+) ;
+
+long umfpack_zl_save_numeric
+(
+ void *Numeric,
+ char *filename
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ int status ;
+ char *filename ;
+ void *Numeric ;
+ status = umfpack_di_save_numeric (Numeric, filename) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ long status ;
+ char *filename ;
+ void *Numeric ;
+ status = umfpack_dl_save_numeric (Numeric, filename) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ int status ;
+ char *filename ;
+ void *Numeric ;
+ status = umfpack_zi_save_numeric (Numeric, filename) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ long status ;
+ char *filename ;
+ void *Numeric ;
+ status = umfpack_zl_save_numeric (Numeric, filename) ;
+
+Purpose:
+
+ Saves a Numeric object to a file, which can later be read by
+ umfpack_*_load_numeric. The Numeric object is not modified. You need
+ to call umfpack_*_free_numeric if you to delete the Numeric object after
+ saving it to a file.
+
+Returns:
+
+ UMFPACK_OK if successful.
+ UMFPACK_ERROR_invalid_Numeric_object if Numeric is not valid.
+ UMFPACK_ERROR_file_IO if an I/O error occurred.
+
+Arguments:
+
+ void *Numeric ; Input argument, not modified.
+
+ Numeric must point to a valid Numeric object, computed by
+ umfpack_*_numeric or loaded by umfpack_*_load_numeric.
+
+ char *filename ; Input argument, not modified.
+
+ A string that contains the filename to which the Numeric
+ object is written.
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_save_symbolic================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_save_symbolic
+(
+ void *Symbolic,
+ char *filename
+) ;
+
+long umfpack_dl_save_symbolic
+(
+ void *Symbolic,
+ char *filename
+) ;
+
+int umfpack_zi_save_symbolic
+(
+ void *Symbolic,
+ char *filename
+) ;
+
+long umfpack_zl_save_symbolic
+(
+ void *Symbolic,
+ char *filename
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ int status ;
+ char *filename ;
+ void *Symbolic ;
+ status = umfpack_di_save_symbolic (Symbolic, filename) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ long status ;
+ char *filename ;
+ void *Symbolic ;
+ status = umfpack_dl_save_symbolic (Symbolic, filename) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ int status ;
+ char *filename ;
+ void *Symbolic ;
+ status = umfpack_zi_save_symbolic (Symbolic, filename) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ long status ;
+ char *filename ;
+ void *Symbolic ;
+ status = umfpack_zl_save_symbolic (Symbolic, filename) ;
+
+Purpose:
+
+ Saves a Symbolic object to a file, which can later be read by
+ umfpack_*_load_symbolic. The Symbolic object is not modified. You need
+ to call umfpack_*_free_symbolic if you to delete the Symbolic object after
+ saving it to a file.
+
+Returns:
+
+ UMFPACK_OK if successful.
+ UMFPACK_ERROR_invalid_Symbolic_object if Symbolic is not valid.
+ UMFPACK_ERROR_file_IO if an I/O error occurred.
+
+Arguments:
+
+ void *Symbolic ; Input argument, not modified.
+
+ Symbolic must point to a valid Symbolic object, computed by
+ umfpack_*_symbolic or loaded by umfpack_*_load_symbolic.
+
+ char *filename ; Input argument, not modified.
+
+ A string that contains the filename to which the Symbolic
+ object is written.
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_scale ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_scale
+(
+ double X [ ],
+ const double B [ ],
+ void *Numeric
+) ;
+
+long umfpack_dl_scale
+(
+ double X [ ],
+ const double B [ ],
+ void *Numeric
+) ;
+
+int umfpack_zi_scale
+(
+ double Xx [ ], double Xz [ ],
+ const double Bx [ ], const double Bz [ ],
+ void *Numeric
+) ;
+
+long umfpack_zl_scale
+(
+ double Xx [ ], double Xz [ ],
+ const double Bx [ ], const double Bz [ ],
+ void *Numeric
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ double *B, *X ;
+ status = umfpack_di_scale (X, B, Numeric) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ double *B, *X ;
+ status = umfpack_dl_scale (X, B, Numeric) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ double *Bx, *Bz, *Xx, *Xz ;
+ status = umfpack_zi_scale (Xx, Xz, Bx, Bz, Numeric) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ double *Bx, *Bz, *Xx, *Xz ;
+ status = umfpack_zl_scale (Xx, Xz, Bx, Bz, Numeric) ;
+
+Purpose:
+
+ Given LU factors computed by umfpack_*_numeric (PAQ=LU, PRAQ=LU, or
+ P(R\A)Q=LU), and a vector B, this routine computes X = B, X = R*B, or
+ X = R\B, as appropriate. X and B must be vectors equal in length to the
+ number of rows of A.
+
+Returns:
+
+ The status code is returned. UMFPACK_OK is returned if successful.
+ UMFPACK_ERROR_invalid_Numeric_object is returned in the Numeric
+ object is invalid. UMFPACK_ERROR_argument_missing is returned if
+ any of the input vectors are missing (X and B for the real version,
+ and Xx, Xz, Bx, and Bz for the complex version).
+
+Arguments:
+
+ double X [n_row] ; Output argument.
+ or:
+ double Xx [n_row] ; Output argument, real part.
+ double Xz [n_row] ; Output argument, imaginary part.
+
+ The output vector X.
+
+ double B [n_row] ; Input argument, not modified.
+ or:
+ double Bx [n_row] ; Input argument, not modified, real part.
+ double Bz [n_row] ; Input argument, not modified, imaginary part.
+
+ The input vector B.
+
+ void *Numeric ; Input argument, not modified.
+
+ Numeric must point to a valid Numeric object, computed by
+ umfpack_*_numeric.
+
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_solve ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_solve
+(
+ int sys,
+ const int Ap [ ],
+ const int Ai [ ],
+ const double Ax [ ],
+ double X [ ],
+ const double B [ ],
+ void *Numeric,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO]
+) ;
+
+long umfpack_dl_solve
+(
+ long sys,
+ const long Ap [ ],
+ const long Ai [ ],
+ const double Ax [ ],
+ double X [ ],
+ const double B [ ],
+ void *Numeric,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO]
+) ;
+
+int umfpack_zi_solve
+(
+ int sys,
+ const int Ap [ ],
+ const int Ai [ ],
+ const double Ax [ ], const double Az [ ],
+ double Xx [ ], double Xz [ ],
+ const double Bx [ ], const double Bz [ ],
+ void *Numeric,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO]
+) ;
+
+long umfpack_zl_solve
+(
+ long sys,
+ const long Ap [ ],
+ const long Ai [ ],
+ const double Ax [ ], const double Az [ ],
+ double Xx [ ], double Xz [ ],
+ const double Bx [ ], const double Bz [ ],
+ void *Numeric,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO]
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ int status, *Ap, *Ai, sys ;
+ double *B, *X, *Ax, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ;
+ status = umfpack_di_solve (sys, Ap, Ai, Ax, X, B, Numeric, Control, Info) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ long status, *Ap, *Ai, sys ;
+ double *B, *X, *Ax, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ;
+ status = umfpack_dl_solve (sys, Ap, Ai, Ax, X, B, Numeric, Control, Info) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ int status, *Ap, *Ai, sys ;
+ double *Bx, *Bz, *Xx, *Xz, *Ax, *Az, Info [UMFPACK_INFO],
+ Control [UMFPACK_CONTROL] ;
+ status = umfpack_zi_solve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric,
+ Control, Info) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ long status, *Ap, *Ai, sys ;
+ double *Bx, *Bz, *Xx, *Xz, *Ax, *Az, Info [UMFPACK_INFO],
+ Control [UMFPACK_CONTROL] ;
+ status = umfpack_zl_solve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric,
+ Control, Info) ;
+
+Purpose:
+
+ Given LU factors computed by umfpack_*_numeric (PAQ=LU, PRAQ=LU, or
+ P(R\A)Q=LU) and the right-hand-side, B, solve a linear system for the
+ solution X. Iterative refinement is optionally performed. Only square
+ systems are handled. Singular matrices result in a divide-by-zero for all
+ systems except those involving just the matrix L. Iterative refinement is
+ not performed for singular matrices. In the discussion below, n is equal
+ to n_row and n_col, because only square systems are handled.
+
+Returns:
+
+ The status code is returned. See Info [UMFPACK_STATUS], below.
+
+Arguments:
+
+ Int sys ; Input argument, not modified.
+
+ Defines which system to solve. (') is the linear algebraic transpose
+ (complex conjugate if A is complex), and (.') is the array transpose.
+
+ sys value system solved
+ UMFPACK_A Ax=b
+ UMFPACK_At A'x=b
+ UMFPACK_Aat A.'x=b
+ UMFPACK_Pt_L P'Lx=b
+ UMFPACK_L Lx=b
+ UMFPACK_Lt_P L'Px=b
+ UMFPACK_Lat_P L.'Px=b
+ UMFPACK_Lt L'x=b
+ UMFPACK_U_Qt UQ'x=b
+ UMFPACK_U Ux=b
+ UMFPACK_Q_Ut QU'x=b
+ UMFPACK_Q_Uat QU.'x=b
+ UMFPACK_Ut U'x=b
+ UMFPACK_Uat U.'x=b
+
+ Iterative refinement can be optionally performed when sys is any of
+ the following:
+
+ UMFPACK_A Ax=b
+ UMFPACK_At A'x=b
+ UMFPACK_Aat A.'x=b
+
+ For the other values of the sys argument, iterative refinement is not
+ performed (Control [UMFPACK_IRSTEP], Ap, Ai, Ax, and Az are ignored).
+
+ Earlier versions used a string argument for sys. It was changed to an
+ integer to make it easier for a Fortran code to call UMFPACK.
+
+ Int Ap [n+1] ; Input argument, not modified.
+ Int Ai [nz] ; Input argument, not modified.
+ double Ax [nz] ; Input argument, not modified.
+ double Az [nz] ; Input argument, not modified, for complex versions.
+
+ If iterative refinement is requested (Control [UMFPACK_IRSTEP] >= 1,
+ Ax=b, A'x=b, or A.'x=b is being solved, and A is nonsingular), then
+ these arrays must be identical to the same ones passed to
+ umfpack_*_numeric. The umfpack_*_solve routine does not check the
+ contents of these arguments, so the results are undefined if Ap, Ai, Ax,
+ and/or Az are modified between the calls the umfpack_*_numeric and
+ umfpack_*_solve. These three arrays do not need to be present (NULL
+ pointers can be passed) if Control [UMFPACK_IRSTEP] is zero, or if a
+ system other than Ax=b, A'x=b, or A.'x=b is being solved, or if A is
+ singular, since in each of these cases A is not accessed.
+
+ Future complex version: if Ax is present and Az is NULL, then both real
+ and imaginary parts will be contained in Ax[0..2*nz-1], with Ax[2*k]
+ and Ax[2*k+1] being the real and imaginary part of the kth entry.
+
+ double X [n] ; Output argument.
+ or:
+ double Xx [n] ; Output argument, real part.
+ double Xz [n] ; Output argument, imaginary part.
+
+ The solution to the linear system, where n = n_row = n_col is the
+ dimension of the matrices A, L, and U.
+
+ Future complex version: if Xx is present and Xz is NULL, then both real
+ and imaginary parts will be returned in Xx[0..2*n-1], with Xx[2*k] and
+ Xx[2*k+1] being the real and imaginary part of the kth entry.
+
+ double B [n] ; Input argument, not modified.
+ or:
+ double Bx [n] ; Input argument, not modified, real part.
+ double Bz [n] ; Input argument, not modified, imaginary part.
+
+ The right-hand side vector, b, stored as a conventional array of size n
+ (or two arrays of size n for complex versions). This routine does not
+ solve for multiple right-hand-sides, nor does it allow b to be stored in
+ a sparse-column form.
+
+ Future complex version: if Bx is present and Bz is NULL, then both real
+ and imaginary parts will be contained in Bx[0..2*n-1], with Bx[2*k]
+ and Bx[2*k+1] being the real and imaginary part of the kth entry.
+
+ void *Numeric ; Input argument, not modified.
+
+ Numeric must point to a valid Numeric object, computed by
+ umfpack_*_numeric.
+
+ double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+ If a (double *) NULL pointer is passed, then the default control
+ settings are used. Otherwise, the settings are determined from the
+ Control array. See umfpack_*_defaults on how to fill the Control
+ array with the default settings. If Control contains NaN's, the
+ defaults are used. The following Control parameters are used:
+
+ Control [UMFPACK_IRSTEP]: The maximum number of iterative refinement
+ steps to attempt. A value less than zero is treated as zero. If
+ less than 1, or if Ax=b, A'x=b, or A.'x=b is not being solved, or
+ if A is singular, then the Ap, Ai, Ax, and Az arguments are not
+ accessed. Default: 2.
+
+ double Info [UMFPACK_INFO] ; Output argument.
+
+ Contains statistics about the solution factorization. If a
+ (double *) NULL pointer is passed, then no statistics are returned in
+ Info (this is not an error condition). The following statistics are
+ computed in umfpack_*_solve:
+
+ Info [UMFPACK_STATUS]: status code. This is also the return value,
+ whether or not Info is present.
+
+ UMFPACK_OK
+
+ The linear system was successfully solved.
+
+ UMFPACK_WARNING_singular_matrix
+
+ A divide-by-zero occured. Your solution will contain Inf's
+ and/or NaN's. Some parts of the solution may be valid. For
+ example, solving Ax=b with
+
+ A = [2 0] b = [ 1 ] returns x = [ 0.5 ]
+ [0 0] [ 0 ] [ Inf ]
+
+ UMFPACK_ERROR_out_of_memory
+
+ Insufficient memory to solve the linear system.
+
+ UMFPACK_ERROR_argument_missing
+
+ One or more required arguments are missing. The B, X, (or
+ Bx, Bz, Xx and Xz for the complex versions) arguments
+ are always required. Info and Control are not required. Ap,
+ Ai, Ax (and Az for complex versions) are required if Ax=b,
+ A'x=b, A.'x=b is to be solved, the (default) iterative
+ refinement is requested, and the matrix A is nonsingular.
+
+ UMFPACK_ERROR_invalid_system
+
+ The sys argument is not valid, or the matrix A is not square.
+
+ UMFPACK_ERROR_invalid_Numeric_object
+
+ The Numeric object is not valid.
+
+ Info [UMFPACK_NROW], Info [UMFPACK_NCOL]:
+ The dimensions of the matrix A (L is n_row-by-n_inner and
+ U is n_inner-by-n_col, with n_inner = min(n_row,n_col)).
+
+ Info [UMFPACK_NZ]: the number of entries in the input matrix, Ap [n],
+ if iterative refinement is requested (Ax=b, A'x=b, or A.'x=b is
+ being solved, Control [UMFPACK_IRSTEP] >= 1, and A is nonsingular).
+
+ Info [UMFPACK_IR_TAKEN]: The number of iterative refinement steps
+ effectively taken. The number of steps attempted may be one more
+ than this; the refinement algorithm backtracks if the last
+ refinement step worsens the solution.
+
+ Info [UMFPACK_IR_ATTEMPTED]: The number of iterative refinement steps
+ attempted. The number of times a linear system was solved is one
+ more than this (once for the initial Ax=b, and once for each Ay=r
+ solved for each iterative refinement step attempted).
+
+ Info [UMFPACK_OMEGA1]: sparse backward error estimate, omega1, if
+ iterative refinement was performed, or -1 if iterative refinement
+ not performed.
+
+ Info [UMFPACK_OMEGA2]: sparse backward error estimate, omega2, if
+ iterative refinement was performed, or -1 if iterative refinement
+ not performed.
+
+ Info [UMFPACK_SOLVE_FLOPS]: the number of floating point operations
+ performed to solve the linear system. This includes the work
+ taken for all iterative refinement steps, including the backtrack
+ (if any).
+
+ Info [UMFPACK_SOLVE_TIME]: The time taken, in seconds.
+
+ ------------------------------------------------------------------------
+ The following statistic was added to Version 4.1:
+ ------------------------------------------------------------------------
+
+ Info [UMFPACK_SOLVE_WALLTIME]: The wallclock time taken, in seconds.
+
+ Only the above listed Info [...] entries are accessed. The remaining
+ entries of Info are not accessed or modified by umfpack_*_solve.
+ Future versions might modify different parts of Info.
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_symbolic ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_symbolic
+(
+ int n_row,
+ int n_col,
+ const int Ap [ ],
+ const int Ai [ ],
+ const double Ax [ ],
+ void **Symbolic,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO]
+) ;
+
+long umfpack_dl_symbolic
+(
+ long n_row,
+ long n_col,
+ const long Ap [ ],
+ const long Ai [ ],
+ const double Ax [ ],
+ void **Symbolic,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO]
+) ;
+
+int umfpack_zi_symbolic
+(
+ int n_row,
+ int n_col,
+ const int Ap [ ],
+ const int Ai [ ],
+ const double Ax [ ], const double Az [ ],
+ void **Symbolic,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO]
+) ;
+
+long umfpack_zl_symbolic
+(
+ long n_row,
+ long n_col,
+ const long Ap [ ],
+ const long Ai [ ],
+ const double Ax [ ], const double Az [ ],
+ void **Symbolic,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO]
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ void *Symbolic ;
+ int n_row, n_col, *Ap, *Ai, status ;
+ double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax ;
+ status = umfpack_di_symbolic (n_row, n_col, Ap, Ai, Ax,
+ &Symbolic, Control, Info) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ void *Symbolic ;
+ long n_row, n_col, *Ap, *Ai, status ;
+ double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax ;
+ status = umfpack_dl_symbolic (n_row, n_col, Ap, Ai, Ax,
+ &Symbolic, Control, Info) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ void *Symbolic ;
+ int n_row, n_col, *Ap, *Ai, status ;
+ double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax, *Az ;
+ status = umfpack_zi_symbolic (n_row, n_col, Ap, Ai, Ax, Az,
+ &Symbolic, Control, Info) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ void *Symbolic ;
+ long n_row, n_col, *Ap, *Ai, status ;
+ double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax, *Az ;
+ status = umfpack_zl_symbolic (n_row, n_col, Ap, Ai, Ax, Az,
+ &Symbolic, Control, Info) ;
+
+Purpose:
+
+ Given nonzero pattern of a sparse matrix A in column-oriented form,
+ umfpack_*_symbolic performs a column pre-ordering to reduce fill-in
+ (using COLAMD or AMD) and a symbolic factorization. This is required
+ before the matrix can be numerically factorized with umfpack_*_numeric.
+ If you wish to bypass the COLAMD or AMD pre-ordering and provide your own
+ ordering, use umfpack_*_qsymbolic instead.
+
+ Since umfpack_*_symbolic and umfpack_*_qsymbolic are very similar, options
+ for both routines are discussed below.
+
+ For the following discussion, let S be the submatrix of A obtained after
+ eliminating all pivots of zero Markowitz cost. S has dimension
+ (n_row-n1-nempty_row) -by- (n_col-n1-nempty_col), where
+ n1 = Info [UMFPACK_COL_SINGLETONS] + Info [UMFPACK_ROW_SINGLETONS],
+ nempty_row = Info [UMFPACK_NEMPTY_ROW] and
+ nempty_col = Info [UMFPACK_NEMPTY_COL].
+
+Returns:
+
+ The status code is returned. See Info [UMFPACK_STATUS], below.
+
+Arguments:
+
+ Int n_row ; Input argument, not modified.
+ Int n_col ; Input argument, not modified.
+
+ A is an n_row-by-n_col matrix. Restriction: n_row > 0 and n_col > 0.
+
+ Int Ap [n_col+1] ; Input argument, not modified.
+
+ Ap is an integer array of size n_col+1. On input, it holds the
+ "pointers" for the column form of the sparse matrix A. Column j of
+ the matrix A is held in Ai [(Ap [j]) ... (Ap [j+1]-1)]. The first
+ entry, Ap [0], must be zero, and Ap [j] <= Ap [j+1] must hold for all
+ j in the range 0 to n_col-1. The value nz = Ap [n_col] is thus the
+ total number of entries in the pattern of the matrix A. nz must be
+ greater than or equal to zero.
+
+ Int Ai [nz] ; Input argument, not modified, of size nz = Ap [n_col].
+
+ The nonzero pattern (row indices) for column j is stored in
+ Ai [(Ap [j]) ... (Ap [j+1]-1)]. The row indices in a given column j
+ must be in ascending order, and no duplicate row indices may be present.
+ Row indices must be in the range 0 to n_row-1 (the matrix is 0-based).
+ See umfpack_*_triplet_to_col for how to sort the columns of a matrix
+ and sum up the duplicate entries. See umfpack_*_report_matrix for how
+ to print the matrix A.
+
+ double Ax [nz] ; Optional input argument, not modified.
+
+ The numerical values of the sparse matrix A. The nonzero pattern (row
+ indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and
+ the corresponding numerical values are stored in
+ Ax [(Ap [j]) ... (Ap [j+1]-1)]. Used only by the 2-by-2 strategy to
+ determine whether entries are "large" or "small". You do not have to
+ pass the same numerical values to umfpack_*_numeric. If Ax is not
+ present (a (double *) NULL pointer), then any entry in A is assumed to
+ be "large".
+
+ double Az [nz] ; Optional input argument, not modified, for complex
+ versions.
+
+ For the complex versions, this holds the imaginary part of A. The
+ imaginary part of column j is held in Az [(Ap [j]) ... (Ap [j+1]-1)].
+
+ Future complex version: if Ax is present and Az is NULL, then both real
+ and imaginary parts will be contained in Ax[0..2*nz-1], with Ax[2*k]
+ and Ax[2*k+1] being the real and imaginary part of the kth entry.
+
+ Used by the 2-by-2 strategy only. See the description of Ax, above.
+
+ void **Symbolic ; Output argument.
+
+ **Symbolic is the address of a (void *) pointer variable in the user's
+ calling routine (see Syntax, above). On input, the contents of this
+ variable are not defined. On output, this variable holds a (void *)
+ pointer to the Symbolic object (if successful), or (void *) NULL if
+ a failure occurred.
+
+ double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+
+ If a (double *) NULL pointer is passed, then the default control
+ settings are used (the defaults are suitable for all matrices,
+ ranging from those with highly unsymmetric nonzero pattern, to
+ symmetric matrices). Otherwise, the settings are determined from the
+ Control array. See umfpack_*_defaults on how to fill the Control
+ array with the default settings. If Control contains NaN's, the
+ defaults are used. The following Control parameters are used:
+
+ Control [UMFPACK_STRATEGY]: This is the most important control
+ parameter. It determines what kind of ordering and pivoting
+ strategy that UMFPACK should use. It is new to Version 4.1
+ There are 4 options:
+
+ UMFPACK_STRATEGY_AUTO: This is the default. The input matrix is
+ analyzed to determine how symmetric the nonzero pattern is, and
+ how many entries there are on the diagonal. It then selects one
+ of the following strategies. Refer to the User Guide for a
+ description of how the strategy is automatically selected.
+
+ UMFPACK_STRATEGY_UNSYMMETRIC: Use the unsymmetric strategy. COLAMD
+ is used to order the columns of A, followed by a postorder of
+ the column elimination tree. No attempt is made to perform
+ diagonal pivoting. The column ordering is refined during
+ factorization. This strategy was the only one provided with
+ UMFPACK V4.0.
+
+ In the numerical factorization, the
+ Control [UMFPACK_SYM_PIVOT_TOLERANCE] parameter is ignored. A
+ pivot is selected if its magnitude is >=
+ Control [UMFPACK_PIVOT_TOLERANCE] (default 0.1) times the
+ largest entry in its column.
+
+ UMFPACK_STRATEGY_SYMMETRIC: Use the symmetric strategy (new to
+ Version 4.1). In this method, the approximate minimum degree
+ ordering (AMD) is applied to A+A', followed by a postorder of
+ the elimination tree of A+A'. UMFPACK attempts to perform
+ diagonal pivoting during numerical factorization. No refinement
+ of the column pre-ordering is performed during factorization.
+
+ In the numerical factorization, a nonzero entry on the diagonal
+ is selected as the pivot if its magnitude is >= Control
+ [UMFPACK_SYM_PIVOT_TOLERANCE] (default 0.001) times the largest
+ entry in its column. If this is not acceptable, then an
+ off-diagonal pivot is selected with magnitude >= Control
+ [UMFPACK_PIVOT_TOLERANCE] (default 0.1) times the largest entry
+ in its column.
+
+ UMFPACK_STRATEGY_2BY2: a row permutation P2 is found that places
+ large entries on the diagonal. The matrix P2*A is then
+ factorized using the symmetric strategy, described above.
+ Refer to the User Guide for more information.
+
+ Control [UMFPACK_DENSE_COL]:
+ If COLAMD is used, columns with more than
+ max (16, Control [UMFPACK_DENSE_COL] * 16 * sqrt (n_row)) entries
+ are placed placed last in the column pre-ordering. Default: 0.2.
+
+ Control [UMFPACK_DENSE_ROW]:
+ Rows with more than max (16, Control [UMFPACK_DENSE_ROW] * 16 *
+ sqrt (n_col)) entries are treated differently in the COLAMD
+ pre-ordering, and in the internal data structures during the
+ subsequent numeric factorization. Default: 0.2.
+
+ Control [UMFPACK_AMD_DENSE]: rows/columns in A+A' with more than
+ max (16, Control [UMFPACK_AMD_DENSE] * sqrt (n)) entries
+ (where n = n_row = n_col) are ignored in the AMD pre-ordering.
+ Default: 10.
+
+ Control [UMFPACK_BLOCK_SIZE]: the block size to use for Level-3 BLAS
+ in the subsequent numerical factorization (umfpack_*_numeric).
+ A value less than 1 is treated as 1. Default: 32. Modifying this
+ parameter affects when updates are applied to the working frontal
+ matrix, and can indirectly affect fill-in and operation count.
+ As long as the block size is large enough (8 or so), this parameter
+ has a modest effect on performance.
+
+ Control [UMFPACK_2BY2_TOLERANCE]: a diagonal entry S (k,k) is
+ considered "small" if it is < tol * max (abs (S (:,k))), where S a
+ submatrix of the scaled input matrix, with pivots of zero Markowitz
+ cost removed.
+
+ Control [UMFPACK_SCALE]: This parameter is new to V4.1. See
+ umfpack_numeric.h for a description. Only affects the 2-by-2
+ strategy. Default: UMFPACK_SCALE_SUM.
+
+ Control [UMFPACK_FIXQ]: If > 0, then the pre-ordering Q is not modified
+ during numeric factorization. If < 0, then Q may be modified. If
+ zero, then this is controlled automatically (the unsymmetric
+ strategy modifies Q, the others do not). Default: 0.
+
+ Control [UMFPACK_AGGRESSIVE]: If nonzero, aggressive absorption is used
+ in COLAMD and AMD. Default: 1.
+
+ double Info [UMFPACK_INFO] ; Output argument, not defined on input.
+
+ Contains statistics about the symbolic analysis. If a (double *) NULL
+ pointer is passed, then no statistics are returned in Info (this is not
+ an error condition). The entire Info array is cleared (all entries set
+ to -1) and then the following statistics are computed:
+
+ Info [UMFPACK_STATUS]: status code. This is also the return value,
+ whether or not Info is present.
+
+ UMFPACK_OK
+
+ Each column of the input matrix contained row indices
+ in increasing order, with no duplicates. Only in this case
+ does umfpack_*_symbolic compute a valid symbolic factorization.
+ For the other cases below, no Symbolic object is created
+ (*Symbolic is (void *) NULL).
+
+ UMFPACK_ERROR_n_nonpositive
+
+ n is less than or equal to zero.
+
+ UMFPACK_ERROR_invalid_matrix
+
+ Number of entries in the matrix is negative, Ap [0] is nonzero,
+ a column has a negative number of entries, a row index is out of
+ bounds, or the columns of input matrix were jumbled (unsorted
+ columns or duplicate entries).
+
+ UMFPACK_ERROR_out_of_memory
+
+ Insufficient memory to perform the symbolic analysis. If the
+ analysis requires more than 2GB of memory and you are using
+ the 32-bit ("int") version of UMFPACK, then you are guaranteed
+ to run out of memory. Try using the 64-bit version of UMFPACK.
+
+ UMFPACK_ERROR_argument_missing
+
+ One or more required arguments is missing.
+
+ UMFPACK_ERROR_internal_error
+
+ Something very serious went wrong. This is a bug.
+ Please contact the author (davis@cise.ufl.edu).
+
+ Note that the UMFPACK_ERROR_problem_too_large error code is no
+ longer returned (it was in Version 4.0).
+
+ Info [UMFPACK_NROW]: the value of the input argument n_row.
+
+ Info [UMFPACK_NCOL]: the value of the input argument n_col.
+
+ Info [UMFPACK_NZ]: the number of entries in the input matrix
+ (Ap [n_col]).
+
+ Info [UMFPACK_SIZE_OF_UNIT]: the number of bytes in a Unit,
+ for memory usage statistics below.
+
+ Info [UMFPACK_SIZE_OF_INT]: the number of bytes in an int.
+
+ Info [UMFPACK_SIZE_OF_LONG]: the number of bytes in a long.
+
+ Info [UMFPACK_SIZE_OF_POINTER]: the number of bytes in a void *
+ pointer.
+
+ Info [UMFPACK_SIZE_OF_ENTRY]: the number of bytes in a numerical entry.
+
+ Info [UMFPACK_NDENSE_ROW]: number of "dense" rows in A. These rows are
+ ignored when the column pre-ordering is computed in COLAMD. They
+ are also treated differently during numeric factorization. If > 0,
+ then the matrix had to be re-analyzed by UMF_analyze, which does
+ not ignore these rows.
+
+ Info [UMFPACK_NEMPTY_ROW]: number of "empty" rows in A, as determined
+ These are rows that either have no entries, or whose entries are
+ all in pivot columns of zero-Markowitz-cost pivots.
+
+ Info [UMFPACK_NDENSE_COL]: number of "dense" columns in A. COLAMD
+ orders these columns are ordered last in the factorization, but
+ before "empty" columns.
+
+ Info [UMFPACK_NEMPTY_COL]: number of "empty" columns in A. These are
+ columns that either have no entries, or whose entries are all in
+ pivot rows of zero-Markowitz-cost pivots. These columns are
+ ordered last in the factorization, to the right of "dense" columns.
+
+ Info [UMFPACK_SYMBOLIC_DEFRAG]: number of garbage collections
+ performed during ordering and symbolic pre-analysis.
+
+ Info [UMFPACK_SYMBOLIC_PEAK_MEMORY]: the amount of memory (in Units)
+ required for umfpack_*_symbolic to complete. This count includes
+ the size of the Symbolic object itself, which is also reported in
+ Info [UMFPACK_SYMBOLIC_SIZE].
+
+ Info [UMFPACK_SYMBOLIC_SIZE]: the final size of the Symbolic object (in
+ Units). This is fairly small, roughly 2*n to 13*n integers,
+ depending on the matrix.
+
+ Info [UMFPACK_VARIABLE_INIT_ESTIMATE]: the Numeric object contains two
+ parts. The first is fixed in size (O (n_row+n_col)). The
+ second part holds the sparse LU factors and the contribution blocks
+ from factorized frontal matrices. This part changes in size during
+ factorization. Info [UMFPACK_VARIABLE_INIT_ESTIMATE] is the exact
+ size (in Units) required for this second variable-sized part in
+ order for the numerical factorization to start.
+
+ Info [UMFPACK_VARIABLE_PEAK_ESTIMATE]: the estimated peak size (in
+ Units) of the variable-sized part of the Numeric object. This is
+ usually an upper bound, but that is not guaranteed.
+
+ Info [UMFPACK_VARIABLE_FINAL_ESTIMATE]: the estimated final size (in
+ Units) of the variable-sized part of the Numeric object. This is
+ usually an upper bound, but that is not guaranteed. It holds just
+ the sparse LU factors.
+
+ Info [UMFPACK_NUMERIC_SIZE_ESTIMATE]: an estimate of the final size (in
+ Units) of the entire Numeric object (both fixed-size and variable-
+ sized parts), which holds the LU factorization (including the L, U,
+ P and Q matrices).
+
+ Info [UMFPACK_PEAK_MEMORY_ESTIMATE]: an estimate of the total amount of
+ memory (in Units) required by umfpack_*_symbolic and
+ umfpack_*_numeric to perform both the symbolic and numeric
+ factorization. This is the larger of the amount of memory needed
+ in umfpack_*_numeric itself, and the amount of memory needed in
+ umfpack_*_symbolic (Info [UMFPACK_SYMBOLIC_PEAK_MEMORY]). The
+ count includes the size of both the Symbolic and Numeric objects
+ themselves. It can be a very loose upper bound, particularly when
+ the symmetric or 2-by-2 strategies are used.
+
+ Info [UMFPACK_FLOPS_ESTIMATE]: an estimate of the total floating-point
+ operations required to factorize the matrix. This is a "true"
+ theoretical estimate of the number of flops that would be performed
+ by a flop-parsimonious sparse LU algorithm. It assumes that no
+ extra flops are performed except for what is strictly required to
+ compute the LU factorization. It ignores, for example, the flops
+ performed by umfpack_di_numeric to add contribution blocks of
+ frontal matrices together. If L and U are the upper bound on the
+ pattern of the factors, then this flop count estimate can be
+ represented in MATLAB (for real matrices, not complex) as:
+
+ Lnz = full (sum (spones (L))) - 1 ; % nz in each col of L
+ Unz = full (sum (spones (U')))' - 1 ; % nz in each row of U
+ flops = 2*Lnz*Unz + sum (Lnz) ;
+
+ The actual "true flop" count found by umfpack_*_numeric will be
+ less than this estimate.
+
+ For the real version, only (+ - * /) are counted. For the complex
+ version, the following counts are used:
+
+ operation flops
+ c = 1/b 6
+ c = a*b 6
+ c -= a*b 8
+
+ Info [UMFPACK_LNZ_ESTIMATE]: an estimate of the number of nonzeros in
+ L, including the diagonal. Since L is unit-diagonal, the diagonal
+ of L is not stored. This estimate is a strict upper bound on the
+ actual nonzeros in L to be computed by umfpack_*_numeric.
+
+ Info [UMFPACK_UNZ_ESTIMATE]: an estimate of the number of nonzeros in
+ U, including the diagonal. This estimate is a strict upper bound on
+ the actual nonzeros in U to be computed by umfpack_*_numeric.
+
+ Info [UMFPACK_MAX_FRONT_SIZE_ESTIMATE]: estimate of the size of the
+ largest frontal matrix (# of entries), for arbitrary partial
+ pivoting during numerical factorization.
+
+ Info [UMFPACK_SYMBOLIC_TIME]: The CPU time taken, in seconds.
+
+ ------------------------------------------------------------------------
+ The rest of the statistics are new to Version 4.1:
+ ------------------------------------------------------------------------
+
+ Info [UMFPACK_SYMBOLIC_WALLTIME]: The wallclock time taken, in seconds.
+
+ Info [UMFPACK_STRATEGY_USED]: The ordering strategy used:
+ UMFPACK_STRATEGY_SYMMETRIC, UMFPACK_STRATEGY_UNSYMMETRIC, or
+ UMFPACK_STRATEGY_2BY2.
+
+ Info [UMFPACK_ORDERING_USED]: The ordering method used:
+ UMFPACK_ORDERING_COLAMD or UMFPACK_ORDERING_AMD. It can be
+ UMFPACK_ORDERING_GIVEN for umfpack_*_qsymbolic.
+
+ Info [UMFPACK_QFIXED]: 1 if the column pre-ordering will be refined
+ during numerical factorization, 0 if not.
+
+ Info [UMFPACK_DIAG_PREFERED]: 1 if diagonal pivoting will be attempted,
+ 0 if not.
+
+ Info [UMFPACK_COL_SINGLETONS]: the matrix A is analyzed by first
+ eliminating all pivots with zero Markowitz cost. This count is the
+ number of these pivots with exactly one nonzero in their pivot
+ column.
+
+ Info [UMFPACK_ROW_SINGLETONS]: the number of zero-Markowitz-cost
+ pivots with exactly one nonzero in their pivot row.
+
+ Info [UMFPACK_PATTERN_SYMMETRY]: the symmetry of the pattern of S.
+
+ Info [UMFPACK_NZ_A_PLUS_AT]: the number of off-diagonal entries in S+S'.
+
+ Info [UMFPACK_NZDIAG]: the number of entries on the diagonal of S.
+
+ Info [UMFPACK_N2]: if S is square, and nempty_row = nempty_col, this
+ is equal to n_row - n1 - nempty_row.
+
+ Info [UMFPACK_S_SYMMETRIC]: 1 if S is square and its diagonal has been
+ preserved, 0 otherwise.
+
+
+ Info [UMFPACK_MAX_FRONT_NROWS_ESTIMATE]: estimate of the max number of
+ rows in any frontal matrix, for arbitrary partial pivoting.
+
+ Info [UMFPACK_MAX_FRONT_NCOLS_ESTIMATE]: estimate of the max number of
+ columns in any frontal matrix, for arbitrary partial pivoting.
+
+ ------------------------------------------------------------------------
+ The next four statistics are computed only if AMD is used:
+ ------------------------------------------------------------------------
+
+ Info [UMFPACK_SYMMETRIC_LUNZ]: The number of nonzeros in L and U,
+ assuming no pivoting during numerical factorization, and assuming a
+ zero-free diagonal of U. Excludes the entries on the diagonal of
+ L. If the matrix has a purely symmetric nonzero pattern, this is
+ often a lower bound on the nonzeros in the actual L and U computed
+ in the numerical factorization, for matrices that fit the criteria
+ for the "symmetric" strategy.
+
+ Info [UMFPACK_SYMMETRIC_FLOPS]: The floating-point operation count in
+ the numerical factorization phase, assuming no pivoting. If the
+ pattern of the matrix is symmetric, this is normally a lower bound
+ on the floating-point operation count in the actual numerical
+ factorization, for matrices that fit the criteria for the symmetric
+ or 2-by-2 strategies
+
+ Info [UMFPACK_SYMMETRIC_NDENSE]: The number of "dense" rows/columns of
+ S+S' that were ignored during the AMD ordering. These are placed
+ last in the output order. If > 0, then the
+ Info [UMFPACK_SYMMETRIC_*] statistics, above are rough upper bounds.
+
+ Info [UMFPACK_SYMMETRIC_DMAX]: The maximum number of nonzeros in any
+ column of L, if no pivoting is performed during numerical
+ factorization. Excludes the part of the LU factorization for
+ pivots with zero Markowitz cost.
+
+ ------------------------------------------------------------------------
+ The following statistics are computed only if the 2-by-2 strategy is
+ used or attempted:
+ ------------------------------------------------------------------------
+
+ Info [UMFPACK_2BY2_NWEAK]: the number of small diagonal entries in S.
+
+ Info [UMFPACK_2BY2_UNMATCHED]: the number of small diagonal entries
+ in P2*S.
+
+ Info [UMFPACK_2BY2_PATTERN_SYMMETRY]: the symmetry of P2*S.
+
+ Info [UMFPACK_2BY2_NZ_PA_PLUS_AT]: the number of off-diagonal entries
+ in (P2*S)+(P2*S)'.
+
+ Info [UMFPACK_2BY2_NZDIAG]: the number of nonzero entries on the
+ diagonal of P2*S.
+
+
+ At the start of umfpack_*_symbolic, all of Info is set of -1, and then
+ after that only the above listed Info [...] entries are accessed.
+ Future versions might modify different parts of Info.
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_tictoc ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_tic (double stats [2]) ;
+
+void umfpack_toc (double stats [2]) ;
+
+
+/*
+Syntax (for all versions: di, dl, zi, and zl):
+
+ #include "umfpack.h"
+ double stats [2] ;
+ umfpack_tic (stats) ;
+ ...
+ umfpack_toc (stats) ;
+
+Purpose:
+
+ umfpack_tic returns the CPU time and wall clock time used by the process.
+ The CPU time includes both "user" and "system" time (the latter is time
+ spent by the system on behalf of the process, and is thus charged to the
+ process). umfpack_toc returns the CPU time and wall clock time since the
+ last call to umfpack_tic with the same stats array.
+
+ Typical usage:
+
+ umfpack_tic (stats) ;
+ ... do some work ...
+ umfpack_toc (stats) ;
+
+ then stats [1] contains the time in seconds used by the code between
+ umfpack_tic and umfpack_toc, and stats [0] contains the wall clock time
+ elapsed between the umfpack_tic and umfpack_toc. These two routines act
+ just like tic and toc in MATLAB, except that the both process time and
+ wall clock time are returned.
+
+ This routine normally uses the sysconf and times routines in the POSIX
+ standard. If -DNPOSIX is defined at compile time, then the ANSI C clock
+ routine is used instead, and only the CPU time is returned (stats [0]
+ is set to zero).
+
+ umfpack_tic and umfpack_toc are the routines used internally in UMFPACK
+ to time the symbolic analysis, numerical factorization, and the forward/
+ backward solve.
+
+Arguments:
+
+ double stats [2]:
+
+ stats [0]: wall clock time, in seconds
+ stats [1]: CPU time, in seconds
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_timer ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+double umfpack_timer ( void ) ;
+
+/*
+Syntax (for all versions: di, dl, zi, and zl):
+
+ #include "umfpack.h"
+ double t ;
+ t = umfpack_timer ( ) ;
+
+Purpose:
+
+ Returns the CPU time used by the process. Includes both "user" and "system"
+ time (the latter is time spent by the system on behalf of the process, and
+ is thus charged to the process). It does not return the wall clock time.
+ This was the timer used internally in UMFPACK V4.0. See umfpack_tic and
+ umfpack_toc (the file umfpack_tictoc.h) for the timer used internally by
+ UMFPACK V4.1.
+
+ This routine uses the Unix getrusage routine, if available. It is less
+ subject to overflow than the ANSI C clock routine. If getrusage is not
+ available, the portable ANSI C clock routine is used instead.
+ Unfortunately, clock ( ) overflows if the CPU time exceeds 2147 seconds
+ (about 36 minutes) when sizeof (clock_t) is 4 bytes. If you have getrusage,
+ be sure to compile UMFPACK with the -DGETRUSAGE flag set; see umf_config.h
+ and the User Guide for details. Even the getrusage routine can overlow.
+
+Arguments:
+
+ None.
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_transpose ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_transpose
+(
+ int n_row,
+ int n_col,
+ const int Ap [ ],
+ const int Ai [ ],
+ const double Ax [ ],
+ const int P [ ],
+ const int Q [ ],
+ int Rp [ ],
+ int Ri [ ],
+ double Rx [ ]
+) ;
+
+long umfpack_dl_transpose
+(
+ long n_row,
+ long n_col,
+ const long Ap [ ],
+ const long Ai [ ],
+ const double Ax [ ],
+ const long P [ ],
+ const long Q [ ],
+ long Rp [ ],
+ long Ri [ ],
+ double Rx [ ]
+) ;
+
+int umfpack_zi_transpose
+(
+ int n_row,
+ int n_col,
+ const int Ap [ ],
+ const int Ai [ ],
+ const double Ax [ ], const double Az [ ],
+ const int P [ ],
+ const int Q [ ],
+ int Rp [ ],
+ int Ri [ ],
+ double Rx [ ], double Rz [ ],
+ int do_conjugate
+) ;
+
+long umfpack_zl_transpose
+(
+ long n_row,
+ long n_col,
+ const long Ap [ ],
+ const long Ai [ ],
+ const double Ax [ ], const double Az [ ],
+ const long P [ ],
+ const long Q [ ],
+ long Rp [ ],
+ long Ri [ ],
+ double Rx [ ], double Rz [ ],
+ long do_conjugate
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ int n_row, n_col, status, *Ap, *Ai, *P, *Q, *Rp, *Ri ;
+ double *Ax, *Rx ;
+ status = umfpack_di_transpose (n_row, n_col, Ap, Ai, Ax, P, Q, Rp, Ri, Rx) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ long n_row, n_col, status, *Ap, *Ai, *P, *Q, *Rp, *Ri ;
+ double *Ax, *Rx ;
+ status = umfpack_dl_transpose (n_row, n_col, Ap, Ai, Ax, P, Q, Rp, Ri, Rx) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ int n_row, n_col, status, *Ap, *Ai, *P, *Q, *Rp, *Ri, do_conjugate ;
+ double *Ax, *Az, *Rx, *Rz ;
+ status = umfpack_zi_transpose (n_row, n_col, Ap, Ai, Ax, Az, P, Q,
+ Rp, Ri, Rx, Rz, do_conjugate) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ long n_row, n_col, status, *Ap, *Ai, *P, *Q, *Rp, *Ri, do_conjugate ;
+ double *Ax, *Az, *Rx, *Rz ;
+ status = umfpack_zl_transpose (n_row, n_col, Ap, Ai, Ax, Az, P, Q,
+ Rp, Ri, Rx, Rz, do_conjugate) ;
+
+Purpose:
+
+ Transposes and optionally permutes a sparse matrix in row or column-form,
+ R = (PAQ)'. In MATLAB notation, R = (A (P,Q))' or R = (A (P,Q)).' doing
+ either the linear algebraic transpose or the array transpose. Alternatively,
+ this routine can be viewed as converting A (P,Q) from column-form to
+ row-form, or visa versa (for the array transpose). Empty rows and columns
+ may exist. The matrix A may be singular and/or rectangular.
+
+ umfpack_*_transpose is useful if you want to factorize A' or A.' instead of
+ A. Factorizing A' or A.' instead of A can be much better, particularly if
+ AA' is much sparser than A'A. You can still solve Ax=b if you factorize
+ A' or A.', by solving with the sys argument UMFPACK_At or UMFPACK_Aat,
+ respectively, in umfpack_*_*solve. The umfpack mexFunction (umfpackmex.c)
+ is one example. To compute x = A/b, it computes x = (A.'\b.').' instead,
+ by factorizing A.'. It then uses the regular solve, since b.' and x.' are
+ stored identically as b and x, respectively (both b.' and b are dense
+ vectors). If b and x were arrays, the umfpack mexFunction would need to
+ first compute b.' and then transpose the resulting solution.
+
+Returns:
+
+ UMFPACK_OK if successful.
+ UMFPACK_ERROR_out_of_memory if umfpack_*_transpose fails to allocate a
+ size-max (n_row,n_col) workspace.
+ UMFPACK_ERROR_argument_missing if Ai, Ap, Ri, and/or Rp are missing.
+ UMFPACK_ERROR_n_nonpositive if n_row <= 0 or n_col <= 0
+ UMFPACK_ERROR_invalid_permutation if P and/or Q are invalid.
+ UMFPACK_ERROR_invalid_matrix if Ap [n_col] < 0, if Ap [0] != 0,
+ if Ap [j] > Ap [j+1] for any j in the range 0 to n_col-1,
+ if any row index i is < 0 or >= n_row, or if the row indices
+ in any column are not in ascending order.
+
+Arguments:
+
+ Int n_row ; Input argument, not modified.
+ Int n_col ; Input argument, not modified.
+
+ A is an n_row-by-n_col matrix. Restriction: n_row > 0 and n_col > 0.
+
+ Int Ap [n_col+1] ; Input argument, not modified.
+
+ The column pointers of the column-oriented form of the matrix A. See
+ umfpack_*_symbolic for a description. The number of entries in
+ the matrix is nz = Ap [n_col]. Ap [0] must be zero, Ap [n_col] must be
+ => 0, and Ap [j] <= Ap [j+1] and Ap [j] <= Ap [n_col] must be true for
+ all j in the range 0 to n_col-1. Empty columns are OK (that is, Ap [j]
+ may equal Ap [j+1] for any j in the range 0 to n_col-1).
+
+ Int Ai [nz] ; Input argument, not modified, of size nz = Ap [n_col].
+
+ The nonzero pattern (row indices) for column j is stored in
+ Ai [(Ap [j]) ... (Ap [j+1]-1)]. The row indices in a given column j
+ must be in ascending order, and no duplicate row indices may be present.
+ Row indices must be in the range 0 to n_row-1 (the matrix is 0-based).
+
+ double Ax [nz] ; Input argument, not modified, of size nz = Ap [n_col].
+ double Az [nz] ; Input argument, not modified, for complex versions.
+
+ If present, these are the numerical values of the sparse matrix A.
+ The nonzero pattern (row indices) for column j is stored in
+ Ai [(Ap [j]) ... (Ap [j+1]-1)], and the corresponding real numerical
+ values are stored in Ax [(Ap [j]) ... (Ap [j+1]-1)]. The imaginary
+ values are stored in Az [(Ap [j]) ... (Ap [j+1]-1)]. The values are
+ transposed only if Ax and Rx are present (for the real version), and
+ only if all four (Ax, Az, Rx, and Rz) are present for the complex
+ version. These are not an error conditions; you are able to transpose
+ and permute just the pattern of a matrix.
+
+ Future complex version: if Ax is present and Az is NULL, then both real
+ and imaginary parts will be contained in Ax[0..2*nz-1], with Ax[2*k]
+ and Ax[2*k+1] being the real and imaginary part of the kth entry.
+
+ Int P [n_row] ; Input argument, not modified.
+
+ The permutation vector P is defined as P [k] = i, where the original
+ row i of A is the kth row of PAQ. If you want to use the identity
+ permutation for P, simply pass (Int *) NULL for P. This is not an error
+ condition. P is a complete permutation of all the rows of A; this
+ routine does not support the creation of a transposed submatrix of A
+ (R = A (1:3,:)' where A has more than 3 rows, for example, cannot be
+ done; a future version might support this operation).
+
+ Int Q [n_col] ; Input argument, not modified.
+
+ The permutation vector Q is defined as Q [k] = j, where the original
+ column j of A is the kth column of PAQ. If you want to use the identity
+ permutation for Q, simply pass (Int *) NULL for Q. This is not an error
+ condition. Q is a complete permutation of all the columns of A; this
+ routine does not support the creation of a transposed submatrix of A.
+
+ Int Rp [n_row+1] ; Output argument.
+
+ The column pointers of the matrix R = (A (P,Q))' or (A (P,Q)).', in the
+ same form as the column pointers Ap for the matrix A.
+
+ Int Ri [nz] ; Output argument.
+
+ The row indices of the matrix R = (A (P,Q))' or (A (P,Q)).' , in the
+ same form as the row indices Ai for the matrix A.
+
+ double Rx [nz] ; Output argument.
+ double Rz [nz] ; Output argument, imaginary part for complex versions.
+
+ If present, these are the numerical values of the sparse matrix R,
+ in the same form as the values Ax and Az of the matrix A.
+
+ Future complex version: if Rx is present and Rz is NULL, then both real
+ and imaginary parts will be contained in Rx[0..2*nz-1], with Rx[2*k]
+ and Rx[2*k+1] being the real and imaginary part of the kth entry.
+
+ Int do_conjugate ; Input argument for complex versions only.
+
+ If true, and if Ax, Az, Rx, and Rz are all present, then the linear
+ algebraic transpose is computed (complex conjugate). If false, the
+ array transpose is computed instead.
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_triplet_to_col =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_triplet_to_col
+(
+ int n_row,
+ int n_col,
+ int nz,
+ const int Ti [ ],
+ const int Tj [ ],
+ const double Tx [ ],
+ int Ap [ ],
+ int Ai [ ],
+ double Ax [ ],
+ int Map [ ]
+) ;
+
+long umfpack_dl_triplet_to_col
+(
+ long n_row,
+ long n_col,
+ long nz,
+ const long Ti [ ],
+ const long Tj [ ],
+ const double Tx [ ],
+ long Ap [ ],
+ long Ai [ ],
+ double Ax [ ],
+ long Map [ ]
+) ;
+
+int umfpack_zi_triplet_to_col
+(
+ int n_row,
+ int n_col,
+ int nz,
+ const int Ti [ ],
+ const int Tj [ ],
+ const double Tx [ ], const double Tz [ ],
+ int Ap [ ],
+ int Ai [ ],
+ double Ax [ ], double Az [ ],
+ int Map [ ]
+) ;
+
+long umfpack_zl_triplet_to_col
+(
+ long n_row,
+ long n_col,
+ long nz,
+ const long Ti [ ],
+ const long Tj [ ],
+ const double Tx [ ], const double Tz [ ],
+ long Ap [ ],
+ long Ai [ ],
+ double Ax [ ], double Az [ ],
+ long Map [ ]
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ int n_row, n_col, nz, *Ti, *Tj, *Ap, *Ai, status, *Map ;
+ double *Tx, *Ax ;
+ status = umfpack_di_triplet_to_col (n_row, n_col, nz, Ti, Tj, Tx,
+ Ap, Ai, Ax, Map) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ long n_row, n_col, nz, *Ti, *Tj, *Ap, *Ai, status, *Map ;
+ double *Tx, *Ax ;
+ status = umfpack_dl_triplet_to_col (n_row, n_col, nz, Ti, Tj, Tx,
+ Ap, Ai, Ax, Map) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ int n_row, n_col, nz, *Ti, *Tj, *Ap, *Ai, status, *Map ;
+ double *Tx, *Tz, *Ax, *Az ;
+ status = umfpack_zi_triplet_to_col (n_row, n_col, nz, Ti, Tj, Tx, Tz,
+ Ap, Ai, Ax, Az, Map) ;
+
+long Syntax:
+
+ #include "umfpack.h"
+ long n_row, n_col, nz, *Ti, *Tj, *Ap, *Ai, status, *Map ;
+ double *Tx, *Tz, *Ax, *Az ;
+ status = umfpack_zl_triplet_to_col (n_row, n_col, nz, Ti, Tj, Tx, Tz,
+ Ap, Ai, Ax, Az, Map) ;
+
+Purpose:
+
+ Converts a sparse matrix from "triplet" form to compressed-column form.
+ Analogous to A = spconvert (Ti, Tj, Tx + Tx*1i) in MATLAB, except that
+ zero entries present in the triplet form are present in A.
+
+ The triplet form of a matrix is a very simple data structure for basic
+ sparse matrix operations. For example, suppose you wish to factorize a
+ matrix A coming from a finite element method, in which A is a sum of
+ dense submatrices, A = E1 + E2 + E3 + ... . The entries in each element
+ matrix Ei can be concatenated together in the three triplet arrays, and
+ any overlap between the elements will be correctly summed by
+ umfpack_*_triplet_to_col.
+
+ Transposing a matrix in triplet form is simple; just interchange the
+ use of Ti and Tj. You can construct the complex conjugate transpose by
+ negating Tz, for the complex versions.
+
+ Permuting a matrix in triplet form is also simple. If you want the matrix
+ PAQ, or A (P,Q) in MATLAB notation, where P [k] = i means that row i of
+ A is the kth row of PAQ and Q [k] = j means that column j of A is the kth
+ column of PAQ, then do the following. First, create inverse permutations
+ Pinv and Qinv such that Pinv [i] = k if P [k] = i and Qinv [j] = k if
+ Q [k] = j. Next, for the mth triplet (Ti [m], Tj [m], Tx [m], Tz [m]),
+ replace Ti [m] with Pinv [Ti [m]] and replace Tj [m] with Qinv [Tj [m]].
+
+ If you have a column-form matrix with duplicate entries or unsorted
+ columns, you can sort it and sum up the duplicates by first converting it
+ to triplet form with umfpack_*_col_to_triplet, and then converting it back
+ with umfpack_*_triplet_to_col.
+
+ Constructing a submatrix is also easy. Just scan the triplets and remove
+ those entries outside the desired subset of 0...n_row-1 and 0...n_col-1,
+ and renumber the indices according to their position in the subset.
+
+ You can do all these operations on a column-form matrix by first
+ converting it to triplet form with umfpack_*_col_to_triplet, doing the
+ operation on the triplet form, and then converting it back with
+ umfpack_*_triplet_to_col.
+
+ The only operation not supported easily in the triplet form is the
+ multiplication of two sparse matrices (UMFPACK does not provide this
+ operation).
+
+ You can print the input triplet form with umfpack_*_report_triplet, and
+ the output matrix with umfpack_*_report_matrix.
+
+ The matrix may be singular (nz can be zero, and empty rows and/or columns
+ may exist). It may also be rectangular and/or complex.
+
+Returns:
+
+ UMFPACK_OK if successful.
+ UMFPACK_ERROR_argument_missing if Ap, Ai, Ti, and/or Tj are missing.
+ UMFPACK_ERROR_n_nonpositive if n_row <= 0 or n_col <= 0.
+ UMFPACK_ERROR_invalid_matrix if nz < 0, or if for any k, Ti [k] and/or
+ Tj [k] are not in the range 0 to n_row-1 or 0 to n_col-1, respectively.
+ UMFPACK_ERROR_out_of_memory if unable to allocate sufficient workspace.
+
+Arguments:
+
+ Int n_row ; Input argument, not modified.
+ Int n_col ; Input argument, not modified.
+
+ A is an n_row-by-n_col matrix. Restriction: n_row > 0 and n_col > 0.
+ All row and column indices in the triplet form must be in the range
+ 0 to n_row-1 and 0 to n_col-1, respectively.
+
+ Int nz ; Input argument, not modified.
+
+ The number of entries in the triplet form of the matrix. Restriction:
+ nz >= 0.
+
+ Int Ti [nz] ; Input argument, not modified.
+ Int Tj [nz] ; Input argument, not modified.
+ double Tx [nz] ; Input argument, not modified.
+ double Tz [nz] ; Input argument, not modified, for complex versions.
+
+ Ti, Tj, Tx, and Tz hold the "triplet" form of a sparse matrix. The kth
+ nonzero entry is in row i = Ti [k], column j = Tj [k], and the real part
+ of a_ij is Tx [k]. The imaginary part of a_ij is Tz [k], for complex
+ versions. The row and column indices i and j must be in the range 0 to
+ n_row-1 and 0 to n_col-1, respectively. Duplicate entries may be
+ present; they are summed in the output matrix. This is not an error
+ condition. The "triplets" may be in any order. Tx, Tz, Ax, and Az
+ are optional. For the real version, Ax is computed only if both Ax
+ and Tx are present (not (double *) NULL). For the complex version, Ax
+ and Az are computed only if Tx, Tz, Ax, and Az are all present. These
+ are not error conditions; the routine can create just the pattern of
+ the output matrix from the pattern of the triplets.
+
+ Future complex version: if Tx is present and Tz is NULL, then both real
+ and imaginary parts will be contained in Tx[0..2*nz-1], with Tx[2*k]
+ and Tx[2*k+1] being the real and imaginary part of the kth entry.
+
+ Int Ap [n_col+1] ; Output argument.
+
+ Ap is an integer array of size n_col+1 on input. On output, Ap holds
+ the "pointers" for the column form of the sparse matrix A. Column j of
+ the matrix A is held in Ai [(Ap [j]) ... (Ap [j+1]-1)]. The first
+ entry, Ap [0], is zero, and Ap [j] <= Ap [j+1] holds for all j in the
+ range 0 to n_col-1. The value nz2 = Ap [n_col] is thus the total
+ number of entries in the pattern of the matrix A. Equivalently, the
+ number of duplicate triplets is nz - Ap [n_col].
+
+ Int Ai [nz] ; Output argument.
+
+ Ai is an integer array of size nz on input. Note that only the first
+ Ap [n_col] entries are used.
+
+ The nonzero pattern (row indices) for column j is stored in
+ Ai [(Ap [j]) ... (Ap [j+1]-1)]. The row indices in a given column j
+ are in ascending order, and no duplicate row indices are present.
+ Row indices are in the range 0 to n_col-1 (the matrix is 0-based).
+
+ double Ax [nz] ; Output argument.
+ double Az [nz] ; Output argument for complex versions.
+
+ Ax and Az (for the complex versions) are double arrays of size nz on
+ input. Note that only the first Ap [n_col] entries are used
+ in both arrays.
+
+ Ax is optional; if Tx and/or Ax are not present (a (double *) NULL
+ pointer), then Ax is not computed. Az is also optional; if Tz and/or
+ Az are not present, then Az is not computed. If present, Ax holds the
+ numerical values of the the real part of the sparse matrix A and Az
+ holds the imaginary parts. The nonzero pattern (row indices) for
+ column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and the
+ corresponding numerical values are stored in
+ Ax [(Ap [j]) ... (Ap [j+1]-1)]. The imaginary parts are stored in
+ Az [(Ap [j]) ... (Ap [j+1]-1)], for the complex versions.
+
+ Future complex version: if Ax is present and Az is NULL, then both real
+ and imaginary parts will be returned in Ax[0..2*nz2-1], with Ax[2*k]
+ and Ax[2*k+1] being the real and imaginary part of the kth entry.
+
+ int Map [nz] ; Optional output argument.
+
+ If Map is present (a non-NULL pointer to an Int array of size nz), then
+ on output it holds the position of the triplets in the column-form
+ matrix. That is, suppose p = Map [k], and the k-th triplet is i=Ti[k],
+ j=Tj[k], and aij=Tx[k]. Then i=Ai[p], and aij will have been summed
+ into Ax[p] (or simply aij=Ax[p] if there were no duplicate entries also
+ in row i and column j). Also, Ap[j] <= p < Ap[j+1]. The Map array is
+ not computed if it is (Int *) NULL. The Map array is useful for
+ converting a subsequent triplet form matrix with the same pattern as the
+ first one, without calling this routine. If Ti and Tj do not change,
+ then Ap, and Ai can be reused from the prior call to
+ umfpack_*_triplet_to_col. You only need to recompute Ax (and Az for the
+ complex version). This code excerpt properly sums up all duplicate
+ values (for the real version):
+
+ for (p = 0 ; p < Ap [n_col] ; p++) Ax [p] = 0 ;
+ for (k = 0 ; k < nz ; k++) Ax [Map [k]] += Tx [k] ;
+
+ This feature is useful (along with the reuse of the Symbolic object) if
+ you need to factorize a sequence of triplet matrices with identical
+ nonzero pattern (the order of the triplets in the Ti,Tj,Tx arrays must
+ also remain unchanged). It is faster than calling this routine for
+ each matrix, and requires no workspace.
+*/
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_wsolve ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+int umfpack_di_wsolve
+(
+ int sys,
+ const int Ap [ ],
+ const int Ai [ ],
+ const double Ax [ ],
+ double X [ ],
+ const double B [ ],
+ void *Numeric,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO],
+ int Wi [ ],
+ double W [ ]
+) ;
+
+long umfpack_dl_wsolve
+(
+ long sys,
+ const long Ap [ ],
+ const long Ai [ ],
+ const double Ax [ ],
+ double X [ ],
+ const double B [ ],
+ void *Numeric,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO],
+ long Wi [ ],
+ double W [ ]
+) ;
+
+int umfpack_zi_wsolve
+(
+ int sys,
+ const int Ap [ ],
+ const int Ai [ ],
+ const double Ax [ ], const double Az [ ],
+ double Xx [ ], double Xz [ ],
+ const double Bx [ ], const double Bz [ ],
+ void *Numeric,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO],
+ int Wi [ ],
+ double W [ ]
+) ;
+
+long umfpack_zl_wsolve
+(
+ long sys,
+ const long Ap [ ],
+ const long Ai [ ],
+ const double Ax [ ], const double Az [ ],
+ double Xx [ ], double Xz [ ],
+ const double Bx [ ], const double Bz [ ],
+ void *Numeric,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO],
+ long Wi [ ],
+ double W [ ]
+) ;
+
+/*
+double int Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ int status, *Ap, *Ai, *Wi, sys ;
+ double *B, *X, *Ax, *W, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ;
+ status = umfpack_di_wsolve (sys, Ap, Ai, Ax, X, B, Numeric,
+ Control, Info, Wi, W) ;
+
+double long Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ long status, *Ap, *Ai, *Wi, sys ;
+ double *B, *X, *Ax, *W, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ;
+ status = umfpack_dl_wsolve (sys, Ap, Ai, Ax, X, B, Numeric,
+ Control, Info, Wi, W) ;
+
+complex int Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ int status, *Ap, *Ai, *Wi, sys ;
+ double *Bx, *Bz, *Xx, *Xz, *Ax, *Az, *W,
+ Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ;
+ status = umfpack_zi_wsolve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric,
+ Control, Info, Wi, W) ;
+
+complex long Syntax:
+
+ #include "umfpack.h"
+ void *Numeric ;
+ long status, *Ap, *Ai, *Wi, sys ;
+ double *Bx, *Bz, *Xx, *Xz, *Ax, *Az, *W,
+ Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ;
+ status = umfpack_zl_wsolve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric,
+ Control, Info, Wi, W) ;
+
+Purpose:
+
+ Given LU factors computed by umfpack_*_numeric (PAQ=LU) and the
+ right-hand-side, B, solve a linear system for the solution X. Iterative
+ refinement is optionally performed. This routine is identical to
+ umfpack_*_solve, except that it does not dynamically allocate any workspace.
+ When you have many linear systems to solve, this routine is faster than
+ umfpack_*_solve, since the workspace (Wi, W) needs to be allocated only
+ once, prior to calling umfpack_*_wsolve.
+
+Returns:
+
+ The status code is returned. See Info [UMFPACK_STATUS], below.
+
+Arguments:
+
+ Int sys ; Input argument, not modified.
+ Int Ap [n+1] ; Input argument, not modified.
+ Int Ai [nz] ; Input argument, not modified.
+ double Ax [nz] ; Input argument, not modified.
+ double X [n] ; Output argument.
+ double B [n] ; Input argument, not modified.
+ void *Numeric ; Input argument, not modified.
+ double Control [UMFPACK_CONTROL] ; Input argument, not modified.
+ double Info [UMFPACK_INFO] ; Output argument.
+
+ for complex versions:
+ double Az [nz] ; Input argument, not modified, imaginary part
+ double Xx [n] ; Output argument, real part.
+ double Xz [n] ; Output argument, imaginary part
+ double Bx [n] ; Input argument, not modified, real part
+ double Bz [n] ; Input argument, not modified, imaginary part
+
+ The above arguments are identical to umfpack_*_solve, except that the
+ error code UMFPACK_ERROR_out_of_memory will not be returned in
+ Info [UMFPACK_STATUS], since umfpack_*_wsolve does not allocate any
+ memory.
+
+ Int Wi [n] ; Workspace.
+ double W [c*n] ; Workspace, where c is defined below.
+
+ The Wi and W arguments are workspace used by umfpack_*_wsolve. They
+ need not be initialized on input, and their contents are undefined on
+ output. The size of W depends on whether or not iterative refinement is
+ used, and which version (real or complex) is called. Iterative
+ refinement is performed if Ax=b, A'x=b, or A.'x=b is being solved,
+ Control [UMFPACK_IRSTEP] > 0, and A is nonsingular. The size of W is
+ given below:
+
+ no iter. with iter.
+ refinement refinement
+ umfpack_di_wsolve n 5*n
+ umfpack_dl_wsolve n 5*n
+ umfpack_zi_wsolve 4*n 10*n
+ umfpack_zl_wsolve 4*n 10*n
+*/
--- /dev/null
+%Contents of the UMFPACK sparse matrix toolbox:
+%
+% umfpack computes x=A\b, x=A/b, or lu (A) for a sparse matrix A
+% umfpack_make to compile umfpack for use in MATLAB
+% umfpack_details details on all the options for using umfpack in MATLAB
+% umfpack_report prints optional control settings and statistics
+% umfpack_demo a long demo
+% umfpack_simple a simple demo
+% umfpack_btf factorize A using a block triangular form
+% umfpack_solve x = A\b or x = b/A
+% lu_normest estimates norm (L*U-A, 1) without forming L*U-A
+% luflop given L and U, computes # of flops required to compute them
+%
+% See also:
+% amd symmetric minimum degree ordering
+% colamd unsymmetric column approx minimum degree ordering
+% symamd symmetric approx minimum degree ordering, based on colamd
+%
+% UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+% Davis. All Rights Reserved. Type umfpack_details for License.
+
+help Contents
--- /dev/null
+#-------------------------------------------------------------------------------
+# UMFPACK GNUmakefile for the UMFPACK MATLAB mexFunction (GNU "make" only)
+#-------------------------------------------------------------------------------
+
+# UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+# Davis. All Rights Reserved. See ../README for License.
+
+all: umfpack luflop
+
+include ../Make/Make.include
+
+MX = $(MEX) -I../Include -I../Source -I../../AMD/Include -I../../AMD/Source
+
+#-------------------------------------------------------------------------------
+# source files
+#-------------------------------------------------------------------------------
+
+# non-user-callable umf_*.[ch] files:
+UMFCH = umf_assemble umf_blas3_update \
+ umf_build_tuples umf_create_element \
+ umf_dump umf_extend_front umf_garbage_collection \
+ umf_get_memory umf_init_front umf_kernel \
+ umf_kernel_init umf_kernel_wrapup \
+ umf_local_search umf_lsolve umf_ltsolve \
+ umf_mem_alloc_element umf_mem_alloc_head_block \
+ umf_mem_alloc_tail_block umf_mem_free_tail_block \
+ umf_mem_init_memoryspace \
+ umf_report_vector umf_row_search umf_scale_column \
+ umf_set_stats umf_solve umf_symbolic_usage umf_transpose \
+ umf_tuple_lengths umf_usolve umf_utsolve umf_valid_numeric \
+ umf_valid_symbolic umf_grow_front umf_start_front umf_2by2 \
+ umf_store_lu umf_scale
+
+# non-user-callable umf_*.[ch] files, int/long versions only (no real/complex):
+UMFINT = umf_analyze umf_apply_order umf_colamd umf_free umf_fsize \
+ umf_is_permutation umf_malloc umf_realloc umf_report_perm \
+ umf_singletons
+
+# non-user-callable and user-callable amd_*.[ch] files (int/long versions only):
+AMD = amd_aat amd_1 amd_2 amd_dump amd_postorder amd_post_tree amd_defaults \
+ amd_order amd_control amd_info amd_valid
+
+# non-user-callable, created from umf_ltsolve.c, umf_utsolve.c,
+# umf_triplet.c, and umf_assemble.c , with int/long and real/complex versions:
+UMF_CREATED = umf_lhsolve umf_uhsolve umf_triplet_map_nox \
+ umf_triplet_nomap_x umf_triplet_nomap_nox umf_triplet_map_x \
+ umf_assemble_fixq umf_store_lu_drop
+
+# non-user-callable, int/long and real/complex versions:
+UMF = $(UMF_CREATED) $(UMFCH)
+
+# user-callable umfpack_*.[ch] files (int/long and real/complex):
+UMFPACK = umfpack_col_to_triplet umfpack_defaults umfpack_free_numeric \
+ umfpack_free_symbolic umfpack_get_numeric umfpack_get_lunz \
+ umfpack_get_symbolic umfpack_numeric umfpack_qsymbolic \
+ umfpack_report_control umfpack_report_info umfpack_report_matrix \
+ umfpack_report_numeric umfpack_report_perm umfpack_report_status \
+ umfpack_report_symbolic umfpack_report_triplet \
+ umfpack_report_vector umfpack_solve umfpack_symbolic \
+ umfpack_transpose umfpack_triplet_to_col umfpack_scale \
+ umfpack_load_numeric umfpack_save_numeric \
+ umfpack_load_symbolic umfpack_save_symbolic
+
+# user-callable, created from umfpack_solve.c (umfpack_wsolve.h exists, though):
+# with int/long and real/complex versions:
+UMFPACKW = umfpack_wsolve
+
+USER = $(UMFPACKW) $(UMFPACK)
+
+# user-callable, only one version for int/long, real/complex, *.[ch] files:
+GENERIC = umfpack_timer umfpack_tictoc
+
+#-------------------------------------------------------------------------------
+# include files:
+#-------------------------------------------------------------------------------
+
+AMDH = ../../AMD/Source/amd_internal.h ../../AMD/Include/amd.h
+
+INC1 = umf_config.h umf_version.h umf_internal.h umf_triplet.h
+
+INC = ../Include/umfpack.h \
+ $(addprefix ../Source/, $(INC1)) \
+ $(addprefix ../Source/, $(addsuffix .h,$(UMFCH))) \
+ $(addprefix ../Source/, $(addsuffix .h,$(UMFINT))) \
+ $(addprefix ../Include/, $(addsuffix .h,$(USER))) \
+ $(addprefix ../Include/, $(addsuffix .h,$(GENERIC))) \
+ $(AMDH)
+
+#-------------------------------------------------------------------------------
+# Create the umfpack and amd mexFunctions for MATLAB (int versions only)
+#-------------------------------------------------------------------------------
+
+MEXI = $(addsuffix .o, $(subst umf_,umf_m_,$(UMFINT)))
+MEXDI = $(addsuffix .o, $(subst umf_,umf_md_,$(UMF)) $(subst umfpack_,umfpack_md_,$(USER)))
+MEXZI = $(addsuffix .o, $(subst umf_,umf_mz_,$(UMF)) $(subst umfpack_,umfpack_mz_,$(USER)) )
+MEXAMD = $(addsuffix .o, $(subst amd_,amd_m_,$(AMD)))
+MEXGN = $(addsuffix .o, $(subst umfpack_,umfpack_m_,$(GENERIC)))
+
+MEXUMFPACK = $(MEXI) $(MEXDI) $(MEXZI) $(MEXGN)
+
+# Note that mex has no "-o" option, thus the need for $(MV) commands.
+# If it did, then the rules would be much simpler:
+# $(MX) -DDINT -c $< -o $@
+
+#----------------------------------------
+# integer-only routines (no real/complex):
+#----------------------------------------
+
+amd_m_%.o: ../../AMD/Source/amd_%.c $(AMDH)
+ $(MX) -DDINT -c $<
+ - $(MV) amd_$*.o $@
+
+umf_m_%.o: ../Source/umf_%.c $(INC)
+ $(MX) -DDINT -c $<
+ - $(MV) umf_$*.o $@
+
+#----------------------------------------
+# Double precision, int version, for MATLAB
+#----------------------------------------
+
+umf_md_%.o: ../Source/umf_%.c $(INC)
+ $(MX) -DDINT -c $<
+ - $(MV) umf_$*.o $@
+
+umf_md_%hsolve.o: ../Source/umf_%tsolve.c $(INC)
+ $(MX) -DDINT -DCONJUGATE_SOLVE -c $<
+ - $(MV) umf_$*tsolve.o $@
+
+umf_md_triplet_map_x.o: ../Source/umf_triplet.c $(INC)
+ $(MX) -DDINT -DDO_MAP -DDO_VALUES -c $<
+ - $(MV) umf_triplet.o $@
+
+umf_md_triplet_map_nox.o: ../Source/umf_triplet.c $(INC)
+ $(MX) -DDINT -DDO_MAP -c $<
+ - $(MV) umf_triplet.o $@
+
+umf_md_triplet_nomap_x.o: ../Source/umf_triplet.c $(INC)
+ $(MX) -DDINT -DDO_VALUES -c $<
+ - $(MV) umf_triplet.o $@
+
+umf_md_triplet_nomap_nox.o: ../Source/umf_triplet.c $(INC)
+ $(MX) -DDINT -c $<
+ - $(MV) umf_triplet.o $@
+
+umf_md_assemble_fixq.o: ../Source/umf_assemble.c $(INC)
+ $(MX) -DDINT -DFIXQ -c $<
+ - $(MV) umf_assemble.o $@
+
+umf_md_store_lu_drop.o: ../Source/umf_store_lu.c $(INC)
+ $(MX) -DDINT -DDROP -c $<
+ - $(MV) umf_store_lu.o $@
+
+umfpack_md_wsolve.o: ../Source/umfpack_solve.c $(INC)
+ $(MX) -DDINT -DWSOLVE -c $<
+ - $(MV) umfpack_solve.o $@
+
+umfpack_md_%.o: ../Source/umfpack_%.c $(INC)
+ $(MX) -DDINT -c $<
+ - $(MV) umfpack_$*.o $@
+
+#----------------------------------------
+# Complex double precision, int version, for MATLAB
+#----------------------------------------
+
+umf_mz_%.o: ../Source/umf_%.c $(INC)
+ $(MX) -DZINT -c $<
+ - $(MV) umf_$*.o $@
+
+umf_mz_%hsolve.o: ../Source/umf_%tsolve.c $(INC)
+ $(MX) -DZINT -DCONJUGATE_SOLVE -c $<
+ - $(MV) umf_$*tsolve.o $@
+
+umf_mz_triplet_map_x.o: ../Source/umf_triplet.c $(INC)
+ $(MX) -DZINT -DDO_MAP -DDO_VALUES -c $<
+ - $(MV) umf_triplet.o $@
+
+umf_mz_triplet_map_nox.o: ../Source/umf_triplet.c $(INC)
+ $(MX) -DZINT -DDO_MAP -c $<
+ - $(MV) umf_triplet.o $@
+
+umf_mz_triplet_nomap_x.o: ../Source/umf_triplet.c $(INC)
+ $(MX) -DZINT -DDO_VALUES -c $<
+ - $(MV) umf_triplet.o $@
+
+umf_mz_triplet_nomap_nox.o: ../Source/umf_triplet.c $(INC)
+ $(MX) -DZINT -c $<
+ - $(MV) umf_triplet.o $@
+
+umf_mz_assemble_fixq.o: ../Source/umf_assemble.c $(INC)
+ $(MX) -DZINT -DFIXQ -c $<
+ - $(MV) umf_assemble.o $@
+
+umf_mz_store_lu_drop.o: ../Source/umf_store_lu.c $(INC)
+ $(MX) -DZINT -DDROP -c $<
+ - $(MV) umf_store_lu.o $@
+
+umfpack_mz_wsolve.o: ../Source/umfpack_solve.c $(INC)
+ $(MX) -DZINT -DWSOLVE -c $<
+ - $(MV) umfpack_solve.o $@
+
+umfpack_mz_%.o: ../Source/umfpack_%.c $(INC)
+ $(MX) -DZINT -c $<
+ - $(MV) umfpack_$*.o $@
+
+#----------------------------------------
+# Generic routines for MATLAB
+#----------------------------------------
+
+umfpack_m_timer.o: ../Source/umfpack_timer.c $(INC)
+ $(MX) -c $<
+ - $(MV) umfpack_timer.o $@
+
+umfpack_m_tictoc.o: ../Source/umfpack_tictoc.c $(INC)
+ $(MX) -c $<
+ - $(MV) umfpack_tictoc.o $@
+
+#----------------------------------------
+# umfpack mexFunction
+#----------------------------------------
+
+umfpack: umfpackmex.c $(MEXUMFPACK) $(MEXAMD)
+ $(MX) -output umfpack umfpackmex.c $(MEXUMFPACK) $(MEXAMD)
+
+luflop: luflopmex.c
+ $(MX) -output luflop luflopmex.c
+
+#-------------------------------------------------------------------------------
+# Remove all but the files in the original distribution
+#-------------------------------------------------------------------------------
+
+purge: clean
+ - $(RM) *.mex* *.dll
--- /dev/null
+#-------------------------------------------------------------------------------
+# UMFPACK Makefile for the UMFPACK MATLAB mexFunction (old "make" only)
+#-------------------------------------------------------------------------------
+
+# UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+# Davis. All Rights Reserved. See ../README for License.
+
+# This is a very ugly Makefile, and is only provided for those who do not
+# have GNU make. Note that it is not used if you have GNU make. It ignores
+# dependency checking and just compiles everything. It was created
+# automatically, via make -n using the GNUmakefile. That way, I don't have
+# maintain two Makefiles.
+
+all: umfpack luflop
+
+include ../Make/Make.include
+
+MX = $(MEX) -I../Include -I../Source -I../../AMD/Include -I../../AMD/Source
+
+umfpack:
+ $(MX) -DDINT -c ../Source/umf_analyze.c
+ $(MV) -f umf_analyze.o umf_m_analyze.o
+ $(MX) -DDINT -c ../Source/umf_apply_order.c
+ $(MV) -f umf_apply_order.o umf_m_apply_order.o
+ $(MX) -DDINT -c ../Source/umf_colamd.c
+ $(MV) -f umf_colamd.o umf_m_colamd.o
+ $(MX) -DDINT -c ../Source/umf_free.c
+ $(MV) -f umf_free.o umf_m_free.o
+ $(MX) -DDINT -c ../Source/umf_fsize.c
+ $(MV) -f umf_fsize.o umf_m_fsize.o
+ $(MX) -DDINT -c ../Source/umf_is_permutation.c
+ $(MV) -f umf_is_permutation.o umf_m_is_permutation.o
+ $(MX) -DDINT -c ../Source/umf_malloc.c
+ $(MV) -f umf_malloc.o umf_m_malloc.o
+ $(MX) -DDINT -c ../Source/umf_realloc.c
+ $(MV) -f umf_realloc.o umf_m_realloc.o
+ $(MX) -DDINT -c ../Source/umf_report_perm.c
+ $(MV) -f umf_report_perm.o umf_m_report_perm.o
+ $(MX) -DDINT -c ../Source/umf_singletons.c
+ $(MV) -f umf_singletons.o umf_m_singletons.o
+ $(MX) -DDINT -DCONJUGATE_SOLVE -c ../Source/umf_ltsolve.c
+ $(MV) -f umf_ltsolve.o umf_md_lhsolve.o
+ $(MX) -DDINT -DCONJUGATE_SOLVE -c ../Source/umf_utsolve.c
+ $(MV) -f umf_utsolve.o umf_md_uhsolve.o
+ $(MX) -DDINT -DDO_MAP -c ../Source/umf_triplet.c
+ $(MV) -f umf_triplet.o umf_md_triplet_map_nox.o
+ $(MX) -DDINT -DDO_VALUES -c ../Source/umf_triplet.c
+ $(MV) -f umf_triplet.o umf_md_triplet_nomap_x.o
+ $(MX) -DDINT -c ../Source/umf_triplet.c
+ $(MV) -f umf_triplet.o umf_md_triplet_nomap_nox.o
+ $(MX) -DDINT -DDO_MAP -DDO_VALUES -c ../Source/umf_triplet.c
+ $(MV) -f umf_triplet.o umf_md_triplet_map_x.o
+ $(MX) -DDINT -DFIXQ -c ../Source/umf_assemble.c
+ $(MV) -f umf_assemble.o umf_md_assemble_fixq.o
+ $(MX) -DDINT -DDROP -c ../Source/umf_store_lu.c
+ $(MV) -f umf_store_lu.o umf_md_store_lu_drop.o
+ $(MX) -DDINT -c ../Source/umf_assemble.c
+ $(MV) -f umf_assemble.o umf_md_assemble.o
+ $(MX) -DDINT -c ../Source/umf_blas3_update.c
+ $(MV) -f umf_blas3_update.o umf_md_blas3_update.o
+ $(MX) -DDINT -c ../Source/umf_build_tuples.c
+ $(MV) -f umf_build_tuples.o umf_md_build_tuples.o
+ $(MX) -DDINT -c ../Source/umf_create_element.c
+ $(MV) -f umf_create_element.o umf_md_create_element.o
+ $(MX) -DDINT -c ../Source/umf_dump.c
+ $(MV) -f umf_dump.o umf_md_dump.o
+ $(MX) -DDINT -c ../Source/umf_extend_front.c
+ $(MV) -f umf_extend_front.o umf_md_extend_front.o
+ $(MX) -DDINT -c ../Source/umf_garbage_collection.c
+ $(MV) -f umf_garbage_collection.o umf_md_garbage_collection.o
+ $(MX) -DDINT -c ../Source/umf_get_memory.c
+ $(MV) -f umf_get_memory.o umf_md_get_memory.o
+ $(MX) -DDINT -c ../Source/umf_init_front.c
+ $(MV) -f umf_init_front.o umf_md_init_front.o
+ $(MX) -DDINT -c ../Source/umf_kernel.c
+ $(MV) -f umf_kernel.o umf_md_kernel.o
+ $(MX) -DDINT -c ../Source/umf_kernel_init.c
+ $(MV) -f umf_kernel_init.o umf_md_kernel_init.o
+ $(MX) -DDINT -c ../Source/umf_kernel_wrapup.c
+ $(MV) -f umf_kernel_wrapup.o umf_md_kernel_wrapup.o
+ $(MX) -DDINT -c ../Source/umf_local_search.c
+ $(MV) -f umf_local_search.o umf_md_local_search.o
+ $(MX) -DDINT -c ../Source/umf_lsolve.c
+ $(MV) -f umf_lsolve.o umf_md_lsolve.o
+ $(MX) -DDINT -c ../Source/umf_ltsolve.c
+ $(MV) -f umf_ltsolve.o umf_md_ltsolve.o
+ $(MX) -DDINT -c ../Source/umf_mem_alloc_element.c
+ $(MV) -f umf_mem_alloc_element.o umf_md_mem_alloc_element.o
+ $(MX) -DDINT -c ../Source/umf_mem_alloc_head_block.c
+ $(MV) -f umf_mem_alloc_head_block.o umf_md_mem_alloc_head_block.o
+ $(MX) -DDINT -c ../Source/umf_mem_alloc_tail_block.c
+ $(MV) -f umf_mem_alloc_tail_block.o umf_md_mem_alloc_tail_block.o
+ $(MX) -DDINT -c ../Source/umf_mem_free_tail_block.c
+ $(MV) -f umf_mem_free_tail_block.o umf_md_mem_free_tail_block.o
+ $(MX) -DDINT -c ../Source/umf_mem_init_memoryspace.c
+ $(MV) -f umf_mem_init_memoryspace.o umf_md_mem_init_memoryspace.o
+ $(MX) -DDINT -c ../Source/umf_report_vector.c
+ $(MV) -f umf_report_vector.o umf_md_report_vector.o
+ $(MX) -DDINT -c ../Source/umf_row_search.c
+ $(MV) -f umf_row_search.o umf_md_row_search.o
+ $(MX) -DDINT -c ../Source/umf_scale_column.c
+ $(MV) -f umf_scale_column.o umf_md_scale_column.o
+ $(MX) -DDINT -c ../Source/umf_set_stats.c
+ $(MV) -f umf_set_stats.o umf_md_set_stats.o
+ $(MX) -DDINT -c ../Source/umf_solve.c
+ $(MV) -f umf_solve.o umf_md_solve.o
+ $(MX) -DDINT -c ../Source/umf_symbolic_usage.c
+ $(MV) -f umf_symbolic_usage.o umf_md_symbolic_usage.o
+ $(MX) -DDINT -c ../Source/umf_transpose.c
+ $(MV) -f umf_transpose.o umf_md_transpose.o
+ $(MX) -DDINT -c ../Source/umf_tuple_lengths.c
+ $(MV) -f umf_tuple_lengths.o umf_md_tuple_lengths.o
+ $(MX) -DDINT -c ../Source/umf_usolve.c
+ $(MV) -f umf_usolve.o umf_md_usolve.o
+ $(MX) -DDINT -c ../Source/umf_utsolve.c
+ $(MV) -f umf_utsolve.o umf_md_utsolve.o
+ $(MX) -DDINT -c ../Source/umf_valid_numeric.c
+ $(MV) -f umf_valid_numeric.o umf_md_valid_numeric.o
+ $(MX) -DDINT -c ../Source/umf_valid_symbolic.c
+ $(MV) -f umf_valid_symbolic.o umf_md_valid_symbolic.o
+ $(MX) -DDINT -c ../Source/umf_grow_front.c
+ $(MV) -f umf_grow_front.o umf_md_grow_front.o
+ $(MX) -DDINT -c ../Source/umf_start_front.c
+ $(MV) -f umf_start_front.o umf_md_start_front.o
+ $(MX) -DDINT -c ../Source/umf_2by2.c
+ $(MV) -f umf_2by2.o umf_md_2by2.o
+ $(MX) -DDINT -c ../Source/umf_store_lu.c
+ $(MV) -f umf_store_lu.o umf_md_store_lu.o
+ $(MX) -DDINT -c ../Source/umf_scale.c
+ $(MV) -f umf_scale.o umf_md_scale.o
+ $(MX) -DDINT -DWSOLVE -c ../Source/umfpack_solve.c
+ $(MV) -f umfpack_solve.o umfpack_md_wsolve.o
+ $(MX) -DDINT -c ../Source/umfpack_col_to_triplet.c
+ $(MV) -f umfpack_col_to_triplet.o umfpack_md_col_to_triplet.o
+ $(MX) -DDINT -c ../Source/umfpack_defaults.c
+ $(MV) -f umfpack_defaults.o umfpack_md_defaults.o
+ $(MX) -DDINT -c ../Source/umfpack_free_numeric.c
+ $(MV) -f umfpack_free_numeric.o umfpack_md_free_numeric.o
+ $(MX) -DDINT -c ../Source/umfpack_free_symbolic.c
+ $(MV) -f umfpack_free_symbolic.o umfpack_md_free_symbolic.o
+ $(MX) -DDINT -c ../Source/umfpack_get_numeric.c
+ $(MV) -f umfpack_get_numeric.o umfpack_md_get_numeric.o
+ $(MX) -DDINT -c ../Source/umfpack_get_lunz.c
+ $(MV) -f umfpack_get_lunz.o umfpack_md_get_lunz.o
+ $(MX) -DDINT -c ../Source/umfpack_get_symbolic.c
+ $(MV) -f umfpack_get_symbolic.o umfpack_md_get_symbolic.o
+ $(MX) -DDINT -c ../Source/umfpack_numeric.c
+ $(MV) -f umfpack_numeric.o umfpack_md_numeric.o
+ $(MX) -DDINT -c ../Source/umfpack_qsymbolic.c
+ $(MV) -f umfpack_qsymbolic.o umfpack_md_qsymbolic.o
+ $(MX) -DDINT -c ../Source/umfpack_report_control.c
+ $(MV) -f umfpack_report_control.o umfpack_md_report_control.o
+ $(MX) -DDINT -c ../Source/umfpack_report_info.c
+ $(MV) -f umfpack_report_info.o umfpack_md_report_info.o
+ $(MX) -DDINT -c ../Source/umfpack_report_matrix.c
+ $(MV) -f umfpack_report_matrix.o umfpack_md_report_matrix.o
+ $(MX) -DDINT -c ../Source/umfpack_report_numeric.c
+ $(MV) -f umfpack_report_numeric.o umfpack_md_report_numeric.o
+ $(MX) -DDINT -c ../Source/umfpack_report_perm.c
+ $(MV) -f umfpack_report_perm.o umfpack_md_report_perm.o
+ $(MX) -DDINT -c ../Source/umfpack_report_status.c
+ $(MV) -f umfpack_report_status.o umfpack_md_report_status.o
+ $(MX) -DDINT -c ../Source/umfpack_report_symbolic.c
+ $(MV) -f umfpack_report_symbolic.o umfpack_md_report_symbolic.o
+ $(MX) -DDINT -c ../Source/umfpack_report_triplet.c
+ $(MV) -f umfpack_report_triplet.o umfpack_md_report_triplet.o
+ $(MX) -DDINT -c ../Source/umfpack_report_vector.c
+ $(MV) -f umfpack_report_vector.o umfpack_md_report_vector.o
+ $(MX) -DDINT -c ../Source/umfpack_solve.c
+ $(MV) -f umfpack_solve.o umfpack_md_solve.o
+ $(MX) -DDINT -c ../Source/umfpack_symbolic.c
+ $(MV) -f umfpack_symbolic.o umfpack_md_symbolic.o
+ $(MX) -DDINT -c ../Source/umfpack_transpose.c
+ $(MV) -f umfpack_transpose.o umfpack_md_transpose.o
+ $(MX) -DDINT -c ../Source/umfpack_triplet_to_col.c
+ $(MV) -f umfpack_triplet_to_col.o umfpack_md_triplet_to_col.o
+ $(MX) -DDINT -c ../Source/umfpack_scale.c
+ $(MV) -f umfpack_scale.o umfpack_md_scale.o
+ $(MX) -DDINT -c ../Source/umfpack_load_numeric.c
+ $(MV) -f umfpack_load_numeric.o umfpack_md_load_numeric.o
+ $(MX) -DDINT -c ../Source/umfpack_save_numeric.c
+ $(MV) -f umfpack_save_numeric.o umfpack_md_save_numeric.o
+ $(MX) -DDINT -c ../Source/umfpack_load_symbolic.c
+ $(MV) -f umfpack_load_symbolic.o umfpack_md_load_symbolic.o
+ $(MX) -DDINT -c ../Source/umfpack_save_symbolic.c
+ $(MV) -f umfpack_save_symbolic.o umfpack_md_save_symbolic.o
+ $(MX) -DZINT -DCONJUGATE_SOLVE -c ../Source/umf_ltsolve.c
+ $(MV) -f umf_ltsolve.o umf_mz_lhsolve.o
+ $(MX) -DZINT -DCONJUGATE_SOLVE -c ../Source/umf_utsolve.c
+ $(MV) -f umf_utsolve.o umf_mz_uhsolve.o
+ $(MX) -DZINT -DDO_MAP -c ../Source/umf_triplet.c
+ $(MV) -f umf_triplet.o umf_mz_triplet_map_nox.o
+ $(MX) -DZINT -DDO_VALUES -c ../Source/umf_triplet.c
+ $(MV) -f umf_triplet.o umf_mz_triplet_nomap_x.o
+ $(MX) -DZINT -c ../Source/umf_triplet.c
+ $(MV) -f umf_triplet.o umf_mz_triplet_nomap_nox.o
+ $(MX) -DZINT -DDO_MAP -DDO_VALUES -c ../Source/umf_triplet.c
+ $(MV) -f umf_triplet.o umf_mz_triplet_map_x.o
+ $(MX) -DZINT -DFIXQ -c ../Source/umf_assemble.c
+ $(MV) -f umf_assemble.o umf_mz_assemble_fixq.o
+ $(MX) -DZINT -DDROP -c ../Source/umf_store_lu.c
+ $(MV) -f umf_store_lu.o umf_mz_store_lu_drop.o
+ $(MX) -DZINT -c ../Source/umf_assemble.c
+ $(MV) -f umf_assemble.o umf_mz_assemble.o
+ $(MX) -DZINT -c ../Source/umf_blas3_update.c
+ $(MV) -f umf_blas3_update.o umf_mz_blas3_update.o
+ $(MX) -DZINT -c ../Source/umf_build_tuples.c
+ $(MV) -f umf_build_tuples.o umf_mz_build_tuples.o
+ $(MX) -DZINT -c ../Source/umf_create_element.c
+ $(MV) -f umf_create_element.o umf_mz_create_element.o
+ $(MX) -DZINT -c ../Source/umf_dump.c
+ $(MV) -f umf_dump.o umf_mz_dump.o
+ $(MX) -DZINT -c ../Source/umf_extend_front.c
+ $(MV) -f umf_extend_front.o umf_mz_extend_front.o
+ $(MX) -DZINT -c ../Source/umf_garbage_collection.c
+ $(MV) -f umf_garbage_collection.o umf_mz_garbage_collection.o
+ $(MX) -DZINT -c ../Source/umf_get_memory.c
+ $(MV) -f umf_get_memory.o umf_mz_get_memory.o
+ $(MX) -DZINT -c ../Source/umf_init_front.c
+ $(MV) -f umf_init_front.o umf_mz_init_front.o
+ $(MX) -DZINT -c ../Source/umf_kernel.c
+ $(MV) -f umf_kernel.o umf_mz_kernel.o
+ $(MX) -DZINT -c ../Source/umf_kernel_init.c
+ $(MV) -f umf_kernel_init.o umf_mz_kernel_init.o
+ $(MX) -DZINT -c ../Source/umf_kernel_wrapup.c
+ $(MV) -f umf_kernel_wrapup.o umf_mz_kernel_wrapup.o
+ $(MX) -DZINT -c ../Source/umf_local_search.c
+ $(MV) -f umf_local_search.o umf_mz_local_search.o
+ $(MX) -DZINT -c ../Source/umf_lsolve.c
+ $(MV) -f umf_lsolve.o umf_mz_lsolve.o
+ $(MX) -DZINT -c ../Source/umf_ltsolve.c
+ $(MV) -f umf_ltsolve.o umf_mz_ltsolve.o
+ $(MX) -DZINT -c ../Source/umf_mem_alloc_element.c
+ $(MV) -f umf_mem_alloc_element.o umf_mz_mem_alloc_element.o
+ $(MX) -DZINT -c ../Source/umf_mem_alloc_head_block.c
+ $(MV) -f umf_mem_alloc_head_block.o umf_mz_mem_alloc_head_block.o
+ $(MX) -DZINT -c ../Source/umf_mem_alloc_tail_block.c
+ $(MV) -f umf_mem_alloc_tail_block.o umf_mz_mem_alloc_tail_block.o
+ $(MX) -DZINT -c ../Source/umf_mem_free_tail_block.c
+ $(MV) -f umf_mem_free_tail_block.o umf_mz_mem_free_tail_block.o
+ $(MX) -DZINT -c ../Source/umf_mem_init_memoryspace.c
+ $(MV) -f umf_mem_init_memoryspace.o umf_mz_mem_init_memoryspace.o
+ $(MX) -DZINT -c ../Source/umf_report_vector.c
+ $(MV) -f umf_report_vector.o umf_mz_report_vector.o
+ $(MX) -DZINT -c ../Source/umf_row_search.c
+ $(MV) -f umf_row_search.o umf_mz_row_search.o
+ $(MX) -DZINT -c ../Source/umf_scale_column.c
+ $(MV) -f umf_scale_column.o umf_mz_scale_column.o
+ $(MX) -DZINT -c ../Source/umf_set_stats.c
+ $(MV) -f umf_set_stats.o umf_mz_set_stats.o
+ $(MX) -DZINT -c ../Source/umf_solve.c
+ $(MV) -f umf_solve.o umf_mz_solve.o
+ $(MX) -DZINT -c ../Source/umf_symbolic_usage.c
+ $(MV) -f umf_symbolic_usage.o umf_mz_symbolic_usage.o
+ $(MX) -DZINT -c ../Source/umf_transpose.c
+ $(MV) -f umf_transpose.o umf_mz_transpose.o
+ $(MX) -DZINT -c ../Source/umf_tuple_lengths.c
+ $(MV) -f umf_tuple_lengths.o umf_mz_tuple_lengths.o
+ $(MX) -DZINT -c ../Source/umf_usolve.c
+ $(MV) -f umf_usolve.o umf_mz_usolve.o
+ $(MX) -DZINT -c ../Source/umf_utsolve.c
+ $(MV) -f umf_utsolve.o umf_mz_utsolve.o
+ $(MX) -DZINT -c ../Source/umf_valid_numeric.c
+ $(MV) -f umf_valid_numeric.o umf_mz_valid_numeric.o
+ $(MX) -DZINT -c ../Source/umf_valid_symbolic.c
+ $(MV) -f umf_valid_symbolic.o umf_mz_valid_symbolic.o
+ $(MX) -DZINT -c ../Source/umf_grow_front.c
+ $(MV) -f umf_grow_front.o umf_mz_grow_front.o
+ $(MX) -DZINT -c ../Source/umf_start_front.c
+ $(MV) -f umf_start_front.o umf_mz_start_front.o
+ $(MX) -DZINT -c ../Source/umf_2by2.c
+ $(MV) -f umf_2by2.o umf_mz_2by2.o
+ $(MX) -DZINT -c ../Source/umf_store_lu.c
+ $(MV) -f umf_store_lu.o umf_mz_store_lu.o
+ $(MX) -DZINT -c ../Source/umf_scale.c
+ $(MV) -f umf_scale.o umf_mz_scale.o
+ $(MX) -DZINT -DWSOLVE -c ../Source/umfpack_solve.c
+ $(MV) -f umfpack_solve.o umfpack_mz_wsolve.o
+ $(MX) -DZINT -c ../Source/umfpack_col_to_triplet.c
+ $(MV) -f umfpack_col_to_triplet.o umfpack_mz_col_to_triplet.o
+ $(MX) -DZINT -c ../Source/umfpack_defaults.c
+ $(MV) -f umfpack_defaults.o umfpack_mz_defaults.o
+ $(MX) -DZINT -c ../Source/umfpack_free_numeric.c
+ $(MV) -f umfpack_free_numeric.o umfpack_mz_free_numeric.o
+ $(MX) -DZINT -c ../Source/umfpack_free_symbolic.c
+ $(MV) -f umfpack_free_symbolic.o umfpack_mz_free_symbolic.o
+ $(MX) -DZINT -c ../Source/umfpack_get_numeric.c
+ $(MV) -f umfpack_get_numeric.o umfpack_mz_get_numeric.o
+ $(MX) -DZINT -c ../Source/umfpack_get_lunz.c
+ $(MV) -f umfpack_get_lunz.o umfpack_mz_get_lunz.o
+ $(MX) -DZINT -c ../Source/umfpack_get_symbolic.c
+ $(MV) -f umfpack_get_symbolic.o umfpack_mz_get_symbolic.o
+ $(MX) -DZINT -c ../Source/umfpack_numeric.c
+ $(MV) -f umfpack_numeric.o umfpack_mz_numeric.o
+ $(MX) -DZINT -c ../Source/umfpack_qsymbolic.c
+ $(MV) -f umfpack_qsymbolic.o umfpack_mz_qsymbolic.o
+ $(MX) -DZINT -c ../Source/umfpack_report_control.c
+ $(MV) -f umfpack_report_control.o umfpack_mz_report_control.o
+ $(MX) -DZINT -c ../Source/umfpack_report_info.c
+ $(MV) -f umfpack_report_info.o umfpack_mz_report_info.o
+ $(MX) -DZINT -c ../Source/umfpack_report_matrix.c
+ $(MV) -f umfpack_report_matrix.o umfpack_mz_report_matrix.o
+ $(MX) -DZINT -c ../Source/umfpack_report_numeric.c
+ $(MV) -f umfpack_report_numeric.o umfpack_mz_report_numeric.o
+ $(MX) -DZINT -c ../Source/umfpack_report_perm.c
+ $(MV) -f umfpack_report_perm.o umfpack_mz_report_perm.o
+ $(MX) -DZINT -c ../Source/umfpack_report_status.c
+ $(MV) -f umfpack_report_status.o umfpack_mz_report_status.o
+ $(MX) -DZINT -c ../Source/umfpack_report_symbolic.c
+ $(MV) -f umfpack_report_symbolic.o umfpack_mz_report_symbolic.o
+ $(MX) -DZINT -c ../Source/umfpack_report_triplet.c
+ $(MV) -f umfpack_report_triplet.o umfpack_mz_report_triplet.o
+ $(MX) -DZINT -c ../Source/umfpack_report_vector.c
+ $(MV) -f umfpack_report_vector.o umfpack_mz_report_vector.o
+ $(MX) -DZINT -c ../Source/umfpack_solve.c
+ $(MV) -f umfpack_solve.o umfpack_mz_solve.o
+ $(MX) -DZINT -c ../Source/umfpack_symbolic.c
+ $(MV) -f umfpack_symbolic.o umfpack_mz_symbolic.o
+ $(MX) -DZINT -c ../Source/umfpack_transpose.c
+ $(MV) -f umfpack_transpose.o umfpack_mz_transpose.o
+ $(MX) -DZINT -c ../Source/umfpack_triplet_to_col.c
+ $(MV) -f umfpack_triplet_to_col.o umfpack_mz_triplet_to_col.o
+ $(MX) -DZINT -c ../Source/umfpack_scale.c
+ $(MV) -f umfpack_scale.o umfpack_mz_scale.o
+ $(MX) -DZINT -c ../Source/umfpack_load_numeric.c
+ $(MV) -f umfpack_load_numeric.o umfpack_mz_load_numeric.o
+ $(MX) -DZINT -c ../Source/umfpack_save_numeric.c
+ $(MV) -f umfpack_save_numeric.o umfpack_mz_save_numeric.o
+ $(MX) -DZINT -c ../Source/umfpack_load_symbolic.c
+ $(MV) -f umfpack_load_symbolic.o umfpack_mz_load_symbolic.o
+ $(MX) -DZINT -c ../Source/umfpack_save_symbolic.c
+ $(MV) -f umfpack_save_symbolic.o umfpack_mz_save_symbolic.o
+ $(MX) -c ../Source/umfpack_timer.c
+ $(MV) -f umfpack_timer.o umfpack_m_timer.o
+ $(MX) -c ../Source/umfpack_tictoc.c
+ $(MV) -f umfpack_tictoc.o umfpack_m_tictoc.o
+ $(MX) -DDINT -c ../../AMD/Source/amd_aat.c
+ $(MV) -f amd_aat.o amd_m_aat.o
+ $(MX) -DDINT -c ../../AMD/Source/amd_1.c
+ $(MV) -f amd_1.o amd_m_1.o
+ $(MX) -DDINT -c ../../AMD/Source/amd_2.c
+ $(MV) -f amd_2.o amd_m_2.o
+ $(MX) -DDINT -c ../../AMD/Source/amd_dump.c
+ $(MV) -f amd_dump.o amd_m_dump.o
+ $(MX) -DDINT -c ../../AMD/Source/amd_postorder.c
+ $(MV) -f amd_postorder.o amd_m_postorder.o
+ $(MX) -DDINT -c ../../AMD/Source/amd_post_tree.c
+ $(MV) -f amd_post_tree.o amd_m_post_tree.o
+ $(MX) -DDINT -c ../../AMD/Source/amd_defaults.c
+ $(MV) -f amd_defaults.o amd_m_defaults.o
+ $(MX) -DDINT -c ../../AMD/Source/amd_order.c
+ $(MV) -f amd_order.o amd_m_order.o
+ $(MX) -DDINT -c ../../AMD/Source/amd_control.c
+ $(MV) -f amd_control.o amd_m_control.o
+ $(MX) -DDINT -c ../../AMD/Source/amd_info.c
+ $(MV) -f amd_info.o amd_m_info.o
+ $(MX) -DDINT -c ../../AMD/Source/amd_valid.c
+ $(MV) -f amd_valid.o amd_m_valid.o
+ $(MX) -output umfpack umfpackmex.c \
+ umf_m_analyze.o umf_m_apply_order.o umf_m_colamd.o umf_m_free.o \
+ umf_m_fsize.o umf_m_is_permutation.o umf_m_malloc.o \
+ umf_m_realloc.o umf_m_report_perm.o umf_m_singletons.o \
+ umf_md_lhsolve.o umf_md_uhsolve.o umf_md_triplet_map_nox.o \
+ umf_md_triplet_nomap_x.o umf_md_triplet_nomap_nox.o \
+ umf_md_triplet_map_x.o umf_md_assemble_fixq.o \
+ umf_md_store_lu_drop.o umf_md_assemble.o umf_md_blas3_update.o \
+ umf_md_build_tuples.o umf_md_create_element.o umf_md_dump.o \
+ umf_md_extend_front.o umf_md_garbage_collection.o \
+ umf_md_get_memory.o umf_md_init_front.o umf_md_kernel.o \
+ umf_md_kernel_init.o umf_md_kernel_wrapup.o umf_md_local_search.o \
+ umf_md_lsolve.o umf_md_ltsolve.o umf_md_mem_alloc_element.o \
+ umf_md_mem_alloc_head_block.o umf_md_mem_alloc_tail_block.o \
+ umf_md_mem_free_tail_block.o umf_md_mem_init_memoryspace.o \
+ umf_md_report_vector.o umf_md_row_search.o umf_md_scale_column.o \
+ umf_md_set_stats.o umf_md_solve.o umf_md_symbolic_usage.o \
+ umf_md_transpose.o umf_md_tuple_lengths.o umf_md_usolve.o \
+ umf_md_utsolve.o umf_md_valid_numeric.o umf_md_valid_symbolic.o \
+ umf_md_grow_front.o umf_md_start_front.o umf_md_2by2.o \
+ umf_md_store_lu.o umf_md_scale.o umfpack_md_wsolve.o \
+ umfpack_md_col_to_triplet.o umfpack_md_defaults.o \
+ umfpack_md_free_numeric.o umfpack_md_free_symbolic.o \
+ umfpack_md_get_numeric.o umfpack_md_get_lunz.o \
+ umfpack_md_get_symbolic.o umfpack_md_numeric.o \
+ umfpack_md_qsymbolic.o umfpack_md_report_control.o \
+ umfpack_md_report_info.o umfpack_md_report_matrix.o \
+ umfpack_md_report_numeric.o umfpack_md_report_perm.o \
+ umfpack_md_report_status.o umfpack_md_report_symbolic.o \
+ umfpack_md_report_triplet.o umfpack_md_report_vector.o \
+ umfpack_md_solve.o umfpack_md_symbolic.o umfpack_md_transpose.o \
+ umfpack_md_triplet_to_col.o umfpack_md_scale.o \
+ umfpack_md_load_numeric.o umfpack_md_save_numeric.o \
+ umfpack_md_load_symbolic.o umfpack_md_save_symbolic.o \
+ umf_mz_lhsolve.o umf_mz_uhsolve.o umf_mz_triplet_map_nox.o \
+ umf_mz_triplet_nomap_x.o umf_mz_triplet_nomap_nox.o \
+ umf_mz_triplet_map_x.o umf_mz_assemble_fixq.o \
+ umf_mz_store_lu_drop.o umf_mz_assemble.o umf_mz_blas3_update.o \
+ umf_mz_build_tuples.o umf_mz_create_element.o umf_mz_dump.o \
+ umf_mz_extend_front.o umf_mz_garbage_collection.o \
+ umf_mz_get_memory.o umf_mz_init_front.o umf_mz_kernel.o \
+ umf_mz_kernel_init.o umf_mz_kernel_wrapup.o umf_mz_local_search.o \
+ umf_mz_lsolve.o umf_mz_ltsolve.o umf_mz_mem_alloc_element.o \
+ umf_mz_mem_alloc_head_block.o umf_mz_mem_alloc_tail_block.o \
+ umf_mz_mem_free_tail_block.o umf_mz_mem_init_memoryspace.o \
+ umf_mz_report_vector.o umf_mz_row_search.o umf_mz_scale_column.o \
+ umf_mz_set_stats.o umf_mz_solve.o umf_mz_symbolic_usage.o \
+ umf_mz_transpose.o umf_mz_tuple_lengths.o umf_mz_usolve.o \
+ umf_mz_utsolve.o umf_mz_valid_numeric.o umf_mz_valid_symbolic.o \
+ umf_mz_grow_front.o umf_mz_start_front.o umf_mz_2by2.o \
+ umf_mz_store_lu.o umf_mz_scale.o umfpack_mz_wsolve.o \
+ umfpack_mz_col_to_triplet.o umfpack_mz_defaults.o \
+ umfpack_mz_free_numeric.o umfpack_mz_free_symbolic.o \
+ umfpack_mz_get_numeric.o umfpack_mz_get_lunz.o \
+ umfpack_mz_get_symbolic.o umfpack_mz_numeric.o \
+ umfpack_mz_qsymbolic.o umfpack_mz_report_control.o \
+ umfpack_mz_report_info.o umfpack_mz_report_matrix.o \
+ umfpack_mz_report_numeric.o umfpack_mz_report_perm.o \
+ umfpack_mz_report_status.o umfpack_mz_report_symbolic.o \
+ umfpack_mz_report_triplet.o umfpack_mz_report_vector.o \
+ umfpack_mz_solve.o umfpack_mz_symbolic.o umfpack_mz_transpose.o \
+ umfpack_mz_triplet_to_col.o umfpack_mz_scale.o \
+ umfpack_mz_load_numeric.o umfpack_mz_save_numeric.o \
+ umfpack_mz_load_symbolic.o umfpack_mz_save_symbolic.o \
+ umfpack_m_timer.o umfpack_m_tictoc.o \
+ amd_m_aat.o amd_m_1.o amd_m_2.o amd_m_dump.o \
+ amd_m_postorder.o amd_m_post_tree.o amd_m_defaults.o amd_m_order.o \
+ amd_m_control.o amd_m_info.o amd_m_valid.o
+
+luflop: luflopmex.c
+ $(MX) -output luflop luflopmex.c
+
+#-------------------------------------------------------------------------------
+# Remove all but the files in the original distribution
+#-------------------------------------------------------------------------------
+
+purge: clean
+ - $(RM) *.mex* *.dll
--- /dev/null
+function rho = lu_normest (A, L, U)
+% LU_NORMEST: estimate the 1-norm of A-L*U without computing L*U
+%
+% Usage:
+%
+% rho = lu_normest (A, L, U)
+%
+% which estimates the computation of the 1-norm:
+%
+% rho = norm (A-L*U, 1)
+%
+% Authors: William W. Hager, Math Dept., Univ. of Florida
+% Timothy A. Davis, CISE Dept., Univ. of Florida
+% Gainesville, FL, 32611, USA.
+% based on normest1, contributed on November, 1997
+%
+% This code can be quite easily adapted to estimate the 1-norm of any
+% matrix E, where E itself is dense or not explicitly represented, but the
+% computation of E (and E') times a vector is easy. In this case, our matrix
+% of interest is:
+%
+% E = A-L*U
+%
+% That is, L*U is the LU factorization of A, where A, L and U
+% are sparse. This code works for dense matrices A and L too,
+% but it would not be needed in that case, since E is easy to compute
+% explicitly. For sparse A, L, and U, computing E explicitly would be quite
+% expensive, and thus normest (A-L*U) would be prohibitive.
+%
+% For a detailed description, see Davis, T. A. and Hager, W. W.,
+% Modifying a sparse Cholesky factorization, SIAM J. Matrix Analysis and
+% Applications, 1999, vol. 20, no. 3, 606-627.
+
+% The three places that the matrix-vector multiply E*x is used are highlighted.
+% Note that E is never formed explicity.
+
+[m n] = size (A) ;
+
+if (m ~= n)
+ % pad A, L, and U with zeros so that they are all square
+ if (m < n)
+ U = [ U ; (sparse (n-m,n)) ] ;
+ L = [ L , (sparse (m,n-m)) ; (sparse (n-m,n)) ] ;
+ A = [ A ; (sparse (n-m,n)) ] ;
+ else
+ U = [ U , (sparse (n,m-n)) ; (sparse (m-n,m)) ] ;
+ L = [ L , (sparse (m,m-n)) ] ;
+ A = [ A , (sparse (m,m-n)) ] ;
+ end
+end
+
+[m n] = size (A) ;
+
+notvisited = ones (m, 1) ; % nonvisited(j) is zero if j is visited, 1 otherwise
+rho = 0 ; % the global rho
+
+At = A' ;
+Lt = L' ;
+
+for trial = 1:3 % {
+
+ x = notvisited ./ sum (notvisited) ;
+ rho1 = 0 ; % the current rho for this trial
+
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ %%% COMPUTE Ex1 = E*x EFFICIENTLY: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ Ex1 = (A*x) - L*(U*x) ;
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ rho2 = norm (Ex1, 1) ;
+
+ while rho2 > rho1 % {
+
+ rho1 = rho2 ;
+ y = 2*(Ex1 >= 0) - 1 ;
+
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ %%% COMPUTE z = E'*y EFFICIENTLY: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ z = (A'*y) - U'*(L'*y) ;
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ [zj, j] = max (abs (z .* notvisited)) ;
+ j = j (1) ;
+ if (abs (z (j)) > z'*x) % {
+ x = zeros (m, 1) ;
+ x (j) = 1 ;
+ notvisited (j) = 0 ;
+ else % } {
+ break ;
+ end % }
+
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ %%% COMPUTE Ex1 = E*x EFFICIENTLY: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ Ex1 = (A*x) - L*(U*x) ;
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ rho2 = norm (Ex1, 1) ;
+
+ end % }
+
+ rho = max (rho, rho1) ;
+
+end % }
--- /dev/null
+function f = luflop (L, U)
+%LUFLOP
+%
+% f = luflop (L, U)
+%
+% Given an LU factorization, compute how many flops took to compute it. This
+% is the same as (assuming U has a zero-free diagonal):
+%
+% Lnz = full (sum (spones (L))) - 1 ;
+% Unz = full (sum (spones (U')))' - 1 ;
+% f = 2*Lnz*Unz + sum (Lnz) ;
+%
+% except that no extra workspace is allocated for spones (L) and spones (U).
+% L and U must be sparse.
+%
+% Note: the above expression has a subtle undercount when exact numerical
+% cancelation occurs. Try [L,U,P] = lu (sparse (ones (10))) and then
+% luflop (L,U).
+
+% UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+% Davis. All Rights Reserved. Type umfpack_details for License.
+
+help luflop
+error ('luflop mexFunction not found! Use umfpack_make to compile luflop.') ;
--- /dev/null
+/* ========================================================================== */
+/* === luflop mexFunction ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+/*
+ f = luflop (L, U) ;
+
+ Given L and U, compute:
+
+ Lnz = full (sum (spones (L))) - 1 ;
+ Unz = full (sum (spones (U')))' - 1 ;
+ f = 2*Lnz*Unz + sum (Lnz) ;
+
+ without allocating O (lunz) space.
+
+*/
+
+#include "mex.h"
+#include "matrix.h"
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+void mexFunction
+(
+ int nlhs, /* number of left-hand sides */
+ mxArray *plhs [ ], /* left-hand side matrices */
+ int nrhs, /* number of right--hand sides */
+ const mxArray *prhs [ ] /* right-hand side matrices */
+)
+{
+
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ int *Lp, *Li, *Up, *Ui, *Unz, n, k, row, col, p, Lnz_k, Unz_k ;
+ mxArray *Lmatrix, *Umatrix ;
+ double flop_count, *pflop ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get inputs L, U */
+ /* ---------------------------------------------------------------------- */
+
+ if (nrhs != 2)
+ {
+ mexErrMsgTxt ("Usage: f = luflop (L, U)") ;
+ }
+
+ Lmatrix = (mxArray *) prhs [0] ;
+ Umatrix = (mxArray *) prhs [1] ;
+
+ n = mxGetM (Lmatrix) ;
+ if (n != mxGetN (Lmatrix) || n != mxGetM (Umatrix) || n != mxGetN (Umatrix))
+ {
+ mexErrMsgTxt ("Usage: f = luflop (L, U) ; L and U must be square") ;
+ }
+
+ if (!mxIsSparse (Lmatrix) || !mxIsSparse (Umatrix))
+ {
+ mexErrMsgTxt ("Usage: f = luflop (L, U) ; L and U must be sparse") ;
+ }
+
+ Lp = mxGetJc (Lmatrix) ;
+ Li = mxGetIr (Lmatrix) ;
+
+ Up = mxGetJc (Umatrix) ;
+ Ui = mxGetIr (Umatrix) ;
+
+ Unz = (int *) mxMalloc (n * sizeof (int)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* count the nonzeros in each row of U */
+ /* ---------------------------------------------------------------------- */
+
+ for (row = 0 ; row < n ; row++)
+ {
+ Unz [row] = 0 ;
+ }
+ for (col = 0 ; col < n ; col++)
+ {
+ for (p = Up [col] ; p < Up [col+1] ; p++)
+ {
+ row = Ui [p] ;
+ Unz [row]++ ;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* count the flops */
+ /* ---------------------------------------------------------------------- */
+
+ flop_count = 0.0 ;
+ for (k = 0 ; k < n ; k++)
+ {
+ /* off-diagonal nonzeros in column k of L: */
+ Lnz_k = Lp [k+1] - Lp [k] - 1 ;
+ Unz_k = Unz [k] - 1 ;
+ flop_count += (2 * Lnz_k * Unz_k) + Lnz_k ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* return the result */
+ /* ---------------------------------------------------------------------- */
+
+ plhs [0] = mxCreateDoubleMatrix (1, 1, mxREAL) ;
+ pflop = mxGetPr (plhs [0]) ;
+ pflop [0] = flop_count ;
+}
+
--- /dev/null
+function [out1, out2, out3, out4, out5] = umfpack (in1, in2, in3, in4, in5)
+% UMFPACK v4.3 is a MATLAB mexFunction for solving sparse linear systems.
+%
+% UMFPACK v4.3: | MATLAB approximate equivalent:
+% ---------------------------------------------------------------------
+% x = umfpack (A, '\', b) ; | x = A \ b
+% |
+% x = umfpack (b, '/', A) ; | x = b / A
+% |
+% [L,U,P,Q] = umfpack (A) ; | [m,n] = size (A) ;
+% | I = speye (n) ;
+% | Q = I (:, colamd (A)) ;
+% | [L,U,P] = lu (A*Q) ;
+% |
+% [L,U,P,Q,R] = umfpack (A) ; | [m,n] = size (A) ;
+% | I = speye (n) ;
+% | Q = I (:, colamd (A)) ;
+% | r = full (sum (abs (A), 2)) ;
+% | r (find (r == 0)) = 1 ;
+% | R = spdiags (r, 0, m, m) ;
+% | [L,U,P] = lu ((R\A)*Q) ;
+% |
+% [P,Q,F,C] = umfpack (A, 'symbolic') | [m,n] = size (A) ;
+% | I = speye (n) ;
+% | Q = I (:, colamd (A)) ;
+% | [count,h,parent,post] = ...
+% | symbfact (A*Q, 'col') ;
+%
+% A must be sparse. It can be complex, singular, and/or rectangular. A must be
+% square for '/' or '\'. b must be a full real or complex vector. For
+% [L,U,P,Q,R] = umfpack (A), the factorization is L*U = P*(R\A)*Q. If A has a
+% mostly symmetric nonzero pattern, then replace "colamd" with "amd" in the
+% MATLAB-equivalent column in the table above. Type umfpack_details for more
+% information.
+%
+% See also: lu_normest, colamd, amd.
+% To use UMFPACK for an arbitrary b, see umfpack_solve.
+
+% UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+% Davis. All Rights Reserved. Type umfpack_details for License.
+
+help umfpack
+error ('umfpack mexFunction not found! Use umfpack_make to compile umfpack.') ;
+
--- /dev/null
+function x = umfpack_btf (A, b, Control)
+% UMFPACK_BTF
+%
+% x = umfpack_btf (A, b, Control)
+%
+% solve Ax=b by first permuting the matrix A to block triangular form via dmperm
+% and then using UMFPACK to factorize each diagonal block. Adjacent 1-by-1
+% blocks are merged into a single upper triangular block, and solved via
+% MATLAB's \ operator. The Control parameter is optional (Type umfpack_details
+% and umfpack_report for details on its use). A must be square.
+%
+% See also: umfpack, umfpack_factorize, umfpack_details, dmperm
+
+% UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+% Davis. All Rights Reserved. Type umfpack_details for License.
+
+if (nargin < 2)
+ help umfpack_btf
+ error ('Usage: x = umfpack_btf (A, b, Control)') ;
+end
+
+[m n] = size (A) ;
+if (m ~= n)
+ help umfpack_btf
+ error ('umfpack_btf: A must be square') ;
+end
+[m1 n1] = size (b) ;
+if (m1 ~= n)
+ help umfpack_btf
+ error ('umfpack_btf: b has the wrong dimensions') ;
+end
+
+if (nargin < 3)
+ Control = umfpack ;
+end
+
+%-------------------------------------------------------------------------------
+% find the block triangular form
+%-------------------------------------------------------------------------------
+
+[p,q,r] = dmperm (A) ;
+nblocks = length (r) - 1 ;
+
+%-------------------------------------------------------------------------------
+% solve the system
+%-------------------------------------------------------------------------------
+
+if (nblocks == 1 | sprank (A) < n)
+
+ %---------------------------------------------------------------------------
+ % matrix is irreducible or structurally singular
+ %---------------------------------------------------------------------------
+
+ x = umfpack_solve (A, '\', b, Control) ;
+
+else
+
+ %---------------------------------------------------------------------------
+ % A (p,q) is in block triangular form
+ %---------------------------------------------------------------------------
+
+ b = b (p,:) ;
+ A = A (p,q) ;
+ x = zeros (size (b)) ;
+
+ %---------------------------------------------------------------------------
+ % merge adjacent singletons into a single upper triangular block
+ %---------------------------------------------------------------------------
+
+ [r, nblocks, is_triangular] = merge_singletons (r) ;
+
+ %---------------------------------------------------------------------------
+ % solve the system: x (q) = A\b
+ %---------------------------------------------------------------------------
+
+ for k = nblocks:-1:1
+
+ % get the kth block
+ k1 = r (k) ;
+ k2 = r (k+1) - 1 ;
+
+ % solve the system
+ x (k1:k2,:) = solver (A (k1:k2, k1:k2), b (k1:k2,:), ...
+ is_triangular (k), Control) ;
+
+ % off-diagonal block back substitution
+ b (1:k1-1,:) = b (1:k1-1,:) - A (1:k1-1, k1:k2) * x (k1:k2,:) ;
+
+ end
+
+ x (q,:) = x ;
+
+end
+
+%-------------------------------------------------------------------------------
+% merge_singletons
+%-------------------------------------------------------------------------------
+
+function [r, nblocks, is_triangular] = merge_singletons (r)
+%
+% Given r from [p,q,r] = dmperm (A), where A is square, return a modified r that
+% reflects the merger of adjacent singletons into a single upper triangular
+% block. is_triangular (k) is 1 if the kth block is upper triangular. nblocks
+% is the number of new blocks.
+
+nblocks = length (r) - 1 ;
+bsize = r (2:nblocks+1) - r (1:nblocks) ;
+t = [0 (bsize == 1)] ;
+z = (t (1:nblocks) == 0 & t (2:nblocks+1) == 1) | t (2:nblocks+1) == 0 ;
+y = [(find (z)) nblocks+1] ;
+r = r (y) ;
+nblocks = length (y) - 1 ;
+is_triangular = y (2:nblocks+1) - y (1:nblocks) > 1 ;
+
+%-------------------------------------------------------------------------------
+% solve Ax=b, but check for small and/or triangular systems
+%-------------------------------------------------------------------------------
+
+function x = solver (A, b, is_triangular, Control)
+if (is_triangular)
+ % back substitution only
+ x = A \ b ;
+elseif (size (A,1) < 4)
+ % a very small matrix, solve it as a dense linear system
+ x = full (A) \ b ;
+else
+ % solve it as a sparse linear system
+ x = umfpack_solve (A, '\', b, Control) ;
+end
--- /dev/null
+function umfpack_demo
+% UMFPACK DEMO
+%
+% A demo of UMFPACK for MATLAB.
+%
+% See also umfpack, umfpack_make, umfpack_details, umfpack_report,
+% and umfpack_simple.
+
+% UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+% Davis. All Rights Reserved. Type umfpack_details for License.
+
+%-------------------------------------------------------------------------------
+% get default control parameters
+%-------------------------------------------------------------------------------
+
+control = umfpack ;
+fprintf ('\nEnter the printing level for UMFPACK''s output statistics:\n') ;
+fprintf ('0: none, 1: errors only, 2: statistics, 4: print some of outputs\n') ;
+c = input ('5: print all output [default is 1]: ') ;
+if (isempty (c))
+ c = 1 ;
+end
+control (1) = c ;
+
+%-------------------------------------------------------------------------------
+% solve a simple system
+%-------------------------------------------------------------------------------
+
+fprintf ('\n--------------------------------------------------------------\n') ;
+fprintf ('Factor and solve a small system, Ax=b, using default parameters\n') ;
+if (control (1) > 1)
+ fprintf ('(except for verbose printing enabled)\n') ;
+end
+
+load west0067
+A = Problem.A ;
+n = size (A, 1) ;
+b = rand (n, 1) ;
+
+fprintf ('Solving Ax=b via UMFPACK:\n') ;
+[xu, info] = umfpack (A, '\', b, control) ;
+x = xu ;
+
+fprintf ('Solving Ax=b via MATLAB:\n') ;
+xm = A\b ;
+x = xm ;
+
+fprintf ('Difference between UMFPACK and MATLAB solution: %g\n', ...
+ norm (xu - xm, Inf)) ;
+
+%-------------------------------------------------------------------------------
+% spy the results
+%-------------------------------------------------------------------------------
+
+figure (1)
+clf
+
+subplot (2,3,1)
+spy (A)
+title ('The matrix A') ;
+
+subplot (2,3,2)
+[P1, Q1, Fr, Ch, Info] = umfpack (A, 'symbolic') ;
+treeplot (Fr (1:end-1,2)') ;
+title ('Supernodal column elimination tree') ;
+
+subplot (2,3,3)
+spy (P1 * A * Q1)
+title ('A, with initial row and column order') ;
+
+subplot (2,3,4)
+fprintf ('\n--------------------------------------------------------------\n') ;
+fprintf ('\nFactorizing [L, U, P, Q, R] = umfpack (A)\n') ;
+[L, U, P, Q, R] = umfpack (A) ;
+spy (P*A*Q)
+title ('A, with final row/column order') ;
+
+fprintf ('\nP * (R\\A) * Q - L*U should be zero:\n') ;
+fprintf ('norm (P*(R\\A)*Q - L*U, 1) = %g (exact) %g (estimated)\n', ...
+ norm (P * (R\A) * Q - L*U, 1), lu_normest (P * (R\A) * Q, L, U)) ;
+
+fprintf ('\nSolution to Ax=b via UMFPACK factorization:\n') ;
+fprintf ('x = Q * (U \\ (L \\ (P * (R \\ b))))\n') ;
+xu = Q * (U \ (L \ (P * (R \ b)))) ;
+x = xu ;
+
+fprintf ('\nUMFPACK flop count: %d\n', luflop (L, U)) ;
+
+subplot (2,3,5)
+spy (spones (L) + spones (U))
+title ('UMFPACK LU factors') ;
+
+subplot (2,3,6)
+fprintf ('\nFactorizing [L, U, P] = lu (A (:, q))\n') ;
+fprintf ('If you are using a version of MATLAB prior to V6.0, then the\n') ;
+fprintf ('following statement (q = colamd (A)) may fail. Either download\n');
+fprintf ('colamd from http://www.cise.ufl.edu/research/sparse, upgrade to\n') ;
+fprintf ('MATLAB V6.0 or later, or replace the statement with\n') ;
+fprintf ('q = colmmd (A) ;\n') ;
+try
+ q = colamd (A) ;
+catch
+ fprintf ('\n *** colamd not found, using colmmd instead *** \n') ;
+ q = colmmd (A) ;
+end
+[L, U, P] = lu (A (:,q)) ;
+spy (spones (L) + spones (U))
+title ('MATLAB LU factors') ;
+
+fprintf ('\nSolution to Ax=b via MATLAB factorization:\n') ;
+fprintf ('x = U \\ (L \\ (P * b)) ; x (q) = x ;\n') ;
+xm = U \ (L \ (P * b)) ;
+xm (q) = xm ;
+
+fprintf ('Difference between UMFPACK and MATLAB solution: %g\n', ...
+ norm (xu - xm, Inf)) ;
+
+fprintf ('\nMATLAB LU flop count: %d\n', luflop (L, U)) ;
+
+%-------------------------------------------------------------------------------
+% solve A'x=b
+%-------------------------------------------------------------------------------
+
+fprintf ('\n--------------------------------------------------------------\n') ;
+fprintf ('Solve A''x=b:\n') ;
+
+fprintf ('Solving A''x=b via UMFPACK:\n') ;
+[xu, info] = umfpack (b', '/', A, control) ;
+xu = xu' ;
+
+fprintf ('Solving A''x=b via MATLAB:\n') ;
+xm = (b'/A)' ;
+x = xm ;
+
+fprintf ('Difference between UMFPACK and MATLAB solution: %g\n', ...
+ norm (xu - xm, Inf)) ;
+
+%-------------------------------------------------------------------------------
+% factor A' and then solve Ax=b using the factors of A'
+%-------------------------------------------------------------------------------
+
+fprintf ('\n--------------------------------------------------------------\n') ;
+fprintf ('Compute C = A'', and compute the LU factorization of C.\n') ;
+fprintf ('Factorizing A'' can sometimes be better than factorizing A itself\n');
+fprintf ('(less work and memory usage). Solve C''x=b; the solution is the\n') ;
+fprintf ('same as the solution to Ax=b for the original A.\n');
+
+C = A' ;
+
+% factorize C (P,Q) = L*U
+[L, U, P, Q, R, info] = umfpack (C, control) ;
+
+fprintf ('\nP * (R\\C) * Q - L*U should be zero:\n') ;
+fprintf ('norm (P*(R\\C)*Q - L*U, 1) = %g (exact) %g (estimated)\n', ...
+ norm (P * (R\C) * Q - L*U, 1), lu_normest (P * (R\C) * Q, L, U)) ;
+
+fprintf ('\nSolution to Ax=b via UMFPACK, using the factors of C:\n') ;
+fprintf ('x = R \\ (P'' * (L'' \\ (U'' \\ (Q'' * b)))) ;\n') ;
+xu = R \ (P' * (L' \ (U' \ (Q' * b)))) ;
+x = xu ;
+
+fprintf ('Solution to Ax=b via MATLAB:\n') ;
+xm = A\b ;
+x = xm ;
+
+fprintf ('Difference between UMFPACK and MATLAB solution: %g\n', ...
+ norm (xu - xm, Inf)) ;
+
+%-------------------------------------------------------------------------------
+% solve Ax=B
+%-------------------------------------------------------------------------------
+
+fprintf ('\n--------------------------------------------------------------\n') ;
+fprintf ('\nSolve AX=B, where B is n-by-10, and sparse\n') ;
+B = sprandn (n, 10, 0.05) ;
+XU = umfpack_solve (A, '\', B, control) ;
+XM = A\B ;
+
+fprintf ('Difference between UMFPACK and MATLAB solution: %g\n', ...
+ norm (XU - XM, Inf)) ;
+
+fprintf ('\n--------------------------------------------------------------\n') ;
+fprintf ('\nSolve AX=B, where B is n-by-10, and sparse, using umfpack_btf\n') ;
+XU = umfpack_btf (A, B, control) ;
+
+fprintf ('Difference between UMFPACK and MATLAB solution: %g\n', ...
+ norm (XU - XM, Inf)) ;
+
+fprintf ('\n--------------------------------------------------------------\n') ;
+fprintf ('\nSolve A''X=B, where B is n-by-10, and sparse\n') ;
+XU = umfpack_solve (B', '/', A, control) ;
+XM = B'/A ;
+
+fprintf ('Difference between UMFPACK and MATLAB solution: %g\n', ...
+ norm (XU - XM, Inf)) ;
--- /dev/null
+>> umfpack_demo
+
+Enter the printing level for UMFPACK's output statistics:
+0: none, 1: errors only, 2: statistics, 4: print some of outputs
+5: print all output [default is 1]:
+
+--------------------------------------------------------------
+Factor and solve a small system, Ax=b, using default parameters
+Solving Ax=b via UMFPACK:
+Solving Ax=b via MATLAB:
+Difference between UMFPACK and MATLAB solution: 1.24345e-14
+
+--------------------------------------------------------------
+
+Factorizing [L, U, P, Q, R] = umfpack (A)
+
+P * (R\A) * Q - L*U should be zero:
+norm (P*(R\A)*Q - L*U, 1) = 4.2068e-16 (exact) 3.74627e-16 (estimated)
+
+Solution to Ax=b via UMFPACK factorization:
+x = Q * (U \ (L \ (P * (R \ b))))
+
+UMFPACK flop count: 2362
+
+Factorizing [L, U, P] = lu (A (:, q))
+If you are using a version of MATLAB prior to V6.0, then the
+following statement (q = colamd (A)) may fail. Either download
+colamd from http://www.cise.ufl.edu/research/sparse, upgrade to
+MATLAB V6.0 or later, or replace the statement with
+q = colmmd (A) ;
+
+Solution to Ax=b via MATLAB factorization:
+x = U \ (L \ (P * b)) ; x (q) = x ;
+Difference between UMFPACK and MATLAB solution: 1.37668e-14
+
+MATLAB LU flop count: 3164
+
+--------------------------------------------------------------
+Solve A'x=b:
+Solving A'x=b via UMFPACK:
+Solving A'x=b via MATLAB:
+Difference between UMFPACK and MATLAB solution: 3.10862e-15
+
+--------------------------------------------------------------
+Compute C = A', and compute the LU factorization of C.
+Factorizing A' can sometimes be better than factorizing A itself
+(less work and memory usage). Solve C'x=b; the solution is the
+same as the solution to Ax=b for the original A.
+
+P * (R\C) * Q - L*U should be zero:
+norm (P*(R\C)*Q - L*U, 1) = 1.31839e-16 (exact) 6.41848e-17 (estimated)
+
+Solution to Ax=b via UMFPACK, using the factors of C:
+x = R \ (P' * (L' \ (U' \ (Q' * b)))) ;
+Solution to Ax=b via MATLAB:
+Difference between UMFPACK and MATLAB solution: 1.77636e-14
+
+--------------------------------------------------------------
+
+Solve AX=B, where B is n-by-10, and sparse
+Difference between UMFPACK and MATLAB solution: 2.88198e-14
+
+--------------------------------------------------------------
+
+Solve AX=B, where B is n-by-10, and sparse, using umfpack_btf
+Difference between UMFPACK and MATLAB solution: 9.79736e-14
+
+--------------------------------------------------------------
+
+Solve A'X=B, where B is n-by-10, and sparse
+Difference between UMFPACK and MATLAB solution: 1.05244e-13
+>> diary off
--- /dev/null
+function [out1, out2, out3, out4, out5] = umfpack (in1, in2, in3, in4, in5)
+% UMFPACK v4.3: details on each usage.
+%
+% Factor or solve a sparse linear system, returning either the solution x to
+% Ax=b or A'x'=b', the factorization LU=PAQ, or LU=P(R\A)Q. A must be sparse.
+% For the solve, A must be square and b must be a dense n-by-1 vector. For LU
+% factorization, A can be rectangular. In both cases, A and/or b can be real
+% or complex.
+%
+% UMFPACK analyzes the matrix and selects one of three strategies to factorize
+% the matrix. It first finds a set of k initial pivot entries of zero Markowitz
+% cost. This forms the first k rows and columns of L and U. The remaining
+% submatrix S is then analyzed, based on the symmetry of the nonzero pattern of
+% the submatrix and the values on the diagaonal. The strategies include:
+%
+% (1) unsymmetric: use a COLAMD pre-ordering, a column elimination tree
+% post-ordering, refine the column ordering during factorization,
+% and make no effort at selecting pivots on the diagonal.
+% (2) 2-by-2: like the symmetric strategy (see below), except that local
+% row permutations are first made to attempt to place large entries
+% on the diagonal.
+% (3) symmetric: use an AMD pre-ordering on the matrix S+S', an
+% elimination tree post-ordering, do not refine the column ordering
+% during factorization, and attempt to select pivots on the diagonal.
+%
+% Each of the following uses of umfpack (except for "Control = umfpack") is
+% stand-alone. That is, no call to umfpack is required for any subsequent
+% call. In each usage, the Info output argument is optional.
+%
+% Usage:
+%
+% [x, Info] = umfpack (A, '\', b) ;
+% [x, Info] = umfpack (A, '\', b, Control) ;
+% [x, Info] = umfpack (A, Qinit, '\', b, Control) ;
+% [x, Info] = umfpack (A, Qinit, '\', b) ;
+%
+% Solves Ax=b (similar to x = A\b in MATLAB).
+%
+% [x, Info] = umfpack (b, '/', A) ;
+% [x, Info] = umfpack (b, '/', A, Control) ;
+% [x, Info] = umfpack (b, '/', A, Qinit) ;
+% [x, Info] = umfpack (b, '/', A, Qinit, Control) ;
+%
+% Solves A'x'=b' (similar to x = b/A in MATLAB).
+%
+% [L, U, P, Q, R, Info] = umfpack (A) ;
+% [L, U, P, Q, R, Info] = umfpack (A, Control) ;
+% [L, U, P, Q, R, Info] = umfpack (A, Qinit) ;
+% [L, U, P, Q, R, Info] = umfpack (A, Qinit, Control) ;
+%
+% Returns the LU factorization of A. P and Q are returned as permutation
+% matrices. R is a diagonal sparse matrix of scale factors for the rows
+% of A, L is lower triangular, and U is upper triangular. The
+% factorization is L*U = P*(R\A)*Q. You can turn off scaling by setting
+% Control (17) to zero (in which case R = speye (m)), or by using the
+% following syntaxes (in which case Control (17) is ignored):
+%
+% [L, U, P, Q] = umfpack (A) ;
+% [L, U, P, Q] = umfpack (A, Control) ;
+% [L, U, P, Q] = umfpack (A, Qinit) ;
+% [L, U, P, Q] = umfpack (A, Qinit, Control) ;
+%
+% Same as above, except that no row scaling is performed. The Info array
+% is not returned, either.
+%
+% [P1, Q1, Fr, Ch, Info] = umfpack (A, 'symbolic') ;
+% [P1, Q1, Fr, Ch, Info] = umfpack (A, 'symbolic', Control) ;
+% [P1, Q1, Fr, Ch, Info] = umfpack (A, Qinit, 'symbolic') ;
+% [P1, Q1, Fr, Ch, Info] = umfpack (A, Qinit, 'symbolic', Control);
+%
+% Performs only the fill-reducing column pre-ordering (including the
+% elimination tree post-ordering) and symbolic factorization. Q1 is the
+% initial column permutation (either from colamd, amd, or the input
+% ordering Qinit), possibly followed by a column elimination tree post-
+% ordering or a symmetric elimination tree post-ordering, depending on
+% the strategy used.
+%
+% For the unsymmetric strategy, P1 is the row ordering induced by Q1
+% (row-merge order). For the 2-by-2 strategy, P1 is the row ordering that
+% places large entries on the diagonal of P1*A*Q1. For the symmetric
+% strategy, P1 = Q1.
+%
+% Fr is a (nfr+1)-by-4 array containing information about each frontal
+% matrix, where nfr <= n is the number of frontal matrices. Fr (:,1) is
+% the number of pivot columns in each front, and Fr (:,2) is the parent
+% of each front in the supercolumn elimination tree. Fr (k,2) is zero if
+% k is a root. The first Fr (1,1) columns of P1*A*Q1 are the pivot
+% columns for the first front, the next Fr (2,1) columns of P1*A*Q1
+% are the pivot columns for the second front, and so on.
+%
+% For the unsymmetric strategy, Fr (:,3) is the row index of the first
+% row in P1*A*Q1 whose leftmost nonzero entry is in a pivot column for
+% the kth front. Fr (:,4) is the leftmost descendent of the kth front.
+% Rows in the range Fr (Fr (k,4),3) to Fr (k+1,3)-1 form the entire set
+% of candidate pivot rows for the kth front (some of these will typically
+% have been selected as pivot rows of fronts Fr (k,3) to k-1, before the
+% factorization reaches the kth front. If front k is a leaf node, then
+% Fr (k,4) is k.
+%
+% Ch is a (nchains+1)-by-3 array containing information about each "chain"
+% (unifrontal sequence) of frontal matrices, and where nchains <= nfr
+% is the number of chains. The ith chain consists of frontal matrices.
+% Chain (i,1) to Chain (i+1,1)-1, and the largest front in chain i is
+% Chain (i,2)-by-Chain (i,3).
+%
+% This use of umfpack is not required to factor or solve a linear system
+% in MATLAB. It analyzes the matrix A and provides information only.
+% The MATLAB statement "treeplot (Fr (:,2)')" plots the column elimination
+% tree.
+%
+% Control = umfpack ;
+%
+% Returns a 20-by-1 vector of default parameter settings for umfpack.
+%
+% umfpack_report (Control, Info) ;
+%
+% Prints the current Control settings, and Info
+%
+% If present, Qinit is a user-supplied 1-by-n permutation vector. It is an
+% initial fill-reducing column pre-ordering for A; if not present, then colamd
+% or amd are used instead. If present, Control is a user-supplied 20-by-1
+% array. Control and Info are optional; if Control is not present, defaults
+% are used. If a Control entry is NaN, then the default is used for that entry.
+%
+% UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+% Davis. All Rights Reserved.
+%
+% UMFPACK License:
+%
+% Your use or distribution of UMFPACK or any modified version of
+% UMFPACK implies that you agree to this License.
+%
+% THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+% EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+%
+% Permission is hereby granted to use or copy this program, provided
+% that the Copyright, this License, and the Availability of the original
+% version is retained on all copies. User documentation of any code that
+% uses UMFPACK or any modified version of UMFPACK code must cite the
+% Copyright, this License, the Availability note, and "Used by permission."
+% Permission to modify the code and to distribute modified code is granted,
+% provided the Copyright, this License, and the Availability note are
+% retained, and a notice that the code was modified is included. This
+% software was developed with support from the National Science Foundation,
+% and is provided to you free of charge.
+%
+% Availability: http://www.cise.ufl.edu/research/sparse/umfpack
+%
+% See also umfpack, umfpack_make, umfpack_report,
+% umfpack_demo, and umfpack_simple.
+
+more on
+help umfpack_details
+more off
+
--- /dev/null
+function umfpack_make
+% UMFPACK_MAKE
+%
+% Compiles the UMFPACK mexFunction and then runs a simple demo.
+%
+% UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+% Davis. All Rights Reserved. Type umfpack_details for License.
+%
+% See also: umfpack, umfpack_details, umfpack_report, umfpack_demo, and
+% umfpack_simple.
+
+help umfpack_make
+
+fprintf ('\n--------------------------------------------------------------\n') ;
+fprintf ('Now compiling the UMFPACK and AMD mexFunctions.\n') ;
+fprintf ('--------------------------------------------------------------\n') ;
+
+try
+ % ispc does not appear in MATLAB 5.3
+ pc = ispc ;
+catch
+ % if ispc fails, assume we aren't on a Windows PC.
+ pc = 0 ;
+end
+
+obj = 'o' ;
+blas_lib = '' ;
+if (pc)
+ obj = 'obj' ;
+end
+
+%-------------------------------------------------------------------------------
+% BLAS option
+%-------------------------------------------------------------------------------
+
+msg = [ ...
+ '\nUsing the BLAS is faster, but might not compile correctly.\n', ...
+ 'If you get an error stating that dgemm, dgemv, dger, zgemm,\n', ...
+ 'zgemv, and/or zger are not defined, then recompile without the\n', ...
+ 'BLAS. You can ignore warnings that these routines are implicitly\n', ...
+ 'declared.\n\nPlease select one of the following options: \n', ...
+ ' 1: attempt to compile with the BLAS (default)\n', ...
+ ' 2: do not use the BLAS\n'] ;
+fprintf (msg) ;
+blas = input (': ') ;
+if (isempty (blas))
+ blas = 1 ;
+end
+if (blas == 1)
+ % try to link to MATLAB's built-in BLAS
+ blas = '' ;
+ if (pc)
+ % the default lcc compiler needs this library to access the BLAS
+ blas_lib = ' libmwlapack.lib' ;
+ msg = [ ...
+ '\nCheck to see if you have a file called libmwlapack.lib in the\n', ...
+ '<matlab>\\extern\\lib\\win32\\lcc\\ directory, where <matlab> is ', ...
+ 'the\ndirectory where MATLAB is installed. If a file of that ', ...
+ 'name is already\nthere, then you don''t have to do anything. ', ...
+ 'Otherwise, you must first\ncopy the libmwlapack.lib file from ', ...
+ 'the umfpack\\lcc_lib\\ directory to the\n', ...
+ '<matlab>\\extern\\lib\\win32\\lcc\\ directory. Next, type\n\n', ...
+ ' mex -setup\n\n', ...
+ 'at the MATLAB prompt, and ask MATLAB to select the lcc compiler. ',...
+ 'You can skip\nall of this if you have already done it, or have ', ...
+ 'configured mex to use\na different compiler. If you are using ', ...
+ 'Norton anti-virus software on Windows\n98SE, then you need to ', ...
+ 'exit MATLAB, turn off virus checking, and restart MATLAB\n', ...
+ 'before you can use the mex command or compile UMFPACK.\n', ...
+ 'You may also need to turn off virus checking in other cases.\n', ...
+ '\nHit enter to continue, or type control-C if you do not wish to '] ;
+ fprintf (msg) ;
+ input ('proceed: ') ;
+ end
+ fprintf ('\nUsing the BLAS (recommended).\n') ;
+else
+ % No BLAS
+ fprintf ('\nNot using the BLAS. UMFPACK will be slow.\n') ;
+ blas = ' -DNBLAS' ;
+end
+
+%-------------------------------------------------------------------------------
+% -DNUTIL option (using utMalloc or mxMalloc)
+%-------------------------------------------------------------------------------
+
+utils = '' ;
+
+if (~pc)
+ msg = [ ...
+ '--------------------------------------------------------------\n', ...
+ '\nUMFPACK uses MATLAB''s memory allocation routines. The internal', ...
+ '\nutMalloc, utFree, and utRealloc allow for better use of memory,', ...
+ '\nbut they are internal utility routines that are not documented.\n', ...
+ 'Thus, they might not always work. Using mxMalloc, mxFree, and\n', ...
+ 'mxRealloc works, but UMFPACK might run out of memory when solving\n', ...
+ 'problems that it could otherwise solve. Try using the default.\n', ...
+ 'If you get an error stating that utMalloc, utFree, and/or\n', ...
+ 'utRealloc are not defined, then recompile with the mx* routines.\n', ...
+ '\nPlease select one of the following options:\n', ...
+ ' 1: attempt to use the ut* routines (default)\n', ...
+ ' 2: use the standard mx* routines\n'] ;
+ fprintf (msg) ;
+ utils = input (': ') ;
+ if (isempty (utils))
+ utils = 1 ;
+ end
+ if (utils == 2)
+ fprintf ('\nNot using utMalloc, utFree, or utRealloc\n') ;
+ utils = ' -DNUTIL' ;
+ else
+ fprintf ('\nUsing utMalloc, utFree, and utRealloc\n') ;
+ utils = '' ;
+ end
+end
+
+%-------------------------------------------------------------------------------
+% -DNPOSIX option (for sysconf and times timer routines)
+%-------------------------------------------------------------------------------
+
+posix = '' ;
+
+if (~pc)
+ msg = [ ...
+ '--------------------------------------------------------------\n', ...
+ '\nUMFPACK can use the POSIX routines sysconf () and times ()\n', ...
+ 'to provide CPU time and wallclock time statistics. If you do not\n', ...
+ 'have a POSIX-compliant operating system, then UMFPACK won''t\n', ...
+ 'compile. If you don''t know which option to pick, try the\n', ...
+ 'default. If you get an error saying that sysconf and/or times\n', ...
+ 'are not defined, then recompile with the non-POSIX option.\n', ...
+ '\nPlease select one of the following options:\n', ...
+ ' 1: use POSIX sysconf and times routines (default)\n', ...
+ ' 2: do not use POSIX routines\n'] ;
+ fprintf (msg) ;
+ posix = input (': ') ;
+ if (isempty (posix))
+ posix = 1 ;
+ end
+ if (posix == 2)
+ fprintf ('\nNot using POSIX sysconf and times routines.\n') ;
+ posix = ' -DNPOSIX' ;
+ else
+ fprintf ('\nUsing POSIX sysconf and times routines.\n') ;
+ posix = '' ;
+ end
+end
+
+%-------------------------------------------------------------------------------
+% mex command
+%-------------------------------------------------------------------------------
+
+umfdir = sprintf ('..%sSource%s', filesep, filesep) ;
+amddir = sprintf ('..%s..%sAMD%sSource%s', filesep, filesep, filesep, filesep) ;
+incdir = sprintf ( ...
+' -I..%sInclude -I..%sSource -I..%s..%sAMD%sInclude -I..%s..%sAMD%sSource', ...
+filesep,filesep, filesep, filesep, filesep, filesep, filesep, filesep) ;
+
+mx = sprintf ('mex -inline -O%s%s%s%s', blas, utils, posix, incdir) ;
+msg = [ ...
+ '--------------------------------------------------------------\n', ...
+ '\nCompile options:\n%s\nNow compiling. Please wait.\n'] ;
+fprintf (msg, mx) ;
+
+% The following is adapted from GNUmakefile
+
+%-------------------------------------------------------------------------------
+% source files
+%-------------------------------------------------------------------------------
+
+% non-user-callable umf_*.[ch] files:
+umfch = { 'assemble', 'blas3_update', ...
+ 'build_tuples', 'create_element', ...
+ 'dump', 'extend_front', 'garbage_collection', ...
+ 'get_memory', 'init_front', 'kernel', ...
+ 'kernel_init', 'kernel_wrapup', ...
+ 'local_search', 'lsolve', 'ltsolve', ...
+ 'mem_alloc_element', 'mem_alloc_head_block', ...
+ 'mem_alloc_tail_block', 'mem_free_tail_block', ...
+ 'mem_init_memoryspace', ...
+ 'report_vector', 'row_search', 'scale_column', ...
+ 'set_stats', 'solve', 'symbolic_usage', 'transpose', ...
+ 'tuple_lengths', 'usolve', 'utsolve', 'valid_numeric', ...
+ 'valid_symbolic', 'grow_front', 'start_front', '2by2', ...
+ 'store_lu', 'scale' } ;
+
+% non-user-callable umf_*.[ch] files, int versions only (no real/complex):
+umfint = { 'analyze', 'apply_order', 'colamd', 'free', 'fsize', ...
+ 'is_permutation', 'malloc', 'realloc', 'report_perm', ...
+ 'singletons' } ;
+
+% non-user-callable and user-callable amd_*.[ch] files (int versions only):
+amd = { 'aat', '1', '2', 'dump', 'postorder', 'post_tree', 'defaults', ...
+ 'order', 'control', 'info', 'valid' } ;
+
+% user-callable umfpack_*.[ch] files (real/complex):
+user = { 'col_to_triplet', 'defaults', 'free_numeric', ...
+ 'free_symbolic', 'get_numeric', 'get_lunz', ...
+ 'get_symbolic', 'numeric', 'qsymbolic', ...
+ 'report_control', 'report_info', 'report_matrix', ...
+ 'report_numeric', 'report_perm', 'report_status', ...
+ 'report_symbolic', 'report_triplet', ...
+ 'report_vector', 'solve', 'symbolic', ...
+ 'transpose', 'triplet_to_col', 'scale' ...
+ 'load_numeric', 'save_numeric', 'load_symbolic', 'save_symbolic' } ;
+
+% user-callable umfpack_*.[ch], only one version
+generic = { 'timer', 'tictoc' } ;
+
+M = cell (0) ;
+
+%-------------------------------------------------------------------------------
+% Create the umfpack and amd mexFunctions for MATLAB (int versions only)
+%-------------------------------------------------------------------------------
+
+for k = 1:length(umfint)
+ M = make (M, '%s -DDINT -c %sumf_%s.c', 'umf_%s.%s', 'umf_%s_%s.%s', ...
+ mx, umfint {k}, umfint {k}, 'm', obj, umfdir) ;
+end
+
+rules = { [mx ' -DDINT'] , [mx ' -DZINT'] } ;
+kinds = { 'md', 'mz' } ;
+
+for what = 1:2
+
+ rule = rules {what} ;
+ kind = kinds {what} ;
+
+ M = make (M, '%s -DCONJUGATE_SOLVE -c %sumf_%s.c', 'umf_%s.%s', ...
+ 'umf_%s_%s.%s', rule, 'ltsolve', 'lhsolve', kind, obj, umfdir) ;
+
+ M = make (M, '%s -DCONJUGATE_SOLVE -c %sumf_%s.c', 'umf_%s.%s', ...
+ 'umf_%s_%s.%s', rule, 'utsolve', 'uhsolve', kind, obj, umfdir) ;
+
+ M = make (M, '%s -DDO_MAP -c %sumf_%s.c', 'umf_%s.%s', ...
+ 'umf_%s_%s_map_nox.%s', rule, 'triplet', 'triplet', kind, obj, umfdir) ;
+
+ M = make (M, '%s -DDO_VALUES -c %sumf_%s.c', 'umf_%s.%s', ...
+ 'umf_%s_%s_nomap_x.%s', rule, 'triplet', 'triplet', kind, obj, umfdir) ;
+
+ M = make (M, '%s -c %sumf_%s.c', 'umf_%s.%s', ...
+ 'umf_%s_%s_nomap_nox.%s', rule, 'triplet', 'triplet', kind, obj, ...
+ umfdir) ;
+
+ M = make (M, '%s -DDO_MAP -DDO_VALUES -c %sumf_%s.c', 'umf_%s.%s', ...
+ 'umf_%s_%s_map_x.%s', rule, 'triplet', 'triplet', kind, obj, umfdir) ;
+
+ M = make (M, '%s -DFIXQ -c %sumf_%s.c', 'umf_%s.%s', ...
+ 'umf_%s_%s_fixq.%s', rule, 'assemble', 'assemble', kind, obj, umfdir) ;
+
+ M = make (M, '%s -DDROP -c %sumf_%s.c', 'umf_%s.%s', ...
+ 'umf_%s_%s_drop.%s', rule, 'store_lu', 'store_lu', kind, obj, umfdir) ;
+
+ for k = 1:length(umfch)
+ M = make (M, '%s -c %sumf_%s.c', 'umf_%s.%s', 'umf_%s_%s.%s', ...
+ rule, umfch {k}, umfch {k}, kind, obj, umfdir) ;
+ end
+
+ M = make (M, '%s -DWSOLVE -c %sumfpack_%s.c', 'umfpack_%s.%s', ...
+ 'umfpack_%s_w%s.%s', rule, 'solve', 'solve', kind, obj, umfdir) ;
+
+ for k = 1:length(user)
+ M = make (M, '%s -c %sumfpack_%s.c', 'umfpack_%s.%s', ...
+ 'umfpack_%s_%s.%s', rule, user {k}, user {k}, kind, obj, umfdir) ;
+ end
+end
+
+for k = 1:length(generic)
+ M = make (M, '%s -c %sumfpack_%s.c', 'umfpack_%s.%s', ...
+ 'umfpack_%s_%s.%s', mx, generic {k}, generic {k}, 'm', obj, umfdir) ;
+end
+
+%----------------------------------------
+% AMD routines (int only)
+%----------------------------------------
+
+for k = 1:length(amd)
+ M = make (M, '%s -DDINT -c %samd_%s.c', 'amd_%s.%s', 'amd_%s_%s.%s', ...
+ mx, amd {k}, amd {k}, 'm', obj, amddir) ;
+end
+
+%----------------------------------------
+% compile the umfpack mexFunction
+%----------------------------------------
+
+C = sprintf ('%s -output umfpack umfpackmex.c', mx) ;
+for i = 1:length (M)
+ C = [C ' ' (M {i})] ;
+end
+C = [C ' ' blas_lib] ;
+cmd (C) ;
+
+%----------------------------------------
+% delete the object files
+%----------------------------------------
+
+for i = 1:length (M)
+ rmfile (M {i}) ;
+end
+
+%----------------------------------------
+% compile the luflop mexFunction
+%----------------------------------------
+
+cmd (sprintf ('%s -output luflop luflopmex.c', mx)) ;
+
+fprintf ('\n\nCompilation has completed. Now trying the umfpack_simple demo.\n');
+umfpack_simple
+
+%-------------------------------------------------------------------------------
+% rmfile: delete a file, but only if it exists
+%-------------------------------------------------------------------------------
+
+function rmfile (file)
+if (length (dir (file)) > 0)
+ delete (file) ;
+end
+
+%-------------------------------------------------------------------------------
+% cpfile: copy the src file to the filename dst, overwriting dst if it exists
+%-------------------------------------------------------------------------------
+
+function cpfile (src, dst)
+rmfile (dst)
+if (length (dir (src)) == 0)
+ help umfpack_make
+ error (sprintf ('File does not exist: %s\n', src)) ;
+end
+copyfile (src, dst) ;
+
+%-------------------------------------------------------------------------------
+% mvfile: move the src file to the filename dst, overwriting dst if it exists
+%-------------------------------------------------------------------------------
+
+function mvfile (src, dst)
+cpfile (src, dst) ;
+rmfile (src) ;
+
+%-------------------------------------------------------------------------------
+% cmd: display and execute a command
+%-------------------------------------------------------------------------------
+
+function cmd (s)
+fprintf ('.') ;
+eval (s) ;
+
+%-------------------------------------------------------------------------------
+% make: execute a "make" command for a source file
+%-------------------------------------------------------------------------------
+
+function M = make (M, s, src, dst, rule, file1, file2, kind, obj, srcdir)
+cmd (sprintf (s, rule, srcdir, file1)) ;
+src = sprintf (src, file1, obj) ;
+dst = sprintf (dst, kind, file2, obj) ;
+mvfile (src, dst) ;
+M {end + 1} = dst ;
+
--- /dev/null
+function umfpack_report (Control, Info)
+% UMFPACK_REPORT
+%
+% umfpack_report (Control, Info) ;
+%
+% Prints the current Control settings for umfpack, and the statistical
+% information returned by umfpack in the Info array. If Control is
+% an empty matrix, then the default control settings are printed.
+%
+% Control is 20-by-1, and Info is 90-by-1. Not all entries are used.
+%
+% Alternative usages:
+%
+% umfpack_report ([ ], Info) ; print the default control parameters
+% and the Info array.
+% umfpack_report (Control) ; print the control parameters only.
+% umfpack_report ; print the default control parameters
+% and an empty Info array.
+%
+% See also umfpack, umfpack_make, umfpack_details,
+% umfpack_demo, and umfpack_simple.
+
+% UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+% Davis. All Rights Reserved. See ../README for License.
+
+%-------------------------------------------------------------------------------
+% get inputs, use defaults if input arguments not present
+%-------------------------------------------------------------------------------
+
+% The contents of Control and Info are defined in umfpack.h
+if (nargin < 1)
+ Control = [] ;
+end
+if (nargin < 2)
+ Info = [] ;
+end
+if (isempty (Control))
+ Control = umfpack ;
+end
+if (isempty (Info))
+ Info = [ 0 (-ones (1, 89)) ] ;
+end
+
+%-------------------------------------------------------------------------------
+% control settings
+%-------------------------------------------------------------------------------
+
+fprintf ('\nUMFPACK Version 4.3: Control settings:\n\n') ;
+fprintf (' Control (1): print level: %d\n', Control (1)) ;
+fprintf (' Control (2): dense row parameter: %g\n', Control (2)) ;
+fprintf (' "dense" rows have > max (16, (%g)*16*sqrt(n_col)) entries\n', Control (2)) ;
+fprintf (' Control (3): dense column parameter: %g\n', Control (3)) ;
+fprintf (' "dense" columns have > max (16, (%g)*16*sqrt(n_row)) entries\n', Control (3)) ;
+fprintf (' Control (4): pivot tolerance: %g\n', Control (4)) ;
+fprintf (' Control (5): max block size for dense matrix kernels: %d\n', Control (5)) ;
+prstrat (' Control (6): strategy: %g ', Control (6)) ;
+fprintf (' Control (7): initial allocation ratio: %g\n', Control (7)) ;
+fprintf (' Control (8): max iterative refinement steps: %d\n', Control (8)) ;
+fprintf (' Control (13): 2-by-2 pivot tolerance: %g\n', Control (13)) ;
+fprintf (' Control (14): Q fixed during numeric factorization: %g ', Control (14)) ;
+if (Control (14) > 0)
+ fprintf ('(yes)\n') ;
+elseif (Control (14) < 0)
+ fprintf ('(no)\n') ;
+else
+ fprintf ('(auto)\n') ;
+end
+fprintf (' Control (15): AMD dense row/column parameter: %g\n', Control (15)) ;
+fprintf (' "dense" rows/columns in A+A'' have > max (16, (%g)*sqrt(n)) entries.\n', Control (15)) ;
+fprintf (' Only used if the AMD ordering is used.\n') ;
+fprintf (' Control (16): diagonal pivot tolerance: %g\n', Control (16)) ;
+fprintf (' Only used if diagonal pivoting is attempted.\n') ;
+
+fprintf (' Control (17): scaling option: %g ', Control (17)) ;
+if (Control (17) == 0)
+ fprintf ('(none)\n') ;
+elseif (Control (17) == 2)
+ fprintf ('(scale the matrix by\n') ;
+ fprintf (' dividing each row by max. abs. value in each row)\n') ;
+else
+ fprintf ('(scale the matrix by\n') ;
+ fprintf (' dividing each row by sum of abs. values in each row)\n') ;
+end
+
+fprintf (' Control (18): frontal matrix allocation ratio: %g\n', Control (18)) ;
+fprintf (' Control (19): drop tolerance: %g\n', Control (19)) ;
+fprintf (' Control (20): AMD and COLAMD aggressive absorption: %g ', Control (20)) ;
+yes_no (Control (20)) ;
+
+% compile-time options:
+
+fprintf ('\n The following options can only be changed at compile-time:\n') ;
+
+if (Control (9) == 1)
+ fprintf (' Control (9): compiled to use the BLAS\n') ;
+else
+ fprintf (' Control (9): compiled without the BLAS\n') ;
+ fprintf (' (you will not get the best possible performance)\n') ;
+end
+
+if (Control (10) == 1)
+ fprintf (' Control (10): compiled for MATLAB\n') ;
+elseif (Control (10) == 2)
+ fprintf (' Control (10): compiled for MATLAB\n') ;
+ fprintf (' Uses internal utMalloc, utFree, utRealloc, utPrintf\n') ;
+ fprintf (' utDivideComplex, and utFdlibm_hypot routines.\n') ;
+else
+ fprintf (' Control (10): not compiled for MATLAB\n') ;
+ fprintf (' Uses ANSI C malloc, free, realloc, and printf\n') ;
+ fprintf (' instead of mxMalloc, mxFree, mxRealloc, and mexPrintf.\n') ;
+ fprintf (' Printing will be in terms of 0-based matrix indexing,\n') ;
+ fprintf (' not 1-based as is expected in MATLAB. Diary output may\n') ;
+ fprintf (' not be properly recorded.\n') ;
+end
+
+if (Control (11) == 2)
+ fprintf (' Control (11): uses POSIX times ( ) to get CPU time and wallclock time.\n') ;
+elseif (Control (11) == 1)
+ fprintf (' Control (11): uses getrusage to get CPU time.\n') ;
+else
+ fprintf (' Control (11): uses ANSI C clock to get CPU time.\n') ;
+ fprintf (' The CPU time may wrap around, type "help cputime".\n') ;
+end
+
+if (Control (12) == 1)
+ fprintf (' Control (12): compiled with debugging enabled\n') ;
+ fprintf (' ###########################################\n') ;
+ fprintf (' ### This will be exceedingly slow! ########\n') ;
+ fprintf (' ###########################################\n') ;
+ if (Control (10) == 1)
+ fprintf (' Uses mxAssert.\n') ;
+ elseif (Control (10) == 2)
+ fprintf (' Uses utAssert.\n') ;
+ else
+ fprintf (' Uses ANSI C assert instead of mxAssert.\n') ;
+ end
+else
+ fprintf (' Control (12): compiled for normal operation (no debugging)\n') ;
+end
+
+%-------------------------------------------------------------------------------
+% Info:
+%-------------------------------------------------------------------------------
+
+if (nargin == 1)
+ return
+end
+
+status = Info (1) ;
+fprintf ('\nUMFPACK status: Info (1): %d, ', status) ;
+
+if (status == 0)
+ fprintf ('OK\n') ;
+elseif (status == 1)
+ fprintf ('WARNING matrix is singular\n') ;
+elseif (status == -1)
+ fprintf ('ERROR out of memory\n') ;
+elseif (status == -3)
+ fprintf ('ERROR numeric LU factorization is invalid\n') ;
+elseif (status == -4)
+ fprintf ('ERROR symbolic LU factorization is invalid\n') ;
+elseif (status == -5)
+ fprintf ('ERROR required argument is missing\n') ;
+elseif (status == -6)
+ fprintf ('ERROR n <= 0\n') ;
+elseif (status <= -7 & status >= -12 | status == -14)
+ fprintf ('ERROR matrix A is corrupted\n') ;
+elseif (status == -13)
+ fprintf ('ERROR invalid system\n') ;
+elseif (status == -15)
+ fprintf ('ERROR invalid permutation\n') ;
+elseif (status == -911)
+ fprintf ('ERROR internal error!\n') ;
+ fprintf ('Please report this error to Tim Davis (davis@cise.ufl.edu)\n') ;
+else
+ fprintf ('ERROR unrecognized error. Info array corrupted\n') ;
+end
+
+fprintf (' (a -1 means the entry has not been computed):\n') ;
+
+fprintf ('\n Basic statistics:\n') ;
+fprintf (' Info (2): %d, # of rows of A\n', Info (2)) ;
+fprintf (' Info (17): %d, # of columns of A\n', Info (17)) ;
+fprintf (' Info (3): %d, nnz (A)\n', Info (3)) ;
+fprintf (' Info (4): %d, Unit size, in bytes, for memory usage reported below\n', Info (4)) ;
+fprintf (' Info (5): %d, size of int (in bytes)\n', Info (5)) ;
+fprintf (' Info (6): %d, size of long (in bytes)\n', Info (6)) ;
+fprintf (' Info (7): %d, size of pointer (in bytes)\n', Info (7)) ;
+fprintf (' Info (8): %d, size of numerical entry (in bytes)\n', Info (8)) ;
+
+fprintf ('\n Pivots with zero Markowitz cost removed to obtain submatrix S:\n') ;
+fprintf (' Info (57): %d, # of pivots with one entry in pivot column\n', Info (57)) ;
+fprintf (' Info (58): %d, # of pivots with one entry in pivot row\n', Info (58)) ;
+fprintf (' Info (59): %d, # of rows/columns in submatrix S (if square)\n', Info (59)) ;
+fprintf (' Info (60): %d ') ;
+if (Info (60) > 0)
+ fprintf ('submatrix S square and diagonal preserved\n') ;
+elseif (Info (60) == 0)
+ fprintf ('submatrix S not square or diagonal not preserved\n') ;
+else
+ fprintf ('\n') ;
+end
+fprintf (' Info (9): %d, # of "dense" rows in S\n', Info (9)) ;
+fprintf (' Info (10): %d, # of empty rows in S\n', Info (10)) ;
+fprintf (' Info (11): %d, # of "dense" columns in S\n', Info (11)) ;
+fprintf (' Info (12): %d, # of empty columns in S\n', Info (12)) ;
+fprintf (' Info (34): %g, symmetry of pattern of S\n', Info (34)) ;
+fprintf (' Info (35): %d, # of off-diagonal nonzeros in S+S''\n', Info (35)) ;
+fprintf (' Info (36): %d, nnz (diag (S))\n', Info (36)) ;
+
+fprintf ('\n 2-by-2 pivoting to place large entries on diagonal:\n') ;
+fprintf (' Info (52): %d, # of small diagonal entries of S\n', Info (52)) ;
+fprintf (' Info (53): %d, # of unmatched small diagonal entries\n', Info (53)) ;
+fprintf (' Info (54): %g, symmetry of P2*S\n', Info (54)) ;
+fprintf (' Info (55): %d, # of off-diagonal entries in (P2*S)+(P2*S)''\n', Info (55)) ;
+fprintf (' Info (56): %d, nnz (diag (P2*S))\n', Info (56)) ;
+
+fprintf ('\n AMD results, for strict diagonal pivoting:\n') ;
+fprintf (' Info (37): %d, est. nz in L and U\n', Info (37)) ;
+fprintf (' Info (38): %g, est. flop count\n', Info (38)) ;
+fprintf (' Info (39): %g, # of "dense" rows in S+S''\n', Info (39)) ;
+fprintf (' Info (40): %g, est. max. nz in any column of L\n', Info (40)) ;
+
+fprintf ('\n Final strategy selection, based on the analysis above:\n') ;
+prstrat (' Info (19): %d, strategy used ', Info (19)) ;
+fprintf (' Info (20): %d, ordering used ', Info (20)) ;
+if (Info (20) == 0)
+ fprintf ('(COLAMD on A)\n') ;
+elseif (Info (20) == 1)
+ fprintf ('(AMD on A+A'')\n') ;
+elseif (Info (20) == 2)
+ fprintf ('(provided by user)\n') ;
+else
+ fprintf ('(undefined ordering option)\n') ;
+end
+fprintf (' Info (32): %d, Q fixed during numeric factorization: ', Info (32)) ;
+yes_no (Info (32)) ;
+fprintf (' Info (33): %d, prefer diagonal pivoting: ', Info (33)) ;
+yes_no (Info (33)) ;
+
+fprintf ('\n symbolic analysis time and memory usage:\n') ;
+fprintf (' Info (13): %d, defragmentations during symbolic analysis\n', Info (13)) ;
+fprintf (' Info (14): %d, memory used during symbolic analysis (Units)\n', Info (14)) ;
+fprintf (' Info (15): %d, final size of symbolic factors (Units)\n', Info (15)) ;
+fprintf (' Info (16): %.2f, symbolic analysis CPU time (seconds)\n', Info (16)) ;
+fprintf (' Info (18): %.2f, symbolic analysis wall clock time (seconds)\n', Info (18)) ;
+
+fprintf ('\n Estimates computed in the symbolic analysis:\n') ;
+fprintf (' Info (21): %d, est. size of LU factors (Units)\n', Info (21)) ;
+fprintf (' Info (22): %d, est. total peak memory usage (Units)\n', Info (22)) ;
+fprintf (' Info (23): %d, est. factorization flop count\n', Info (23)) ;
+fprintf (' Info (24): %d, est. nnz (L)\n', Info (24)) ;
+fprintf (' Info (25): %d, est. nnz (U)\n', Info (25)) ;
+fprintf (' Info (26): %d, est. initial size, variable-part of LU (Units)\n', Info (26)) ;
+fprintf (' Info (27): %d, est. peak size, of variable-part of LU (Units)\n', Info (27)) ;
+fprintf (' Info (28): %d, est. final size, of variable-part of LU (Units)\n', Info (28)) ;
+fprintf (' Info (29): %d, est. max frontal matrix size (# of entries)\n', Info (29)) ;
+fprintf (' Info (30): %d, est. max # of rows in frontal matrix\n', Info (30)) ;
+fprintf (' Info (31): %d, est. max # of columns in frontal matrix\n', Info (31)) ;
+
+fprintf ('\n Computed in the numeric factorization (estimates shown above):\n') ;
+fprintf (' Info (41): %d, size of LU factors (Units)\n', Info (41)) ;
+fprintf (' Info (42): %d, total peak memory usage (Units)\n', Info (42)) ;
+fprintf (' Info (43): %d, factorization flop count\n', Info (43)) ;
+fprintf (' Info (44): %d, nnz (L)\n', Info (44)) ;
+fprintf (' Info (45): %d, nnz (U)\n', Info (45)) ;
+fprintf (' Info (46): %d, initial size of variable-part of LU (Units)\n', Info (46)) ;
+fprintf (' Info (47): %d, peak size of variable-part of LU (Units)\n', Info (47)) ;
+fprintf (' Info (48): %d, final size of variable-part of LU (Units)\n', Info (48)) ;
+fprintf (' Info (49): %d, max frontal matrix size (# of numerical entries)\n', Info (49)) ;
+fprintf (' Info (50): %d, max # of rows in frontal matrix\n', Info (50)) ;
+fprintf (' Info (51): %d, max # of columns in frontal matrix\n', Info (51)) ;
+
+fprintf ('\n Computed in the numeric factorization (no estimates computed a priori):\n') ;
+fprintf (' Info (61): %d, defragmentations during numeric factorization\n', Info (61)) ;
+fprintf (' Info (62): %d, reallocations during numeric factorization\n', Info (62)) ;
+fprintf (' Info (63): %d, costly reallocations during numeric factorization\n', Info (63)) ;
+fprintf (' Info (64): %d, integer indices in compressed pattern of L and U\n', Info (64)) ;
+fprintf (' Info (65): %d, numerical values stored in L and U\n', Info (65)) ;
+fprintf (' Info (66): %.2f, numeric factorization CPU time (seconds)\n', Info (66)) ;
+fprintf (' Info (76): %.2f, numeric factorization wall clock time (seconds)\n', Info (76)) ;
+if (Info (66) > 0.05 & Info (43) > 0)
+fprintf (' mflops in numeric factorization phase: %.2f\n', 1e-6 * Info (43) / Info (66)) ;
+end
+fprintf (' Info (67): %d, nnz (diag (U))\n', Info (67)) ;
+fprintf (' Info (68): %g, reciprocal condition number estimate\n', Info (68)) ;
+fprintf (' Info (69): %g, matrix was ', Info (69)) ;
+if (Info (69) == 0)
+ fprintf ('not scaled\n') ;
+elseif (Info (69) == 2)
+ fprintf ('scaled (row max)\n') ;
+else
+ fprintf ('scaled (row sum)\n') ;
+end
+fprintf (' Info (70): %g, min. scale factor of rows of A\n', Info (70)) ;
+fprintf (' Info (71): %g, max. scale factor of rows of A\n', Info (71)) ;
+fprintf (' Info (72): %g, min. abs. on diagonal of U\n', Info (72)) ;
+fprintf (' Info (73): %g, max. abs. on diagonal of U\n', Info (73)) ;
+fprintf (' Info (74): %g, initial allocation parameter used\n', Info (74)) ;
+fprintf (' Info (75): %g, # of forced updates due to frontal growth\n', Info (75)) ;
+fprintf (' Info (77): %d, # of off-diaogonal pivots\n', Info (77)) ;
+fprintf (' Info (78): %d, nnz (L), if no small entries dropped\n', Info (78)) ;
+fprintf (' Info (79): %d, nnz (U), if no small entries dropped\n', Info (79)) ;
+fprintf (' Info (80): %d, # of small entries dropped\n', Info (80)) ;
+
+fprintf ('\n Computed in the solve step:\n') ;
+fprintf (' Info (81): %d, iterative refinement steps taken\n', Info (81)) ;
+fprintf (' Info (82): %d, iterative refinement steps attempted\n', Info (82)) ;
+fprintf (' Info (83): %g, omega(1), sparse-backward error estimate\n', Info (83)) ;
+fprintf (' Info (84): %g, omega(2), sparse-backward error estimate\n', Info (84)) ;
+fprintf (' Info (85): %d, solve flop count\n', Info (85)) ;
+fprintf (' Info (86): %.2f, solve CPU time (seconds)\n', Info (86)) ;
+fprintf (' Info (87): %.2f, solve wall clock time (seconds)\n', Info (87)) ;
+
+fprintf ('\n Info (88:90): unused\n\n') ;
+
+%-------------------------------------------------------------------------------
+
+function prstrat (fmt, strategy)
+fprintf (fmt, strategy) ;
+if (strategy == 1)
+ fprintf ('(unsymmetric)\n') ;
+ fprintf (' Q = COLAMD (A), Q refined during numerical\n') ;
+ fprintf (' factorization, and no attempt at diagonal pivoting.\n') ;
+elseif (strategy == 2)
+ fprintf ('(symmetric, with 2-by-2 pivoting)\n') ;
+ fprintf (' P2 = row permutation to place large values on the diagonal\n') ;
+ fprintf (' Q = AMD (P2*A+(P2*A)''), Q not refined during numeric factorization,\n') ;
+ fprintf (' and diagonal pivoting attempted.\n') ;
+elseif (strategy == 3)
+ fprintf ('(symmetric)\n') ;
+ fprintf (' Q = AMD (A+A''), Q not refined during numeric factorization,\n') ;
+ fprintf (' and diagonal pivoting (P=Q'') attempted.\n') ;
+else
+ strategy = 0 ;
+ fprintf ('(auto)\n') ;
+end
+
+%-------------------------------------------------------------------------------
+
+function yes_no (s)
+if (s == 0)
+ fprintf ('(no)\n') ;
+else
+ fprintf ('(yes)\n') ;
+end
--- /dev/null
+% umfpack_simple: a simple demo of UMFPACK
+%
+% UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+% Davis. All Rights Reserved.
+%
+% UMFPACK License:
+%
+% Your use or distribution of UMFPACK or any modified version of
+% UMFPACK implies that you agree to this License.
+%
+% THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+% EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+%
+% Permission is hereby granted to use or copy this program, provided
+% that the Copyright, this License, and the Availability of the original
+% version is retained on all copies. User documentation of any code that
+% uses UMFPACK or any modified version of UMFPACK code must cite the
+% Copyright, this License, the Availability note, and "Used by permission."
+% Permission to modify the code and to distribute modified code is granted,
+% provided the Copyright, this License, and the Availability note are
+% retained, and a notice that the code was modified is included. This
+% software was developed with support from the National Science Foundation,
+% and is provided to you free of charge.
+%
+% Availability: http://www.cise.ufl.edu/research/sparse/umfpack
+%
+% See also: umfpack, umfpack_details
+
+help umfpack_simple
+i = input ('Hit enter to agree to the above License: ', 's') ;
+if (~isempty (i))
+ error ('terminating') ;
+end
+
+format short
+
+A = [
+ 2 3 0 0 0
+ 3 0 4 0 6
+ 0 -1 -3 2 0
+ 0 0 1 0 0
+ 0 4 2 0 1
+]
+
+A = sparse (A) ;
+
+b = [8 45 -3 3 19]'
+
+fprintf ('Solution to Ax=b via UMFPACK:\n') ;
+fprintf ('x1 = umfpack (A, ''\\'', b)\n') ;
+
+x1 = umfpack (A, '\', b)
+
+fprintf ('Solution to Ax=b via MATLAB:\n') ;
+fprintf ('x2 = A\\b\n') ;
+
+x2 = A\b
+
+fprintf ('norm (x1-x2) should be small: %g\n', norm (x1-x2)) ;
+
+fprintf ('Type ''umfpack_demo'' for a full demo of UMFPACK\n') ;
--- /dev/null
+>> umfpack_simple
+
+ umfpack_simple: a simple demo of UMFPACK
+
+ UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+ Davis. All Rights Reserved.
+
+ UMFPACK License:
+
+ Your use or distribution of UMFPACK or any modified version of
+ UMFPACK implies that you agree to this License.
+
+ THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+ EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+
+ Permission is hereby granted to use or copy this program, provided
+ that the Copyright, this License, and the Availability of the original
+ version is retained on all copies. User documentation of any code that
+ uses UMFPACK or any modified version of UMFPACK code must cite the
+ Copyright, this License, the Availability note, and "Used by permission."
+ Permission to modify the code and to distribute modified code is granted,
+ provided the Copyright, this License, and the Availability note are
+ retained, and a notice that the code was modified is included. This
+ software was developed with support from the National Science Foundation,
+ and is provided to you free of charge.
+
+ Availability: http://www.cise.ufl.edu/research/sparse/umfpack
+
+ See also: umfpack, umfpack_details
+
+Hit enter to agree to the above License:
+
+A =
+
+ 2 3 0 0 0
+ 3 0 4 0 6
+ 0 -1 -3 2 0
+ 0 0 1 0 0
+ 0 4 2 0 1
+
+
+b =
+
+ 8
+ 45
+ -3
+ 3
+ 19
+
+Solution to Ax=b via UMFPACK:
+x1 = umfpack (A, '\', b)
+
+x1 =
+
+ 1.0000
+ 2.0000
+ 3.0000
+ 4.0000
+ 5.0000
+
+Solution to Ax=b via MATLAB:
+x2 = A\b
+
+x2 =
+
+ 1.0000
+ 2.0000
+ 3.0000
+ 4.0000
+ 5.0000
+
+norm (x1-x2) should be small: 1.28037e-15
+Type 'umfpack_demo' for a full demo of UMFPACK
+>> diary off
--- /dev/null
+function x = umfpack_solve (arg1, op, arg2, Control)
+% UMFPACK_SOLVE
+%
+% x = umfpack_solve (A, '\', b, Control)
+% x = umfpack_solve (b, '/', A, Control)
+%
+% Computes x = A\b, or b/A, where A is square. Uses UMFPACK if A is sparse.
+% The Control argument is optional.
+%
+% See also umfpack, umfpack_make, umfpack_details, umfpack_report,
+% and umfpack_simple.
+
+% UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 by Timothy A.
+% Davis. All Rights Reserved. Type umfpack_details for License.
+
+%-------------------------------------------------------------------------------
+% check inputs and get default control parameters
+%-------------------------------------------------------------------------------
+
+if (op == '\')
+ A = arg1 ;
+ b = arg2 ;
+elseif (op == '/')
+ A = arg2 ;
+ b = arg1 ;
+else
+ help umfack_solve
+ error ('umfpack_solve: unrecognized operator') ;
+end
+
+[m n] = size (A) ;
+if (m ~= n)
+ help umfpack_solve
+ error ('umfpack_solve: A must be square') ;
+end
+
+[m1 n1] = size (b) ;
+if ((op == '\' & n ~= m1) | (op == '/' & n1 ~= m))
+ help umfpack_solve
+ error ('umfpack_solve: b has the wrong dimensions') ;
+end
+
+if (nargin < 4)
+ Control = umfpack ;
+end
+
+%-------------------------------------------------------------------------------
+% solve the system
+%-------------------------------------------------------------------------------
+
+if (op == '\')
+
+ if (~issparse (A))
+
+ % A is not sparse, so just use MATLAB
+ x = A\b ;
+
+ elseif (n1 == 1 & ~issparse (b))
+
+ % the UMFPACK '\' requires b to be a dense column vector
+ x = umfpack (A, '\', b, Control) ;
+
+ else
+
+ % factorize with UMFPACK and do the forward/back solves in MATLAB
+ [L, U, P, Q, R] = umfpack (A, Control) ;
+ x = Q * (U \ (L \ (P * (R \ b)))) ;
+
+ end
+
+else
+
+ if (~issparse (A))
+
+ % A is not sparse, so just use MATLAB
+ x = b/A ;
+
+ elseif (m1 == 1 & ~issparse (b))
+
+ % the UMFPACK '\' requires b to be a dense column vector
+ x = umfpack (b, '/', A, Control) ;
+
+ else
+
+ % factorize with UMFPACK and do the forward/back solves in MATLAB
+ % this mimics the behavior of x = b/A, except for the row scaling
+ [L, U, P, Q, R] = umfpack (A.', Control) ;
+ x = (Q * (U \ (L \ (P * (R \ (b.')))))).' ;
+
+ % an alternative method:
+ % [L, U, P, Q, r] = umfpack (A, Control) ;
+ % x = (R \ (P' * (L.' \ (U.' \ (Q' * b.'))))).' ;
+
+ end
+
+end
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK mexFunction ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+/* Minor revision, Aug 13, 2003 (version 4.1.1). Removed call to spparms. */
+/* -------------------------------------------------------------------------- */
+
+/*
+ MATLAB interface for umfpack.
+
+ Factor or solve a sparse linear system, returning either the solution
+ x to Ax=b or A'x'=b', or the factorization LU=P(R\A)Q or LU=PAQ. A must be
+ sparse, with nonzero dimensions, but it may be complex, singular, and/or
+ rectangular. b must be a dense n-by-1 vector (real or complex).
+ L is unit lower triangular, U is upper triangular, and R is diagonal.
+ P and Q are permutation matrices (permutations of an identity matrix).
+
+ This has changed since v4.0. The outputs P and Q are returned as
+ permutation matrices instead of permutation vectors, and the row scale
+ factor r is also returned. v4.0 did not scale the matrix.
+
+ The matrix A is scaled, by default. Each row i is divided by r (i), where
+ r (i) is the sum of the absolute values of the entries in that row. The
+ scaled matrix has an infinity norm of 1. The scale factors r (i) are
+ returned in a diagonal sparse matrix. If the factorization is:
+
+ [L, U, P, Q, R] = umfpack (A) ;
+
+ then the factorization is
+
+ L*U = P * (R \ A) * Q
+
+ This is safer than returning a matrix R such that L*U = P*R*A*Q, because
+ it avoids the division by small entries. If r(i) is subnormal, multiplying
+ by 1/r(i) would result in an IEEE Infinity, but dividing by r(i) is safe.
+
+ The factorization
+
+ [L, U, P, Q] = umfpack (A) ;
+
+ returns LU factors such that L*U = P*A*Q, with no scaling.
+
+ See umfpack.m and umfpack.h for details.
+
+ Note that this mexFunction accesses only the user-callable UMFPACK routines.
+ Thus, is also provides another example of how user C code can access
+ UMFPACK.
+
+ If NO_TRANSPOSE_FORWARD_SLASH is not defined at compile time, then the
+ forward slash (/) operator acts almost like x = b/A in MATLAB 6.1. It is
+ solved by factorizing the array transpose, and then x = (A.'\b.').' is
+ solved. This is the default behavior (for historical reasons), since
+ factorizing A can behave perform much differently than factorizing its
+ transpose.
+
+ If NO_TRANSPOSE_FORWARD_SLASH is defined at compile time, then the forward
+ slash operator does not act like x=b/A in MATLAB 6.1. It is solved by
+ factorizing A, and then solving via the transposed L and U matrices.
+ The solution is still x = (A.'\b.').', except that A is factorized instead
+ of A.'.
+*/
+
+#include "umfpack.h"
+#include "mex.h"
+#include "matrix.h"
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define STRING_MATCH(s1,s2) (strcmp ((s1), (s2)) == 0)
+#ifndef TRUE
+#define TRUE (1)
+#endif
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+/* ========================================================================== */
+/* === error ================================================================ */
+/* ========================================================================== */
+
+/* Return an error message */
+
+static void error
+(
+ char *s,
+ int A_is_complex,
+ int nargout,
+ mxArray *pargout [ ],
+ double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO],
+ int status,
+ int do_info
+)
+{
+ int i ;
+ double *OutInfo ;
+ if (A_is_complex)
+ {
+ umfpack_zi_report_status (Control, status) ;
+ umfpack_zi_report_info (Control, Info) ;
+ }
+ else
+ {
+ umfpack_di_report_status (Control, status) ;
+ umfpack_di_report_info (Control, Info) ;
+ }
+ if (do_info > 0)
+ {
+ /* return Info */
+ pargout [do_info] = mxCreateDoubleMatrix (1, UMFPACK_INFO, mxREAL) ;
+ OutInfo = mxGetPr (pargout [do_info]) ;
+ for (i = 0 ; i < UMFPACK_INFO ; i++)
+ {
+ OutInfo [i] = Info [i] ;
+ }
+ }
+ mexErrMsgTxt (s) ;
+}
+
+
+/* ========================================================================== */
+/* === UMFPACK ============================================================== */
+/* ========================================================================== */
+
+void mexFunction
+(
+ int nargout, /* number of outputs */
+ mxArray *pargout [ ], /* output arguments */
+ int nargin, /* number of inputs */
+ const mxArray *pargin [ ] /* input arguments */
+)
+{
+
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ void *Symbolic, *Numeric ;
+ int *Lp, *Li, *Up, *Ui, *Ap, *Ai, *P, *Q, do_solve, lnz, unz, nn, i,
+ transpose, size, do_info, do_numeric, *Front_npivcol, op, k, *Rp, *Ri,
+ *Front_parent, *Chain_start, *Chain_maxrows, *Chain_maxcols, nz, status,
+ nfronts, nchains, *Ltp, *Ltj, *Qinit, print_level, status2, no_scale,
+ *Front_1strow, *Front_leftmostdesc, n_row, n_col, n_inner, sys,
+ ignore1, ignore2, ignore3, A_is_complex, B_is_complex, X_is_complex,
+ *Pp, *Pi, *Qp, *Qi, do_recip ;
+ double *Lx, *Lz, *Ux, *Uz, *Ax, *Az, *Bx, *Bz, *Xx, *Xz, *User_Control,
+ *p, *q, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL], *OutInfo,
+ *p1, *p2, *p3, *p4, *Ltx, *Ltz, *Rs, *Px, *Qx ;
+ mxArray *Amatrix, *Bmatrix, *User_Control_matrix, *User_Qinit ;
+ char *operator, *operation ;
+ mxComplexity Atype, Xtype ;
+ char warning [200] ;
+
+#ifndef NO_TRANSPOSE_FORWARD_SLASH
+ int *Cp, *Ci ;
+ double *Cx, *Cz ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* get inputs A, b, and the operation to perform */
+ /* ---------------------------------------------------------------------- */
+
+ User_Control_matrix = (mxArray *) NULL ;
+ User_Qinit = (mxArray *) NULL ;
+
+ do_info = 0 ;
+ do_solve = FALSE ;
+ do_numeric = TRUE ;
+ transpose = FALSE ;
+ no_scale = FALSE ;
+
+ /* find the operator */
+ op = 0 ;
+ for (i = 0 ; i < nargin ; i++)
+ {
+ if (mxIsChar (pargin [i]))
+ {
+ op = i ;
+ break ;
+ }
+ }
+
+ if (op > 0)
+ {
+ operator = mxArrayToString (pargin [op]) ;
+
+ if (STRING_MATCH (operator, "\\"))
+ {
+
+ /* -------------------------------------------------------------- */
+ /* matrix left divide, x = A\b */
+ /* -------------------------------------------------------------- */
+
+ /*
+ [x, Info] = umfpack (A, '\', b) ;
+ [x, Info] = umfpack (A, '\', b, Control) ;
+ [x, Info] = umfpack (A, Qinit, '\', b, Control) ;
+ [x, Info] = umfpack (A, Qinit, '\', b) ;
+ */
+
+ operation = "x = A\\b" ;
+ do_solve = TRUE ;
+ Amatrix = (mxArray *) pargin [0] ;
+ Bmatrix = (mxArray *) pargin [op+1] ;
+
+ if (nargout == 2)
+ {
+ do_info = 1 ;
+ }
+ if (op == 2)
+ {
+ User_Qinit = (mxArray *) pargin [1] ;
+ }
+ if ((op == 1 && nargin == 4) || (op == 2 && nargin == 5))
+ {
+ User_Control_matrix = (mxArray *) pargin [nargin-1] ;
+ }
+ if (nargin < 3 || nargin > 5 || nargout > 2)
+ {
+ mexErrMsgTxt ("wrong number of arguments") ;
+ }
+
+ }
+ else if (STRING_MATCH (operator, "/"))
+ {
+
+ /* -------------------------------------------------------------- */
+ /* matrix right divide, x = b/A */
+ /* -------------------------------------------------------------- */
+
+ /*
+ [x, Info] = umfpack (b, '/', A) ;
+ [x, Info] = umfpack (b, '/', A, Control) ;
+ [x, Info] = umfpack (b, '/', A, Qinit) ;
+ [x, Info] = umfpack (b, '/', A, Qinit, Control) ;
+ */
+
+ operation = "x = b/A" ;
+ do_solve = TRUE ;
+ transpose = TRUE ;
+ Amatrix = (mxArray *) pargin [2] ;
+ Bmatrix = (mxArray *) pargin [0] ;
+
+ if (nargout == 2)
+ {
+ do_info = 1 ;
+ }
+ if (nargin == 5)
+ {
+ User_Qinit = (mxArray *) pargin [3] ;
+ User_Control_matrix = (mxArray *) pargin [4] ;
+ }
+ else if (nargin == 4)
+ {
+ /* Control is k-by-1 where k > 1, Qinit is 1-by-n */
+ if (mxGetM (pargin [3]) == 1)
+ {
+ User_Qinit = (mxArray *) pargin [3] ;
+ }
+ else
+ {
+ User_Control_matrix = (mxArray *) pargin [3] ;
+ }
+ }
+ else if (nargin < 3 || nargin > 5 || nargout > 2)
+ {
+ mexErrMsgTxt ("wrong number of arguments") ;
+ }
+
+ }
+ else if (STRING_MATCH (operator, "symbolic"))
+ {
+
+ /* -------------------------------------------------------------- */
+ /* symbolic factorization only */
+ /* -------------------------------------------------------------- */
+
+ /*
+ [P Q Fr Ch Info] = umfpack (A, 'symbolic') ;
+ [P Q Fr Ch Info] = umfpack (A, 'symbolic', Control) ;
+ [P Q Fr Ch Info] = umfpack (A, Qinit, 'symbolic') ;
+ [P Q Fr Ch Info] = umfpack (A, Qinit, 'symbolic', Control) ;
+ */
+
+ operation = "symbolic factorization" ;
+ do_numeric = FALSE ;
+ Amatrix = (mxArray *) pargin [0] ;
+
+ if (nargout == 5)
+ {
+ do_info = 4 ;
+ }
+ if (op == 2)
+ {
+ User_Qinit = (mxArray *) pargin [1] ;
+ }
+ if ((op == 1 && nargin == 3) || (op == 2 && nargin == 4))
+ {
+ User_Control_matrix = (mxArray *) pargin [nargin-1] ;
+ }
+ if (nargin < 2 || nargin > 4 || nargout > 5 || nargout < 4)
+ {
+ mexErrMsgTxt ("wrong number of arguments") ;
+ }
+
+ }
+ else
+ {
+ mexErrMsgTxt ("operator must be '/', '\\', or 'symbolic'") ;
+ }
+ mxFree (operator) ;
+
+ }
+ else if (nargin > 0)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* LU factorization */
+ /* ------------------------------------------------------------------ */
+
+ /*
+ with scaling:
+ [L, U, P, Q, R, Info] = umfpack (A) ;
+ [L, U, P, Q, R, Info] = umfpack (A, Qinit) ;
+
+ scaling determined by Control settings:
+ [L, U, P, Q, R, Info] = umfpack (A, Control) ;
+ [L, U, P, Q, R, Info] = umfpack (A, Qinit, Control) ;
+
+ with no scaling:
+ [L, U, P, Q] = umfpack (A) ;
+ [L, U, P, Q] = umfpack (A, Control) ;
+ [L, U, P, Q] = umfpack (A, Qinit) ;
+ [L, U, P, Q] = umfpack (A, Qinit, Control) ;
+ */
+
+ operation = "numeric factorization" ;
+ Amatrix = (mxArray *) pargin [0] ;
+
+ no_scale = nargout <= 4 ;
+
+ if (nargout == 6)
+ {
+ do_info = 5 ;
+ }
+ if (nargin == 3)
+ {
+ User_Qinit = (mxArray *) pargin [1] ;
+ User_Control_matrix = (mxArray *) pargin [2] ;
+ }
+ else if (nargin == 2)
+ {
+ /* Control is k-by-1 where k > 1, Qinit is 1-by-n */
+ if (mxGetM (pargin [1]) == 1)
+ {
+ User_Qinit = (mxArray *) pargin [1] ;
+ }
+ else
+ {
+ User_Control_matrix = (mxArray *) pargin [1] ;
+ }
+ }
+ else if (nargin > 3 || nargout > 6 || nargout < 4)
+ {
+ mexErrMsgTxt ("wrong number of arguments") ;
+ }
+
+ }
+ else
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* return default control settings */
+ /* ------------------------------------------------------------------ */
+
+ /*
+ Control = umfpack ;
+ umfpack ;
+ */
+
+ if (nargout > 1)
+ {
+ mexErrMsgTxt ("wrong number of arguments") ;
+ }
+
+ pargout [0] = mxCreateDoubleMatrix (UMFPACK_CONTROL, 1, mxREAL) ;
+ User_Control = mxGetPr (pargout [0]) ;
+ umfpack_di_defaults (User_Control) ;
+
+ return ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* check inputs */
+ /* ---------------------------------------------------------------------- */
+
+ if (mxGetNumberOfDimensions (Amatrix) != 2)
+ {
+ mexErrMsgTxt ("input matrix A must be 2-dimensional") ;
+ }
+ n_row = mxGetM (Amatrix) ;
+ n_col = mxGetN (Amatrix) ;
+ nn = MAX (n_row, n_col) ;
+ n_inner = MIN (n_row, n_col) ;
+ if (do_solve && n_row != n_col)
+ {
+ mexErrMsgTxt ("input matrix A must square for '\\' or '/'") ;
+ }
+ if (!mxIsSparse (Amatrix))
+ {
+ mexErrMsgTxt ("input matrix A must be sparse") ;
+ }
+ if (n_row == 0 || n_col == 0)
+ {
+ mexErrMsgTxt ("input matrix A cannot have zero rows or zero columns") ;
+ }
+
+ /* The real/complex status of A determines which version to use, */
+ /* (umfpack_di_* or umfpack_zi_*). */
+ A_is_complex = mxIsComplex (Amatrix) ;
+ Atype = A_is_complex ? mxCOMPLEX : mxREAL ;
+ Ap = mxGetJc (Amatrix) ;
+ Ai = mxGetIr (Amatrix) ;
+ Ax = mxGetPr (Amatrix) ;
+ Az = mxGetPi (Amatrix) ;
+
+ if (do_solve)
+ {
+
+ if (n_row != n_col)
+ {
+ mexErrMsgTxt ("A must be square for \\ or /") ;
+ }
+ if (transpose)
+ {
+ if (mxGetM (Bmatrix) != 1 || mxGetN (Bmatrix) != nn)
+ {
+ mexErrMsgTxt ("b has the wrong dimensions") ;
+ }
+ }
+ else
+ {
+ if (mxGetM (Bmatrix) != nn || mxGetN (Bmatrix) != 1)
+ {
+ mexErrMsgTxt ("b has the wrong dimensions") ;
+ }
+ }
+ if (mxGetNumberOfDimensions (Bmatrix) != 2)
+ {
+ mexErrMsgTxt ("input matrix b must be 2-dimensional") ;
+ }
+ if (mxIsSparse (Bmatrix))
+ {
+ mexErrMsgTxt ("input matrix b cannot be sparse") ;
+ }
+ if (mxGetClassID (Bmatrix) != mxDOUBLE_CLASS)
+ {
+ mexErrMsgTxt ("input matrix b must double precision matrix") ;
+ }
+
+ B_is_complex = mxIsComplex (Bmatrix) ;
+ Bx = mxGetPr (Bmatrix) ;
+ Bz = mxGetPi (Bmatrix) ;
+
+ X_is_complex = A_is_complex || B_is_complex ;
+ Xtype = X_is_complex ? mxCOMPLEX : mxREAL ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* set the Control parameters */
+ /* ---------------------------------------------------------------------- */
+
+ if (A_is_complex)
+ {
+ umfpack_zi_defaults (Control) ;
+ }
+ else
+ {
+ umfpack_di_defaults (Control) ;
+ }
+ if (User_Control_matrix)
+ {
+ if (mxGetClassID (User_Control_matrix) != mxDOUBLE_CLASS ||
+ mxIsSparse (User_Control_matrix))
+ {
+ mexErrMsgTxt ("Control must be a dense real matrix") ;
+ }
+ size = UMFPACK_CONTROL ;
+ size = MIN (size, mxGetNumberOfElements (User_Control_matrix)) ;
+ User_Control = mxGetPr (User_Control_matrix) ;
+ for (i = 0 ; i < size ; i++)
+ {
+ Control [i] = User_Control [i] ;
+ }
+ }
+
+ if (no_scale)
+ {
+ /* turn off scaling for [L, U, P, Q] = umfpack (A) ;
+ * ignoring the input value of Control (24) for the usage
+ * [L, U, P, Q] = umfpack (A, Control) ; */
+ Control [UMFPACK_SCALE] = UMFPACK_SCALE_NONE ;
+ }
+
+ if (mxIsNaN (Control [UMFPACK_PRL]))
+ {
+ print_level = UMFPACK_DEFAULT_PRL ;
+ }
+ else
+ {
+ print_level = (int) Control [UMFPACK_PRL] ;
+ }
+
+ Control [UMFPACK_PRL] = print_level ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get Qinit, if present */
+ /* ---------------------------------------------------------------------- */
+
+ if (User_Qinit)
+ {
+ if (mxGetM (User_Qinit) != 1 || mxGetN (User_Qinit) != n_col)
+ {
+ mexErrMsgTxt ("Qinit must be 1-by-n_col") ;
+ }
+ if (mxGetNumberOfDimensions (User_Qinit) != 2)
+ {
+ mexErrMsgTxt ("input Qinit must be 2-dimensional") ;
+ }
+ if (mxIsComplex (User_Qinit))
+ {
+ mexErrMsgTxt ("input Qinit must not be complex") ;
+ }
+ if (mxGetClassID (User_Qinit) != mxDOUBLE_CLASS)
+ {
+ mexErrMsgTxt ("input Qinit must be a double matrix") ;
+ }
+ if (mxIsSparse (User_Qinit))
+ {
+ mexErrMsgTxt ("input Qinit must be dense") ;
+ }
+ Qinit = (int *) mxMalloc (n_col * sizeof (int)) ;
+ p = mxGetPr (User_Qinit) ;
+ for (k = 0 ; k < n_col ; k++)
+ {
+ /* convert from 1-based to 0-based indexing */
+ Qinit [k] = ((int) (p [k])) - 1 ;
+ }
+
+ }
+ else
+ {
+ /* umfpack_*_qsymbolic will call colamd to get Qinit. This is the */
+ /* same as calling umfpack_*_symbolic with Qinit set to NULL*/
+ Qinit = (int *) NULL ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* report the inputs A and Qinit */
+ /* ---------------------------------------------------------------------- */
+
+ if (print_level >= 2)
+ {
+ /* print the operation */
+ mexPrintf ("\numfpack: %s\n", operation) ;
+ }
+
+ if (A_is_complex)
+ {
+ umfpack_zi_report_control (Control) ;
+ if (print_level >= 3) mexPrintf ("\nA: ") ;
+ (void) umfpack_zi_report_matrix (n_row, n_col, Ap, Ai, Ax, Az,
+ 1, Control) ;
+ if (Qinit)
+ {
+ if (print_level >= 3) mexPrintf ("\nQinit: ") ;
+ (void) umfpack_zi_report_perm (n_col, Qinit, Control) ;
+ }
+ }
+ else
+ {
+ umfpack_di_report_control (Control) ;
+ if (print_level >= 3) mexPrintf ("\nA: ") ;
+ (void) umfpack_di_report_matrix (n_row, n_col, Ap, Ai, Ax,
+ 1, Control) ;
+ if (Qinit)
+ {
+ if (print_level >= 3) mexPrintf ("\nQinit: ") ;
+ (void) umfpack_di_report_perm (n_col, Qinit, Control) ;
+ }
+ }
+
+#ifndef NO_TRANSPOSE_FORWARD_SLASH
+ /* ---------------------------------------------------------------------- */
+ /* create the array transpose for x = b/A */
+ /* ---------------------------------------------------------------------- */
+
+ if (transpose)
+ {
+ /* note that in this case A will be square (nn = n_row = n_col) */
+ /* x = (A.'\b.').' will be computed */
+
+ /* make sure Ci and Cx exist, avoid malloc of zero-sized arrays. */
+ nz = MAX (Ap [nn], 1) ;
+
+ Cp = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
+ Ci = (int *) mxMalloc (nz * sizeof (int)) ;
+ Cx = (double *) mxMalloc (nz * sizeof (double)) ;
+ if (A_is_complex)
+ {
+ Cz = (double *) mxMalloc (nz * sizeof (double)) ;
+ status = umfpack_zi_transpose (nn, nn, Ap, Ai, Ax, Az,
+ (int *) NULL, (int *) NULL, Cp, Ci, Cx, Cz, FALSE) ;
+ }
+ else
+ {
+ status = umfpack_di_transpose (nn, nn, Ap, Ai, Ax,
+ (int *) NULL, (int *) NULL, Cp, Ci, Cx) ;
+ }
+
+ if (status != UMFPACK_OK)
+ {
+ error ("transpose of A failed", A_is_complex, nargout, pargout,
+ Control, Info, status, do_info);
+ return ;
+ }
+
+ /* modify pointers so that C will be factorized and solved, not A */
+ Ap = Cp ;
+ Ai = Ci ;
+ Ax = Cx ;
+ if (A_is_complex)
+ {
+ Az = Cz ;
+ }
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* perform the symbolic factorization */
+ /* ---------------------------------------------------------------------- */
+
+ if (A_is_complex)
+ {
+ status = umfpack_zi_qsymbolic (n_row, n_col, Ap, Ai, Ax, Az,
+ Qinit, &Symbolic, Control, Info) ;
+ }
+ else
+ {
+ status = umfpack_di_qsymbolic (n_row, n_col, Ap, Ai, Ax,
+ Qinit, &Symbolic, Control, Info) ;
+ }
+
+ if (Qinit)
+ {
+ mxFree (Qinit) ;
+ }
+
+ if (status < 0)
+ {
+ error ("symbolic factorization failed", A_is_complex, nargout, pargout,
+ Control, Info, status, do_info) ;
+ return ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* report the Symbolic object */
+ /* ---------------------------------------------------------------------- */
+
+ if (A_is_complex)
+ {
+ (void) umfpack_zi_report_symbolic (Symbolic, Control) ;
+ }
+ else
+ {
+ (void) umfpack_di_report_symbolic (Symbolic, Control) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* perform numeric factorization, or just return symbolic factorization */
+ /* ---------------------------------------------------------------------- */
+
+ if (do_numeric)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* perform the numeric factorization */
+ /* ------------------------------------------------------------------ */
+
+ if (A_is_complex)
+ {
+ status = umfpack_zi_numeric (Ap, Ai, Ax, Az, Symbolic, &Numeric,
+ Control, Info) ;
+ }
+ else
+ {
+ status = umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric,
+ Control, Info) ;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* free the symbolic factorization */
+ /* ------------------------------------------------------------------ */
+
+ if (A_is_complex)
+ {
+ umfpack_zi_free_symbolic (&Symbolic) ;
+ }
+ else
+ {
+ umfpack_di_free_symbolic (&Symbolic) ;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* report the Numeric object */
+ /* ------------------------------------------------------------------ */
+
+ if (status < 0)
+ {
+ error ("numeric factorization failed", A_is_complex, nargout,
+ pargout, Control, Info, status, do_info);
+ return ;
+ }
+
+ if (A_is_complex)
+ {
+ (void) umfpack_zi_report_numeric (Numeric, Control) ;
+ }
+ else
+ {
+ (void) umfpack_di_report_numeric (Numeric, Control) ;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* return the solution or the factorization */
+ /* ------------------------------------------------------------------ */
+
+ if (do_solve)
+ {
+ /* -------------------------------------------------------------- */
+ /* solve Ax=b or A'x'=b', and return just the solution x */
+ /* -------------------------------------------------------------- */
+
+#ifndef NO_TRANSPOSE_FORWARD_SLASH
+ if (transpose)
+ {
+ /* A.'x.'=b.' gives the same x=b/A as solving A'x'=b' */
+ /* since C=A.' was factorized, solve with sys = UMFPACK_A */
+ /* since x and b are vectors, x.' and b.' are implicit */
+ pargout [0] = mxCreateDoubleMatrix (1, nn, Xtype) ;
+ }
+ else
+ {
+ pargout [0] = mxCreateDoubleMatrix (nn, 1, Xtype) ;
+ }
+ sys = UMFPACK_A ;
+#else
+ if (transpose)
+ {
+ /* If A is real, A'x=b is the same as A.'x=b. */
+ /* x and b are vectors, so x and b are the same as x' and b'. */
+ /* If A is complex, then A.'x.'=b.' gives the same solution x */
+ /* as the complex conjugate transpose. If we used the A'x=b */
+ /* option in umfpack_*_solve, we would have to form b' on */
+ /* input and x' on output (negating the imaginary part). */
+ /* We can save this work by just using the A.'x=b option in */
+ /* umfpack_*_solve. Then, forming x.' and b.' is implicit, */
+ /* since x and b are just vectors anyway. */
+ /* In both cases, the system to solve is A.'x=b */
+ pargout [0] = mxCreateDoubleMatrix (1, nn, Xtype) ;
+ sys = UMFPACK_Aat ;
+ }
+ else
+ {
+ pargout [0] = mxCreateDoubleMatrix (nn, 1, Xtype) ;
+ sys = UMFPACK_A ;
+ }
+#endif
+
+ /* -------------------------------------------------------------- */
+ /* print the right-hand-side, B */
+ /* -------------------------------------------------------------- */
+
+ if (print_level >= 3) mexPrintf ("\nright-hand side, b: ") ;
+ if (B_is_complex)
+ {
+ (void) umfpack_zi_report_vector (nn, Bx, Bz, Control) ;
+ }
+ else
+ {
+ (void) umfpack_di_report_vector (nn, Bx, Control) ;
+ }
+
+ /* -------------------------------------------------------------- */
+ /* solve the system */
+ /* -------------------------------------------------------------- */
+
+ Xx = mxGetPr (pargout [0]) ;
+ Xz = mxGetPi (pargout [0]) ;
+ status2 = UMFPACK_OK ;
+
+ if (A_is_complex)
+ {
+ if (!B_is_complex)
+ {
+ /* umfpack_zi_solve expects a complex B */
+ Bz = (double *) mxCalloc (nn, sizeof (double)) ;
+ }
+ status = umfpack_zi_solve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz,
+ Numeric, Control, Info) ;
+ if (!B_is_complex)
+ {
+ mxFree (Bz) ;
+ }
+ }
+ else
+ {
+ if (B_is_complex)
+ {
+ /* Ax=b when b is complex and A is sparse can be split */
+ /* into two systems, A*xr=br and A*xi=bi, where r denotes */
+ /* the real part and i the imaginary part of x and b. */
+ status2 = umfpack_di_solve (sys, Ap, Ai, Ax, Xz, Bz,
+ Numeric, Control, Info) ;
+ }
+ status = umfpack_di_solve (sys, Ap, Ai, Ax, Xx, Bx,
+ Numeric, Control, Info) ;
+ }
+
+#ifndef NO_TRANSPOSE_FORWARD_SLASH
+ /* -------------------------------------------------------------- */
+ /* free the transposed matrix C */
+ /* -------------------------------------------------------------- */
+
+ if (transpose)
+ {
+ mxFree (Cp) ;
+ mxFree (Ci) ;
+ mxFree (Cx) ;
+ if (A_is_complex)
+ {
+ mxFree (Cz) ;
+ }
+ }
+#endif
+
+ /* -------------------------------------------------------------- */
+ /* free the Numeric object */
+ /* -------------------------------------------------------------- */
+
+ if (A_is_complex)
+ {
+ umfpack_zi_free_numeric (&Numeric) ;
+ }
+ else
+ {
+ umfpack_di_free_numeric (&Numeric) ;
+ }
+
+ /* -------------------------------------------------------------- */
+ /* check error status */
+ /* -------------------------------------------------------------- */
+
+ if (status < 0 || status2 < 0)
+ {
+ mxDestroyArray (pargout [0]) ;
+ error ("solve failed", A_is_complex, nargout, pargout, Control,
+ Info, status, do_info) ;
+ return ;
+ }
+
+ /* -------------------------------------------------------------- */
+ /* print the solution, X */
+ /* -------------------------------------------------------------- */
+
+ if (print_level >= 3) mexPrintf ("\nsolution, x: ") ;
+ if (X_is_complex)
+ {
+ (void) umfpack_zi_report_vector (nn, Xx, Xz, Control) ;
+ }
+ else
+ {
+ (void) umfpack_di_report_vector (nn, Xx, Control) ;
+ }
+
+ /* -------------------------------------------------------------- */
+ /* warn about singular or near-singular matrices */
+ /* -------------------------------------------------------------- */
+
+ /* no warning is given if Control (1) is zero */
+
+ if (Control [UMFPACK_PRL] >= 1)
+ {
+ if (status == UMFPACK_WARNING_singular_matrix)
+ {
+ sprintf (warning, "matrix is singular\n"
+ "Try increasing Control (%d) and Control (%d).\n"
+ "(Suppress this warning with Control (%d) = 0.)\n",
+ 1+UMFPACK_PIVOT_TOLERANCE,
+ 1+UMFPACK_SYM_PIVOT_TOLERANCE,
+ 1+UMFPACK_PRL) ;
+ mexWarnMsgTxt (warning) ;
+ }
+ else if (Info [UMFPACK_RCOND] < DBL_EPSILON)
+ {
+ sprintf (warning, "matrix is nearly singular, rcond = %g\n"
+ "Try increasing Control (%d) and Control (%d).\n"
+ "(Suppress this warning with Control (%d) = 0.)\n",
+ Info [UMFPACK_RCOND],
+ 1+UMFPACK_PIVOT_TOLERANCE,
+ 1+UMFPACK_SYM_PIVOT_TOLERANCE,
+ 1+UMFPACK_PRL) ;
+ mexWarnMsgTxt (warning) ;
+ }
+ }
+
+ }
+ else
+ {
+
+ /* -------------------------------------------------------------- */
+ /* get L, U, P, Q, and r */
+ /* -------------------------------------------------------------- */
+
+ if (A_is_complex)
+ {
+ status = umfpack_zi_get_lunz (&lnz, &unz, &ignore1, &ignore2,
+ &ignore3, Numeric) ;
+ }
+ else
+ {
+ status = umfpack_di_get_lunz (&lnz, &unz, &ignore1, &ignore2,
+ &ignore3, Numeric) ;
+ }
+
+ if (status < 0)
+ {
+ if (A_is_complex)
+ {
+ umfpack_zi_free_numeric (&Numeric) ;
+ }
+ else
+ {
+ umfpack_di_free_numeric (&Numeric) ;
+ }
+ error ("extracting LU factors failed", A_is_complex, nargout,
+ pargout, Control, Info, status, do_info) ;
+ return ;
+ }
+
+ /* avoid malloc of zero-sized arrays */
+ lnz = MAX (lnz, 1) ;
+ unz = MAX (unz, 1) ;
+
+ /* get temporary space, for the *** ROW *** form of L */
+ Ltp = (int *) mxMalloc ((n_row+1) * sizeof (int)) ;
+ Ltj = (int *) mxMalloc (lnz * sizeof (int)) ;
+ Ltx = (double *) mxMalloc (lnz * sizeof (double)) ;
+ if (A_is_complex)
+ {
+ Ltz = (double *) mxMalloc (lnz * sizeof (double)) ;
+ }
+ else
+ {
+ Ltz = (double *) NULL ;
+ }
+
+ /* create permanent copy of the output matrix U */
+ pargout [1] = mxCreateSparse (n_inner, n_col, unz, Atype) ;
+ Up = mxGetJc (pargout [1]) ;
+ Ui = mxGetIr (pargout [1]) ;
+ Ux = mxGetPr (pargout [1]) ;
+ Uz = mxGetPi (pargout [1]) ;
+
+ /* temporary space for the integer permutation vectors */
+ P = (int *) mxMalloc (n_row * sizeof (int)) ;
+ Q = (int *) mxMalloc (n_col * sizeof (int)) ;
+
+ /* get scale factors, if requested */
+ status2 = UMFPACK_OK ;
+ if (!no_scale)
+ {
+ /* create a diagonal sparse matrix for the scale factors */
+ pargout [4] = mxCreateSparse (n_row, n_row, n_row, mxREAL) ;
+ Rp = mxGetJc (pargout [4]) ;
+ Ri = mxGetIr (pargout [4]) ;
+ for (i = 0 ; i < n_row ; i++)
+ {
+ Rp [i] = i ;
+ Ri [i] = i ;
+ }
+ Rp [n_row] = n_row ;
+ Rs = mxGetPr (pargout [4]) ;
+ }
+ else
+ {
+ Rs = (double *) NULL ;
+ }
+
+ /* get Lt, U, P, Q, and Rs from the numeric object */
+ if (A_is_complex)
+ {
+ status = umfpack_zi_get_numeric (Ltp, Ltj, Ltx, Ltz, Up, Ui, Ux,
+ Uz, P, Q, (double *) NULL, (double *) NULL,
+ &do_recip, Rs, Numeric) ;
+ umfpack_zi_free_numeric (&Numeric) ;
+ }
+ else
+ {
+ status = umfpack_di_get_numeric (Ltp, Ltj, Ltx, Up, Ui,
+ Ux, P, Q, (double *) NULL,
+ &do_recip, Rs, Numeric) ;
+ umfpack_di_free_numeric (&Numeric) ;
+ }
+
+ /* for the mexFunction, -DNRECIPROCAL must be set,
+ * so do_recip must be FALSE */
+
+ if (status < 0 || status2 < 0 || do_recip)
+ {
+ mxFree (Ltp) ;
+ mxFree (Ltj) ;
+ mxFree (Ltx) ;
+ if (Ltz) mxFree (Ltz) ;
+ mxFree (P) ;
+ mxFree (Q) ;
+ mxDestroyArray (pargout [1]) ;
+ error ("extracting LU factors failed", A_is_complex, nargout,
+ pargout, Control, Info, status, do_info) ;
+ return ;
+ }
+
+ /* create sparse permutation matrix for P */
+ pargout [2] = mxCreateSparse (n_row, n_row, n_row, mxREAL) ;
+ Pp = mxGetJc (pargout [2]) ;
+ Pi = mxGetIr (pargout [2]) ;
+ Px = mxGetPr (pargout [2]) ;
+ for (k = 0 ; k < n_row ; k++)
+ {
+ Pp [k] = k ;
+ Px [k] = 1 ;
+ Pi [P [k]] = k ;
+ }
+ Pp [n_row] = n_row ;
+
+ /* create sparse permutation matrix for Q */
+ pargout [3] = mxCreateSparse (n_col, n_col, n_col, mxREAL) ;
+ Qp = mxGetJc (pargout [3]) ;
+ Qi = mxGetIr (pargout [3]) ;
+ Qx = mxGetPr (pargout [3]) ;
+ for (k = 0 ; k < n_col ; k++)
+ {
+ Qp [k] = k ;
+ Qx [k] = 1 ;
+ Qi [k] = Q [k] ;
+ }
+ Qp [n_col] = n_col ;
+
+ /* permanent copy of L */
+ pargout [0] = mxCreateSparse (n_row, n_inner, lnz, Atype) ;
+ Lp = mxGetJc (pargout [0]) ;
+ Li = mxGetIr (pargout [0]) ;
+ Lx = mxGetPr (pargout [0]) ;
+ Lz = mxGetPi (pargout [0]) ;
+
+ /* convert L from row form to column form */
+ if (A_is_complex)
+ {
+ /* non-conjugate array transpose */
+ status = umfpack_zi_transpose (n_inner, n_row, Ltp, Ltj, Ltx,
+ Ltz, (int *) NULL, (int *) NULL, Lp, Li, Lx, Lz, FALSE) ;
+ }
+ else
+ {
+ status = umfpack_di_transpose (n_inner, n_row, Ltp, Ltj, Ltx,
+ (int *) NULL, (int *) NULL, Lp, Li, Lx) ;
+ }
+
+ mxFree (Ltp) ;
+ mxFree (Ltj) ;
+ mxFree (Ltx) ;
+ if (Ltz) mxFree (Ltz) ;
+
+ if (status < 0)
+ {
+ mxFree (P) ;
+ mxFree (Q) ;
+ mxDestroyArray (pargout [0]) ;
+ mxDestroyArray (pargout [1]) ;
+ mxDestroyArray (pargout [2]) ;
+ mxDestroyArray (pargout [3]) ;
+ error ("constructing L failed", A_is_complex, nargout, pargout,
+ Control, Info, status, do_info) ;
+ return ;
+ }
+
+ /* -------------------------------------------------------------- */
+ /* print L, U, P, and Q */
+ /* -------------------------------------------------------------- */
+
+ if (A_is_complex)
+ {
+ if (print_level >= 3) mexPrintf ("\nL: ") ;
+ (void) umfpack_zi_report_matrix (n_row, n_inner, Lp, Li,
+ Lx, Lz, 1, Control) ;
+ if (print_level >= 3) mexPrintf ("\nU: ") ;
+ (void) umfpack_zi_report_matrix (n_inner, n_col, Up, Ui,
+ Ux, Uz, 1, Control) ;
+ if (print_level >= 3) mexPrintf ("\nP: ") ;
+ (void) umfpack_zi_report_perm (n_row, P, Control) ;
+ if (print_level >= 3) mexPrintf ("\nQ: ") ;
+ (void) umfpack_zi_report_perm (n_col, Q, Control) ;
+ }
+ else
+ {
+ if (print_level >= 3) mexPrintf ("\nL: ") ;
+ (void) umfpack_di_report_matrix (n_row, n_inner, Lp, Li,
+ Lx, 1, Control) ;
+ if (print_level >= 3) mexPrintf ("\nU: ") ;
+ (void) umfpack_di_report_matrix (n_inner, n_col, Up, Ui,
+ Ux, 1, Control) ;
+ if (print_level >= 3) mexPrintf ("\nP: ") ;
+ (void) umfpack_di_report_perm (n_row, P, Control) ;
+ if (print_level >= 3) mexPrintf ("\nQ: ") ;
+ (void) umfpack_di_report_perm (n_col, Q, Control) ;
+ }
+
+ mxFree (P) ;
+ mxFree (Q) ;
+
+ }
+
+ }
+ else
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* return the symbolic factorization */
+ /* ------------------------------------------------------------------ */
+
+ Q = (int *) mxMalloc (n_col * sizeof (int)) ;
+ P = (int *) mxMalloc (n_row * sizeof (int)) ;
+ Front_npivcol = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
+ Front_parent = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
+ Front_1strow = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
+ Front_leftmostdesc = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
+ Chain_start = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
+ Chain_maxrows = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
+ Chain_maxcols = (int *) mxMalloc ((nn+1) * sizeof (int)) ;
+
+ if (A_is_complex)
+ {
+ status = umfpack_zi_get_symbolic (&ignore1, &ignore2, &ignore3,
+ &nz, &nfronts, &nchains, P, Q, Front_npivcol,
+ Front_parent, Front_1strow, Front_leftmostdesc,
+ Chain_start, Chain_maxrows, Chain_maxcols, Symbolic) ;
+ umfpack_zi_free_symbolic (&Symbolic) ;
+ }
+ else
+ {
+ status = umfpack_di_get_symbolic (&ignore1, &ignore2, &ignore3,
+ &nz, &nfronts, &nchains, P, Q, Front_npivcol,
+ Front_parent, Front_1strow, Front_leftmostdesc,
+ Chain_start, Chain_maxrows, Chain_maxcols, Symbolic) ;
+ umfpack_di_free_symbolic (&Symbolic) ;
+ }
+
+ if (status < 0)
+ {
+ mxFree (P) ;
+ mxFree (Q) ;
+ mxFree (Front_npivcol) ;
+ mxFree (Front_parent) ;
+ mxFree (Front_1strow) ;
+ mxFree (Front_leftmostdesc) ;
+ mxFree (Chain_start) ;
+ mxFree (Chain_maxrows) ;
+ mxFree (Chain_maxcols) ;
+ error ("extracting symbolic factors failed", A_is_complex, nargout,
+ pargout, Control, Info, status, do_info) ;
+ return ;
+ }
+
+ /* create sparse permutation matrix for P */
+ pargout [0] = mxCreateSparse (n_row, n_row, n_row, mxREAL) ;
+ Pp = mxGetJc (pargout [0]) ;
+ Pi = mxGetIr (pargout [0]) ;
+ Px = mxGetPr (pargout [0]) ;
+ for (k = 0 ; k < n_row ; k++)
+ {
+ Pp [k] = k ;
+ Px [k] = 1 ;
+ Pi [P [k]] = k ;
+ }
+ Pp [n_row] = n_row ;
+
+ /* create sparse permutation matrix for Q */
+ pargout [1] = mxCreateSparse (n_col, n_col, n_col, mxREAL) ;
+ Qp = mxGetJc (pargout [1]) ;
+ Qi = mxGetIr (pargout [1]) ;
+ Qx = mxGetPr (pargout [1]) ;
+ for (k = 0 ; k < n_col ; k++)
+ {
+ Qp [k] = k ;
+ Qx [k] = 1 ;
+ Qi [k] = Q [k] ;
+ }
+ Qp [n_col] = n_col ;
+
+ /* create Fr */
+ pargout [2] = mxCreateDoubleMatrix (nfronts+1, 4, mxREAL) ;
+
+ p1 = mxGetPr (pargout [2]) ;
+ p2 = p1 + nfronts + 1 ;
+ p3 = p2 + nfronts + 1 ;
+ p4 = p3 + nfronts + 1 ;
+ for (i = 0 ; i <= nfronts ; i++)
+ {
+ /* convert parent, 1strow, and leftmostdesc to 1-based */
+ p1 [i] = (double) (Front_npivcol [i]) ;
+ p2 [i] = (double) (Front_parent [i] + 1) ;
+ p3 [i] = (double) (Front_1strow [i] + 1) ;
+ p4 [i] = (double) (Front_leftmostdesc [i] + 1) ;
+ }
+
+ /* create Ch */
+ pargout [3] = mxCreateDoubleMatrix (nchains+1, 3, mxREAL) ;
+ p1 = mxGetPr (pargout [3]) ;
+ p2 = p1 + nchains + 1 ;
+ p3 = p2 + nchains + 1 ;
+ for (i = 0 ; i < nchains ; i++)
+ {
+ p1 [i] = (double) (Chain_start [i] + 1) ; /* convert to 1-based */
+ p2 [i] = (double) (Chain_maxrows [i]) ;
+ p3 [i] = (double) (Chain_maxcols [i]) ;
+ }
+ p1 [nchains] = Chain_start [nchains] + 1 ;
+ p2 [nchains] = 0 ;
+ p3 [nchains] = 0 ;
+
+ mxFree (P) ;
+ mxFree (Q) ;
+ mxFree (Front_npivcol) ;
+ mxFree (Front_parent) ;
+ mxFree (Front_1strow) ;
+ mxFree (Front_leftmostdesc) ;
+ mxFree (Chain_start) ;
+ mxFree (Chain_maxrows) ;
+ mxFree (Chain_maxcols) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* report Info */
+ /* ---------------------------------------------------------------------- */
+
+ if (A_is_complex)
+ {
+ umfpack_zi_report_info (Control, Info) ;
+ }
+ else
+ {
+ umfpack_di_report_info (Control, Info) ;
+ }
+
+ if (do_info > 0)
+ {
+ /* return Info */
+ pargout [do_info] = mxCreateDoubleMatrix (1, UMFPACK_INFO, mxREAL) ;
+ OutInfo = mxGetPr (pargout [do_info]) ;
+ for (i = 0 ; i < UMFPACK_INFO ; i++)
+ {
+ OutInfo [i] = Info [i] ;
+ }
+ }
+}
--- /dev/null
+UMFPACK Version 4.3: a set of routines solving sparse linear systems via LU
+ factorization. Requires two other packages: the BLAS (dense matrix
+ operations) and AMD (sparse matrix minimum degree ordering). Includes
+ a C-callable and MATLAB interface, and a basic FORTRAN 77 interface to
+ a subset of the C-callable routines.
+
+Quick start (Unix, or Windows with Cygwin):
+
+ To compile, test, and install both UMFPACK and AMD, the UMFPACK and AMD
+ directories must be in the same parent directory. To configure, edit
+ UMFPACK/Make/Make.include and AMD/Make/Make.include (otherwise the BLAS
+ will not be used, and UMFPACK will be slow). cd to this directory (UMFPACK)
+ and type "make" (or "make lib" if you do not have MATLAB). To compile and
+ run a demo program for Harwell/Boeing matrices, type "make hb". To compile
+ a FORTRAN main program that calls the 32-bit C-callable UMFPACK library,
+ type "make fortran". When done, type "make clean" to remove unused *.o
+ files (keeps the compiled libraries and demo programs). See the User Guide
+ (Doc/UserGuide.pdf), or UMFPACK/Make/Make.include, for more details
+ (including options for compiling 64-bit mode).
+
+Quick start (for MATLAB users):
+
+ To compile, test, and install the UMFPACK mexFunction, cd to the
+ UMFPACK/MATLAB directory and type umfpack_make at the MATLAB prompt.
+ This works on any system supported by MATLAB.
+
+--------------------------------------------------------------------------------
+
+UMFPACK Version 4.3 (Jan. 16, 2003), Copyright (c) 2003 by Timothy A.
+Davis. All Rights Reserved.
+
+UMFPACK License:
+
+ Your use or distribution of UMFPACK or any modified version of
+ UMFPACK implies that you agree to this License.
+
+ THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+ EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+
+ Permission is hereby granted to use or copy this program, provided
+ that the Copyright, this License, and the Availability of the original
+ version is retained on all copies. User documentation of any code that
+ uses UMFPACK or any modified version of UMFPACK code must cite the
+ Copyright, this License, the Availability note, and "Used by permission."
+ Permission to modify the code and to distribute modified code is granted,
+ provided the Copyright, this License, and the Availability note are
+ retained, and a notice that the code was modified is included. This
+ software was developed with support from the National Science Foundation,
+ and is provided to you free of charge.
+
+Availability:
+
+ http://www.cise.ufl.edu/research/sparse/umfpack
+
+ UMFPACK (including versions 2.2.1 and earlier, in Fortran) is available at
+ http://www.cise.ufl.edu/research/sparse. MA38 is available in the Harwell
+ Subroutine Library. This version of UMFPACK includes a modified form of
+ COLAMD Version 2.0, originally released on Jan. 31, 2000, also available at
+ http://www.cise.ufl.edu/research/sparse. COLAMD V2.0 is also incorporated
+ as a built-in function in MATLAB version 6.1, by The MathWorks, Inc.
+ (http://www.mathworks.com). COLAMD V1.0 appears as a column-preordering
+ in SuperLU (SuperLU is available at http://www.netlib.org).
+ UMFPACK v4.0 is a built-in routine in MATLAB 6.5.
+
+--------------------------------------------------------------------------------
+
+Refer to ../AMD/README for the License for AMD, which is a separate
+package for ordering sparse matrices that is required by UMFPACK.
+UMFPACK v4.3 can use either AMD v1.0 or v1.1.
+
+--------------------------------------------------------------------------------
+
+This is the UMFPACK README file. It is a terse overview of UMFPACK.
+Refer to the User Guide (Doc/UserGuide.pdf) for how to install and use UMFPACK,
+or to the Quick Start Guide, QuickStart.pdf.
+
+Description:
+
+ UMFPACK is a set of routines for solving unsymmetric sparse linear systems,
+ Ax=b, using the Unsymmetric MultiFrontal method. Written in ANSI/ISO C,
+ with a MATLAB (Version 6.0 or later) interface.
+
+ For best performance, UMFPACK requires an optimized BLAS library. It can
+ also be compiled without any BLAS at all. UMFPACK requires AMD Version 1.0
+ or Version 1.1
+
+Authors:
+
+ Timothy A. Davis (davis@cise.ufl.edu), University of Florida.
+
+ Includes a modified version of COLAMD V2.0, by Stefan I. Larimore and
+ Timothy A. Davis, University of Florida. The COLAMD algorithm was developed
+ in collaboration with John Gilbert, Xerox Palo Alto Research Center, and
+ Esmond Ng, Lawrence Berkeley National Laboratory.
+
+ Includes AMD, by Timothy A. Davis, Patrick R. Amestoy, and Iain S. Duff.
+
+ UMFPACK Version 2.2.1 (MA38 in the Harwell Subroutine Library) is
+ co-authored with Iain S. Duff, Rutherford Appleton Laboratory.
+
+Acknowledgements:
+
+ This work was supported by the National Science Foundation, under
+ grants DMS-9504974, DMS-9803599, and CCR-0203270.
+
+ Portions of this work were done while on sabbatical at Stanford University
+ and Lawrence Berkeley National Laboratory (with funding from the SciDAC
+ program). I would like to thank Gene Golub, Esmond Ng, and Horst Simon
+ for making this sabbatical possible.
+
+ I would also like to thank the many researchers who provided sparse
+ matrices from a wide range of domains and used earlier versions of UMFPACK/
+ MA38 in their applications, and thus assisted in the practical development
+ of the algorithm (see http://www.cise.ufl.edu/research/sparse, future
+ contributions of matrices are always welcome).
+
+ The MathWorks, Inc., provided a pre-release of MATLAB V6 which allowed me
+ to release the first umfpack mexFunction (v3.0) about 6 months earlier than
+ I had originally planned. They also supported the extension of UMFPACK to
+ complex, singular, and rectangular matrices (UMFPACK v4.0).
+
+ Penny Anderson (The MathWorks, Inc.), Anshul Gupta (IBM), and Friedrich
+ Grund (WAIS) assisted in porting UMFPACK to different platforms. Penny
+ Anderson also incorporated UMFPACK v4.0 into MATLAB, for lu, backslash (\),
+ and forward slash (/).
+
+--------------------------------------------------------------------------------
+Files and directories in the UMFPACK distribution:
+--------------------------------------------------------------------------------
+
+ ----------------------------------------------------------------------------
+ Subdirectories of the UMFPACK directory:
+ ----------------------------------------------------------------------------
+
+ Doc documentation
+ Make for compiling UMFPACK (a symbolic link to ../AMD/Make)
+ Source primary source code
+ Include include files for use in your code that calls UMFPACK
+ Demo demo programs. also serves as test of the UMFPACK installation.
+ MATLAB UMFPACK mexFunction for MATLAB, and supporting m-files
+ Lib where the compiled C-callable UMFPACK library is placed.
+
+ ----------------------------------------------------------------------------
+ Files in the UMFPACK directory:
+ ----------------------------------------------------------------------------
+
+ Makefile top-level Makefile for GNU make or original make.
+ Windows users would require Cygwin to use "make"
+
+ README this file
+
+ ----------------------------------------------------------------------------
+ Doc directory: documentation
+ ----------------------------------------------------------------------------
+
+ ChangeLog change log
+ License the UMFPACK License
+ Makefile for creating the documentation
+ QuickStart.tex Quick Start guide (source)
+ QuickStart.pdf Quick Start guide (PDF)
+ UserGuide.bib User Guide (references)
+ UserGuide.sed1 sed script for processing UserGuide.stex
+ UserGuide.sed2 sed script for processing UserGuide.stex
+ UserGuide.stex User Guide (LaTeX)
+ UserGuide.pdf User Guide (PDF)
+
+ ----------------------------------------------------------------------------
+ Make directory: for compiling the UMFPACK library (Lib/libumfpack.a)
+ ----------------------------------------------------------------------------
+
+ This is a symbolic link to the ../AMD/Make directory. Refer to the
+ ../AMD/README file for a list of its contents.
+
+ ----------------------------------------------------------------------------
+ Source directory:
+ ----------------------------------------------------------------------------
+
+ GNUmakefile a nice Makefile, for GNU make
+ Makefile an ugly Unix Makefile (for older make's)
+
+ umfpack_col_to_triplet.c convert col form to triplet
+ umfpack_defaults.c set Control defaults
+ umfpack_free_numeric.c free Numeric object
+ umfpack_free_symbolic.c free Symbolic object
+ umfpack_get_lunz.c get nz's in L and U
+ umfpack_get_numeric.c get Numeric object
+ umfpack_get_symbolic.c get Symbolic object
+ umfpack_numeric.c numeric factorization
+ umfpack_qsymbolic.c symbolic factorization, user Q
+ umfpack_report_control.c print Control settings
+ umfpack_report_info.c print Info statistics
+ umfpack_report_matrix.c print col or row-form sparse matrix
+ umfpack_report_numeric.c print Numeric object
+ umfpack_report_perm.c print permutation
+ umfpack_report_status.c print return status
+ umfpack_report_symbolic.c print Symbolic object
+ umfpack_report_triplet.c print triplet matrix
+ umfpack_report_vector.c print dense vector
+ umfpack_scale.c scale a vector
+ umfpack_solve.c solve a linear system
+ umfpack_symbolic.c symbolic factorization
+ umfpack_tictoc.c timer
+ umfpack_timer.c timer
+ umfpack_transpose.c transpose a matrix
+ umfpack_triplet_to_col.c convert triplet to col form
+
+ umf_config.h configuration file (BLAS, memory, timer)
+ umf_internal.h definitions internal to UMFPACK
+ umf_version.h version definitions (int/long, real/complex)
+
+ umf_2by2.[ch]
+ umf_analyze.[ch] symbolic factorization of A'*A
+ umf_apply_order.[ch] apply column etree postorder
+ umf_assemble.[ch] assemble elements into current front
+ umf_blas3_update.[ch] rank-k update. Uses level-3 BLAS
+ umf_build_tuples.[ch] construct tuples for elements
+ umf_colamd.[ch] COLAMD pre-ordering, modified for UMFPACK
+ umf_create_element.[ch] create a new element
+ umf_dump.[ch] debugging routines, not normally active
+ umf_extend_front.[ch] extend the current frontal matrix
+ umf_free.[ch] free memory
+ umf_fsize.[ch] determine largest front in each subtree
+ umf_garbage_collection.[ch] compact Numeric->Memory
+ umf_get_memory.[ch] make Numeric->Memory bigger
+ umf_grow_front.[ch] make current frontal matrix bigger
+ umf_init_front.[ch] initialize a new frontal matrix
+ umf_is_permutation.[ch] checks the validity of a permutation vector
+ umf_kernel.[ch] the main numeric factorization kernel
+ umf_kernel_init.[ch] initializations for umf_kernel
+ umf_kernel_wrapup.[ch] wrapup for umf_kernel
+ umf_local_search.[ch] local row and column pivot search
+ umf_lsolve.[ch] solve Lx=b
+ umf_ltsolve.[ch] solve L'x=b and L.'x=b
+ umf_malloc.[ch] malloc some memory
+ umf_mem_alloc_element.[ch] allocate element in Numeric->Memory
+ umf_mem_alloc_head_block.[ch] alloc. block at head of Numeric->Memory
+ umf_mem_alloc_tail_block.[ch] alloc. block at tail of Numeric->Memory
+ umf_mem_free_tail_block.[ch] free block at tail of Numeric->Memory
+ umf_mem_init_memoryspace.[ch] initialize Numeric->Memory
+ umf_realloc.[ch] realloc memory
+ umf_report_perm.[ch] print a permutation vector
+ umf_report_vector.[ch] print a double vector
+ umf_row_search.[ch] look for a pivot row
+ umf_scale.[ch] scale the pivot column
+ umf_scale_column.[ch] move pivot row & column into place, log P and Q
+ umf_set_stats.[ch] set statistics (final or estimates)
+ umf_singletons.[ch] find all zero-cost pivots
+ umf_solve.[ch] solve a linear system
+ umf_start_front.[ch] start a new frontal matrix for one frontal chain
+ umf_store_lu.[ch] store LU factors of current front
+ umf_symbolic_usage.[ch] determine memory usage for Symbolic object
+ umf_transpose.[ch] transpose a matrix in row or col form
+ umf_triplet.[ch] convert triplet to column form
+ umf_tuple_lengths.[ch] determine the tuple list lengths
+ umf_usolve.[ch] solve Ux=b
+ umf_utsolve.[ch] solve U'x=b and U.'x=b
+ umf_valid_numeric.[ch] checks the validity of a Numeric object
+ umf_valid_symbolic.[ch] check the validity of a Symbolic object
+
+ ----------------------------------------------------------------------------
+ Include directory:
+ ----------------------------------------------------------------------------
+
+ umfpack.h include file for user programs. Includes all of
+ the following files. This serves are source-
+ code level documenation. These files are also
+ used to construct the User Guide.
+
+ umfpack_col_to_triplet.h
+ umfpack_defaults.h
+ umfpack_free_numeric.h
+ umfpack_free_symbolic.h
+ umfpack_get_lunz.h
+ umfpack_get_numeric.h
+ umfpack_get_symbolic.h
+ umfpack_numeric.h
+ umfpack_qsymbolic.h
+ umfpack_report_control.h
+ umfpack_report_info.h
+ umfpack_report_matrix.h
+ umfpack_report_numeric.h
+ umfpack_report_perm.h
+ umfpack_report_status.h
+ umfpack_report_symbolic.h
+ umfpack_report_triplet.h
+ umfpack_report_vector.h
+ umfpack_scale.h
+ umfpack_solve.h
+ umfpack_symbolic.h
+ umfpack_tictoc.h
+ umfpack_timer.h
+ umfpack_transpose.h
+ umfpack_triplet_to_col.h
+ umfpack_wsolve.h note that there is no umfpack_wsolve.c. The
+ umfpack_*_wsolve routines are created from the
+ umfpack_solve.c file.
+
+ ----------------------------------------------------------------------------
+ Demo directory:
+ ----------------------------------------------------------------------------
+
+ Makefile for GNU make or original make
+
+ umfpack_simple.c a simple demo
+ umpack_xx_demo.c template to create the demo codes below
+
+ umfpack_di_demo.sed for creating umfpack_di_demo.c
+ umfpack_dl_demo.sed for creating umfpack_dl_demo.c
+ umfpack_zi_demo.sed for creating umfpack_zi_demo.c
+ umfpack_zl_demo.sed for creating umfpack_zl_demo.c
+
+ umfpack_di_demo.c a full demo (real/int version)
+ umfpack_dl_demo.c a full demo (real/long version)
+ umfpack_zi_demo.c a full demo (complex/int version)
+ umfpack_zl_demo.c a full demo (complex/long version)
+
+ umfpack_di_demo.out umfpack_di_demo output, unmodified Make.include
+ umfpack_dl_demo.out umfpack_dl_demo output, unmodified Make.include
+ umfpack_zi_demo.out umfpack_zi_demo output, unmodified Make.include
+ umfpack_zl_demo.out umfpack_zl_demo output, unmodified Make.include
+
+ umf4.c a demo (real/int) for Harwell/Boeing matrices
+ umf4.out output of "make hb", unmodified Make.include
+ HB directory of sample Harwell/Boeing matrices
+ readhb.f reads HB matrices, keeps zero entries
+ readhb_nozeros.f reads HB matrices, removes zero entries
+ readhb_size.f reads HB matrix dimension, nnz
+ tmp empty directory for umf4.c demo
+
+ umf4_f77wrapper.c a simple FORTRAN interface for UMFPACK.
+ compile with "make fortran"
+ umf4hb.f a demo of the FORTRAN interface
+ umf4hb.out output of "make fortran"
+
+ umf4_f77zwrapper.c a simple FORTRAN interface for the complex
+ UMFPACK routines. compile with "make fortran"
+ umf4zhb.f a demo of the FORTRAN interface (complex)
+ umf4zhb.out output of umf4zhb with Bai/qc324.cua, which is
+ not included in this distribution, see
+ http://www.cise.ufl.edu/research/sparse/matrices
+
+ umf4hb64.f 64-bit version of umf4hb.f
+
+ ----------------------------------------------------------------------------
+ MATLAB directory:
+ ----------------------------------------------------------------------------
+
+ Contents.m for "help umfpack" listing of toolbox contents
+ GNUmakefile a nice Makefile, for GNU make
+ Makefile an ugly Unix Makefile (for older make's)
+
+ luflop.m for "help luflop"
+ luflopmex.c luflop mexFunction, for computing LU flop count
+ lu_normest.m 1-norm estimate of A-L*U (by Hager & Davis).
+ umfpack_btf.m solve Ax=b using umfpack and dmperm
+ umfpack_demo.m a full umfpack demo
+ umfpack_details.m the details of how to use umfpack
+ umfpack.m for "help umfpack"
+ umfpack_make.m compile the umfpack mexFunction within MATLAB
+ umfpackmex.c the umfpack mexFunction
+ umfpack_report.m report statistics
+ umfpack_simple.m a simple umfpack demo
+ umfpack_solve.m x=A\b or b/A for arbitrary b
+ west0067.mat sparse matrix for umfpack_demo.m
+
+ umfpack_demo.m.out output of umfpack_demo.m
+ umfpack_simple.m.out output of umfpack_simple
+
+ lcc_lib/lapacksyms.def LAPACK definitions for lcc compiler (Windows)
+ lcc_lib/libmwlapack.lib LAPACK definitions for lcc compiler (Windows)
+
+ ----------------------------------------------------------------------------
+ Lib directory: libumfpack.a library placed here
+ ----------------------------------------------------------------------------
+
+ libumfpack.def UMPFACK definitions for Windows
--- /dev/null
+#-------------------------------------------------------------------------------
+# UMFPACK Makefile for compiling on Unix systems (for GNU Make)
+#-------------------------------------------------------------------------------
+
+include ../../../../common/Make.global_options
+
+#-------------------------------------------------------------------------------
+# source files
+#-------------------------------------------------------------------------------
+
+# non-user-callable umf_*.[ch] files:
+UMFCH = umf_assemble umf_blas3_update umf_build_tuples umf_create_element \
+ umf_dump umf_extend_front umf_garbage_collection umf_get_memory \
+ umf_init_front umf_kernel umf_kernel_init umf_kernel_wrapup \
+ umf_local_search umf_lsolve umf_ltsolve umf_mem_alloc_element \
+ umf_mem_alloc_head_block umf_mem_alloc_tail_block \
+ umf_mem_free_tail_block umf_mem_init_memoryspace \
+ umf_report_vector umf_row_search umf_scale_column \
+ umf_set_stats umf_solve umf_symbolic_usage umf_transpose \
+ umf_tuple_lengths umf_usolve umf_utsolve umf_valid_numeric \
+ umf_valid_symbolic umf_grow_front umf_start_front umf_2by2 \
+ umf_store_lu umf_scale
+
+# non-user-callable umf_*.[ch] files, int/long versions only (no real/complex):
+UMFINT = umf_analyze umf_apply_order umf_colamd umf_free umf_fsize \
+ umf_is_permutation umf_malloc umf_realloc umf_report_perm \
+ umf_singletons
+
+# non-user-callable, created from umf_ltsolve.c, umf_utsolve.c,
+# umf_triplet.c, and umf_assemble.c , with int/long and real/complex versions:
+UMF_CREATED = umf_lhsolve umf_uhsolve umf_triplet_map_nox \
+ umf_triplet_nomap_x umf_triplet_nomap_nox umf_triplet_map_x \
+ umf_assemble_fixq umf_store_lu_drop
+
+# non-user-callable, int/long and real/complex versions:
+UMF = $(UMF_CREATED) $(UMFCH)
+
+# user-callable umfpack_*.[ch] files (int/long and real/complex):
+UMFPACK = umfpack_col_to_triplet umfpack_defaults umfpack_free_numeric \
+ umfpack_free_symbolic umfpack_get_numeric umfpack_get_lunz \
+ umfpack_get_symbolic umfpack_numeric umfpack_qsymbolic \
+ umfpack_report_control umfpack_report_info umfpack_report_matrix \
+ umfpack_report_numeric umfpack_report_perm umfpack_report_status \
+ umfpack_report_symbolic umfpack_report_triplet \
+ umfpack_report_vector umfpack_solve umfpack_symbolic \
+ umfpack_transpose umfpack_triplet_to_col umfpack_scale \
+ umfpack_load_numeric umfpack_save_numeric \
+ umfpack_load_symbolic umfpack_save_symbolic
+
+# user-callable, created from umfpack_solve.c (umfpack_wsolve.h exists, though):
+# with int/long and real/complex versions:
+UMFPACKW = umfpack_wsolve
+
+USER = $(UMFPACKW) $(UMFPACK)
+
+# user-callable, only one version for int/long, real/complex, *.[ch] files:
+GENERIC = umfpack_timer umfpack_tictoc
+
+#-------------------------------------------------------------------------------
+# include files:
+#-------------------------------------------------------------------------------
+
+INC = ../Include/umfpack.h \
+ umf_config.h umf_version.h umf_internal.h umf_triplet.h \
+ $(addsuffix .h,$(UMFCH)) \
+ $(addsuffix .h,$(UMFINT)) \
+ $(addprefix ../Include/, $(addsuffix .h,$(USER))) \
+ $(addprefix ../Include/, $(addsuffix .h,$(GENERIC))) \
+ ../../AMD/Source/amd_internal.h ../../AMD/Include/amd.h
+
+#-------------------------------------------------------------------------------
+# object files for each version
+#-------------------------------------------------------------------------------
+
+DI = $(addprefix $D/lib/umfpack/, $(addsuffix .$(OBJEXT), $(subst umf_,umf_di_,$(UMF)) $(subst umfpack_,umfpack_di_,$(USER))))
+DL = $(addprefix $D/lib/umfpack/, $(addsuffix .$(OBJEXT), $(subst umf_,umf_dl_,$(UMF)) $(subst umfpack_,umfpack_dl_,$(USER))))
+I = $(addprefix $D/lib/umfpack/, $(addsuffix .$(OBJEXT), $(subst umf_,umf_i_,$(UMFINT))))
+L = $(addprefix $D/lib/umfpack/, $(addsuffix .$(OBJEXT), $(subst umf_,umf_l_,$(UMFINT))))
+GN = $(addprefix $D/lib/umfpack/, $(addsuffix .$(OBJEXT), $(subst umfpack_,umfpack_gn_,$(GENERIC))))
+
+#-------------------------------------------------------------------------------
+# compile each int and long routine (with no real/complex version)
+#-------------------------------------------------------------------------------
+
+$D/lib/umfpack/umf_i_%.$(OBJEXT): umf_%.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -c $< -o $@
+
+$D/lib/umfpack/umf_l_%.$(OBJEXT): umf_%.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -c $< -o $@
+
+#-------------------------------------------------------------------------------
+# compile each routine in the DI version
+#-------------------------------------------------------------------------------
+
+$D/lib/umfpack/umf_di_%.$(OBJEXT): umf_%.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -c $< -o $@
+
+$D/lib/umfpack/umf_di_%hsolve.$(OBJEXT): umf_%tsolve.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -DCONJUGATE_SOLVE -c $< -o $@
+
+$D/lib/umfpack/umf_di_triplet_map_x.$(OBJEXT): umf_triplet.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -DDO_MAP -DDO_VALUES -c $< -o $@
+
+$D/lib/umfpack/umf_di_triplet_map_nox.$(OBJEXT): umf_triplet.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -DDO_MAP -c $< -o $@
+
+$D/lib/umfpack/umf_di_triplet_nomap_x.$(OBJEXT): umf_triplet.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -DDO_VALUES -c $< -o $@
+
+$D/lib/umfpack/umf_di_triplet_nomap_nox.$(OBJEXT): umf_triplet.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -c $< -o $@
+
+$D/lib/umfpack/umf_di_assemble_fixq.$(OBJEXT): umf_assemble.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -DFIXQ -c $< -o $@
+
+$D/lib/umfpack/umf_di_store_lu_drop.$(OBJEXT): umf_store_lu.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -DDROP -c $< -o $@
+
+$D/lib/umfpack/umfpack_di_wsolve.$(OBJEXT): umfpack_solve.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -DWSOLVE -c $< -o $@
+
+$D/lib/umfpack/umfpack_di_%.$(OBJEXT): umfpack_%.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDINT -c $< -o $@
+
+#-------------------------------------------------------------------------------
+# compile each routine in the DL version
+#-------------------------------------------------------------------------------
+
+$D/lib/umfpack/umf_dl_%.$(OBJEXT): umf_%.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -c $< -o $@
+
+$D/lib/umfpack/umf_dl_%hsolve.$(OBJEXT): umf_%tsolve.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -DCONJUGATE_SOLVE -c $< -o $@
+
+$D/lib/umfpack/umf_dl_triplet_map_x.$(OBJEXT): umf_triplet.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -DDO_MAP -DDO_VALUES -c $< -o $@
+
+$D/lib/umfpack/umf_dl_triplet_map_nox.$(OBJEXT): umf_triplet.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -DDO_MAP -c $< -o $@
+
+$D/lib/umfpack/umf_dl_triplet_nomap_x.$(OBJEXT): umf_triplet.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -DDO_VALUES -c $< -o $@
+
+$D/lib/umfpack/umf_dl_triplet_nomap_nox.$(OBJEXT): umf_triplet.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -c $< -o $@
+
+$D/lib/umfpack/umf_dl_assemble_fixq.$(OBJEXT): umf_assemble.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -DFIXQ -c $< -o $@
+
+$D/lib/umfpack/umf_dl_store_lu_drop.$(OBJEXT): umf_store_lu.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -DDROP -c $< -o $@
+
+$D/lib/umfpack/umfpack_dl_wsolve.$(OBJEXT): umfpack_solve.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -DWSOLVE -c $< -o $@
+
+$D/lib/umfpack/umfpack_dl_%.$(OBJEXT): umfpack_%.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -DDLONG -c $< -o $@
+
+#-------------------------------------------------------------------------------
+# Create the generic routines (GN) using a generic rule
+#-------------------------------------------------------------------------------
+
+$D/lib/umfpack/umfpack_gn_%.$(OBJEXT): umfpack_%.c $(INC)
+ @echo =====umfpack==========optimized==$(MT)== $(<F)
+ $(CC) $(CFLAGS) -I../Include -I../../AMD/Include -I../../AMD/Source -c $< -o $@
+
+#-------------------------------------------------------------------------------
+# Create the libumfpack.a library
+#-------------------------------------------------------------------------------
+
+all: $(I) $(L) $(GN) $(DI) $(DL)
--- /dev/null
+/* ========================================================================== */
+/* === UMF_2by2 ============================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 row permutation P so that A (P,:) has a
+ * mostly zero-free diagonal, with large entries on the diagonal. It does this
+ * by swapping pairs of rows. Once a row is swapped it is not swapped again.
+ * This is a "cheap" assignment, not a complete max. transversal or
+ * bi-partite matching. It is only a partial matching. For most matrices
+ * for which this algorithm is used, however, the matching is complete (in
+ * UMFPACK this algorithm is used for matrices with roughly symmetric pattern,
+ * and these matrices typically have a mostly-zero-free diagonal to begin with.
+ * This algorithm is not meant to be used on arbitrary unsymmetric matrices
+ * (for those matrices, UMFPACK uses its unsymmetric strategy and does not
+ * use this algorithm).
+ *
+ * Even if incomplete, the matching is usually good enough for UMFPACK's
+ * symmetric strategy, which can easily pivot off the diagonal during numerical
+ * factorization if it finds a weak diagonal entry.
+ *
+ * The algorithms works as follows. First, row scaling factors are computed,
+ * and weak diagonal entries are found. A weak entry is a value A(k,k) whose
+ * absolute value is < tol * max (abs (A (:,k))). For each weak diagonal k in
+ * increasing order of degree in A+A', the algorithm finds an index j such
+ * that A (k,j) and A (j,k) are "large" (greater than or equal to tol times
+ * the largest magnitude in their columns). Row j must also not have already
+ * been swapped. Rows j and k are then swapped. If we come to a diagonal k
+ * that has already been swapped, then it is not modified. This case occurs
+ * for "oxo" pivots:
+ *
+ * k j
+ * k o x
+ * j x o
+ *
+ * which are swapped once to obtain
+ *
+ * k j
+ * j x o
+ * k o x
+ *
+ * These two rows are then not modified any further (A (j,j) was weak, but
+ * after one swap the permuted the jth diagonal entry is strong.
+ *
+ * This algorithm only works on square matrices (real, complex, or pattern-
+ * only). The numerical values are optional. If not present, each entry is
+ * treated as numerically acceptable (tol is ignored), and the algorithm
+ * operates by just using the pattern, not the values. Each column of the
+ * input matrix A must be sorted, with no duplicate entries. The matrix A
+ * can be optionally scaled prior to the numerical test. The matrix A (:,P)
+ * has the same diagonal entries as A (:,P), except in different order. So
+ * the output permutation P can also be used to swap the columns of A.
+ */
+
+#include "umf_internal.h"
+
+#ifndef NDEBUG
+#include "umf_is_permutation.h"
+#endif
+
+/* x is "weak" if it is less than ctol. If x or ctol are NaN, then define
+ * x as not "weak". This is a rather arbitrary choice, made to simplify the
+ * computation. On all but a PC with Microsoft C/C++, this test becomes
+ * ((x) - ctol < 0). */
+#define WEAK(x,ctol) (SCALAR_IS_LTZERO ((x)-(ctol)))
+
+/* For flag value in Next [col] */
+#define IS_WEAK -2
+
+/* ========================================================================== */
+/* === two_by_two =========================================================== */
+/* ========================================================================== */
+
+PRIVATE Int two_by_two /* returns # unmatched weak diagonals */
+(
+ /* input, not modified */
+ Int n2, /* C is n2-by-n2 */
+ Int Cp [ ], /* size n2+1, column pointers for C */
+ Int Ci [ ], /* size snz = Cp [n2], row indices for C */
+ Int Degree [ ], /* Degree [i] = degree of row i of C+C' */
+
+ /* input, not defined on output */
+ Int Next [ ], /* Next [k] == IS_WEAK if k is a weak diagonal */
+ Int Ri [ ], /* Ri [i] is the length of row i in C */
+
+ /* output, not defined on input */
+ Int P [ ],
+
+ /* workspace, not defined on input or output */
+ Int Rp [ ],
+ Int Head [ ]
+)
+{
+ Int deg, newcol, row, col, p, p2, unmatched, k, j, j2, j_best, best, jdiff,
+ jdiff_best, jdeg, jdeg_best, cp, cp1, cp2, rp, rp1, rp2, maxdeg,
+ mindeg ;
+
+ /* ---------------------------------------------------------------------- */
+ /* place weak diagonals in the degree lists */
+ /* ---------------------------------------------------------------------- */
+
+ for (deg = 0 ; deg < n2 ; deg++)
+ {
+ Head [deg] = EMPTY ;
+ }
+
+ maxdeg = 0 ;
+ mindeg = Int_MAX ;
+ for (newcol = n2-1 ; newcol >= 0 ; newcol--)
+ {
+ if (Next [newcol] == IS_WEAK)
+ {
+ /* add this column to the list of weak nodes */
+ DEBUGm1 ((" newcol "ID" has a weak diagonal deg "ID"\n",
+ newcol, deg)) ;
+ deg = Degree [newcol] ;
+ ASSERT (deg >= 0 && deg < n2) ;
+ Next [newcol] = Head [deg] ;
+ Head [deg] = newcol ;
+ maxdeg = MAX (maxdeg, deg) ;
+ mindeg = MIN (mindeg, deg) ;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* construct R = C' (C = strong entries in pruned submatrix) */
+ /* ---------------------------------------------------------------------- */
+
+ /* Ri [0..n2-1] is the length of each row of R */
+ /* use P as temporary pointer into the row form of R [ */
+ Rp [0] = 0 ;
+ for (row = 0 ; row < n2 ; row++)
+ {
+ Rp [row+1] = Rp [row] + Ri [row] ;
+ P [row] = Rp [row] ;
+ }
+ /* Ri no longer needed for row counts */
+
+ /* all entries in C are strong */
+ for (col = 0 ; col < n2 ; col++)
+ {
+ p2 = Cp [col+1] ;
+ for (p = Cp [col] ; p < p2 ; p++)
+ {
+ /* place the column index in row = Ci [p] */
+ Ri [P [Ci [p]]++] = col ;
+ }
+ }
+
+ /* contents of P no longer needed ] */
+
+#ifndef NDEBUG
+ DEBUG0 (("==================R: row form of strong entries in A:\n")) ;
+ UMF_dump_col_matrix ((double *) NULL,
+#ifdef COMPLEX
+ (double *) NULL,
+#endif
+ Ri, Rp, n2, n2, Rp [n2]) ;
+#endif
+ ASSERT (AMD_valid (n2, n2, Rp, Ri)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* for each weak diagonal, find a pair of strong off-diagonal entries */
+ /* ---------------------------------------------------------------------- */
+
+ for (row = 0 ; row < n2 ; row++)
+ {
+ P [row] = EMPTY ;
+ }
+
+ unmatched = 0 ;
+ best = EMPTY ;
+ jdiff = EMPTY ;
+ jdeg = EMPTY ;
+
+ for (deg = mindeg ; deg <= maxdeg ; deg++)
+ {
+ /* find the next weak diagonal of lowest degree */
+ DEBUGm2 (("---------------------------------- Deg: "ID"\n", deg)) ;
+ for (k = Head [deg] ; k != EMPTY ; k = Next [k])
+ {
+ DEBUGm2 (("k: "ID"\n", k)) ;
+ if (P [k] == EMPTY)
+ {
+ /* C (k,k) is a weak diagonal entry. Find an index j != k such
+ * that C (j,k) and C (k,j) are both strong, and also such
+ * that Degree [j] is minimized. In case of a tie, pick
+ * the smallest index j. C and R contain the pattern of
+ * strong entries only.
+ *
+ * Note that row k of R and column k of C are both sorted. */
+
+ DEBUGm4 (("===== Weak diagonal k = "ID"\n", k)) ;
+ DEBUG1 (("Column k of C:\n")) ;
+ for (p = Cp [k] ; p < Cp [k+1] ; p++)
+ {
+ DEBUG1 ((" "ID": deg "ID"\n", Ci [p], Degree [Ci [p]]));
+ }
+ DEBUG1 (("Row k of R (strong entries only):\n")) ;
+ for (p = Rp [k] ; p < Rp [k+1] ; p++)
+ {
+ DEBUG1 ((" "ID": deg "ID"\n", Ri [p], Degree [Ri [p]]));
+ }
+
+ /* no (C (k,j), C (j,k)) pair exists yet */
+ j_best = EMPTY ;
+ jdiff_best = Int_MAX ;
+ jdeg_best = Int_MAX ;
+
+ /* pointers into column k (including values) */
+ cp1 = Cp [k] ;
+ cp2 = Cp [k+1] ;
+ cp = cp1 ;
+
+ /* pointers into row k (strong entries only, no values) */
+ rp1 = Rp [k] ;
+ rp2 = Rp [k+1] ;
+ rp = rp1 ;
+
+ /* while entries searched in column k and row k */
+ while (TRUE)
+ {
+
+ if (cp >= cp2)
+ {
+ /* no more entries in this column */
+ break ;
+ }
+
+ /* get C (j,k), which is strong */
+ j = Ci [cp] ;
+
+ if (rp >= rp2)
+ {
+ /* no more entries in this column */
+ break ;
+ }
+
+ /* get R (k,j2), which is strong */
+ j2 = Ri [rp] ;
+
+ if (j < j2)
+ {
+ /* C (j,k) is strong, but R (k,j) is not strong */
+ cp++ ;
+ continue ;
+ }
+
+ if (j2 < j)
+ {
+ /* C (k,j2) is strong, but R (j2,k) is not strong */
+ rp++ ;
+ continue ;
+ }
+
+ /* j == j2: C (j,k) is strong and R (k,j) is strong */
+
+ best = FALSE ;
+
+ if (P [j] == EMPTY)
+ {
+ /* j has not yet been matched */
+ jdeg = Degree [j] ;
+ jdiff = SCALAR_ABS (k-j) ;
+
+ DEBUG1 (("Try candidate j "ID" deg "ID" diff "ID
+ "\n", j, jdeg, jdiff)) ;
+
+ if (j_best == EMPTY)
+ {
+ /* this is the first candidate seen */
+ DEBUG1 ((" first\n")) ;
+ best = TRUE ;
+ }
+ else
+ {
+ if (jdeg < jdeg_best)
+ {
+ /* the degree of j is best seen so far. */
+ DEBUG1 ((" least degree\n")) ;
+ best = TRUE ;
+ }
+ else if (jdeg == jdeg_best)
+ {
+ /* degree of j and j_best are the same */
+ /* tie break by nearest node number */
+ if (jdiff < jdiff_best)
+ {
+ DEBUG1 ((" tie degree, closer\n")) ;
+ best = TRUE ;
+ }
+ else if (jdiff == jdiff_best)
+ {
+ /* |j-k| = |j_best-k|. For any given k
+ * and j_best there is only one other j
+ * than can be just as close as j_best.
+ * Tie break by picking the smaller of
+ * j and j_best */
+ DEBUG1 ((" tie degree, as close\n"));
+ best = j < j_best ;
+ }
+ }
+ else
+ {
+ /* j has higher degree than best so far */
+ best = FALSE ;
+ }
+ }
+ }
+
+ if (best)
+ {
+ /* j is best match for k */
+ /* found a strong pair, A (j,k) and A (k,j) */
+ DEBUG1 ((" --- Found pair k: "ID" j: " ID
+ " jdeg: "ID" jdiff: "ID"\n",
+ k, j, jdeg, jdiff)) ;
+ ASSERT (jdiff != EMPTY) ;
+ ASSERT (jdeg != EMPTY) ;
+ j_best = j ;
+ jdeg_best = jdeg ;
+ jdiff_best = jdiff ;
+ }
+
+ /* get the next entries in column k and row k */
+ cp++ ;
+ rp++ ;
+ }
+
+ /* save the pair (j,k), if we found one */
+ if (j_best != EMPTY)
+ {
+ j = j_best ;
+ DEBUGm4 ((" --- best pair j: "ID" for k: "ID"\n", j, k)) ;
+ P [k] = j ;
+ P [j] = k ;
+ }
+ else
+ {
+ /* no match was found for k */
+ unmatched++ ;
+ }
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* finalize the row permutation, P */
+ /* ---------------------------------------------------------------------- */
+
+ for (k = 0 ; k < n2 ; k++)
+ {
+ if (P [k] == EMPTY)
+ {
+ P [k] = k ;
+ }
+ }
+ ASSERT (UMF_is_permutation (P, Rp, n2, n2)) ;
+
+ return (unmatched) ;
+}
+
+
+/* ========================================================================== */
+/* === UMF_2by2 ============================================================= */
+/* ========================================================================== */
+
+GLOBAL void UMF_2by2
+(
+ /* input, not modified: */
+ Int n, /* A is n-by-n */
+ const Int Ap [ ], /* size n+1 */
+ const Int Ai [ ], /* size nz = Ap [n] */
+ const double Ax [ ], /* size nz if present */
+#ifdef COMPLEX
+ const double Az [ ], /* size nz if present */
+#endif
+ double tol, /* tolerance for determining whether or not an
+ * entry is numerically acceptable. If tol <= 0
+ * then all numerical values ignored. */
+ Int scale, /* scaling to perform (none, sum, or max) */
+ Int Cperm1 [ ], /* singleton permutations */
+#ifndef NDEBUG
+ Int Rperm1 [ ], /* not needed, since Rperm1 = Cperm1 for submatrix S */
+#endif
+ Int InvRperm1 [ ], /* inverse of Rperm1 */
+ Int n1, /* number of singletons */
+ Int nempty, /* number of empty rows/cols */
+
+ /* input, contents undefined on output: */
+ Int Degree [ ], /* Degree [j] is the number of off-diagonal
+ * entries in row/column j of S+S', where
+ * where S = A (Cperm1 [n1..], Rperm1 [n1..]).
+ * Note that S is not used, nor formed. */
+
+ /* output: */
+ Int P [ ], /* P [k] = i means original row i is kth row in S(P,:)
+ * where S = A (Cperm1 [n1..], Rperm1 [n1..]) */
+ Int *p_nweak,
+ Int *p_unmatched,
+
+ /* workspace (not defined on input or output): */
+ Int Ri [ ], /* of size >= max (nz, n) */
+ Int Rp [ ], /* of size n+1 */
+ double Rs [ ], /* of size n if present. Rs = sum (abs (A),2) or
+ * max (abs (A),2), the sum or max of each row. Unused
+ * if scale is equal to UMFPACK_SCALE_NONE. */
+ Int Head [ ], /* of size n. Head pointers for bucket sort */
+ Int Next [ ], /* of size n. Next pointers for bucket sort */
+ Int Ci [ ], /* size nz */
+ Int Cp [ ] /* size n+1 */
+)
+{
+
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int k, p, row, col, do_values, do_sum, do_max, do_scale, nweak, weak,
+ p1, p2, dfound, unmatched, n2, oldrow, newrow, oldcol, newcol, pp ;
+
+ double cmax, value, rs, ctol, dvalue ;
+ Entry aij ;
+
+#ifndef NRECIPROCAL
+ Int do_recip = FALSE ;
+#endif
+
+#ifndef NDEBUG
+ /* UMF_debug += 99 ; */
+ DEBUGm3 (("\n ==================================UMF_2by2: tol %g\n", tol)) ;
+ ASSERT (AMD_valid (n, n, Ap, Ai)) ;
+ for (k = n1 ; k < n - nempty ; k++)
+ {
+ ASSERT (Cperm1 [k] == Rperm1 [k]) ;
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* determine scaling options */
+ /* ---------------------------------------------------------------------- */
+
+ /* use the values, but only if they are present */
+ /* ignore the values if tol <= 0 */
+ do_values = (tol > 0)
+ && (Ax != (double *) NULL)
+#ifdef COMPLEX
+ && (Az != (double *) NULL)
+#endif
+ ;
+ if (do_values && (Rs != (double *) NULL))
+ {
+ do_sum = (scale == UMFPACK_SCALE_SUM) ;
+ do_max = (scale == UMFPACK_SCALE_MAX) ;
+ }
+ else
+ {
+ /* no scaling */
+ do_sum = FALSE ;
+ do_max = FALSE ;
+ }
+ do_scale = do_max || do_sum ;
+ DEBUGm3 (("do_values "ID" do_sum "ID" do_max "ID" do_scale "ID"\n",
+ do_values, do_sum, do_max, do_scale)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* compute the row scaling, if requested */
+ /* ---------------------------------------------------------------------- */
+
+ /* see also umf_kernel_init */
+
+ if (do_scale)
+ {
+#ifndef NRECIPROCAL
+ double rsmin ;
+#endif
+ for (row = 0 ; row < n ; row++)
+ {
+ Rs [row] = 0.0 ;
+ }
+ for (col = 0 ; col < n ; col++)
+ {
+ p2 = Ap [col+1] ;
+ for (p = Ap [col] ; p < p2 ; p++)
+ {
+ row = Ai [p] ;
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ APPROX_ABS (value, aij) ;
+ rs = Rs [row] ;
+ if (!SCALAR_IS_NAN (rs))
+ {
+ if (SCALAR_IS_NAN (value))
+ {
+ /* if any entry in a row is NaN, then the scale factor
+ * for the row is NaN. It will be set to 1 later. */
+ Rs [row] = value ;
+ }
+ else if (do_max)
+ {
+ Rs [row] = MAX (rs, value) ;
+ }
+ else
+ {
+ Rs [row] += value ;
+ }
+ }
+ }
+ }
+#ifndef NRECIPROCAL
+ rsmin = Rs [0] ;
+ if (SCALAR_IS_ZERO (rsmin) || SCALAR_IS_NAN (rsmin))
+ {
+ rsmin = 1.0 ;
+ }
+#endif
+ for (row = 0 ; row < n ; row++)
+ {
+ /* do not scale an empty row, or a row with a NaN */
+ rs = Rs [row] ;
+ if (SCALAR_IS_ZERO (rs) || SCALAR_IS_NAN (rs))
+ {
+ Rs [row] = 1.0 ;
+ }
+#ifndef NRECIPROCAL
+ rsmin = MIN (rsmin, Rs [row]) ;
+#endif
+ }
+
+#ifndef NRECIPROCAL
+ /* multiply by the reciprocal if Rs is not too small */
+ do_recip = (rsmin >= RECIPROCAL_TOLERANCE) ;
+ if (do_recip)
+ {
+ /* invert the scale factors */
+ for (row = 0 ; row < n ; row++)
+ {
+ Rs [row] = 1.0 / Rs [row] ;
+ }
+ }
+#endif
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* compute the max in each column and find diagonal */
+ /* ---------------------------------------------------------------------- */
+
+ nweak = 0 ;
+
+#ifndef NDEBUG
+ for (k = 0 ; k < n ; k++)
+ {
+ ASSERT (Rperm1 [k] >= 0 && Rperm1 [k] < n) ;
+ ASSERT (InvRperm1 [Rperm1 [k]] == k) ;
+ }
+#endif
+
+ n2 = n - n1 - nempty ;
+
+ /* use Ri to count the number of strong entries in each row */
+ for (row = 0 ; row < n2 ; row++)
+ {
+ Ri [row] = 0 ;
+ }
+
+ pp = 0 ;
+ ctol = 0 ;
+ dvalue = 1 ;
+
+ /* construct C = pruned submatrix, strong values only, column form */
+
+ for (k = n1 ; k < n - nempty ; k++)
+ {
+ oldcol = Cperm1 [k] ;
+ newcol = k - n1 ;
+ Next [newcol] = EMPTY ;
+ DEBUGm1 (("Column "ID" newcol "ID" oldcol "ID"\n", k, newcol, oldcol)) ;
+
+ Cp [newcol] = pp ;
+
+ dfound = FALSE ;
+ p1 = Ap [oldcol] ;
+ p2 = Ap [oldcol+1] ;
+ if (do_values)
+ {
+ cmax = 0 ;
+ dvalue = 0 ;
+
+ if (!do_scale)
+ {
+ /* no scaling */
+ for (p = p1 ; p < p2 ; p++)
+ {
+ oldrow = Ai [p] ;
+ ASSERT (oldrow >= 0 && oldrow < n) ;
+ newrow = InvRperm1 [oldrow] - n1 ;
+ ASSERT (newrow >= -n1 && newrow < n2) ;
+ if (newrow < 0) continue ;
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ APPROX_ABS (value, aij) ;
+ /* if either cmax or value is NaN, define cmax as NaN */
+ if (!SCALAR_IS_NAN (cmax))
+ {
+ if (SCALAR_IS_NAN (value))
+ {
+ cmax = value ;
+ }
+ else
+ {
+ cmax = MAX (cmax, value) ;
+ }
+ }
+ if (oldrow == oldcol)
+ {
+ /* we found the diagonal entry in this column */
+ dvalue = value ;
+ dfound = TRUE ;
+ ASSERT (newrow == newcol) ;
+ }
+ }
+ }
+#ifndef NRECIPROCAL
+ else if (do_recip)
+ {
+ /* multiply by the reciprocal */
+ for (p = p1 ; p < p2 ; p++)
+ {
+ oldrow = Ai [p] ;
+ ASSERT (oldrow >= 0 && oldrow < n) ;
+ newrow = InvRperm1 [oldrow] - n1 ;
+ ASSERT (newrow >= -n1 && newrow < n2) ;
+ if (newrow < 0) continue ;
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ APPROX_ABS (value, aij) ;
+ value *= Rs [oldrow] ;
+ /* if either cmax or value is NaN, define cmax as NaN */
+ if (!SCALAR_IS_NAN (cmax))
+ {
+ if (SCALAR_IS_NAN (value))
+ {
+ cmax = value ;
+ }
+ else
+ {
+ cmax = MAX (cmax, value) ;
+ }
+ }
+ if (oldrow == oldcol)
+ {
+ /* we found the diagonal entry in this column */
+ dvalue = value ;
+ dfound = TRUE ;
+ ASSERT (newrow == newcol) ;
+ }
+ }
+ }
+#endif
+ else
+ {
+ /* divide instead */
+ for (p = p1 ; p < p2 ; p++)
+ {
+ oldrow = Ai [p] ;
+ ASSERT (oldrow >= 0 && oldrow < n) ;
+ newrow = InvRperm1 [oldrow] - n1 ;
+ ASSERT (newrow >= -n1 && newrow < n2) ;
+ if (newrow < 0) continue ;
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ APPROX_ABS (value, aij) ;
+ value /= Rs [oldrow] ;
+ /* if either cmax or value is NaN, define cmax as NaN */
+ if (!SCALAR_IS_NAN (cmax))
+ {
+ if (SCALAR_IS_NAN (value))
+ {
+ cmax = value ;
+ }
+ else
+ {
+ cmax = MAX (cmax, value) ;
+ }
+ }
+ if (oldrow == oldcol)
+ {
+ /* we found the diagonal entry in this column */
+ dvalue = value ;
+ dfound = TRUE ;
+ ASSERT (newrow == newcol) ;
+ }
+ }
+ }
+
+ ctol = tol * cmax ;
+ DEBUGm1 ((" cmax col "ID" %g ctol %g\n", oldcol, cmax, ctol)) ;
+ }
+ else
+ {
+ for (p = p1 ; p < p2 ; p++)
+ {
+ oldrow = Ai [p] ;
+ ASSERT (oldrow >= 0 && oldrow < n) ;
+ newrow = InvRperm1 [oldrow] - n1 ;
+ ASSERT (newrow >= -n1 && newrow < n2) ;
+ if (newrow < 0) continue ;
+ Ci [pp++] = newrow ;
+ if (oldrow == oldcol)
+ {
+ /* we found the diagonal entry in this column */
+ ASSERT (newrow == newcol) ;
+ dfound = TRUE ;
+ }
+ /* count the entries in each column */
+ Ri [newrow]++ ;
+ }
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* flag the weak diagonals */
+ /* ------------------------------------------------------------------ */
+
+ if (!dfound)
+ {
+ /* no diagonal entry present */
+ weak = TRUE ;
+ }
+ else
+ {
+ /* diagonal entry is present, check its value */
+ weak = (do_values) ? WEAK (dvalue, ctol) : FALSE ;
+ }
+ if (weak)
+ {
+ /* flag this column as weak */
+ DEBUG0 (("Weak!\n")) ;
+ Next [newcol] = IS_WEAK ;
+ nweak++ ;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* count entries in each row that are not numerically weak */
+ /* ------------------------------------------------------------------ */
+
+ if (do_values)
+ {
+ if (!do_scale)
+ {
+ /* no scaling */
+ for (p = p1 ; p < p2 ; p++)
+ {
+ oldrow = Ai [p] ;
+ newrow = InvRperm1 [oldrow] - n1 ;
+ if (newrow < 0) continue ;
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ APPROX_ABS (value, aij) ;
+ weak = WEAK (value, ctol) ;
+ if (!weak)
+ {
+ DEBUG0 ((" strong: row "ID": %g\n", oldrow, value)) ;
+ Ci [pp++] = newrow ;
+ Ri [newrow]++ ;
+ }
+ }
+ }
+#ifndef NRECIPROCAL
+ else if (do_recip)
+ {
+ /* multiply by the reciprocal */
+ for (p = p1 ; p < p2 ; p++)
+ {
+ oldrow = Ai [p] ;
+ newrow = InvRperm1 [oldrow] - n1 ;
+ if (newrow < 0) continue ;
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ APPROX_ABS (value, aij) ;
+ value *= Rs [oldrow] ;
+ weak = WEAK (value, ctol) ;
+ if (!weak)
+ {
+ DEBUG0 ((" strong: row "ID": %g\n", oldrow, value)) ;
+ Ci [pp++] = newrow ;
+ Ri [newrow]++ ;
+ }
+ }
+ }
+#endif
+ else
+ {
+ /* divide instead */
+ for (p = p1 ; p < p2 ; p++)
+ {
+ oldrow = Ai [p] ;
+ newrow = InvRperm1 [oldrow] - n1 ;
+ if (newrow < 0) continue ;
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ APPROX_ABS (value, aij) ;
+ value /= Rs [oldrow] ;
+ weak = WEAK (value, ctol) ;
+ if (!weak)
+ {
+ DEBUG0 ((" strong: row "ID": %g\n", oldrow, value)) ;
+ Ci [pp++] = newrow ;
+ Ri [newrow]++ ;
+ }
+ }
+ }
+ }
+ }
+ Cp [n2] = pp ;
+ ASSERT (AMD_valid (n2, n2, Cp, Ci)) ;
+
+ if (nweak == 0)
+ {
+ /* nothing to do, quick return */
+ DEBUGm2 (("\n =============================UMF_2by2: quick return\n")) ;
+ for (k = 0 ; k < n ; k++)
+ {
+ P [k] = k ;
+ }
+ *p_nweak = 0 ;
+ *p_unmatched = 0 ;
+ return ;
+ }
+
+#ifndef NDEBUG
+ for (k = 0 ; k < n2 ; k++)
+ {
+ P [k] = EMPTY ;
+ }
+ for (k = 0 ; k < n2 ; k++)
+ {
+ ASSERT (Degree [k] >= 0 && Degree [k] < n2) ;
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* find the 2-by-2 permutation */
+ /* ---------------------------------------------------------------------- */
+
+ /* The matrix S is now mapped to the index range 0 to n2-1. We have
+ * S = A (Rperm [n1 .. n-nempty-1], Cperm [n1 .. n-nempty-1]), and then
+ * C = pattern of strong entries in S. A weak diagonal k in S is marked
+ * with Next [k] = IS_WEAK. */
+
+ unmatched = two_by_two (n2, Cp, Ci, Degree, Next, Ri, P, Rp, Head) ;
+
+ /* ---------------------------------------------------------------------- */
+
+ *p_nweak = nweak ;
+ *p_unmatched = unmatched ;
+
+#ifndef NDEBUG
+ DEBUGm4 (("UMF_2by2: weak "ID" unmatched "ID"\n", nweak, unmatched)) ;
+ for (row = 0 ; row < n ; row++)
+ {
+ DEBUGm2 (("P ["ID"] = "ID"\n", row, P [row])) ;
+ }
+ DEBUGm2 (("\n =============================UMF_2by2: done\n\n")) ;
+#endif
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_2by2
+(
+ Int n,
+ const Int Ap [ ],
+ const Int Ai [ ],
+ const double Ax [ ],
+#ifdef COMPLEX
+ const double Az [ ],
+#endif
+ double tol,
+ Int scale,
+ Int Cperm1 [ ],
+#ifndef NDEBUG
+ Int Rperm1 [ ],
+#endif
+ Int InvRperm [ ],
+ Int n1,
+ Int nempty,
+ Int Degree [ ],
+ Int P [ ],
+ Int *p_nweak,
+ Int *p_nmatched,
+ Int Ri [ ],
+ Int Rp [ ],
+ double Rs [ ],
+ Int Head [ ],
+ Int Next [ ],
+ Int Si [ ],
+ Int Sp [ ]
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_analyze ========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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_apply_order.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+#include "umf_fsize.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.
+ * for column etree postorder. */
+
+ Int fixQ,
+
+ /* 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,
+ i, *Winv, kk, npiv, jnext, krow, knext, pfirst, jlast, ncompactions,
+ *Front_stack, *Front_order, *Front_child, *Front_sibling,
+ Wflag, npivcol, fallrows, fallcols, fpiv, frows, fcols, *Front_size ;
+
+ nfr = 0 ;
+ DEBUG0 (("UMF_analyze: anzmax "ID" anrow "ID" ancol "ID"\n",
+ Ap [n_row], n_row, n_col)) ;
+
+ /* ====================================================================== */
+ /* ==== initializations ================================================= */
+ /* ====================================================================== */
+
+#pragma ivdep
+ 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 ;
+
+ /* this test requires the size of Ai to be >= n_col + nz */
+ 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 in umf_analyze :: */
+ /* it can't happen, 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]) ;
+ DEBUG1 (("initial thickness: "ID"\n", thickness)) ;
+
+ }
+ 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")) ;
+ DEBUG1 (("thickness, prior to supercol detect: "ID"\n", thickness)) ;
+#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 ;
+ DEBUG1 (("Number of pivot columns: "ID"\n", npivots)) ;
+
+ /* 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 */
+ DEBUG1 (("Frontal matrix evaporation\n")) ;
+ 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", nfr "ID" pivot columns "ID":"ID
+ " all front: "ID"-by-"ID" Parent: "ID"\n", j, nfr, j,j+npivots-1,
+ Front_nrows [j], Front_ncols [j], Front_parent [j])) ;
+ nfr++ ;
+
+ /* ================================================================== */
+ /* === prepare this row for its parent ============================== */
+ /* ================================================================== */
+
+ if (parent != EMPTY)
+ {
+ Link [j] = Link [parent] ;
+ Link [parent] = j ;
+ }
+
+ ASSERT (jnext > j) ;
+
+ jlast = j ;
+ }
+
+ /* ====================================================================== */
+ /* === postorder the fronts ============================================= */
+ /* ====================================================================== */
+
+ *nfr_out = nfr ;
+
+ Front_order = W ; /* use W for Front_order [ */
+
+ if (fixQ)
+ {
+ /* do not postorder the fronts if Q is fixed */
+ DEBUG1 (("\nNo postorder (Q is fixed)\n")) ;
+ k = 0 ;
+ /* Pragma added May 14, 2003. The Intel compiler icl 6.0 (an old
+ * version) incorrectly vectorizes this loop. */
+#pragma novector
+ for (j = 0 ; j < n_col ; j++)
+ {
+ if (Front_npivcol [j] > 0)
+ {
+ Front_order [j] = k++ ;
+ DEBUG1 (("Front order of j: "ID" is:"ID"\n", j,
+ Front_order [j])) ;
+ }
+ else
+ {
+ Front_order [j] = EMPTY ;
+ }
+ }
+ }
+ else
+ {
+
+ /* use Ap for Front_child and use Link for Front_sibling [ */
+ Front_child = Ap ;
+ Front_sibling = Link ;
+
+ /* use Ai for Front_stack, size of Ai is >= 2*n_col */
+ Front_stack = Ai ;
+ Front_size = Front_stack + n_col ;
+
+ UMF_fsize (n_col, Front_size, Front_nrows, Front_ncols,
+ Front_parent, Front_npivcol) ;
+
+ AMD_postorder (n_col, Front_parent, Front_npivcol, Front_size,
+ Front_order, Front_child, Front_sibling, Front_stack) ;
+
+ /* done with Front_child, Front_sibling, Front_size, and Front_stack ]*/
+
+ /* ------------------------------------------------------------------ */
+ /* 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 */
+ /* (or pack them in same order, if fixQ) */
+ /* ---------------------------------------------------------------------- */
+
+ /* 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) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_analyze
+(
+ Int n_row,
+ Int n_col,
+ Int Ai [ ],
+ Int Ap [ ],
+ Int Up [ ],
+ Int fixQ,
+ Int Front_ncols [ ],
+ Int W [ ],
+ Int Link [ ],
+ Int Front_nrows [ ],
+ Int Front_npivcol [ ],
+ Int Front_parent [ ],
+ Int *nfr_out,
+ Int *p_ncompactions
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_apply_order ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 [ ], /* of size nn on input, size nfr on output */
+ const Int Order [ ], /* Order [i] = k, i in the range 0..nn-1,
+ * and k in the range 0..nfr-1, means that node
+ * i is the kth node in the postordered tree. */
+ Int Temp [ ], /* workspace of size nfr */
+ Int nn, /* nodes are numbered in the range 0..nn-1 */
+ Int nfr /* the number of nodes actually in use */
+)
+{
+ Int i, k ;
+ for (i = 0 ; i < nn ; i++)
+ {
+ k = Order [i] ;
+ ASSERT (k >= EMPTY && k < nfr) ;
+ if (k != EMPTY)
+ {
+ Temp [k] = Front [i] ;
+ }
+ }
+
+ for (k = 0 ; k < nfr ; k++)
+ {
+ Front [k] = Temp [k] ;
+ }
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_apply_order
+(
+ Int Front [ ],
+ const Int Order [ ],
+ Int Temp [ ],
+ Int n_col,
+ Int nfr
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_assemble ========================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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. This is compiled twice (with and
+ * without FIXQ) for each real/complex int/long version, for a total of 8
+ * versions.*/
+
+#include "umf_internal.h"
+#include "umf_mem_free_tail_block.h"
+
+/* ========================================================================== */
+/* === row_assemble ========================================================= */
+/* ========================================================================== */
+
+PRIVATE void row_assemble
+(
+ Int row,
+ NumericType *Numeric,
+ WorkType *Work
+)
+{
+
+ Int tpi, e, *E, *Fcpos, *Frpos, *Row_degree, *Row_tuples, *Row_tlen, rdeg0,
+ f, nrows, ncols, *Rows, *Cols, col, ncolsleft, j ;
+ Tuple *tp, *tp1, *tp2, *tpend ;
+ Unit *Memory, *p ;
+ Element *ep ;
+ Entry *S, *Fcblock, *Frow ;
+
+#ifndef FIXQ
+ Int *Col_degree ;
+ Col_degree = Numeric->Cperm ;
+#endif
+
+ Row_tuples = Numeric->Uip ;
+ tpi = Row_tuples [row] ;
+ if (!tpi) return ;
+
+ Memory = Numeric->Memory ;
+ E = Work->E ;
+ Fcpos = Work->Fcpos ;
+ Frpos = Work->Frpos ;
+ Row_degree = Numeric->Rperm ;
+ Row_tlen = Numeric->Uilen ;
+ E = Work->E ;
+ Memory = Numeric->Memory ;
+ rdeg0 = Work->rdeg0 ;
+ Fcblock = Work->Fcblock ;
+
+#ifndef NDEBUG
+ DEBUG6 (("SCAN2-row: "ID"\n", row)) ;
+ UMF_dump_rowcol (0, Numeric, Work, row, FALSE) ;
+#endif
+
+ ASSERT (NON_PIVOTAL_ROW (row)) ;
+
+ 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 < Work->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) ;
+ S = ((Entry *) p) + f ;
+
+ DEBUG6 (("Old LSON: "ID"\n", e)) ;
+#ifndef NDEBUG
+ UMF_dump_element (Numeric, Work, e, FALSE) ;
+#endif
+
+ ncolsleft = ep->ncolsleft ;
+
+ Frow = Fcblock + 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 */
+ /* -------------------------------------------------- */
+
+#pragma ivdep
+ for (j = 0 ; j < ncols ; j++)
+ {
+ col = Cols [j] ;
+ ASSERT (col >= 0 && col < Work->n_col) ;
+#ifndef FIXQ
+ Col_degree [col] -- ;
+#endif
+ /* Frow [Fcpos [col]] += *S ; */
+ ASSEMBLE (Frow [Fcpos [col]], *S) ;
+ S += nrows ;
+ }
+
+ }
+ else
+ {
+ /* -------------------------------------------------- */
+ /* some columns have been assembled out of this Lson */
+ /* -------------------------------------------------- */
+
+#pragma ivdep
+ for (j = 0 ; j < ncols ; j++)
+ {
+ col = Cols [j] ;
+ if (col >= 0)
+ {
+ ASSERT (col < Work->n_col) ;
+#ifndef FIXQ
+ Col_degree [col] -- ;
+#endif
+ /* Frow [Fcpos [col]] += *S ; */
+ ASSEMBLE (Frow [Fcpos [col]], *S) ;
+ }
+ S += 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)) ;
+ UMF_dump_rowcol (0, Numeric, Work, row, FALSE) ;
+ DEBUG7 (("Current frontal matrix: (scan 1b)\n")) ;
+ UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+}
+
+/* ========================================================================== */
+/* === col_assemble ========================================================= */
+/* ========================================================================== */
+
+PRIVATE void col_assemble
+(
+ Int col,
+ NumericType *Numeric,
+ WorkType *Work
+)
+{
+
+ Int tpi, e, *E, *Fcpos, *Frpos, *Row_degree, *Col_tuples, *Col_tlen, cdeg0,
+ f, nrows, ncols, *Rows, *Cols, row, nrowsleft, i ;
+ Tuple *tp, *tp1, *tp2, *tpend ;
+ Unit *Memory, *p ;
+ Element *ep ;
+ Entry *S, *Fcblock, *Fcol ;
+
+#if !defined (FIXQ) || !defined (NDEBUG)
+ Int *Col_degree ;
+ Col_degree = Numeric->Cperm ;
+#endif
+
+ Col_tuples = Numeric->Lip ;
+ tpi = Col_tuples [col] ;
+ if (!tpi) return ;
+
+ Memory = Numeric->Memory ;
+ E = Work->E ;
+ Fcpos = Work->Fcpos ;
+ Frpos = Work->Frpos ;
+ Row_degree = Numeric->Rperm ;
+ Col_tlen = Numeric->Lilen ;
+ E = Work->E ;
+ Memory = Numeric->Memory ;
+ cdeg0 = Work->cdeg0 ;
+ Fcblock = Work->Fcblock ;
+
+ DEBUG6 (("SCAN2-col: "ID"\n", col)) ;
+#ifndef NDEBUG
+ UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
+#endif
+
+ ASSERT (NON_PIVOTAL_COL (col)) ;
+ 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 ; /* col already assembled */
+ ASSERT (col == Cols [f] && col >= 0 && col < Work->n_col) ;
+
+ if (ep->cdeg == cdeg0)
+ {
+ /* ------------------------------------------------------ */
+ /* this is an old Uson - assemble just one col */
+ /* ------------------------------------------------------ */
+
+ /* flag the col as assembled from the Uson */
+ Cols [f] = EMPTY ;
+
+ nrows = ep->nrows ;
+ ncols = ep->ncols ;
+ Rows = Cols + ncols ;
+ p += UNITS (Int, ncols + nrows) ;
+ S = ((Entry *) p) + f * nrows ;
+
+ DEBUG6 (("Old USON: "ID"\n", e)) ;
+#ifndef NDEBUG
+ UMF_dump_element (Numeric, Work, e, FALSE) ;
+#endif
+
+ nrowsleft = ep->nrowsleft ;
+
+ Fcol = Fcblock + Fcpos [col] ;
+ DEBUG6 (("USON found (in scan2-col): "ID"\n", e)) ;
+#ifndef FIXQ
+ Col_degree [col] -= nrowsleft ;
+#endif
+ if (nrows == nrowsleft)
+ {
+ /* -------------------------------------------------- */
+ /* no rows assembled out of this Uson yet */
+ /* -------------------------------------------------- */
+
+#pragma ivdep
+ for (i = 0 ; i < nrows ; i++)
+ {
+ row = Rows [i] ;
+ ASSERT (row >= 0 && row < Work->n_row) ;
+ Row_degree [row]-- ;
+ /* Fcol [Frpos [row]] += S [i] ; */
+ ASSEMBLE (Fcol [Frpos [row]], S [i]) ;
+ }
+ }
+ else
+ {
+ /* -------------------------------------------------- */
+ /* some rows have been assembled out of this Uson */
+ /* -------------------------------------------------- */
+
+#pragma ivdep
+ for (i = 0 ; i < nrows ; i++)
+ {
+ row = Rows [i] ;
+ if (row >= 0)
+ {
+ ASSERT (row < Work->n_row) ;
+ Row_degree [row]-- ;
+ /* Fcol [Frpos [row]] += S [i] ; */
+ ASSEMBLE (Fcol [Frpos [row]], S [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)) ;
+ UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
+ DEBUG7 (("Current frontal matrix: after scan2-col\n")) ;
+ UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+}
+
+
+/* ========================================================================== */
+/* === UMF_assemble / UMF_assemble_fixq ===================================== */
+/* ========================================================================== */
+
+#ifndef FIXQ
+GLOBAL void UMF_assemble
+#else
+GLOBAL void UMF_assemble_fixq
+#endif
+(
+ NumericType *Numeric,
+ WorkType *Work
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int e, i, row, col, i2, nrows, ncols, f, tpi, extcdeg, extrdeg, rdeg0,
+ cdeg0, son_list, next, nrows_to_assemble,
+ ncols_to_assemble, ngetrows, j, j2,
+ nrowsleft, /* number of rows remaining in S */
+ ncolsleft, /* number of columns remaining in S */
+ prior_Lson, prior_Uson, *E, *Cols, *Rows, *Wm, *Woo,
+ *Row_tuples, *Row_degree, *Row_tlen,
+ *Col_tuples, *Col_tlen ;
+ Unit *Memory, *p ;
+ Element *ep ;
+ Tuple *tp, *tp1, *tp2, *tpend ;
+ Entry
+ *S, /* a pointer into the contribution block of a son */
+ *Fcblock, /* current contribution block */
+ *Fcol ; /* a column of FC */
+ Int *Frpos,
+ *Fcpos,
+ fnrows, /* number of rows in contribution block in F */
+ fncols ; /* number of columns in contribution block in F */
+
+#if !defined (FIXQ) || !defined (NDEBUG)
+ Int *Col_degree ;
+#endif
+
+#ifndef NDEBUG
+ Int 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
+
+#if !defined (FIXQ) || !defined (NDEBUG)
+ Col_degree = Numeric->Cperm ; /* not updated if FIXQ is true */
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ fncols = Work->fncols ;
+ fnrows = Work->fnrows ;
+ Fcpos = Work->Fcpos ;
+ Frpos = Work->Frpos ;
+ 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 ;
+ rdeg0 = Work->rdeg0 ;
+ cdeg0 = Work->cdeg0 ;
+
+#ifndef NDEBUG
+ DEBUG6 (("============================================\n")) ;
+ DEBUG6 (("Degree update, assembly.\n")) ;
+ DEBUG6 (("pivot row pattern: fncols="ID"\n", fncols)) ;
+ for (j = 0 ; j < fncols ; j++)
+ {
+ col = Work->Fcols [j] ;
+ DEBUG6 ((ID" ", col)) ;
+ ASSERT (Fcpos [col] == j * Work->fnr_curr) ;
+ ASSERT (NON_PIVOTAL_COL (col)) ;
+ }
+ ASSERT (Fcpos [Work->pivcol] >= 0) ;
+ DEBUG6 (("pivcol: "ID" pos "ID" fnr_curr "ID" fncols "ID"\n",
+ Work->pivcol, Fcpos [Work->pivcol], Work->fnr_curr, fncols)) ;
+ ASSERT (Fcpos [Work->pivcol] < fncols * Work->fnr_curr) ;
+ DEBUG6 (("\npivot col pattern: fnrows="ID"\n", fnrows)) ;
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ row = Work->Frows [i] ;
+ DEBUG6 ((ID" ", row)) ;
+ ASSERT (Frpos [row] == i) ;
+ ASSERT (NON_PIVOTAL_ROW (row)) ;
+ }
+ DEBUG6 (("\n")) ;
+ ASSERT (Frpos [Work->pivrow] >= 0) ;
+ ASSERT (Frpos [Work->pivrow] < fnrows) ;
+ ASSERT (Work->Flublock == (Entry *) (Numeric->Memory + E [0])) ;
+ ASSERT (Work->Fcblock == Work->Flublock + Work->nb *
+ (Work->nb + Work->fnr_curr + Work->fnc_curr)) ;
+#endif
+
+ Fcblock = Work->Fcblock ;
+
+ /* ---------------------------------------------------------------------- */
+ /* determine the largest actual frontal matrix size (for Info only) */
+ /* ---------------------------------------------------------------------- */
+
+ ASSERT (fnrows == Work->fnrows_new + 1) ;
+ ASSERT (fncols == Work->fncols_new + 1) ;
+
+ Numeric->maxnrows = MAX (Numeric->maxnrows, fnrows) ;
+ Numeric->maxncols = MAX (Numeric->maxncols, fncols) ;
+
+ /* this is safe from integer overflow, since the current frontal matrix
+ * is already allocated. */
+ Numeric->maxfrsize = MAX (Numeric->maxfrsize, fnrows * fncols) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* assemble from prior elements into the current frontal matrix */
+ /* ---------------------------------------------------------------------- */
+
+ DEBUG2 (("New assemble start [prior_element:"ID"\n", Work->prior_element)) ;
+
+ /* 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 */
+ /* ---------------------------------------------------------------------- */
+
+ for (i2 = Work->fscan_row ; i2 < fnrows ; i2++)
+ {
+ /* Get a row */
+ row = Work->NewRows [i2] ;
+ if (row < 0) row = FLIP (row) ;
+ ASSERT (row >= 0 && row < n_row) ;
+
+ 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 */
+ /* ---------------------------------------------------------------------- */
+
+ for (j2 = Work->fscan_col ; j2 < fncols ; j2++)
+ {
+ /* Get a column */
+ col = Work->NewCols [j2] ;
+ if (col < 0) col = FLIP (col) ;
+ 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, S) ;
+ 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 ;
+ DEBUG2 (("extrdeg "ID" extcdeg "ID"\n", extrdeg, 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 */
+#pragma ivdep
+ 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] ;
+#ifndef FIXQ
+ Col_degree [col] -= nrowsleft ;
+#endif
+ Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+ for (i = 0 ; i < nrows ; i++)
+ {
+ /* Fcol [Wm [i]] += S [i] ; */
+ ASSEMBLE (Fcol [Wm [i]], S [i]) ;
+ }
+ S += nrows ;
+ }
+
+
+ }
+ else
+ {
+ /* ------------------------------------------------------ */
+ /* only cols have been assembled out of LUson */
+ /* ------------------------------------------------------ */
+
+ for (j = 0 ; j < ncols ; j++)
+ {
+ col = Cols [j] ;
+ if (col >= 0)
+ {
+#ifndef FIXQ
+ Col_degree [col] -= nrowsleft ;
+#endif
+ Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+ for (i = 0 ; i < nrows ; i++)
+ {
+ /* Fcol [Wm [i]] += S [i] ; */
+ ASSEMBLE (Fcol [Wm [i]], S [i]) ;
+ }
+ }
+ S += 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] ;
+#ifndef FIXQ
+ Col_degree [col] -= nrowsleft ;
+#endif
+ Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+ for (i = 0 ; i < nrowsleft ; i++)
+ {
+ /* Fcol [Wm [i]] += S [Woo [i]] ; */
+ ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ;
+ }
+ S += nrows ;
+ }
+
+ }
+ else
+ {
+ /* ------------------------------------------------------ */
+ /* both rows and columns have been assembled out of LUson */
+ /* ------------------------------------------------------ */
+
+ for (j = 0 ; j < ncols ; j++)
+ {
+ col = Cols [j] ;
+ if (col >= 0)
+ {
+#ifndef FIXQ
+ Col_degree [col] -= nrowsleft ;
+#endif
+ Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+ for (i = 0 ; i < nrowsleft ; i++)
+ {
+ /* Fcol [Wm [i]] += S [Woo [i]] ; */
+ ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ;
+ }
+ }
+ S += 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)
+ {
+
+ Int skip = FALSE ;
+ if (ncols_to_assemble * 16 < ncols && nrows == 1)
+ {
+ /* this is a tall and thin frontal matrix consisting of
+ * only one column (most likely an original column). Do
+ * not assemble it. It cannot be the pivot column, since
+ * the pivot column element would be an LU son, not an Lson,
+ * of the current frontal matrix. */
+ ASSERT (nrowsleft == 1) ;
+ ASSERT (Rows [0] >= 0 && Rows [0] < Work->n_row) ;
+ skip = TRUE ;
+ Work->any_skip = TRUE ;
+ }
+
+ if (!skip)
+ {
+
+ 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 */
+#pragma ivdep
+ 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))
+ {
+#ifndef FIXQ
+ Col_degree [col] -= nrowsleft ;
+#endif
+ Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+ for (i = 0 ; i < nrows ; i++)
+ {
+ /* Fcol [Wm [i]] += S [i] ; */
+ ASSEMBLE (Fcol [Wm [i]], S [i]) ;
+ }
+ /* flag the column as assembled from Uson */
+ Cols [j] = EMPTY ;
+ }
+ S += 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))
+ {
+#ifndef FIXQ
+ Col_degree [col] -= nrowsleft ;
+#endif
+ Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+ for (i = 0 ; i < nrowsleft ; i++)
+ {
+ /* Fcol [Wm [i]] += S [Woo [i]] ; */
+ ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ;
+ }
+ /* flag the column as assembled from Uson */
+ Cols [j] = EMPTY ;
+ }
+ S += 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)
+ {
+
+ Int skip = FALSE ;
+ if (nrows_to_assemble * 16 < nrows && ncols == 1)
+ {
+ /* this is a tall and thin frontal matrix consisting of
+ * only one column (most likely an original column). Do
+ * not assemble it. It cannot be the pivot column, since
+ * the pivot column element would be an LU son, not an Lson,
+ * of the current frontal matrix. */
+ ASSERT (ncolsleft == 1) ;
+ ASSERT (Cols [0] >= 0 && Cols [0] < Work->n_col) ;
+ Work->any_skip = TRUE ;
+ skip = TRUE ;
+ }
+
+ if (!skip)
+ {
+
+ /* 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) ;
+#ifndef FIXQ
+ Col_degree [col] -= nrows_to_assemble ;
+#endif
+ Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+ for (i = 0 ; i < nrows_to_assemble ; i++)
+ {
+ /* Fcol [Wm [i]] += S [Woo [i]] ; */
+ ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ;
+ }
+ S += 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)
+ {
+#ifndef FIXQ
+ Col_degree [col] -= nrows_to_assemble ;
+#endif
+ Fcol = Fcblock + Fcpos [col] ;
+#pragma ivdep
+ for (i = 0 ; i < nrows_to_assemble ; i++)
+ {
+ /* Fcol [Wm [i]] += S [Woo [i]] ; */
+ ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ;
+ }
+ }
+ S += 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
+
+ /* rescan the pivot row */
+ if (Work->any_skip)
+ {
+ row_assemble (Work->pivrow, Numeric, Work) ;
+ }
+
+ if (Work->do_scan2row)
+ {
+ for (i2 = Work->fscan_row ; i2 < fnrows ; i2++)
+ {
+ /* Get a row */
+ row = Work->NewRows [i2] ;
+ if (row < 0) row = FLIP (row) ;
+ ASSERT (row >= 0 && row < n_row) ;
+ if (!(row == Work->pivrow && Work->any_skip))
+ {
+ /* assemble it */
+ row_assemble (row, Numeric, Work) ;
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* 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
+
+ /* rescan the pivot col */
+ if (Work->any_skip)
+ {
+ col_assemble (Work->pivcol, Numeric, Work) ;
+ }
+
+ if (Work->do_scan2col)
+ {
+
+ for (j2 = Work->fscan_col ; j2 < fncols ; j2++)
+ {
+ /* Get a column */
+ col = Work->NewCols [j2] ;
+ if (col < 0) col = FLIP (col) ;
+ ASSERT (col >= 0 && col < n_col) ;
+ if (!(col == Work->pivcol && Work->any_skip))
+ {
+ /* assemble it */
+ col_assemble (col, Numeric, Work) ;
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* 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")) ;
+
+ for (i2 = 0 ; i2 < fnrows ; i2++)
+ {
+ /* Get a row */
+ row = Work->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) ;
+ Cols = (Int *) p ;
+ 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)) ;
+
+ if (Work->any_skip)
+ {
+ /* no Lsons in any row, except for very tall and thin ones */
+ ASSERT (extrdeg >= 0) ;
+ if (extrdeg == 0)
+ {
+ /* this is an unassemble Lson */
+ ASSERT (ep->ncols == 1) ;
+ ASSERT (ep->ncolsleft == 1) ;
+ col = Cols [0] ;
+ ASSERT (col != Work->pivcol) ;
+ }
+ }
+ else
+ {
+ /* no Lsons in any row */
+ ASSERT (extrdeg > 0) ;
+ /* Uson external row degree is = number of cols left */
+ ASSERT (IMPLIES (extcdeg == 0, extrdeg == ep->ncolsleft)) ;
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+
+ for (j2 = 0 ; j2 < fncols ; j2++)
+ {
+ /* Get a column */
+ col = Work->Fcols [j2] ;
+ ASSERT (col >= 0 && col < n_col) ;
+
+ DEBUG6 (("DEBUG SCAN 2: "ID"\n", col)) ;
+#ifndef FIXQ
+ UMF_dump_rowcol (1, Numeric, Work, col, TRUE) ;
+#else
+ 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) ;
+ 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 ;
+ Rows = ((Int *) p) + ep->ncols ;
+ 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)) ;
+
+ if (Work->any_skip)
+ {
+ /* no Usons in any column, except for very tall and thin ones */
+ ASSERT (extcdeg >= 0) ;
+ if (extcdeg == 0)
+ {
+ /* this is an unassemble Uson */
+ ASSERT (ep->nrows == 1) ;
+ ASSERT (ep->nrowsleft == 1) ;
+ row = Rows [0] ;
+ ASSERT (row != Work->pivrow) ;
+ }
+ }
+ else
+ {
+ /* 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 */
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_assemble
+(
+ NumericType *Numeric,
+ WorkType *Work
+) ;
+
+GLOBAL void UMF_assemble_fixq
+(
+ NumericType *Numeric,
+ WorkType *Work
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_blas3_update ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 *L, *U, *C, *LU ;
+ Int k, m, n, d, nb, dc ;
+
+ DEBUG5 (("In UMF_blas3_update "ID" "ID" "ID"\n",
+ Work->fnpiv, Work->fnrows, Work->fncols)) ;
+
+ k = Work->fnpiv ;
+ if (k == 0)
+ {
+ /* no work to do */
+ return ;
+ }
+
+ m = Work->fnrows ;
+ n = Work->fncols ;
+
+ d = Work->fnr_curr ;
+ dc = Work->fnc_curr ;
+ nb = Work->nb ;
+ ASSERT (d >= 0 && (d % 2) == 1) ;
+ C = Work->Fcblock ; /* ldc is fnr_curr */
+ L = Work->Flblock ; /* ldl is fnr_curr */
+ U = Work->Fublock ; /* ldu is fnc_curr, stored by rows */
+ LU = Work->Flublock ; /* nb-by-nb */
+
+#ifndef NDEBUG
+ DEBUG5 (("DO RANK-NB UPDATE of frontal:\n")) ;
+ DEBUG5 (("DGEMM : "ID" "ID" "ID"\n", k, m, n)) ;
+ DEBUG7 (("C block: ")) ; UMF_dump_dense (C, d, m, n) ;
+ DEBUG7 (("A block: ")) ; UMF_dump_dense (L, d, m, k) ;
+ DEBUG7 (("B' block: ")) ; UMF_dump_dense (U, dc, n, k) ;
+ DEBUG7 (("LU block: ")) ; UMF_dump_dense (LU, nb, k, k) ;
+#endif
+
+ if (k == 1)
+ {
+
+#ifdef USE_NO_BLAS
+
+ /* no BLAS available - use plain C code instead */
+ Int i, j ;
+
+ /* rank-1 outer product to update the C block */
+ for (j = 0 ; j < n ; j++)
+ {
+ Entry u_j = U [j] ;
+ if (IS_NONZERO (u_j))
+ {
+ Entry *c_ij, *l_is ;
+ c_ij = & C [j*d] ;
+ l_is = & L [0] ;
+#pragma ivdep
+ for (i = 0 ; i < m ; i++)
+ {
+ /* C [i+j*d]-= L [i] * U [j] */
+ MULT_SUB (*c_ij, *l_is, u_j) ;
+ c_ij++ ;
+ l_is++ ;
+ }
+ }
+ }
+
+#else
+ BLAS_GER (m, n, L, U, C, d) ;
+
+#endif /* USE_NO_BLAS */
+
+ }
+ else
+ {
+
+#ifdef USE_NO_BLAS
+
+ /* no BLAS available - use plain C code instead */
+ Int i, j, s ;
+
+ /* triangular solve to update the U block */
+ for (s = 0 ; s < k ; s++)
+ {
+ for (i = s+1 ; i < k ; i++)
+ {
+ Entry l_is = LU [i+s*nb] ;
+ if (IS_NONZERO (l_is))
+ {
+ Entry *u_ij, *u_sj ;
+ u_ij = & U [i*dc] ;
+ u_sj = & U [s*dc] ;
+#pragma ivdep
+ for (j = 0 ; j < n ; j++)
+ {
+ /* U [i*dc+j] -= LU [i+s*nb] * U [s*dc+j] ; */
+ MULT_SUB (*u_ij, l_is, *u_sj) ;
+ u_ij++ ;
+ u_sj++ ;
+ }
+ }
+ }
+ }
+
+ /* rank-k outer product to update the C block */
+ /* C = C - L*U' (U is stored by rows, not columns) */
+ for (s = 0 ; s < k ; s++)
+ {
+ for (j = 0 ; j < n ; j++)
+ {
+ Entry u_sj = U [j+s*dc] ;
+ if (IS_NONZERO (u_sj))
+ {
+ Entry *c_ij, *l_is ;
+ c_ij = & C [j*d] ;
+ l_is = & L [s*d] ;
+#pragma ivdep
+ for (i = 0 ; i < m ; i++)
+ {
+ /* C [i+j*d]-= L [i+s*d] * U [s*dc+j] */
+ MULT_SUB (*c_ij, *l_is, u_sj) ;
+ c_ij++ ;
+ l_is++ ;
+ }
+ }
+ }
+ }
+
+#else
+
+ BLAS_TRSM_RIGHT (n, k, LU, nb, U, dc) ;
+ BLAS_GEMM (m, n, k, L, U, dc, C, d) ;
+
+#endif /* USE_NO_BLAS */
+
+ }
+
+#ifndef NDEBUG
+ DEBUG5 (("RANK-NB UPDATE of frontal done:\n")) ;
+ DEBUG5 (("DGEMM : "ID" "ID" "ID"\n", k, m, n)) ;
+ DEBUG7 (("C block: ")) ; UMF_dump_dense (C, d, m, n) ;
+ DEBUG7 (("A block: ")) ; UMF_dump_dense (L, d, m, k) ;
+ DEBUG7 (("B' block: ")) ; UMF_dump_dense (U, dc, n, k) ;
+ DEBUG7 (("LU block: ")) ; UMF_dump_dense (LU, nb, k, k) ;
+#endif
+
+ DEBUG2 (("blas3 "ID" "ID" "ID"\n", k, Work->fnrows, Work->fncols)) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_blas3_update
+(
+ WorkType *Work
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_build_tuples ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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,
+ *Col_tuples, *Col_degree, *Col_tlen, n1 ;
+ 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 ;
+ n1 = Work->n1 ;
+
+ 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 = n1 ; row < n_row ; row++)
+ {
+ if (NON_PIVOTAL_ROW (row))
+ {
+ Row_tuples [row] = UMF_mem_alloc_tail_block (Numeric,
+ UNITS (Tuple, TUPLES (Row_tlen [row]))) ;
+ if (!Row_tuples [row])
+ {
+ /* :: out of memory for row tuples :: */
+ DEBUGm4 (("out of memory: build row tuples\n")) ;
+ 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 >= n1 ; col--)
+ {
+ if (NON_PIVOTAL_COL (col))
+ {
+ Col_tuples [col] = UMF_mem_alloc_tail_block (Numeric,
+ UNITS (Tuple, TUPLES (Col_tlen [col]))) ;
+ if (!Col_tuples [col])
+ {
+ /* :: out of memory for col tuples :: */
+ DEBUGm4 (("out of memory: build col tuples\n")) ;
+ 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 >= n1 && 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 >= n1 && 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) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_build_tuples
+(
+ NumericType *Numeric,
+ WorkType *Work
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_colamd =========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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.
+
+NOTE: if this routine is used outside of UMFPACK, for a sparse Cholesky
+factorization of (AQ)'*(AQ) or a QR factorization of A, then one line should
+be removed (the "&& pivot_row_thickness > 0" expression). See the comment
+regarding the Cholesky factorization, below.
+
+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, DMS-9803599, and CCR-0203270.
+
+UMFPACK: Copyright (c) 2003 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 (double 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.
+
+ knobs [COLAMD_AGGRESSIVE]: if nonzero, then perform aggressive
+ absorption. Otherwise, do not. This version does aggressive
+ absorption by default. COLAMD v2.1 (in MATLAB) always
+ does aggressive absorption (it doesn't have an option to turn
+ it off).
+
+ ----------------------------------------------------------------------------
+ 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 moved to amd_internal.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_apply_order.h"
+#include "umf_fsize.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
+ , Int aggressive
+ , Int InFront [ ]
+ /* ------------------ */
+) ;
+
+/* ------------------ */
+/* 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] if nonzero, then perform aggressive absorption.
+
+ knobs [3..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 0
+ if (!knobs)
+ {
+ return ; /* UMFPACK always passes knobs array */
+ }
+#endif
+ 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 */
+ knobs [COLAMD_AGGRESSIVE] = TRUE ; /* default is to do aggressive
+ * absorption */
+}
+
+
+/* ========================================================================== */
+/* === 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.
+*/
+
+/* For UMFPACK: colamd always returns TRUE */
+
+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+1 */
+ , 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 */
+ , Int InFront [ ] /* InFront [row] = f if the original row was
+ * absorbed into front f. EMPTY if the row was
+ * empty, dense, or not absorbed. This array
+ * has size n_row+1 */
+ /* ------------------ */
+)
+{
+ /* === Local variables ================================================== */
+
+ Int row ; /* row index */
+ 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 */
+#if 0
+ Int need ; /* minimum required length of A */
+#endif
+ 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 */
+ Int aggressive ; /* TRUE if doing aggressive absorption */
+#if 0
+ double default_knobs [COLAMD_KNOBS] ; /* default knobs array */
+#endif
+
+ /* ------------------ */
+ /* debugging initializations moved for UMFPACK */
+ /* ------------------ */
+
+ /* ------------------ */
+ /* added for UMFPACK: */
+ Int ndense_row, nempty_row, parent, ndense_col,
+ nempty_col, k, col, nfr, *Front_child, *Front_sibling, *Front_stack,
+ *Front_order, *Front_size ;
+ Int nnewlyempty_col, nnewlyempty_row ;
+ /* ------------------ */
+
+ /* === Check the input arguments ======================================== */
+
+#if 0
+ if (!stats)
+ {
+ DEBUG0 (("colamd: stats not present\n")) ;
+ return (FALSE) ; /* UMFPACK: always passes stats [ ] */
+ }
+#endif
+
+ ASSERT (stats != (Int *) NULL) ;
+
+ for (i = 0 ; i < COLAMD_STATS ; i++)
+ {
+ stats [i] = 0 ;
+ }
+ stats [COLAMD_STATUS] = COLAMD_OK ;
+ stats [COLAMD_INFO1] = -1 ;
+ stats [COLAMD_INFO2] = -1 ;
+
+#if 0
+ 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) ;
+ }
+#endif
+
+ ASSERT (A != (Int *) NULL) ;
+ ASSERT (p != (Int *) NULL) ;
+ ASSERT (n_row >= 0) ;
+ ASSERT (n_col >= 0) ;
+
+ nnz = p [n_col] ;
+
+#if 0
+ 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) ;
+ }
+#endif
+
+ ASSERT (nnz >= 0) ;
+ ASSERT (p [0] == 0) ;
+
+ /* === If no knobs, set default knobs =================================== */
+
+#if 0
+ if (!knobs)
+ {
+ /* UMFPACK: always passes the knobs */
+ UMF_colamd_set_defaults (default_knobs) ;
+ knobs = default_knobs ;
+ }
+#endif
+
+ ASSERT (knobs != (double *) NULL) ;
+
+ /* --------------------- */
+ /* added for UMFPACK v4.1: */
+ aggressive = (knobs [COLAMD_AGGRESSIVE] != 0) ;
+ /* --------------------- */
+
+ /* === Allocate the Row and Col arrays from array A ===================== */
+
+ Col_size = UMF_COLAMD_C (n_col) ;
+ Row_size = UMF_COLAMD_R (n_row) ;
+
+#if 0
+ need = MAX (2*nnz, 4*n_col) + 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) ;
+ }
+#endif
+
+ Alen -= Col_size + Row_size ;
+ Col = (Colamd_Col *) &A [Alen] ;
+ Row = (Colamd_Row *) &A [Alen + Col_size] ;
+
+ /* Size of A is now Alen >= MAX (2*nnz, 4*n_col) + n_col. The ordering
+ * requires Alen >= 2*nnz + n_col, and the postorder requires
+ * Alen >= 5*n_col. */
+
+ /* === Construct the row and column data structures ===================== */
+
+ i = init_rows_cols (n_row, n_col, Row, Col, A, p) ;
+
+#if 0
+ if (!i)
+ {
+ /* input matrix is invalid */
+ DEBUG0 (("colamd: Matrix invalid\n")) ;
+ return (FALSE) ;
+ }
+#endif
+
+ ASSERT (i) ;
+
+ /* === 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, aggressive, InFront
+ /* ------------------ */
+ ) ;
+
+ /* ------------------ */
+ /* changed for UMFPACK: */
+
+ /* A is no longer needed, so use A [0..5*nfr-1] as workspace [ [ */
+ /* This step requires Alen >= 5*n_col */
+ Front_child = A ;
+ Front_sibling = Front_child + nfr ;
+ Front_stack = Front_sibling + nfr ;
+ Front_order = Front_stack + nfr ;
+ Front_size = Front_order + nfr ;
+
+ UMF_fsize (nfr, Front_size, Front_nrows, Front_ncols,
+ Front_parent, Front_npivcol) ;
+
+ AMD_postorder (nfr, Front_parent, Front_npivcol, Front_size,
+ Front_order, Front_child, Front_sibling, Front_stack) ;
+
+ /* Front_size, Front_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] ;
+ }
+ }
+
+ /* fix InFront to refer to the new numbering */
+ for (row = 0 ; row < n_row ; row++)
+ {
+ i = InFront [row] ;
+ ASSERT (i >= EMPTY && i < nfr) ;
+ if (i != EMPTY)
+ {
+ InFront [row] = Front_order [i] ;
+ }
+ }
+
+ /* 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] = EMPTY ;
+ }
+ 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) ;
+ DEBUG1 (("Colamd output ordering: k "ID" col "ID"\n", k, col)) ;
+ p [k] = col ;
+ ASSERT (A [col] == EMPTY) ;
+ A [col] = k ;
+ 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] == EMPTY)
+ {
+ k = Col [col].shared2.order ;
+ ASSERT (k >= n_col2 && k < n_col) ;
+ DEBUG1 (("Colamd output ordering: k "ID" col "ID
+ " (dense or null col)\n", k, 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.
+*/
+
+/* For UMFPACK, this always returns TRUE */
+
+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, removed for UMFPACK
+*/
+)
+{
+ /* === 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 */
+
+ /* === 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 0
+ 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) ;
+ }
+#endif
+
+ ASSERT (Col [col].length >= 0) ;
+
+ /* added for UMFPACK v4.1 */
+ ASSERT (Col [col].length > 0) ;
+
+ 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++)
+ {
+#ifndef NDEBUG
+ Int last_row = -1 ;
+#endif
+
+ cp = &A [p [col]] ;
+ cp_end = &A [p [col+1]] ;
+
+ while (cp < cp_end)
+ {
+ row = *cp++ ;
+
+#if 0
+ /* 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) ;
+ }
+#endif
+
+ ASSERT (row >= 0 && row < n_row) ;
+
+#if 0
+ /* ------------------ */
+ /* 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) ;
+ }
+ /* ------------------ */
+#endif
+
+ ASSERT (row > last_row) ;
+
+ /* ------------------ */
+ /* changed for UMFPACK - jumbled columns not tolerated */
+ Row [row].length++ ;
+ /* ------------------ */
+
+#ifndef NDEBUG
+ last_row = row ;
+#endif
+ }
+ }
+
+ /* === 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 */
+ /* ------------------ */
+
+ 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 =============================================== */
+
+ /* removed for UMFPACK v4.1. prune_singletons has already removed empty
+ * columns and empty rows */
+
+#if 0
+ /* 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)) ;
+#endif
+
+#ifndef NDEBUG
+ for (c = 0 ; c < n_col ; c++)
+ {
+ ASSERT (Col [c].length > 0) ;
+ }
+#endif
+
+ /* === Count null rows ================================================== */
+
+#if 0
+ for (r = 0 ; r < n_row ; r++)
+ {
+ deg = Row [r].shared1.degree ;
+ if (deg == 0)
+ {
+ /* this is an original empty row */
+ nempty_row++ ;
+ }
+ }
+#endif
+
+#ifndef NDEBUG
+ for (r = 0 ; r < n_row ; r++)
+ {
+ ASSERT (Row [r].shared1.degree > 0) ;
+ ASSERT (Row [r].length > 0) ;
+ }
+#endif
+
+ /* === Kill dense columns =============================================== */
+
+ /* Put the dense columns at the end, in their natural order */
+ for (c = n_col-1 ; c >= 0 ; c--)
+ {
+
+ /* ----------------------------------------------------------------- */
+#if 0
+ /* removed for UMFPACK v4.1: no empty columns */
+ /* skip any dead columns */
+ if (COL_IS_DEAD (c))
+ {
+ continue ;
+ }
+#endif
+ ASSERT (COL_IS_ALIVE (c)) ;
+ ASSERT (Col [c].length > 0) ;
+ /* ----------------------------------------------------------------- */
+
+ 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 ======================================== */
+
+ /* Note that there can now be empty rows, since dense columns have
+ * been deleted. These are "newly" 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 */
+ , Int aggressive
+ , Int InFront [ ]
+ /* ------------------ */
+)
+{
+ /* === 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)) ;
+
+ for (row = 0 ; row < n_row ; row++)
+ {
+ InFront [row] = EMPTY ;
+ }
+
+ /* === 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 %d "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++ ;
+
+ DEBUG2 (("Kill row in pivot col: "ID" alive? %d, front "ID"\n",
+ row, ROW_IS_ALIVE (row), Row [row].front)) ;
+
+ /* added for UMFPACK: */
+ if (ROW_IS_ALIVE (row))
+ {
+ if (Row [row].front != EMPTY)
+ {
+ /* This row represents a frontal matrix. */
+ /* Row [row].front is a child of current front */
+ child = Row [row].front ;
+ Front_parent [child] = nfr ;
+ DEBUG1 (("Front "ID" => front "ID", normal\n", child, nfr));
+ }
+ else
+ {
+ /* This is an original row. Keep track of which front
+ * is its parent in the row-merge tree. */
+ InFront [row] = nfr ;
+ DEBUG1 (("Row "ID" => front "ID", normal\n", row, 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) ;
+ ASSERT (ROW_IS_ALIVE (row)) ;
+
+ /* absorb this row if the set difference becomes zero */
+ if (set_difference == 0 && aggressive)
+ {
+ /* v4.1: do aggressive absorption */
+ DEBUG3 (("aggressive absorption. Row: "ID"\n", row)) ;
+
+ if (Row [row].front != EMPTY)
+ {
+ /* Row [row].front is a child of current front. */
+ child = Row [row].front ;
+ Front_parent [child] = nfr ;
+ DEBUG1 (("Front "ID" => front "ID", aggressive\n",
+ child, nfr)) ;
+ }
+ else
+ {
+ /* this is an original row. Keep track of which front
+ * assembles it, for the row-merge tree */
+ InFront [row] = nfr ;
+ DEBUG1 (("Row "ID" => front "ID", aggressive\n",
+ row, nfr)) ;
+ }
+
+ KILL_ROW (row) ;
+
+ /* sum the thicknesses of all the rows */
+ /* ASSERT (Row [row].thickness > 0) ; */
+ pivot_row_thickness += Row [row].thickness ;
+ Row [row].thickness = 0 ;
+
+ }
+ else
+ {
+ /* 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 */
+ /* NOTE: hash is an unsigned Int to avoid a problem in ANSI C.
+ * The sign of the expression a % b is not defined when a and/or
+ * b are negative. Since hash is unsigned and n_col >= 0,
+ * this problem is avoided. */
+ hash %= n_col + 1 ;
+
+ DEBUG4 ((" Hash = "ID", n_col = "ID".\n", (Int) hash, n_col)) ;
+ ASSERT (((Int) 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). */
+ cur_score = Col [col].shared2.score + pivot_row_degree ;
+ DEBUG3 ((" cur_score "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. Note that this part of the expression should be
+ * removed if this routine is used outside of UMFPACK, for a Cholesky
+ * factorization of (AQ)'(AQ) */
+ && 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]) ;
+ ASSERT (Row [pivot_row].length > 0) ;
+ 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)
+ {
+ /* :: defrag row kill :: */
+ /* This row is of zero length. cannot compact it, so kill it.
+ * NOTE: in the current version, there are no zero-length live
+ * rows when garbage_collection is called. So this code will
+ * never trigger. However, if the code is modified, or if
+ * garbage_collection is called at a different place, then rows
+ * can be of zero length. So this test is kept, just in case.
+ */
+ DEBUGm4 (("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? %d\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 ((" %d col "ID"\n", COL_IS_ALIVE (c), c)) ;
+ }
+ }
+
+ for (c = 0 ; c < n_col ; c++)
+ {
+ DEBUG3 (("Col "ID" alive? %d\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 ((" %d 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 */
--- /dev/null
+/* ========================================================================== */
+/* === umf_colamd.h ========================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+/*
+
+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.
+
+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, DMS-9803599, and CCR-0203270.
+
+UMFPACK: Copyright (c) 2003 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.
+
+*/
+
+#ifndef COLAMD_H
+#define COLAMD_H
+
+/* ========================================================================== */
+/* === Include files ======================================================== */
+/* ========================================================================== */
+
+#include <stdlib.h>
+
+/* ========================================================================== */
+/* === Knob and statistics definitions ====================================== */
+/* ========================================================================== */
+
+/* size of the knobs [ ] array. Only knobs [0..2] are currently used. */
+#define COLAMD_KNOBS 20
+
+/* number of output statistics. Only stats [0..8] are currently used. */
+#define COLAMD_STATS 20
+
+/* knobs [0] and stats [0]: dense row knob and output statistic. */
+#define COLAMD_DENSE_ROW 0
+
+/* knobs [1] and stats [1]: dense column knob and output statistic. */
+#define COLAMD_DENSE_COL 1
+
+/* knobs [2]: aggressive absorption option */
+#define COLAMD_AGGRESSIVE 2
+
+/* stats [2]: memory defragmentation count output statistic */
+#define COLAMD_DEFRAG_COUNT 2
+
+/* stats [3]: colamd status: zero OK, > 0 warning or notice, < 0 error */
+#define COLAMD_STATUS 3
+
+/* stats [4..6]: error info, or info on jumbled columns */
+#define COLAMD_INFO1 4
+#define COLAMD_INFO2 5
+#define COLAMD_INFO3 6
+
+/* ------------------ */
+/* added for UMFPACK: */
+/* stats [7]: number of originally empty rows */
+#define COLAMD_EMPTY_ROW 7
+/* stats [8]: number of originally empty cols */
+#define COLAMD_EMPTY_COL 8
+/* stats [9]: number of rows with entries only in dense cols */
+#define COLAMD_NEWLY_EMPTY_ROW 9
+/* stats [10]: number of cols with entries only in dense rows */
+#define COLAMD_NEWLY_EMPTY_COL 10
+/* ------------------ */
+
+/* error codes returned in stats [3]: */
+#define COLAMD_OK (0)
+#define COLAMD_ERROR_jumbled_matrix (-11)
+#define COLAMD_ERROR_A_not_present (-1)
+#define COLAMD_ERROR_p_not_present (-2)
+#define COLAMD_ERROR_nrow_negative (-3)
+#define COLAMD_ERROR_ncol_negative (-4)
+#define COLAMD_ERROR_nnz_negative (-5)
+#define COLAMD_ERROR_p0_nonzero (-6)
+#define COLAMD_ERROR_A_too_small (-7)
+#define COLAMD_ERROR_col_length_negative (-8)
+#define COLAMD_ERROR_row_index_out_of_bounds (-9)
+#define COLAMD_ERROR_out_of_memory (-10)
+#define COLAMD_ERROR_internal_error (-999)
+
+/* ========================================================================== */
+/* === Row and Column structures ============================================ */
+/* ========================================================================== */
+
+/* User code that makes use of the colamd/symamd routines need not directly */
+/* reference these structures. They are used only for the COLAMD_RECOMMENDED */
+/* macro. */
+
+typedef struct Colamd_Col_struct
+{
+ Int start ; /* index for A of first row in this column, or DEAD */
+ /* if column is dead */
+ Int length ; /* number of rows in this column */
+ union
+ {
+ Int thickness ; /* number of original columns represented by this */
+ /* col, if the column is alive */
+ Int parent ; /* parent in parent tree super-column structure, if */
+ /* the column is dead */
+ } shared1 ;
+ union
+ {
+ Int score ; /* the score used to maintain heap, if col is alive */
+ Int order ; /* pivot ordering of this column, if col is dead */
+ } shared2 ;
+ union
+ {
+ Int headhash ; /* head of a hash bucket, if col is at the head of */
+ /* a degree list */
+ Int hash ; /* hash value, if col is not in a degree list */
+ Int prev ; /* previous column in degree list, if col is in a */
+ /* degree list (but not at the head of a degree list) */
+ } shared3 ;
+ union
+ {
+ Int degree_next ; /* next column, if col is in a degree list */
+ Int hash_next ; /* next column, if col is in a hash list */
+ } shared4 ;
+
+ /* ------------------ */
+ /* added for UMFPACK: */
+ Int nextcol ; /* next column in this supercolumn */
+ Int lastcol ; /* last column in this supercolumn */
+ /* ------------------ */
+
+} Colamd_Col ;
+
+typedef struct Colamd_Row_struct
+{
+ Int start ; /* index for A of first col in this row */
+ Int length ; /* number of principal columns in this row */
+ union
+ {
+ Int degree ; /* number of principal & non-principal columns in row */
+ Int p ; /* used as a row pointer in init_rows_cols () */
+ } shared1 ;
+ union
+ {
+ Int mark ; /* for computing set differences and marking dead rows*/
+ Int first_column ;/* first column in row (used in garbage collection) */
+ } shared2 ;
+
+ /* ------------------ */
+ /* added for UMFPACK: */
+ Int thickness ; /* number of original rows represented by this row */
+ /* that are not yet pivotal */
+ Int front ; /* -1 if an original row */
+ /* k if this row represents the kth frontal matrix */
+ /* where k goes from 0 to at most n_col-1 */
+ /* ------------------ */
+
+} Colamd_Row ;
+
+
+
+/* ========================================================================== */
+/* === Colamd recommended memory size ======================================= */
+/* ========================================================================== */
+
+/*
+ The recommended length Alen of the array A passed to colamd is given by
+ the COLAMD_RECOMMENDED (nnz, n_row, n_col) macro. It returns -1 if any
+ argument is negative. 2*nnz space is required for the row and column
+ indices of the matrix. COLAMD_C (n_col) + COLAMD_R (n_row) space is
+ required for the Col and Row arrays, respectively, which are internal to
+ colamd. An additional n_col space is the minimal amount of "elbow room",
+ and nnz/5 more space is recommended for run time efficiency.
+
+ This macro is not needed when using symamd.
+*/
+
+/* about 8*(n_col+1) integers: */
+#define UMF_COLAMD_C(n_col) ((n_col + 1) * sizeof (Colamd_Col) / sizeof (Int))
+
+/* about 6*(n_row+1) integers: */
+#define UMF_COLAMD_R(n_row) ((n_row + 1) * sizeof (Colamd_Row) / sizeof (Int))
+
+/* UMFPACK: make sure Alen is >= 5*n_col + size of Col and Row structures.
+ * Alen is typically about 2.2*nz + 9*n_col + 6*n_row, or 2.2nz+15n for
+ * square matrices. */
+#define UMF_COLAMD_RECOMMENDED(nnz, n_row, n_col) \
+( \
+((nnz) < 0 || (n_row) < 0 || (n_col) < 0) \
+? \
+ (-1) \
+: \
+ (MAX (2 * (nnz), 4 * (n_col)) + \
+ (Int) UMF_COLAMD_C (n_col) + \
+ (Int) UMF_COLAMD_R (n_row) + (n_col) + ((nnz) / 5)) \
+)
+
+/* ========================================================================== */
+/* === Prototypes of user-callable routines ================================= */
+/* ========================================================================== */
+
+/* colamd_recommended removed for UMFPACK */
+
+void UMF_colamd_set_defaults /* sets default parameters */
+( /* knobs argument is modified on output */
+ double knobs [COLAMD_KNOBS] /* parameter settings for colamd */
+) ;
+
+Int UMF_colamd /* returns (1) if successful, (0) otherwise*/
+( /* A and p arguments are modified on output */
+ Int n_row, /* number of rows in A */
+ Int n_col, /* number of columns in A */
+ Int Alen, /* size of the array A */
+ Int A [], /* row indices of A, of size Alen */
+ Int p [], /* column pointers of A, of size n_col+1 */
+ double knobs [COLAMD_KNOBS],/* parameter settings for colamd */
+ Int stats [COLAMD_STATS] /* colamd output statistics and error codes */
+ /* ------------------ */
+ /* added for UMFPACK: */
+ , Int Front_npivcol [ ]
+ , Int Front_nrows [ ]
+ , Int Front_ncols [ ]
+ , Int Front_parent [ ]
+ , Int Front_cols [ ]
+ , Int *p_nfr
+ , Int InFront [ ]
+ /* ------------------ */
+) ;
+
+/* symamd deleted for UMFPACK */
+
+/* colamd_report deleted for UMFPACK */
+
+/* symamd_report deleted for UMFPACK */
+
+#endif /* COLAMD_H */
--- /dev/null
+/* ========================================================================== */
+/* === umf_config.h ========================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+/*
+ This file controls the compile-time configuration of UMFPACK. Modify the
+ Makefile, the architecture-dependent Make.* file, and this file if
+ necessary, to control these options. The following flags may be given
+ as options to your C compiler (as in "cc -DNBLAS", for example). These
+ flags are normally placed in your CONFIG string, defined in your Make.*.
+
+ All of these options, except for the timer, are for accessing the BLAS.
+
+ -DNBLAS
+
+ BLAS mode. If -DNBLAS is set, then no BLAS will be used. Vanilla
+ C code will be used instead. This is portable, and easier to
+ install, but you won't get the best performance.
+
+ If -DNBLAS is not set, then externally-available BLAS routines
+ (dgemm, dger, and dgemv or the equivalent C-BLAS routines) will be
+ used. This will give you the best performance, but perhaps at the
+ expense of portability.
+
+ The default is to use the BLAS, for both the C-callable libumfpack.a
+ library and the MATLAB mexFunction. If you have trouble installing
+ UMFPACK, set -DNBLAS (but then UMFPACK will be slow).
+
+ -DCBLAS
+
+ If -DCBLAS is set, then the C-BLAS interface to the BLAS is
+ used. If your vendor-supplied BLAS library does not have a C-BLAS
+ interface, you can obtain the ATLAS BLAS, available at
+ http://www.netlib.org/atlas.
+
+ This flag is ignored if -DNBLAS is set.
+
+ -DLP64
+
+ This should be defined if you are compiling in the LP64 model
+ (32 bit int's, 64 bit long's, and 64 bit pointers). In Solaris,
+ this is obtained with the flags -xtarget=ultra -xarch=v9 for
+ the cc compiler (for example).
+
+ -DLONGBLAS
+
+ If not defined, then the BLAS are not called in the long integer
+ version of UMFPACK (the umfpack_*l_* routines). The most common
+ definitions of the BLAS, unfortunately, use int arguments, and
+ are thus not suitable for use in the LP64 model. Only the Sun
+ Performance Library, as far as I can tell, has a version of the
+ BLAS that allows long integer (64-bit) input arguments. This
+ flag is set automatically in Sun Solaris if you are using the
+ Sun Performance BLAS. You can set it yourself, too, if your BLAS
+ routines can take long integer input arguments.
+
+ -DNSUNPERF
+
+ Applies only to Sun Solaris. If -DNSUNPERF is set, then the Sun
+ Performance Library BLAS will not be used.
+
+ The Sun Performance Library BLAS is used by default when compiling
+ the C-callable libumfpack.a library on Sun Solaris.
+
+ This flag is ignored if -DNBLAS is set.
+
+ -DNSCSL
+
+ Applies only to SGI IRIX. If -DSCSL is set, then the SGI SCSL
+ Scientific Library BLAS will not be used.
+
+ The SGI SCSL Scientific Library BLAS is used by default when
+ compiling the C-callable libumfpack.a library on SGI IRIX.
+
+ This flag is ignored if -DNBLAS is set.
+
+ -DNPOSIX
+
+ If -DNPOSIX is set, then your Unix operating system is not POSIX-
+ compliant, and the POSIX routines sysconf ( ) and times ( )
+ routines are not used. These routines provide CPU time and
+ wallclock time information. If -DNPOSIX is set, then the ANSI
+ C clock ( ) routine is used. If -DNPOSIX is not set, then
+ sysconf ( ) and times ( ) are used in umfpack_tic and umfpack_toc.
+ See umfpack_tictoc.c for more information.
+ The default is to use the POSIX routines, except for Windows,
+ which is not POSIX-compliant.
+
+ -DGETRUSAGE
+
+ If -DGETRUSAGE is set, then your system's getrusage ( ) routine
+ will be used for getting the process CPU time. Otherwise the ANSI
+ C clock ( ) routine will be used. The default is to use getrusage
+ ( ) on Unix systems, and to use clock on all other architectures.
+
+ -DNO_TIMER
+
+ If -DNO_TIMER is set, then no timing routines are used at all.
+
+ -DNUTIL
+
+ If -DNUTIL is set, then the internal MATLAB utMalloc, utFree, and
+ utRealloc routines are not used in the UMFPACK mexFunction. The
+ regular mxMalloc, mxFree, and mxRealloc routines are used instead.
+ These routines are not documented, but are available for use. For
+ Windows, -DNUTIL is defined below, because access to the ut*
+ routines is not available by default.
+
+ -DNRECIPROCAL
+
+ This option controls a tradeoff between speed and accuracy. Using
+ -DNRECIPROCAL can lead to more accurate results, but with perhaps
+ some cost in performance, particularly if floating-point division
+ is much more costly than floating-point multiplication.
+
+ This option determines the method used to scale the pivot column.
+ If set, or if the absolute value of the pivot is < 1e-12 (or is a
+ NaN), then the pivot column is divided by the pivot value.
+ Otherwise, the reciprocal of the pivot value is computed, and the
+ pivot column is multiplied by (1/pivot). Multiplying by the
+ reciprocal can be slightly less accurate than dividing by the
+ pivot, but it is often faster. See umf_scale.c.
+
+ This has a small effect on the performance of UMFPACK, at least on
+ a Pentium 4M. It may have a larger effect on other architectures
+ where floating-point division is much more costly than floating-
+ point multiplication. The RS 6000 is one such example.
+
+ By default, the method chosen is to multiply by the reciprocal
+ (sacrificing accuracy for speed), except when compiling UMFPACK
+ as a built-in routine in MATLAB, or when gcc is being used.
+
+ When MATHWORKS is defined, -DNRECIPROCAL is forced on, and the pivot
+ column is divided by the pivot value. The only way of using the
+ other method in this case is to edit this file.
+
+ If -DNRECIPROCAL is enabled, then the row scaling factors are always
+ applied by dividing each row by the scale factor, rather than
+ multiplying by the reciprocal. If -DNRECIPROCAL is not enabled
+ (the default case), then the scale factors are normally applied by
+ multiplying by the reciprocal. If, however, the smallest scale
+ factor is tiny, then the scale factors are applied via division.
+
+ -DNO_DIVIDE_BY_ZERO
+
+ If the pivot is zero, and this flag is set, then no divide-by-zero
+ occurs.
+
+ You should normally not set these flags yourself:
+
+ -DBLAS_BY_VALUE if scalars are passed by value, not reference
+ -DBLAS_NO_UNDERSCORE if no underscore should be appended
+ -DBLAS_CHAR_ARG if BLAS options are single char's, not strings
+
+ The BLAS options are normally set automatically. If your
+ architecture cannot be determined (see UMFPACK_ARCHITECTURE, below)
+ then you may need to set these flags yourself.
+
+ The following options are controlled by amd_internal.h:
+
+ -DMATLAB_MEX_FILE
+
+ This flag is turned on when compiling the umfpack mexFunction for
+ use in MATLAB. When compiling the MATLAB mexFunction, the MATLAB
+ BLAS are used (unless -DNBLAS is set). The -DCBLAS, -DNSCSL, and
+ -DNSUNPERF flags are all ignored. The -DNRECIPROCAL flag is
+ forced on. Otherwise, [L,U,P,Q,R] = umfpack (A) would return
+ either L*U = P*(R\A)*Q or L*U = P*R*A*Q. Rather than returning a
+ flag stating how the scale factors R are to be applied, the umfpack
+ mexFunction always takes the more accurate route and returns
+ L*U = P*(R\A)*Q.
+
+ -DMATHWORKS
+
+ This flag is turned on when compiling umfpack as a built-in routine
+ in MATLAB. The MATLAB BLAS are used for all architectures (-DNBLAS,
+ -DCBLAS, -DNSCSL, and -DNSUNPERF flags are all ignored). Internal
+ routines utMalloc, utFree, utRealloc, utPrintf, utDivideComplex,
+ and utFdlibm_hypot are used, and the "util.h" file is included.
+ This avoids the problem discussed in the User Guide regarding memory
+ allocation in MATLAB. utMalloc returns NULL on failure, instead of
+ terminating the mexFunction (which is what mxMalloc does). However,
+ the ut* routines are not documented by The MathWorks, Inc., so I
+ cannot guarantee that you will always be able to use them.
+ The -DNRECIPROCAL flag is turned on.
+
+ -DNDEBUG
+
+ Debugging mode (if NDEBUG is not defined). The default, of course,
+ is no debugging. Turning on debugging takes some work (see below).
+ If you do not edit this file, then debugging is turned off anyway,
+ regardless of whether or not -DNDEBUG is specified in your compiler
+ options.
+*/
+
+/* ========================================================================== */
+/* === AMD configuration ==================================================== */
+/* ========================================================================== */
+
+/* NDEBUG, PRINTF defined in amd_internal.h */
+
+/* ========================================================================== */
+/* === reciprocal option ==================================================== */
+/* ========================================================================== */
+
+/* Force the definition NRECIPROCAL when MATHWORKS or MATLAB_MEX_FILE
+ * are defined. Do not multiply by the reciprocal in those cases. */
+
+#ifndef NRECIPROCAL
+#if defined (MATHWORKS) || defined (MATLAB_MEX_FILE)
+#define NRECIPROCAL
+#endif
+#endif
+
+/* ========================================================================== */
+/* === Microsoft Windows configuration ====================================== */
+/* ========================================================================== */
+
+#ifdef UMF_WINDOWS
+/* Windows can't access the ut* routines, and it isn't Unix. */
+#define NUTIL
+#define NPOSIX
+#endif
+
+/* ========================================================================== */
+/* === 0-based or 1-based printing ========================================== */
+/* ========================================================================== */
+
+#if defined (MATLAB_MEX_FILE) && defined (NDEBUG)
+/* In MATLAB, matrices are 1-based to the user, but 0-based internally. */
+/* One is added to all row and column indices when printing matrices */
+/* for the MATLAB user. The +1 shift is turned off when debugging. */
+#define INDEX(i) ((i)+1)
+#else
+/* In ANSI C, matrices are 0-based and indices are reported as such. */
+/* This mode is also used for debug mode, and if MATHWORKS is defined rather */
+/* than MATLAB_MEX_FILE. */
+#define INDEX(i) (i)
+#endif
+
+/* ========================================================================== */
+/* === Timer ================================================================ */
+/* ========================================================================== */
+
+/*
+ If you have the getrusage routine (all Unix systems I've test do), then use
+ that. Otherwise, use the ANSI C clock function. Note that on many
+ systems, the ANSI clock function wraps around after only 2147 seconds, or
+ about 36 minutes. BE CAREFUL: if you compare the run time of UMFPACK with
+ other sparse matrix packages, be sure to use the same timer. See
+ umfpack_tictoc.c for the timer used internally by UMFPACK. See also
+ umfpack_timer.c for the timer used in an earlier version of UMFPACK (V4.0).
+ That timer is still available as a user-callable routine, but it is no
+ longer used internally by UMFPACK.
+*/
+
+/* Sun Solaris, SGI Irix, Linux, Compaq Alpha, and IBM RS 6000 all have */
+/* getrusage. It's in BSD unix, so perhaps all unix systems have it. */
+#if defined (UMF_SOL2) || defined (UMF_SGI) || defined (UMF_LINUX) \
+|| defined (UMF_ALPHA) || defined (UMF_AIX)
+#define GETRUSAGE
+#endif
+
+
+/* ========================================================================== */
+/* === BLAS ================================================================= */
+/* ========================================================================== */
+
+/*
+ The adventure begins. Figure out how to call the BLAS ...
+
+ This works, but it is incredibly ugly. The C-BLAS was supposed to solve
+ this problem, and make it easier to interface a C program to the BLAS.
+ Unfortunately, the C-BLAS does not have a "long" integer (64 bit) version.
+ Various vendors have done their own 64-bit BLAS. Sun has dgemm_64 routines
+ with "long" integers, SGI has a 64-bit dgemm in their scsl_blas_i8 library
+ with "long long" integers, and so on.
+
+ Different vendors also have different ways of defining a complex number,
+ some using struct's. That's a bad idea. See umf_version.h for the better
+ way to do it (the method that was also chosen for the complex C-BLAS,
+ which is compatible and guaranteed to be portable with ANSI C).
+
+ To make matters worse, SGI's SCSL BLAS has a C-BLAS interface which
+ differs from the ATLAS C-BLAS interface (see immediately below);
+ although a more recent version of SGI's C-BLAS interface is correct
+ if SCSL_VOID_ARGS is defined.
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* Determine which BLAS to use. */
+/* -------------------------------------------------------------------------- */
+
+#if defined (MATHWORKS)
+#define USE_MATLAB_BLAS
+
+#elif defined (NBLAS)
+#define USE_NO_BLAS
+
+#elif defined (MATLAB_MEX_FILE)
+#define USE_MATLAB_BLAS
+
+#elif defined (CBLAS)
+#define USE_C_BLAS
+
+#elif defined (UMF_SOL2) && !defined (NSUNPERF)
+#define USE_SUNPERF_BLAS
+
+#elif defined (UMF_SGI) && !defined (NSCSL)
+#define USE_SCSL_BLAS
+
+#else
+#define USE_FORTRAN_BLAS
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* int vs. long integer arguments */
+/* -------------------------------------------------------------------------- */
+
+/*
+ Determine if the BLAS exists for the long integer version. It exists if
+ LONGBLAS is defined in the Makefile, or if using the BLAS from the
+ Sun Performance Library, or SGI's SCSL Scientific Library.
+*/
+
+#if defined (USE_SUNPERF_BLAS) || defined (USE_SCSL_BLAS)
+#ifndef LONGBLAS
+#define LONGBLAS
+#endif
+#endif
+
+/* do not use the BLAS if Int's are long and LONGBLAS is not defined */
+#if defined (LONG_INTEGER) && !defined (LONGBLAS) && !defined (USE_NO_BLAS)
+#define USE_NO_BLAS
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* Use (void *) arguments for the SGI */
+/* -------------------------------------------------------------------------- */
+
+#if defined (UMF_SGI)
+/*
+ Use (void *) pointers for complex types in SCSL.
+ The ATLAS C-BLAS, and the SGI C-BLAS differ. The former uses (void *)
+ arguments, the latter uses SCSL_ZOMPLEX_T, which are either scsl_zomplex
+ or (void *). Using (void *) is simpler, and is selected by defining
+ SCSL_VOID_ARGS, below. The cc compiler doesn't complain, but gcc is
+ more picky, and generates a warning without this next statement.
+ With gcc and the 07/09/98 version of SGI's cblas.h, spurious warnings
+ about complex BLAS arguments will be reported anyway. This is because this
+ older version of SGI's cblas.h does not make use of the SCSL_VOID_ARGS
+ parameter, which is present in the 12/6/01 version of SGI's cblas.h. You
+ can safely ignore these warnings.
+*/
+#define SCSL_VOID_ARGS
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* The BLAS exists, construct appropriate macros */
+/* -------------------------------------------------------------------------- */
+
+#if !defined (USE_NO_BLAS) /* { */
+
+/*
+ If the compile-time flag -DNBLAS is defined, then the BLAS are not used,
+ portable vanilla C code is used instead, and the remainder of this file
+ is ignored.
+
+ Using the BLAS is much faster, but how C calls the Fortran BLAS is
+ machine-dependent and thus can cause portability problems. Thus, use
+ -DNBLAS to ensure portability (at the expense of speed).
+
+ Preferences:
+
+ *** The best interface to use, regardless of the option you select
+ below, is the standard C-BLAS interface. Not all BLAS libraries
+ use this interface. The only problem with this interface is that
+ it does not extend to the LP64 model. The C-BLAS does not provide
+ for a 64-bit integer. In addition, SGI's older cblas.h can cause
+ spurious warnings when using the C-BLAS interface.
+
+ 1) often the most preferred (but see option (3)): use the
+ optimized vendor-supplied library (such as the Sun Performance
+ Library, or IBM's ESSL). This is often the fastest, but might not
+ be portable and might not always be available. When compiling a
+ MATLAB mexFunction it might be difficult get the mex compiler
+ script to recognize the vendor- supplied BLAS. Note that the
+ freely-available BLAS (option 3) can be faster than the vendor-
+ specific BLAS. You are encourage to try both option (1) and (3).
+
+ 2) When compiling the UMFPACK mexFunction to use UMFPACK in MATLAB, use
+ the BLAS provided by The Mathworks, Inc. This assumes you are using
+ MATLAB V6 or higher, since the BLAS are not incorporated in V5 or
+ earlier versions. On my Sun workstation, the MATLAB BLAS gave
+ slightly worse performance than the Sun Perf. BLAS. The advantage
+ of using the MATLAB BLAS is that it's available on any computer that
+ has MATLAB V6 or higher. I have not tried using MATLAB BLAS outside
+ of a mexFunction in a stand-alone C code, but MATLAB (V6) allows for
+ this. This is well worth trying if you have MATLAB and don't want
+ to bother installing the ATLAS BLAS (option 3a, below). The only
+ glitch to this is that MATLAB does not provide a portable interface
+ to the BLAS (an underscore is required for some but not all
+ architectures). For Windows and MATLAB 6.0 or 6.1, you also need
+ to copy the libmwlapack.dll file into your MATLAB installation
+ directory; see the User Guide for details.
+
+ In the current distribution, the only BLAS that the UMFPACK
+ mexFunction will use is the internal MATLAB BLAS. It's possible to
+ use other BLAS, but handling the porting of using the mex compiler
+ with different BLAS libraries is not trivial.
+
+ As of MATLAB 6.5, the BLAS used internally in MATLAB is the ATLAS
+ BLAS.
+
+ 3) Use a freely-available high-performance BLAS library:
+
+ (a) The BLAS by Kazashige Goto and Robert van de Geijn, at
+ http://www.cs.utexas.edu/users/flame/goto. This BLAS increased
+ the performance of UMFPACK by almost 50% as compared to the
+ ATLAS BLAS (v3.2).
+
+ (b) The ATLAS BLAS, available at http://www.netlib.org/atlas,
+ by R. Clint Whaley, Antoine Petitet, and Jack Dongarra.
+ This has a standard C interface, and thus the interface to it is
+ fully portable. Its performance rivals, and sometimes exceeds,
+ the vendor-supplied BLAS on many computers.
+
+ (b) The Fortran RISC BLAS by Michel Dayde', Iain Duff, Antoine
+ Petitet, and Abderrahim Qrichi Aniba, available via anonymous
+ ftp to ftp.enseeiht.fr in the pub/numerique/BLAS/RISC directory,
+ See M. J. Dayde' and I. S. Duff, "The RISC BLAS: A blocked
+ implementation of level 3 BLAS for RISC processors, ACM Trans.
+ Math. Software, vol. 25, no. 3., Sept. 1999. This will give
+ you good performance, but with the same C-to-Fortran portability
+ problems as option (1).
+
+ 4) Use UMFPACK's built-in vanilla C code by setting -DNBLAS at compile
+ time. The key advantage is portability, which is guaranteed if you
+ have an ANSI C compliant compiler. You also don't need to download
+ any other package - UMFPACK is stand-alone. No Fortran is used
+ anywhere in UMFPACK. UMFPACK will be much slower than when using
+ options (1) through (3), however.
+
+ 5) least preferred: use the standard Fortran implementation of the
+ BLAS, also available at Netlib (http://www.netlib.org/blas). This
+ will be no faster than option (4), and not portable because of
+ C-to-Fortran calling conventions. Don't bother trying option (5).
+
+ The mechanics of how C calls the BLAS on various computers are as follows:
+
+ * C-BLAS (from the ATLAS library, for example):
+ The same interface is used on all computers.
+
+ * Defaults for calling the Fortran BLAS:
+ add underscore, pass scalars by reference, use string arguments.
+
+ * The Fortran BLAS on Sun Solaris (when compiling the MATLAB mexFunction
+ or when using the Fortran RISC BLAS), SGI IRIX, Linux, and Compaq
+ Alpha: use defaults.
+
+ * Sun Solaris (when using the C-callable Sun Performance library):
+ no underscore, pass scalars by value, use character arguments.
+
+ * The Fortran BLAS (ESSL Library) on the IBM RS 6000, and HP Unix:
+ no underscore, pass scalars by reference, use string arguments.
+
+ * The Fortran BLAS on Windows:
+ no underscore, pass scalars by reference, use string arguments.
+ If you compile the umfpack mexFunction using umfpack_make, and are
+ using the lcc compiler bundled with MATLAB, then you must first
+ copy the umfpack\lcc_lib\libmwlapack.lib file into the
+ <matlab>\extern\lib\win32\lcc\ directory, where <matlab> is the
+ directory in which MATLAB is installed. Next, type mex -setup
+ at the MATLAB prompt, and ask MATLAB to select the lcc compiler.
+ MATLAB has built-in BLAS, but it cannot be accessed by a program
+ compiled by lcc without first copying this file.
+*/
+
+
+
+/* -------------------------------------------------------------------------- */
+#ifdef USE_C_BLAS /* { */
+/* -------------------------------------------------------------------------- */
+
+
+/* -------------------------------------------------------------------------- */
+/* use the C-BLAS (any computer) */
+/* -------------------------------------------------------------------------- */
+
+/*
+ C-BLAS is the default interface, with the following exceptions. Solaris
+ uses the Sun Performance BLAS for libumfpack.a (the C-callable library).
+ SGI IRIX uses the SCSL BLAS for libumfpack.a. All architectures use
+ MATLAB's internal BLAS for the mexFunction on any architecture. These
+ options are set in the Make.* files. The Make.generic file uses no BLAS
+ at all.
+
+ If you use the ATLAS C-BLAS, then be sure to set the -I flag to
+ -I/path/ATLAS/include, where /path/ATLAS is the ATLAS installation
+ directory. See Make.solaris for an example. You do not need to do this
+ for the SGI, which has a /usr/include/cblas.h.
+*/
+
+#include "cblas.h"
+
+#ifdef COMPLEX
+#define BLAS_GEMM_ROUTINE cblas_zgemm
+#define BLAS_TRSM_ROUTINE cblas_ztrsm
+#define BLAS_TRSV_ROUTINE cblas_ztrsv
+#define BLAS_GEMV_ROUTINE cblas_zgemv
+#define BLAS_GER_ROUTINE cblas_zgeru
+#define BLAS_SCAL_ROUTINE cblas_zscal
+#define BLAS_COPY_ROUTINE cblas_zcopy
+#define BLAS_DECLARE_SCALAR(x) double x [2]
+#define BLAS_ASSIGN(x,xr,xi) { x [0] = xr ; x [1] = xi ; }
+#else
+#define BLAS_GEMM_ROUTINE cblas_dgemm
+#define BLAS_TRSM_ROUTINE cblas_dtrsm
+#define BLAS_TRSV_ROUTINE cblas_dtrsv
+#define BLAS_GEMV_ROUTINE cblas_dgemv
+#define BLAS_GER_ROUTINE cblas_dger
+#define BLAS_SCAL_ROUTINE cblas_dscal
+#define BLAS_COPY_ROUTINE cblas_dcopy
+#define BLAS_DECLARE_SCALAR(x) double x
+#define BLAS_ASSIGN(x,xr,xi) { x = xr ; }
+#endif
+
+#define BLAS_LOWER CblasLower
+#define BLAS_UNIT_DIAGONAL CblasUnit
+#define BLAS_RIGHT CblasRight
+#define BLAS_NO_TRANSPOSE CblasNoTrans
+#define BLAS_TRANSPOSE CblasTrans
+#define BLAS_COLUMN_MAJOR_ORDER CblasColMajor,
+#define BLAS_SCALAR(x) x
+#define BLAS_INT_SCALAR(n) n
+#define BLAS_ARRAY(a) a
+
+
+
+/* -------------------------------------------------------------------------- */
+#else /* } USE_C_BLAS { */
+/* -------------------------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* use Fortran (or other architecture-specific) BLAS */
+/* -------------------------------------------------------------------------- */
+
+/* No such argument when not using the C-BLAS */
+#define BLAS_COLUMN_MAJOR_ORDER
+
+/* Determine which architecture we're on and set options accordingly. */
+/* The default, if nothing is defined is to add an underscore, */
+/* pass scalars by reference, and use string arguments. */
+
+/* ---------------------------------- */
+/* Sun Performance BLAS */
+/* ---------------------------------- */
+
+#ifdef USE_SUNPERF_BLAS
+#ifdef _SUNPERF_H
+/* <sunperf.h> has been included somehow anyway, outside of umf_config.h */
+#error "sunperf.h must NOT be #include'd. See umf_config.h for details."
+#endif
+#define BLAS_BY_VALUE
+#define BLAS_NO_UNDERSCORE
+#define BLAS_CHAR_ARG
+#endif /* USE_SUNPERF_BLAS */
+
+/* ---------------------------------- */
+/* SGI SCSL BLAS */
+/* ---------------------------------- */
+
+#ifdef USE_SCSL_BLAS
+#if defined (LP64)
+#include <scsl_blas_i8.h>
+#else
+#include <scsl_blas.h>
+#endif
+#define BLAS_BY_VALUE
+#define BLAS_NO_UNDERSCORE
+#endif /* USE_SCSL_BLAS */
+
+/* ---------------------------------- */
+/* IBM AIX, Windows, and HP Fortran BLAS */
+/* ---------------------------------- */
+
+#if defined (UMF_AIX) || defined (UMF_WINDOWS) || defined (UMF_HP)
+#define BLAS_NO_UNDERSCORE
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* BLAS names */
+/* -------------------------------------------------------------------------- */
+
+#if defined (LP64) && defined (USE_SUNPERF_BLAS) && defined (LONG_INTEGER)
+
+/* 64-bit sunperf BLAS, for Sun Solaris only */
+#ifdef COMPLEX
+#define BLAS_GEMM_ROUTINE zgemm_64
+#define BLAS_TRSM_ROUTINE ztrsm_64
+#define BLAS_TRSV_ROUTINE ztrsv_64
+#define BLAS_GEMV_ROUTINE zgemv_64
+#define BLAS_GER_ROUTINE zgeru_64
+#define BLAS_SCAL_ROUTINE zscal_64
+#define BLAS_COPY_ROUTINE zcopy_64
+#else
+#define BLAS_GEMM_ROUTINE dgemm_64
+#define BLAS_TRSM_ROUTINE dtrsm_64
+#define BLAS_TRSV_ROUTINE dtrsv_64
+#define BLAS_GEMV_ROUTINE dgemv_64
+#define BLAS_GER_ROUTINE dger_64
+#define BLAS_SCAL_ROUTINE dscal_64
+#define BLAS_COPY_ROUTINE dcopy_64
+#endif /* COMPLEX */
+
+#else
+
+#ifdef COMPLEX
+
+/* naming convention (use underscore, or not) */
+#ifdef BLAS_NO_UNDERSCORE
+#define BLAS_GEMM_ROUTINE zgemm
+#define BLAS_TRSM_ROUTINE ztrsm
+#define BLAS_TRSV_ROUTINE ztrsv
+#define BLAS_GEMV_ROUTINE zgemv
+#define BLAS_GER_ROUTINE zgeru
+#define BLAS_SCAL_ROUTINE zscal
+#define BLAS_COPY_ROUTINE zcopy
+#else
+/* default: add underscore */
+#define BLAS_GEMM_ROUTINE zgemm_
+#define BLAS_TRSM_ROUTINE ztrsm_
+#define BLAS_TRSV_ROUTINE ztrsv_
+#define BLAS_GEMV_ROUTINE zgemv_
+#define BLAS_GER_ROUTINE zgeru_
+#define BLAS_SCAL_ROUTINE zscal_
+#define BLAS_COPY_ROUTINE zcopy_
+#endif
+
+#else
+
+/* naming convention (use underscore, or not) */
+#ifdef BLAS_NO_UNDERSCORE
+#define BLAS_GEMM_ROUTINE dgemm
+#define BLAS_TRSM_ROUTINE dtrsm
+#define BLAS_TRSV_ROUTINE dtrsv
+#define BLAS_GEMV_ROUTINE dgemv
+#define BLAS_GER_ROUTINE dger
+#define BLAS_SCAL_ROUTINE dscal
+#define BLAS_COPY_ROUTINE dcopy
+#else
+/* default: add underscore */
+#define BLAS_GEMM_ROUTINE dgemm_
+#define BLAS_TRSM_ROUTINE dtrsm_
+#define BLAS_TRSV_ROUTINE dtrsv_
+#define BLAS_GEMV_ROUTINE dgemv_
+#define BLAS_GER_ROUTINE dger_
+#define BLAS_SCAL_ROUTINE dscal_
+#define BLAS_COPY_ROUTINE dcopy_
+#endif
+
+#endif /* COMPLEX */
+
+#endif /* LP64 && USE_SUNPERF_BLAS */
+
+
+/* -------------------------------------------------------------------------- */
+/* BLAS real or complex floating-point scalars */
+/* -------------------------------------------------------------------------- */
+
+#ifdef COMPLEX
+
+/*
+ The SunPerf BLAS expects to see a doublecomplex scalar, but it
+ also will accept an array of size 2. See the manual, normally at
+ file:///opt/SUNWspro/WS6U1/lib/locale/C/html/manuals/perflib/user_guide
+ /plug_using_perflib.html . This manual is inconsistent with the man pages
+ for zgemm, zgemv, and zgeru and also inconsistent with the <sunperf.h>
+ include file. Use this instead, for SunPerf (only works if you do NOT
+ include sunperf.h). Fortunately, this file (umf_config.h) is not included
+ in any user code that calls UMFPACK. Thus, the caller may include
+ sunperf.h in his or her own code, and that is safely ignored here.
+ SGI's SCSL BLAS has yet a different kind of struct, but we can use a
+ double array of size 2 instead (since SCSL_VOID_ARGS is defined).
+ Most BLAS expect complex scalars as pointers to double arrays of size 2.
+*/
+
+#define BLAS_DECLARE_SCALAR(x) double x [2]
+#define BLAS_ASSIGN(x,xr,xi) { x [0] = xr ; x [1] = xi ; }
+#define BLAS_SCALAR(x) x
+
+#else
+
+#define BLAS_DECLARE_SCALAR(x) double x
+#define BLAS_ASSIGN(x,xr,xi) { x = xr ; }
+#ifdef BLAS_BY_VALUE
+#define BLAS_SCALAR(x) x
+#else
+#define BLAS_SCALAR(x) &(x)
+#endif
+
+#endif /* COMPLEX */
+
+
+/* -------------------------------------------------------------------------- */
+/* BLAS integer scalars */
+/* -------------------------------------------------------------------------- */
+
+/*
+ Fortran requires integers to be passed by reference.
+ The SCSL BLAS requires long long arguments in LP64 mode.
+*/
+
+#if defined (USE_SCSL_BLAS) && defined (LP64)
+#define BLAS_INT_SCALAR(n) ((long long) n)
+#else
+#ifdef BLAS_BY_VALUE
+#define BLAS_INT_SCALAR(n) n
+#else
+#define BLAS_INT_SCALAR(n) &(n)
+#endif
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* BLAS strings */
+/* -------------------------------------------------------------------------- */
+
+/*
+ The Sun Performance BLAS wants a character instead of a string.
+*/
+
+#ifdef BLAS_CHAR_ARG
+#define BLAS_NO_TRANSPOSE 'N'
+#define BLAS_TRANSPOSE 'T'
+#define BLAS_LEFT 'L'
+#define BLAS_RIGHT 'R'
+#define BLAS_LOWER 'L'
+#define BLAS_UNIT_DIAGONAL 'U'
+#else
+#define BLAS_NO_TRANSPOSE "N"
+#define BLAS_TRANSPOSE "T"
+#define BLAS_LEFT "L"
+#define BLAS_RIGHT "R"
+#define BLAS_LOWER "L"
+#define BLAS_UNIT_DIAGONAL "U"
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* BLAS arrays */
+/* -------------------------------------------------------------------------- */
+
+/*
+ The complex SunPerf BLAS expects to see a doublecomplex array of size s.
+ This is broken (see above, regarding complex scalars in sunperf.h).
+ For SunPerf BLAS, just pass a pointer to the array, and ignore sunperf.h.
+ With sunperf.h, you would need:
+
+ #define BLAS_ARRAY(a) ((doublecomplex *)(a))
+
+ SGI's SCSL BLAS has yet a different kind of struct, but we can use a
+ double array of size 2 instead (since SCSL_VOID_ARGS is defined).
+
+ The real versions all use just a (double *) pointer.
+
+ In all cases, no typecast is required. This will break if <sunperf.h> is
+ included.
+
+ If you have read this far, I hope you see now why (void *) a much better
+ choice for complex BLAS prototypes, and why double x [2] is better than
+ an architecture dependent struct { double real ; double imag ; }
+ type definition.
+
+*/
+
+#define BLAS_ARRAY(a) (a)
+
+
+/* -------------------------------------------------------------------------- */
+#endif /* USE_C_BLAS } */
+/* -------------------------------------------------------------------------- */
+
+
+
+
+
+/* -------------------------------------------------------------------------- */
+/* BLAS macros, for all interfaces */
+/* -------------------------------------------------------------------------- */
+
+/*
+ All architecture dependent issues have now been taken into consideration,
+ and folded into the macros BLAS_DECLARE_SCALAR, BLAS_ASSIGN, BLAS_*_ROUTINE,
+ BLAS_COLUMN_MAJOR_ORDER, BLAS_NO_TRANSPOSE, BLAS_TRANSPOSE, BLAS_SCALAR,
+ BLAS_INT_SCALAR, BLAS_ARRAY, and Int.
+
+ You will note that there is not a *** single *** name, declaration, or
+ argument to the BLAS which is not somehow different in one or more versions
+ of the BLAS!
+*/
+
+
+/* C = C - A*B', where:
+ * A is m-by-k with leading dimension ldac
+ * B is k-by-n with leading dimension ldb
+ * C is m-by-n with leading dimension ldac */
+#define BLAS_GEMM(m,n,k,A,B,ldb,C,ldac) \
+{ \
+ BLAS_DECLARE_SCALAR (alpha) ; \
+ BLAS_DECLARE_SCALAR (beta) ; \
+ BLAS_ASSIGN (alpha, -1.0, 0.0) ; \
+ BLAS_ASSIGN (beta, 1.0, 0.0) ; \
+ (void) BLAS_GEMM_ROUTINE (BLAS_COLUMN_MAJOR_ORDER \
+ BLAS_NO_TRANSPOSE, BLAS_TRANSPOSE, \
+ BLAS_INT_SCALAR (m), BLAS_INT_SCALAR (n), BLAS_INT_SCALAR (k), \
+ BLAS_SCALAR (alpha), \
+ BLAS_ARRAY (A), BLAS_INT_SCALAR (ldac), \
+ BLAS_ARRAY (B), BLAS_INT_SCALAR (ldb), BLAS_SCALAR (beta), \
+ BLAS_ARRAY (C), BLAS_INT_SCALAR (ldac)) ; \
+}
+
+/* A = A - x*y', where:
+ * A is m-by-n with leading dimension d
+ x is a column vector with stride 1
+ y is a column vector with stride 1 */
+#define BLAS_GER(m,n,x,y,A,d) \
+{ \
+ Int one = 1 ; \
+ BLAS_DECLARE_SCALAR (alpha) ; \
+ BLAS_ASSIGN (alpha, -1.0, 0.0) ; \
+ (void) BLAS_GER_ROUTINE (BLAS_COLUMN_MAJOR_ORDER \
+ BLAS_INT_SCALAR (m), BLAS_INT_SCALAR (n), \
+ BLAS_SCALAR (alpha), \
+ BLAS_ARRAY (x), BLAS_INT_SCALAR (one), \
+ BLAS_ARRAY (y), BLAS_INT_SCALAR (one), \
+ BLAS_ARRAY (A), BLAS_INT_SCALAR (d)) ; \
+}
+
+/* y = y - A*x, where A is m-by-n with leading dimension d,
+ x is a column vector with stride 1
+ y is a column vector with stride 1 */
+#define BLAS_GEMV(m,n,A,x,y,d) \
+{ \
+ Int one = 1 ; \
+ BLAS_DECLARE_SCALAR (alpha) ; \
+ BLAS_DECLARE_SCALAR (beta) ; \
+ BLAS_ASSIGN (alpha, -1.0, 0.0) ; \
+ BLAS_ASSIGN (beta, 1.0, 0.0) ; \
+ (void) BLAS_GEMV_ROUTINE (BLAS_COLUMN_MAJOR_ORDER \
+ BLAS_NO_TRANSPOSE, \
+ BLAS_INT_SCALAR (m), BLAS_INT_SCALAR (n), \
+ BLAS_SCALAR (alpha), \
+ BLAS_ARRAY (A), BLAS_INT_SCALAR (d), \
+ BLAS_ARRAY (x), BLAS_INT_SCALAR (one), BLAS_SCALAR (beta), \
+ BLAS_ARRAY (y), BLAS_INT_SCALAR (one)) ; \
+}
+
+
+/* solve Lx=b, where:
+ * B is a column vector (m-by-1) with leading dimension d
+ * A is m-by-m with leading dimension d */
+#define BLAS_TRSV(m,A,b,d) \
+{ \
+ Int one = 1 ; \
+ (void) BLAS_TRSV_ROUTINE (BLAS_COLUMN_MAJOR_ORDER \
+ BLAS_LOWER, BLAS_NO_TRANSPOSE, BLAS_UNIT_DIAGONAL, \
+ BLAS_INT_SCALAR (m), \
+ BLAS_ARRAY (A), BLAS_INT_SCALAR (d), \
+ BLAS_ARRAY (b), BLAS_INT_SCALAR (one)) ; \
+}
+
+/* solve XL'=B where:
+ * B is m-by-n with leading dimension ldb
+ * A is n-by-n with leading dimension lda */
+#define BLAS_TRSM_RIGHT(m,n,A,lda,B,ldb) \
+{ \
+ BLAS_DECLARE_SCALAR (alpha) ; \
+ BLAS_ASSIGN (alpha, 1.0, 0.0) ; \
+ (void) BLAS_TRSM_ROUTINE (BLAS_COLUMN_MAJOR_ORDER \
+ BLAS_RIGHT, BLAS_LOWER, BLAS_TRANSPOSE, BLAS_UNIT_DIAGONAL, \
+ BLAS_INT_SCALAR (m), BLAS_INT_SCALAR (n), \
+ BLAS_SCALAR (alpha), \
+ BLAS_ARRAY (A), BLAS_INT_SCALAR (lda), \
+ BLAS_ARRAY (B), BLAS_INT_SCALAR (ldb)) ; \
+}
+
+/* x = s*x, where x is a stride-1 vector of length n */
+#define BLAS_SCAL(n,s,x) \
+{ \
+ Int one = 1 ; \
+ BLAS_DECLARE_SCALAR (alpha) ; \
+ BLAS_ASSIGN (alpha, REAL_COMPONENT (s), IMAG_COMPONENT (s)) ; \
+ (void) BLAS_SCAL_ROUTINE ( \
+ BLAS_INT_SCALAR (n), BLAS_SCALAR (alpha), \
+ BLAS_ARRAY (x), BLAS_INT_SCALAR (one)) ; \
+}
+
+/* x = y, where x and y are a stride-1 vectors of length n */
+#define BLAS_COPY(n,x,y) \
+{ \
+ Int one = 1 ; \
+ (void) BLAS_COPY_ROUTINE ( \
+ BLAS_INT_SCALAR (n), \
+ BLAS_ARRAY (x), BLAS_INT_SCALAR (one), \
+ BLAS_ARRAY (y), BLAS_INT_SCALAR (one)) ; \
+}
+
+#endif /* !defined (USE_NO_BLAS) } */
--- /dev/null
+/* ========================================================================== */
+/* === UMF_create_element =================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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"
+
+/* ========================================================================== */
+/* === copy_column ========================================================== */
+/* ========================================================================== */
+
+PRIVATE void copy_column (Int len, Entry *X, Entry *Y)
+{
+ Int i ;
+#pragma ivdep
+ for (i = 0 ; i < len ; i++)
+ {
+ Y [i] = X [i] ;
+ }
+}
+
+/* ========================================================================== */
+/* === UMF_create_element =================================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMF_create_element
+(
+ NumericType *Numeric,
+ WorkType *Work,
+ SymbolicType *Symbolic
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int j, col, row, *Fcols, *Frows, fnrows, fncols, *Cols, len, needunits, t1,
+ t2, size, e, i, *E, *Fcpos, *Frpos, *Rows, eloc, fnr_curr, f,
+ got_memory, *Row_tuples, *Row_degree, *Row_tlen, *Col_tuples, max_mark,
+ *Col_degree, *Col_tlen, nn, n_row, n_col, r2, c2, do_Fcpos ;
+ Entry *C, *Fcol ;
+ Element *ep ;
+ Unit *p, *Memory ;
+ Tuple *tp, *tp1, *tp2, tuple, *tpend ;
+#ifndef NDEBUG
+ DEBUG2 (("FRONTAL WRAPUP\n")) ;
+ UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ ASSERT (Work->fnpiv == 0) ;
+ ASSERT (Work->fnzeros == 0) ;
+ Row_degree = Numeric->Rperm ;
+ Row_tuples = Numeric->Uip ;
+ Row_tlen = Numeric->Uilen ;
+ Col_degree = Numeric->Cperm ;
+ Col_tuples = Numeric->Lip ;
+ Col_tlen = Numeric->Lilen ;
+ n_row = Work->n_row ;
+ n_col = Work->n_col ;
+ nn = MAX (n_row, n_col) ;
+ Fcols = Work->Fcols ;
+ Frows = Work->Frows ;
+ Fcpos = Work->Fcpos ;
+ Frpos = Work->Frpos ;
+ Memory = Numeric->Memory ;
+ fncols = Work->fncols ;
+ fnrows = Work->fnrows ;
+
+ tp = (Tuple *) NULL ;
+ tp1 = (Tuple *) NULL ;
+ tp2 = (Tuple *) NULL ;
+
+ /* ---------------------------------------------------------------------- */
+ /* add the current frontal matrix to the degrees of each column */
+ /* ---------------------------------------------------------------------- */
+
+ if (!Symbolic->fixQ)
+ {
+ /* but only if the column ordering is not fixed */
+#pragma ivdep
+ for (j = 0 ; j < fncols ; j++)
+ {
+ /* add the current frontal matrix to the degree */
+ ASSERT (Fcols [j] >= 0 && Fcols [j] < n_col) ;
+ Col_degree [Fcols [j]] += fnrows ;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* add the current frontal matrix to the degrees of each row */
+ /* ---------------------------------------------------------------------- */
+
+#pragma ivdep
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ /* add the current frontal matrix to the degree */
+ ASSERT (Frows [i] >= 0 && Frows [i] < n_row) ;
+ Row_degree [Frows [i]] += fncols ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* Reset the external degree counters */
+ /* ---------------------------------------------------------------------- */
+
+ E = Work->E ;
+ max_mark = MAX_MARK (nn) ;
+
+ if (!Work->pivcol_in_front)
+ {
+ /* clear the external column degrees. no more Usons of current front */
+ Work->cdeg0 += (nn + 1) ;
+ if (Work->cdeg0 >= max_mark)
+ {
+ /* guard against integer overflow. This is very rare */
+ DEBUG1 (("Integer overflow, cdeg\n")) ;
+ Work->cdeg0 = 1 ;
+#pragma ivdep
+ for (e = 1 ; e <= Work->nel ; e++)
+ {
+ if (E [e])
+ {
+ ep = (Element *) (Memory + E [e]) ;
+ ep->cdeg = 0 ;
+ }
+ }
+ }
+ }
+
+ if (!Work->pivrow_in_front)
+ {
+ /* clear the external row degrees. no more Lsons of current front */
+ Work->rdeg0 += (nn + 1) ;
+ if (Work->rdeg0 >= max_mark)
+ {
+ /* guard against integer overflow. This is very rare */
+ DEBUG1 (("Integer overflow, rdeg\n")) ;
+ Work->rdeg0 = 1 ;
+#pragma ivdep
+ for (e = 1 ; e <= Work->nel ; e++)
+ {
+ if (E [e])
+ {
+ ep = (Element *) (Memory + E [e]) ;
+ ep->rdeg = 0 ;
+ }
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* clear row/col offsets */
+ /* ---------------------------------------------------------------------- */
+
+ if (!Work->pivrow_in_front)
+ {
+#pragma ivdep
+ for (j = 0 ; j < fncols ; j++)
+ {
+ Fcpos [Fcols [j]] = EMPTY ;
+ }
+ }
+
+ if (!Work->pivcol_in_front)
+ {
+#pragma ivdep
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ Frpos [Frows [i]] = EMPTY ;
+ }
+ }
+
+ if (fncols <= 0 || fnrows <= 0)
+ {
+ /* no element to create */
+ DEBUG2 (("Element evaporation\n")) ;
+ Work->prior_element = EMPTY ;
+ return (TRUE) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* create element for later assembly */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ UMF_allocfail = FALSE ;
+ if (UMF_gprob > 0)
+ {
+ double rrr = ((double) (rand ( ))) / (((double) RAND_MAX) + 1) ;
+ DEBUG4 (("Check random %e %e\n", rrr, UMF_gprob)) ;
+ UMF_allocfail = rrr < UMF_gprob ;
+ if (UMF_allocfail) DEBUGm2 (("Random garbage collection (create)\n"));
+ }
+#endif
+
+ needunits = 0 ;
+ got_memory = FALSE ;
+ eloc = UMF_mem_alloc_element (Numeric, fnrows, fncols, &Rows, &Cols, &C,
+ &needunits, &ep) ;
+
+ /* if UMF_get_memory needs to be called */
+ if (Work->do_grow)
+ {
+ /* full compaction of current frontal matrix, since UMF_grow_front will
+ * be called next anyway. */
+ r2 = fnrows ;
+ c2 = fncols ;
+ do_Fcpos = FALSE ;
+ }
+ else
+ {
+ /* partial compaction. */
+ r2 = MAX (fnrows, Work->fnrows_new + 1) ;
+ c2 = MAX (fncols, Work->fncols_new + 1) ;
+ /* recompute Fcpos if pivot row is in the front */
+ do_Fcpos = Work->pivrow_in_front ;
+ }
+
+ if (!eloc)
+ {
+ /* Do garbage collection, realloc, and try again. */
+ /* Compact the current front if it needs to grow anyway. */
+ /* Note that there are no pivot rows or columns in the current front */
+ DEBUGm3 (("get_memory from umf_create_element, 1\n")) ;
+ if (!UMF_get_memory (Numeric, Work, needunits, r2, c2, do_Fcpos))
+ {
+ /* :: out of memory in umf_create_element (1) :: */
+ DEBUGm4 (("out of memory: create element (1)\n")) ;
+ return (FALSE) ; /* out of memory */
+ }
+ got_memory = TRUE ;
+ Memory = Numeric->Memory ;
+ eloc = UMF_mem_alloc_element (Numeric, fnrows, fncols, &Rows, &Cols, &C,
+ &needunits, &ep) ;
+ ASSERT (eloc >= 0) ;
+ if (!eloc)
+ {
+ /* :: out of memory in umf_create_element (2) :: */
+ DEBUGm4 (("out of memory: create element (2)\n")) ;
+ return (FALSE) ; /* out of memory */
+ }
+ }
+
+ e = ++(Work->nel) ; /* get the name of this new frontal matrix */
+ Work->prior_element = e ;
+ DEBUG8 (("wrapup e "ID" nel "ID"\n", e, Work->nel)) ;
+
+ ASSERT (e > 0 && e < Work->elen) ;
+ ASSERT (E [e] == 0) ;
+ E [e] = eloc ;
+
+ if (Work->pivcol_in_front)
+ {
+ /* the new element is a Uson of the next frontal matrix */
+ ep->cdeg = Work->cdeg0 ;
+ }
+
+ if (Work->pivrow_in_front)
+ {
+ /* the new element is an Lson of the next frontal matrix */
+ ep->rdeg = Work->rdeg0 ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* copy frontal matrix into the new element */
+ /* ---------------------------------------------------------------------- */
+
+#pragma ivdep
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ Rows [i] = Frows [i] ;
+ }
+#pragma ivdep
+ for (i = 0 ; i < fncols ; i++)
+ {
+ Cols [i] = Fcols [i] ;
+ }
+ Fcol = Work->Fcblock ;
+ DEBUG0 (("copy front "ID" by "ID"\n", fnrows, fncols)) ;
+ fnr_curr = Work->fnr_curr ;
+ ASSERT (fnr_curr >= 0 && fnr_curr % 2 == 1) ;
+ for (j = 0 ; j < fncols ; j++)
+ {
+ copy_column (fnrows, Fcol, C) ;
+#if 0
+#ifdef USE_NO_BLAS
+ copy_column (fnrows, Fcol, C) ;
+#else
+ could also use BLAS-COPY (fnrows, Fcol, C) here, but it is typically
+ not as fast as the inlined copy_column subroutine, above.
+#endif
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ C [i] = Fcol [i] ;
+ }
+#endif
+ Fcol += fnr_curr ;
+ C += fnrows ;
+ }
+
+ DEBUG8 (("element copied\n")) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* add tuples for the new element */
+ /* ---------------------------------------------------------------------- */
+
+ tuple.e = e ;
+
+ if (got_memory)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* UMF_get_memory ensures enough space exists for each new tuple */
+ /* ------------------------------------------------------------------ */
+
+ /* place (e,f) in the element list of each column */
+ for (tuple.f = 0 ; tuple.f < fncols ; tuple.f++)
+ {
+ col = Fcols [tuple.f] ;
+ ASSERT (col >= 0 && col < n_col) ;
+ ASSERT (NON_PIVOTAL_COL (col)) ;
+ ASSERT (Col_tuples [col]) ;
+ tp = ((Tuple *) (Memory + Col_tuples [col])) + Col_tlen [col]++ ;
+ *tp = tuple ;
+ }
+
+ /* ------------------------------------------------------------------ */
+
+ /* place (e,f) in the element list of each row */
+ for (tuple.f = 0 ; tuple.f < fnrows ; tuple.f++)
+ {
+ row = Frows [tuple.f] ;
+ ASSERT (row >= 0 && row < n_row) ;
+ ASSERT (NON_PIVOTAL_ROW (row)) ;
+ ASSERT (Row_tuples [row]) ;
+ tp = ((Tuple *) (Memory + Row_tuples [row])) + Row_tlen [row]++ ;
+ *tp = tuple ;
+ }
+
+ }
+ else
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* place (e,f) in the element list of each column */
+ /* ------------------------------------------------------------------ */
+
+ /* might not have enough space for each tuple */
+
+ for (tuple.f = 0 ; tuple.f < fncols ; tuple.f++)
+ {
+ col = Fcols [tuple.f] ;
+ ASSERT (col >= 0 && col < n_col) ;
+ ASSERT (NON_PIVOTAL_COL (col)) ;
+ t1 = Col_tuples [col] ;
+ DEBUG1 (("Placing on col:"ID" , tuples at "ID"\n",
+ col, Col_tuples [col])) ;
+
+ size = 0 ;
+ len = 0 ;
+
+ if (t1)
+ {
+ p = Memory + t1 ;
+ tp = (Tuple *) p ;
+ size = GET_BLOCK_SIZE (p) ;
+ len = Col_tlen [col] ;
+ tp2 = tp + len ;
+ }
+
+ needunits = UNITS (Tuple, len + 1) ;
+ DEBUG1 (("len: "ID" size: "ID" needunits: "ID"\n",
+ len, size, needunits));
+
+ if (needunits > size && t1)
+ {
+ /* prune the tuples */
+ tp1 = tp ;
+ tp2 = tp ;
+ tpend = tp + len ;
+ for ( ; tp < tpend ; tp++)
+ {
+ e = tp->e ;
+ ASSERT (e > 0 && e <= Work->nel) ;
+ if (!E [e]) continue ; /* element already deallocated */
+ f = tp->f ;
+ p = Memory + E [e] ;
+ ep = (Element *) p ;
+ p += UNITS (Element, 1) ;
+ Cols = (Int *) p ;
+ ;
+ if (Cols [f] == EMPTY) continue ; /* already assembled */
+ ASSERT (col == Cols [f]) ;
+ *tp2++ = *tp ; /* leave the tuple in the list */
+ }
+ len = tp2 - tp1 ;
+ Col_tlen [col] = len ;
+ needunits = UNITS (Tuple, len + 1) ;
+ }
+
+ if (needunits > size)
+ {
+ /* no room exists - reallocate elsewhere */
+ DEBUG1 (("REALLOCATE Col: "ID", size "ID" to "ID"\n",
+ col, size, 2*needunits)) ;
+
+#ifndef NDEBUG
+ UMF_allocfail = FALSE ;
+ if (UMF_gprob > 0) /* a double relop, but ignore NaN case */
+ {
+ double rrr = ((double) (rand ( ))) /
+ (((double) RAND_MAX) + 1) ;
+ DEBUG1 (("Check random %e %e\n", rrr, UMF_gprob)) ;
+ UMF_allocfail = rrr < UMF_gprob ;
+ if (UMF_allocfail) DEBUGm2 (("Random gar. (col tuple)\n")) ;
+ }
+#endif
+
+ needunits = MIN (2*needunits, (Int) UNITS (Tuple, nn)) ;
+ t2 = UMF_mem_alloc_tail_block (Numeric, needunits) ;
+ if (!t2)
+ {
+ /* :: get memory in umf_create_element (1) :: */
+ /* get memory, reconstruct all tuple lists, and return */
+ /* Compact the current front if it needs to grow anyway. */
+ /* Note: no pivot rows or columns in the current front */
+ DEBUGm4 (("get_memory from umf_create_element, 1\n")) ;
+ return (UMF_get_memory (Numeric, Work, 0, r2, c2,do_Fcpos));
+ }
+ Col_tuples [col] = t2 ;
+ tp2 = (Tuple *) (Memory + t2) ;
+ if (t1)
+ {
+ for (i = 0 ; i < len ; i++)
+ {
+ *tp2++ = *tp1++ ;
+ }
+ UMF_mem_free_tail_block (Numeric, t1) ;
+ }
+ }
+
+ /* place the new (e,f) tuple in the element list of the column */
+ Col_tlen [col]++ ;
+ *tp2 = tuple ;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* place (e,f) in the element list of each row */
+ /* ------------------------------------------------------------------ */
+
+ for (tuple.f = 0 ; tuple.f < fnrows ; tuple.f++)
+ {
+ row = Frows [tuple.f] ;
+ ASSERT (row >= 0 && row < n_row) ;
+ ASSERT (NON_PIVOTAL_ROW (row)) ;
+ t1 = Row_tuples [row] ;
+ DEBUG1 (("Placing on row:"ID" , tuples at "ID"\n",
+ row, Row_tuples [row])) ;
+
+ size = 0 ;
+ len = 0 ;
+ if (t1)
+ {
+ p = Memory + t1 ;
+ tp = (Tuple *) p ;
+ size = GET_BLOCK_SIZE (p) ;
+ len = Row_tlen [row] ;
+ tp2 = tp + len ;
+ }
+
+ needunits = UNITS (Tuple, len + 1) ;
+ DEBUG1 (("len: "ID" size: "ID" needunits: "ID"\n",
+ len, size, needunits)) ;
+
+ if (needunits > size && t1)
+ {
+ /* prune the tuples */
+ tp1 = tp ;
+ tp2 = tp ;
+ tpend = tp + len ;
+ for ( ; tp < tpend ; tp++)
+ {
+ e = tp->e ;
+ ASSERT (e > 0 && e <= Work->nel) ;
+ if (!E [e])
+ {
+ continue ; /* element already deallocated */
+ }
+ f = tp->f ;
+ p = Memory + E [e] ;
+ ep = (Element *) p ;
+ p += UNITS (Element, 1) ;
+ Cols = (Int *) p ;
+ Rows = Cols + (ep->ncols) ;
+ if (Rows [f] == EMPTY) continue ; /* already assembled */
+ ASSERT (row == Rows [f]) ;
+ *tp2++ = *tp ; /* leave the tuple in the list */
+ }
+ len = tp2 - tp1 ;
+ Row_tlen [row] = len ;
+ needunits = UNITS (Tuple, len + 1) ;
+ }
+
+ if (needunits > size)
+ {
+ /* no room exists - reallocate elsewhere */
+ DEBUG1 (("REALLOCATE Row: "ID", size "ID" to "ID"\n",
+ row, size, 2*needunits)) ;
+
+#ifndef NDEBUG
+ UMF_allocfail = FALSE ;
+ if (UMF_gprob > 0) /* a double relop, but ignore NaN case */
+ {
+ double rrr = ((double) (rand ( ))) /
+ (((double) RAND_MAX) + 1) ;
+ DEBUG1 (("Check random %e %e\n", rrr, UMF_gprob)) ;
+ UMF_allocfail = rrr < UMF_gprob ;
+ if (UMF_allocfail) DEBUGm2 (("Random gar. (row tuple)\n")) ;
+ }
+#endif
+
+ needunits = MIN (2*needunits, (Int) UNITS (Tuple, nn)) ;
+ t2 = UMF_mem_alloc_tail_block (Numeric, needunits) ;
+ if (!t2)
+ {
+ /* :: get memory in umf_create_element (2) :: */
+ /* get memory, reconstruct all tuple lists, and return */
+ /* Compact the current front if it needs to grow anyway. */
+ /* Note: no pivot rows or columns in the current front */
+ DEBUGm4 (("get_memory from umf_create_element, 2\n")) ;
+ return (UMF_get_memory (Numeric, Work, 0, r2, c2,do_Fcpos));
+ }
+ Row_tuples [row] = t2 ;
+ tp2 = (Tuple *) (Memory + t2) ;
+ if (t1)
+ {
+ for (i = 0 ; i < len ; i++)
+ {
+ *tp2++ = *tp1++ ;
+ }
+ UMF_mem_free_tail_block (Numeric, t1) ;
+ }
+ }
+
+ /* place the new (e,f) tuple in the element list of the row */
+ Row_tlen [row]++ ;
+ *tp2 = tuple ;
+ }
+
+ }
+
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ DEBUG1 (("Done extending\nFINAL: element row pattern: len="ID"\n", fncols));
+ for (j = 0 ; j < fncols ; j++) DEBUG1 ((""ID"\n", Fcols [j])) ;
+ DEBUG1 (("FINAL: element col pattern: len="ID"\n", fnrows)) ;
+ for (j = 0 ; j < fnrows ; j++) DEBUG1 ((""ID"\n", Frows [j])) ;
+ for (j = 0 ; j < fncols ; j++)
+ {
+ col = Fcols [j] ;
+ ASSERT (col >= 0 && col < n_col) ;
+ UMF_dump_rowcol (1, Numeric, Work, col, !Symbolic->fixQ) ;
+ }
+ for (j = 0 ; j < fnrows ; j++)
+ {
+ row = Frows [j] ;
+ ASSERT (row >= 0 && row < n_row) ;
+ UMF_dump_rowcol (0, Numeric, Work, row, TRUE) ;
+ }
+ if (n_row < 1000 && n_col < 1000)
+ {
+ UMF_dump_memory (Numeric) ;
+ }
+ DEBUG1 (("New element, after filling with stuff: "ID"\n", e)) ;
+ UMF_dump_element (Numeric, Work, e, TRUE) ;
+ if (nn < 1000)
+ {
+ DEBUG4 (("Matrix dump, after New element: "ID"\n", e)) ;
+ UMF_dump_matrix (Numeric, Work, TRUE) ;
+ }
+ DEBUG3 (("FRONTAL WRAPUP DONE\n")) ;
+#endif
+
+ return (TRUE) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_create_element
+(
+ NumericType *Numeric,
+ WorkType *Work,
+ SymbolicType *Symbolic
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_dump ============================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 = -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 *C,
+ Int dim,
+ Int m,
+ Int n
+)
+{
+
+ /* dump C [1..m,1..n], with column dimenstion dim */
+ Int i, j;
+
+ if (UMF_debug < 7) return ;
+ if (C == (Entry *) NULL)
+ {
+ 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 (C [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 (C [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 ;
+
+ if (e == 0)
+ {
+ UMF_dump_current_front (Numeric, Work, FALSE) ;
+ 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)) ;
+ 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", (Int) (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",
+ (Int) (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")) ;
+ }
+ }
+
+ /* Col_degree is not maintained when fixQ is true */
+ 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, FALSE) ;
+ }
+ 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 *Flublock, *Flblock, *Fublock, *Fcblock ;
+ Int fnrows_max, fncols_max, fnrows, fncols, fnpiv, *Frows, *Fcols,
+ i, j, *Fcpos, *Frpos, fnr_curr, fnc_curr, *E ;
+ if (!Work) return ;
+ DEBUG7 (("\n\n========CURRENT FRONTAL MATRIX:\n")) ;
+
+ Flublock = Work->Flublock ;
+ Flblock = Work->Flblock ;
+ Fublock = Work->Fublock ;
+ Fcblock = Work->Fcblock ;
+
+ Frows = Work->Frows ;
+ Fcols = Work->Fcols ;
+ Frpos = Work->Frpos ;
+ Fcpos = Work->Fcpos ;
+ fnrows_max = Work->fnrows_max ;
+ fncols_max = Work->fncols_max ;
+ fnr_curr = Work->fnr_curr ;
+ fnc_curr = Work->fnc_curr ;
+ fnrows = Work->fnrows ;
+ fncols = Work->fncols ;
+ fnpiv = Work->fnpiv ;
+ E = Work->E ;
+
+ DEBUG6 (("=== fnpiv= "ID"\n", fnpiv)) ;
+ DEBUG6 (("fnrows_max fncols_max "ID" "ID"\n",fnrows_max, fncols_max)) ;
+ DEBUG6 (("fnr_curr fnc_curr "ID" "ID"\n",fnr_curr, fnc_curr)) ;
+ DEBUG6 (("fnrows fncols "ID" "ID"\n",fnrows, fncols)) ;
+ ASSERT ((fnr_curr % 2 == 1) || fnr_curr == 0) ;
+ DEBUG6 (("Pivot row pattern:\n")) ;
+ for (j = 0 ; j < fncols ; j++)
+ {
+ DEBUG7 ((ID" "ID" "ID" %d\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 * fnr_curr) ;
+ }
+ }
+ DEBUG6 (("Pivot col pattern:\n")) ;
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ DEBUG7 ((ID" "ID" "ID" %d\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 ;
+
+ if (!E [0])
+ {
+ DEBUG6 (("current front not allocated\n")) ;
+ ASSERT (!Work->Flublock) ;
+ return ;
+ }
+
+ ASSERT (Work->Flublock == (Entry *) (Numeric->Memory + E [0])) ;
+ DEBUG7 (("C block: ")) ;
+ UMF_dump_dense (Fcblock, fnr_curr, fnrows, fncols) ;
+ DEBUG7 (("L block: ")) ;
+ UMF_dump_dense (Flblock, fnr_curr, fnrows, fnpiv) ;
+ DEBUG7 (("U' block: ")) ;
+ UMF_dump_dense (Fublock, fnc_curr, fncols, fnpiv) ;
+ DEBUG7 (("LU block: ")) ;
+ UMF_dump_dense (Flublock, Work->nb, fnpiv, fnpiv) ;
+ if (fnpiv > 0)
+ {
+ DEBUG7 (("Pivot entry: ")) ;
+ EDEBUG7 (Flublock [(fnpiv-1)+(fnpiv-1)*Work->nb]) ;
+ 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,
+ (Int) (p-Numeric->Memory), (Int) (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 ; /* for NON_PIVOTAL_COL macro */
+ Row_degree = Numeric->Rperm ; /* for NON_PIVOTAL_ROW macro */
+ 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",
+ (Int) (p-Numeric->Memory), (Int) (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 ;
+ if (p3 == Numeric->Memory + Work->E [0])
+ {
+ /* this is the current frontal matrix */
+ UMF_dump_current_front (Numeric, Work, FALSE) ;
+ }
+ else
+ {
+
+ /* this is a packed element */
+ GET_ELEMENT (ep, p3, Cols, Rows, ncols, nrows, C) ;
+ DEBUG9 (("ep "ID"\n nrows "ID" ncols "ID"\n",
+ (Int) ((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" \n", n_row)) ;
+ DEBUG2 (("n_col "ID" \n", n_col)) ;
+
+ 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 != (double *) NULL)
+ {
+#ifdef COMPLEX
+ if (Az != (double *) NULL)
+ {
+ 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 = -999 ;
+ 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) ;
+ srand (1) ; /* restart the random number generator */
+ }
+
+ 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 "ID"\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: %d\n", row, NON_PIVOTAL_ROW (row))) ;
+ }
+ }
+}
+
+/* ========================================================================== */
+/* === UMF_dump_diagonal_map ================================================ */
+/* ========================================================================== */
+
+GLOBAL void UMF_dump_diagonal_map
+(
+ Int Diagonal_map [ ],
+ Int Diagonal_imap [ ],
+ Int n1,
+ Int nn,
+ Int nempty
+)
+{
+ Int row, col ;
+ if (Diagonal_map != (Int *) NULL)
+ {
+ DEBUG2 (("\nDump the Diagonal_map: n1 "ID" nn "ID" nempty "ID"\n",
+ n1, nn, nempty)) ;
+ for (col = n1 ; col < nn - nempty ; col++)
+ {
+ row = Diagonal_map [col] ;
+ DEBUG2 ((" Diagonal_map [col = "ID"] gives "ID": ",
+ col, row)) ;
+ row = UNFLIP (row) ;
+ DEBUG2 ((" row "ID"\n", row)) ;
+ ASSERT (Diagonal_imap [row] == col) ;
+ }
+ }
+}
+
+#endif /* NDEBUG */
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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_dump.h: debugging definitions. */
+
+#ifndef NDEBUG
+
+GLOBAL void UMF_dump_dense
+(
+ Entry *C,
+ Int dim,
+ Int m,
+ Int n
+) ;
+
+GLOBAL void UMF_dump_element
+(
+ NumericType *Numeric,
+ WorkType *Work,
+ Int e,
+ Int clean
+) ;
+
+GLOBAL void UMF_dump_rowcol
+(
+ Int dump_which,
+ NumericType *Numeric,
+ WorkType *Work,
+ Int dump_index,
+ Int check_degree
+) ;
+
+GLOBAL void UMF_dump_matrix
+(
+ NumericType *Numeric,
+ WorkType *Work,
+ Int check_degree
+) ;
+
+GLOBAL void UMF_dump_current_front
+(
+ NumericType *Numeric,
+ WorkType *Work,
+ Int check
+) ;
+
+GLOBAL void UMF_dump_lu
+(
+ NumericType *Numeric
+) ;
+
+GLOBAL void UMF_dump_memory
+(
+ NumericType *Numeric
+) ;
+
+GLOBAL void UMF_dump_packed_memory
+(
+ NumericType *Numeric,
+ WorkType *Work
+) ;
+
+GLOBAL void UMF_dump_col_matrix
+(
+ const double Ax [ ],
+#ifdef COMPLEX
+ const double Az [ ],
+#endif
+ const Int Ai [ ],
+ const Int Ap [ ],
+ Int n_row,
+ Int n_col,
+ Int nz
+) ;
+
+GLOBAL void UMF_dump_chain
+(
+ Int frontid,
+ Int Front_parent [ ],
+ Int Front_npivcol [ ],
+ Int Front_nrows [ ],
+ Int Front_ncols [ ],
+ Int nfr
+) ;
+
+GLOBAL void UMF_dump_rowmerge
+(
+ NumericType *Numeric,
+ SymbolicType *Symbolic,
+ WorkType *Work
+) ;
+
+GLOBAL void UMF_dump_start
+(
+ void
+) ;
+
+
+GLOBAL void UMF_dump_diagonal_map
+(
+ Int Diagonal_map [ ],
+ Int Diagonal_imap [ ],
+ Int n1,
+ Int nn,
+ Int nempty
+) ;
+
+#define UMF_DBMAX 50000
+GLOBAL extern Int UMF_debug ;
+GLOBAL extern Int UMF_allocfail ;
+GLOBAL extern double UMF_gprob ;
+
+#define DEBUGk(k,params) { if (UMF_debug >= (k)) { PRINTF (params) ; } }
+
+#define DEBUGm4(params) DEBUGk (-4, params)
+#define DEBUGm3(params) DEBUGk (-3, params)
+#define DEBUGm2(params) DEBUGk (-2, params)
+#define DEBUGm1(params) DEBUGk (-1, params)
+#define DEBUG0(params) DEBUGk (0, params)
+#define DEBUG1(params) DEBUGk (1, params)
+#define DEBUG2(params) DEBUGk (2, params)
+#define DEBUG3(params) DEBUGk (3, params)
+#define DEBUG4(params) DEBUGk (4, params)
+#define DEBUG5(params) DEBUGk (5, params)
+#define DEBUG6(params) DEBUGk (6, params)
+#define DEBUG7(params) DEBUGk (7, params)
+#define DEBUG8(params) DEBUGk (8, params)
+#define DEBUG9(params) DEBUGk (9, params)
+
+#define EDEBUGk(k,a) { if (UMF_debug >= (k)) { PRINT_ENTRY (a) ; } }
+
+#define EDEBUG0(a) EDEBUGk (0, a)
+#define EDEBUG1(a) EDEBUGk (1, a)
+#define EDEBUG2(a) EDEBUGk (2, a)
+#define EDEBUG3(a) EDEBUGk (3, a)
+#define EDEBUG4(a) EDEBUGk (4, a)
+#define EDEBUG5(a) EDEBUGk (5, a)
+#define EDEBUG6(a) EDEBUGk (6, a)
+#define EDEBUG7(a) EDEBUGk (7, a)
+#define EDEBUG8(a) EDEBUGk (8, a)
+#define EDEBUG9(a) EDEBUGk (9, a)
+
+/* ASSERT defined in amd_dump.h */
+
+#else
+
+/* ========================================================================== */
+/* === No debugging ========================================================= */
+/* ========================================================================== */
+
+/* turn off all debugging macros */
+
+#define DEBUGk(k,params)
+
+#define DEBUGm4(params)
+#define DEBUGm3(params)
+#define DEBUGm2(params)
+#define DEBUGm1(params)
+#define DEBUG0(params)
+#define DEBUG1(params)
+#define DEBUG2(params)
+#define DEBUG3(params)
+#define DEBUG4(params)
+#define DEBUG5(params)
+#define DEBUG6(params)
+#define DEBUG7(params)
+#define DEBUG8(params)
+#define DEBUG9(params)
+
+#define EDEBUGk(k,a)
+
+#define EDEBUG0(a)
+#define EDEBUG1(a)
+#define EDEBUG2(a)
+#define EDEBUG3(a)
+#define EDEBUG4(a)
+#define EDEBUG5(a)
+#define EDEBUG6(a)
+#define EDEBUG7(a)
+#define EDEBUG8(a)
+#define EDEBUG9(a)
+
+#endif /* NDEBUG */
--- /dev/null
+/* ========================================================================== */
+/* === UMF_extend_front ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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"
+#include "umf_grow_front.h"
+
+/* ========================================================================== */
+/* === zero_front =========================================================== */
+/* ========================================================================== */
+
+PRIVATE void zero_front (
+ Entry *Flblock, Entry *Fublock, Entry *Fcblock,
+ Int fnrows, Int fncols, Int fnr_curr, Int fnc_curr,
+ Int fnpiv, Int fnrows_extended, Int fncols_extended)
+{
+ Int j, i ;
+ Entry *F, *Fj, *Fi ;
+
+ Fj = Fcblock + fnrows ;
+ for (j = 0 ; j < fncols ; j++)
+ {
+ /* zero the new rows in the contribution block: */
+ F = Fj ;
+ Fj += fnr_curr ;
+#pragma ivdep
+ for (i = fnrows ; i < fnrows_extended ; i++)
+ {
+ /* CLEAR (Fcblock [i + j*fnr_curr]) ; */
+ CLEAR_AND_INCREMENT (F) ;
+ }
+ }
+
+ Fj -= fnrows ;
+ for (j = fncols ; j < fncols_extended ; j++)
+ {
+ /* zero the new columns in the contribution block: */
+ F = Fj ;
+ Fj += fnr_curr ;
+#pragma ivdep
+ for (i = 0 ; i < fnrows_extended ; i++)
+ {
+ /* CLEAR (Fcblock [i + j*fnr_curr]) ; */
+ CLEAR_AND_INCREMENT (F) ;
+ }
+ }
+
+ Fj = Flblock + fnrows ;
+ for (j = 0 ; j < fnpiv ; j++)
+ {
+ /* zero the new rows in L block: */
+ F = Fj ;
+ Fj += fnr_curr ;
+#pragma ivdep
+ for (i = fnrows ; i < fnrows_extended ; i++)
+ {
+ /* CLEAR (Flblock [i + j*fnr_curr]) ; */
+ CLEAR_AND_INCREMENT (F) ;
+ }
+ }
+
+ Fi = Fublock + fncols ;
+ for (i = 0 ; i < fnpiv ; i++)
+ {
+ /* zero the new columns in U block: */
+ F = Fi ;
+ Fi += fnc_curr ;
+#pragma ivdep
+ for (j = fncols ; j < fncols_extended ; j++)
+ {
+ /* CLEAR (Fublock [i*fnc_curr + j]) ; */
+ CLEAR_AND_INCREMENT (F) ;
+ }
+ }
+
+}
+
+/* ========================================================================== */
+/* === UMF_extend_front ===================================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMF_extend_front
+(
+ NumericType *Numeric,
+ WorkType *Work
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int j, i, *Frows, row, col, *Wrow, fnr2, fnc2, *Frpos, *Fcpos, *Fcols,
+ fnrows_extended, rrdeg, ccdeg, fncols_extended, fnr_curr, fnc_curr,
+ fnrows, fncols, pos, fnpiv, *Wm ;
+ Entry *Wx, *Wy, *Fu, *Fl ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get current frontal matrix and check for frontal growth */
+ /* ---------------------------------------------------------------------- */
+
+ fnpiv = Work->fnpiv ;
+
+#ifndef NDEBUG
+ DEBUG2 (("EXTEND FRONT\n")) ;
+ DEBUG2 (("Work->fnpiv "ID"\n", fnpiv)) ;
+ ASSERT (Work->Flblock == Work->Flublock + Work->nb*Work->nb) ;
+ ASSERT (Work->Fublock == Work->Flblock + Work->fnr_curr*Work->nb) ;
+ ASSERT (Work->Fcblock == Work->Fublock + Work->nb*Work->fnc_curr) ;
+ DEBUG7 (("C block: ")) ;
+ UMF_dump_dense (Work->Fcblock, Work->fnr_curr, Work->fnrows, Work->fncols) ;
+ DEBUG7 (("L block: ")) ;
+ UMF_dump_dense (Work->Flblock, Work->fnr_curr, Work->fnrows, fnpiv);
+ DEBUG7 (("U' block: ")) ;
+ UMF_dump_dense (Work->Fublock, Work->fnc_curr, Work->fncols, fnpiv) ;
+ DEBUG7 (("LU block: ")) ;
+ UMF_dump_dense (Work->Flublock, Work->nb, fnpiv, fnpiv) ;
+#endif
+
+ if (Work->do_grow)
+ {
+ fnr2 = UMF_FRONTAL_GROWTH * Work->fnrows_new + 2 ;
+ fnc2 = UMF_FRONTAL_GROWTH * Work->fncols_new + 2 ;
+ if (!UMF_grow_front (Numeric, fnr2, fnc2, Work, 1))
+ {
+ DEBUGm4 (("out of memory: extend front\n")) ;
+ return (FALSE) ;
+ }
+ }
+
+ fnr_curr = Work->fnr_curr ;
+ fnc_curr = Work->fnc_curr ;
+ ASSERT (Work->fnrows_new + 1 <= fnr_curr) ;
+ ASSERT (Work->fncols_new + 1 <= fnc_curr) ;
+ ASSERT (fnr_curr >= 0 && fnr_curr % 2 == 1) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ Frows = Work->Frows ;
+ Frpos = Work->Frpos ;
+ Fcols = Work->Fcols ;
+ Fcpos = Work->Fcpos ;
+ fnrows = Work->fnrows ;
+ fncols = Work->fncols ;
+ rrdeg = Work->rrdeg ;
+ ccdeg = Work->ccdeg ;
+
+ /* 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 ;
+ Work->NewCols = Fcols ;
+
+ /* 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 ;
+ Work->NewRows = Frows ;
+
+ /* ---------------------------------------------------------------------- */
+ /* extend row pattern of the front with the new pivot column */
+ /* ---------------------------------------------------------------------- */
+
+ fnrows_extended = fnrows ;
+ fncols_extended = fncols ;
+
+#ifndef NDEBUG
+ DEBUG2 (("Pivot col, before extension: "ID"\n", fnrows)) ;
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ DEBUG2 ((" "ID": row "ID"\n", i, Frows [i])) ;
+ ASSERT (Frpos [Frows [i]] == i) ;
+ }
+ DEBUG2 (("Extending pivot column: pivcol_in_front: "ID"\n",
+ Work->pivcol_in_front)) ;
+#endif
+
+ Fl = Work->Flblock + fnpiv * fnr_curr ;
+
+ if (Work->pivcol_in_front)
+ {
+ /* extended pattern and position already in Frows, Frpos. Values above
+ * the diagonal are already in LU block. Values on and below the
+ * diagonal are in Wy [0 .. fnrows_extended-1]. Copy into the L
+ * block. */
+ fnrows_extended += ccdeg ;
+ Wy = Work->Wy ;
+
+ for (i = 0 ; i < fnrows_extended ; i++)
+ {
+ Fl [i] = Wy [i] ;
+#ifndef NDEBUG
+ row = Frows [i] ;
+ DEBUG2 ((" "ID": row "ID" ", i, row)) ;
+ EDEBUG2 (Fl [i]) ;
+ if (row == Work->pivrow) DEBUG2 ((" <- pivrow")) ;
+ DEBUG2 (("\n")) ;
+ if (i == fnrows - 1) DEBUG2 ((" :::::::\n")) ;
+ ASSERT (row >= 0 && row < Work->n_row) ;
+ ASSERT (Frpos [row] == i) ;
+#endif
+ }
+
+ }
+ else
+ {
+ /* extended pattern,values is in (Wm,Wx), not yet in the front */
+ Entry *F ;
+ Fu = Work->Flublock + fnpiv * Work->nb ;
+ Wm = Work->Wm ;
+ Wx = Work->Wx ;
+ F = Fu ;
+ for (i = 0 ; i < fnpiv ; i++)
+ {
+ CLEAR_AND_INCREMENT (F) ;
+ }
+ F = Fl ;
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ CLEAR_AND_INCREMENT (F) ;
+ }
+ for (i = 0 ; i < ccdeg ; i++)
+ {
+ row = Wm [i] ;
+#ifndef NDEBUG
+ DEBUG2 ((" "ID": row "ID" (ext) ", fnrows_extended, row)) ;
+ EDEBUG2 (Wx [i]) ;
+ if (row == Work->pivrow) DEBUG2 ((" <- pivrow")) ;
+ DEBUG2 (("\n")) ;
+ ASSERT (row >= 0 && row < Work->n_row) ;
+#endif
+ pos = Frpos [row] ;
+ if (pos < 0)
+ {
+ pos = fnrows_extended++ ;
+ Frows [pos] = row ;
+ Frpos [row] = pos ;
+ }
+ Fl [pos] = Wx [i] ;
+ }
+ }
+
+ ASSERT (fnrows_extended <= fnr_curr) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* extend the column pattern of the front with the new pivot row */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ DEBUG6 (("Pivot row, before extension: "ID"\n", fncols)) ;
+ for (j = 0 ; j < fncols ; j++)
+ {
+ DEBUG7 ((" "ID": col "ID"\n", j, Fcols [j])) ;
+ ASSERT (Fcpos [Fcols [j]] == j * fnr_curr) ;
+ }
+ DEBUG6 (("Extending pivot row:\n")) ;
+#endif
+
+ if (Work->pivrow_in_front)
+ {
+ if (Work->pivcol_in_front)
+ {
+ ASSERT (Fcols == Work->Wrow) ;
+ for (j = fncols ; j < rrdeg ; j++)
+ {
+#ifndef NDEBUG
+ col = Fcols [j] ;
+ DEBUG2 ((" "ID": col "ID" (ext)\n", j, col)) ;
+ ASSERT (col != Work->pivcol) ;
+ ASSERT (col >= 0 && col < Work->n_col) ;
+ ASSERT (Fcpos [col] < 0) ;
+#endif
+ Fcpos [Fcols [j]] = j * fnr_curr ;
+ }
+ }
+ else
+ {
+ /* OUT-IN option: pivcol not in front, but pivrow is in front */
+ Wrow = Work->Wrow ;
+ ASSERT (IMPLIES (Work->pivcol_in_front, Wrow == Fcols)) ;
+ if (Wrow == Fcols)
+ {
+ /* Wrow and Fcols are equivalenced */
+ for (j = fncols ; j < rrdeg ; j++)
+ {
+ col = Wrow [j] ;
+ DEBUG2 ((" "ID": col "ID" (ext)\n", j, col)) ;
+ ASSERT (Fcpos [col] < 0) ;
+ /* Fcols [j] = col ; not needed */
+ Fcpos [col] = j * fnr_curr ;
+ }
+ }
+ else
+ {
+ for (j = fncols ; j < rrdeg ; j++)
+ {
+ col = Wrow [j] ;
+ DEBUG2 ((" "ID": col "ID" (ext)\n", j, col)) ;
+ ASSERT (Fcpos [col] < 0) ;
+ Fcols [j] = col ;
+ Fcpos [col] = j * fnr_curr ;
+ }
+ }
+ }
+ fncols_extended = rrdeg ;
+ }
+ else
+ {
+ ASSERT (Fcols != Work->Wrow) ;
+ Wrow = Work->Wrow ;
+ for (j = 0 ; j < rrdeg ; j++)
+ {
+ col = Wrow [j] ;
+ ASSERT (col >= 0 && col < Work->n_col) ;
+ if (Fcpos [col] < 0)
+ {
+ DEBUG2 ((" col:: "ID" (ext)\n", col)) ;
+ Fcols [fncols_extended] = col ;
+ Fcpos [col] = fncols_extended * fnr_curr ;
+ fncols_extended++ ;
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* pivot row and column have been extended */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ ASSERT (fncols_extended <= fnc_curr) ;
+ ASSERT (fnrows_extended <= fnr_curr) ;
+
+ DEBUG6 (("Pivot col, after ext: "ID" "ID"\n", fnrows,fnrows_extended)) ;
+ for (i = 0 ; i < fnrows_extended ; i++)
+ {
+ row = Frows [i] ;
+ DEBUG7 ((" "ID": row "ID" pos "ID" old: %d", i, row, Frpos [row],
+ i < fnrows)) ;
+ if (row == Work->pivrow ) DEBUG7 ((" <-- pivrow")) ;
+ DEBUG7 (("\n")) ;
+ ASSERT (Frpos [Frows [i]] == i) ;
+ }
+
+ DEBUG6 (("Pivot row position: "ID"\n", Frpos [Work->pivrow])) ;
+ ASSERT (Frpos [Work->pivrow] >= 0) ;
+ ASSERT (Frpos [Work->pivrow] < fnrows_extended) ;
+
+ DEBUG6 (("Pivot row, after ext: "ID" "ID"\n", fncols,fncols_extended)) ;
+ for (j = 0 ; j < fncols_extended ; j++)
+ {
+ col = Fcols [j] ;
+ DEBUG7 ((" "ID": col "ID" pos "ID" old: %d", j, col, Fcpos [col],
+ j < fncols)) ;
+ if (col == Work->pivcol ) DEBUG7 ((" <-- pivcol")) ;
+ DEBUG7 (("\n")) ;
+ ASSERT (Fcpos [Fcols [j]] == j * fnr_curr) ;
+ }
+
+ DEBUG6 (("Pivot col position: "ID"\n", Fcpos [Work->pivcol])) ;
+ ASSERT (Fcpos [Work->pivcol] >= 0) ;
+ ASSERT (Fcpos [Work->pivcol] < fncols_extended * fnr_curr) ;
+
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* Zero the newly extended frontal matrix */
+ /* ---------------------------------------------------------------------- */
+
+ zero_front (Work->Flblock, Work->Fublock, Work->Fcblock,
+ fnrows, fncols, fnr_curr, fnc_curr,
+ fnpiv, fnrows_extended, fncols_extended) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* finalize extended row and column pattern of the frontal matrix */
+ /* ---------------------------------------------------------------------- */
+
+ Work->fnrows = fnrows_extended ;
+ Work->fncols = fncols_extended ;
+
+ ASSERT (fnrows_extended == Work->fnrows_new + 1) ;
+ ASSERT (fncols_extended == Work->fncols_new + 1) ;
+
+ return (TRUE) ;
+
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_extend_front
+(
+ NumericType *Numeric,
+ WorkType *Work
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_free ============================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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
+)
+{
+ DEBUG0 (("UMF_free: "ID"\n", (Int) 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-- ;
+ DEBUG0 ((" new malloc count: "ID"\n", UMF_malloc_count)) ;
+#endif
+
+ }
+
+ return ((void *) NULL) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void *UMF_free
+(
+ void *p
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_fsize ============================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 largest frontal matrix size for each subtree. Called by
+ * UMF_colamd and UMF_analyze. Only required to sort the children of each
+ * node prior to AMD_postorder. */
+
+#include "umf_internal.h"
+
+GLOBAL void UMF_fsize
+(
+ Int nn,
+ Int Fsize [ ],
+ Int Fnrows [ ],
+ Int Fncols [ ],
+ Int Parent [ ],
+ Int Npiv [ ]
+)
+{
+ Int j, parent, frsize, r, c ;
+
+ for (j = 0 ; j < nn ; j++)
+ {
+ Fsize [j] = EMPTY ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* find max front size for tree rooted at node j, for each front j */
+ /* ---------------------------------------------------------------------- */
+
+ DEBUG1 (("\n\n========================================FRONTS:\n")) ;
+ for (j = 0 ; j < nn ; j++)
+ {
+ if (Npiv [j] > 0)
+ {
+ /* this is a frontal matrix */
+ parent = Parent [j] ;
+ r = Fnrows [j] ;
+ c = Fncols [j] ;
+ frsize = r * c ;
+ /* avoid integer overflow */
+ if (INT_OVERFLOW (((double) r) * ((double) c)))
+ {
+ /* :: frsize int overflow :: */
+ frsize = Int_MAX ;
+ }
+ DEBUG1 ((""ID" : npiv "ID" size "ID" parent "ID" ",
+ j, Npiv [j], frsize, parent)) ;
+ Fsize [j] = MAX (Fsize [j], frsize) ;
+ DEBUG1 (("Fsize [j = "ID"] = "ID"\n", j, Fsize [j])) ;
+ if (parent != EMPTY)
+ {
+ /* find the maximum frontsize of self and children */
+ ASSERT (Npiv [parent] > 0) ;
+ ASSERT (parent > j) ;
+ Fsize [parent] = MAX (Fsize [parent], Fsize [j]) ;
+ DEBUG1 (("Fsize [parent = "ID"] = "ID"\n",
+ parent, Fsize [parent]));
+ }
+ }
+ }
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_fsize
+(
+ Int nn,
+ Int MaxFsize [ ],
+ Int Fnrows [ ],
+ Int Fncols [ ],
+ Int Parent [ ],
+ Int Npiv [ ]
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_garbage_collection =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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).
+
+ Only called by UMF_get_memory.
+
+ There are 5 ways in which garbage collection can be performed:
+
+ Allocate a new working array for the current frontal matrix. In this
+ case, there are never any pivot rows/columns in the current frontal
+ matrix (fnpiv = 0), and the old working array for the current frontal
+ matrix can always be fully compacted, to fnrows-by-fncols.
+
+ UMF_kernel : UMF_extend : UMF_grow_front : UMF_get_memory
+ UMF_kernel : UMF_init_front : UMF_grow_front : UMF_get_memory
+ UMF_kernel : UMF_start_front : UMF_grow_front : UMF_get_memory
+
+ Allocate a new element. In this case, UMF_grow_front may or may not
+ be subsequently called, depending on Work->do_grow. There are never
+ any pivot rows/columns in the current frontal matrix (fnpiv=0), but one
+ may be added if UMF_init_front is to be called just after
+ UMF_create_element. If do_grow is true, then the current front can be
+ fully compacted, to fnrows-by-fncols. Otherwise, it can only be
+ partially compacted, to MAX (fnrows, fnrows_new + 1) -by-
+ MAX (fncols, fncols_new + 1).
+
+ UMF_kernel : UMF_create_element : UMF_get_memory
+
+ Allocate rows of L and columns of U. In this case, the current
+ frontal matrix is only partially compacted, to (fnrows_new + 1)-by-
+ (fncols_new + 1). There are pivots in the frontal matrix (fnpiv > 0).
+
+ UMF_kernel : UMF_store_lu : UMF_get_memory
+*/
+
+#include "umf_internal.h"
+
+GLOBAL void UMF_garbage_collection
+(
+ NumericType *Numeric,
+ WorkType *Work,
+ Int drnew, /* compact current front to drnew-by-dcnew */
+ Int dcnew,
+ Int do_Fcpos
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* 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,
+ *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 ;
+
+ /* 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
+ DEBUGm1 (("::::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, (Int) (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, (Int) (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 ;
+ ASSERT (nel < Work->elen) ;
+
+#ifndef NDEBUG
+ nmark = 0 ;
+ UMF_dump_current_front (Numeric, Work, FALSE) ;
+ DEBUGm1 (("E [0] "ID" \n", E [0])) ;
+ ASSERT (IMPLIES (E [0],
+ Work->Flublock == (Entry *) (Numeric->Memory + E [0]))) ;
+ ASSERT (IMPLIES (Work->Flublock,
+ Work->Flublock == (Entry *) (Numeric->Memory + E [0]))) ;
+ ASSERT ((E [0] != 0) == (Work->Flublock != (Entry *) NULL)) ;
+#endif
+
+ e2 = 0 ;
+
+ 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, (Int) (psrc-Numeric->Memory), e2)) ;
+ E [e] = 0 ;
+ 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 < Work->elen ; 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,
+ (Int) (psrc-Numeric->Memory), prevsize, size)) ;
+
+ if (e == 0)
+ {
+ /* -------------------------------------------------------------- */
+ /* this is the current frontal matrix */
+ /* -------------------------------------------------------------- */
+
+ Entry *F1, *F2, *Fsrc, *Fdst ;
+ Int c, r, k, dr, dc, gap, gap1, gap2, nb ;
+
+ /* shift the frontal matrix down */
+ F1 = (Entry *) (psrc + 1) ;
+
+ /* get the size of the current front. r and c could be zero */
+ k = Work->fnpiv ;
+ dr = Work->fnr_curr ;
+ dc = Work->fnc_curr ;
+ r = Work->fnrows ;
+ c = Work->fncols ;
+ nb = Work->nb ;
+
+ ASSERT ((dr >= 0 && (dr % 2) == 1) || dr == 0) ;
+ ASSERT (drnew >= 0) ;
+ if (drnew % 2 == 0)
+ {
+ /* make sure leading frontal matrix dimension is always odd */
+ drnew++ ;
+ }
+ drnew = MIN (dr, drnew) ;
+ ASSERT ((drnew >= 0 && (drnew % 2) == 1) || drnew == 0) ;
+
+ pnext = pdest ;
+
+#ifndef NDEBUG
+ DEBUGm2 (("move front: dr "ID" dc "ID" r "ID" drnew "ID" c "ID
+ " dcnew " ID" k "ID"\n", dr, dc, r, drnew, c, dcnew, k)) ;
+ DEBUG7 (("\n")) ;
+ DEBUG7 ((ID":: Move current frontal matrix from: psrc-S: "ID" \n",
+ nmark, (Int) (psrc-Numeric->Memory))) ;
+ nmark-- ;
+ ASSERT (E [e] == 0) ;
+ ASSERT (Work->Flublock == F1) ;
+ ASSERT (Work->Flblock == Work->Flublock + nb*nb) ;
+ ASSERT (Work->Fublock == Work->Flblock + dr*nb) ;
+ ASSERT (Work->Fcblock == Work->Fublock + nb*dc) ;
+ DEBUG7 (("C block: ")) ;
+ UMF_dump_dense (Work->Fcblock, dr, r, c) ;
+ DEBUG7 (("L block: ")) ;
+ UMF_dump_dense (Work->Flblock, dr, r, k);
+ DEBUG7 (("U' block: ")) ;
+ UMF_dump_dense (Work->Fublock, dc, c, k) ;
+ DEBUG7 (("LU block: ")) ;
+ UMF_dump_dense (Work->Flublock, nb, k, k) ;
+ ASSERT (r <= drnew && c <= dcnew && drnew <= dr && dcnew <= dc) ;
+#endif
+
+ /* compact frontal matrix to drnew-by-dcnew before moving it */
+
+ /* do not compact the LU block (nb-by-nb) */
+
+ /* compact the columns of L (from dr-by-nb to drnew-by-nb) */
+ Fsrc = Work->Flblock ;
+ Fdst = Work->Flblock ;
+ ASSERT (Fdst == F1 + nb*nb) ;
+ gap1 = dr - r ;
+ gap2 = drnew - r ;
+ ASSERT (gap1 >= 0) ;
+ for (j = 0 ; j < k ; j++)
+ {
+ for (i = 0 ; i < r ; i++)
+ {
+ *Fdst++ = *Fsrc++ ;
+ }
+ Fsrc += gap1 ;
+ Fdst += gap2 ;
+ }
+ ASSERT (Fdst == F1 + nb*nb + drnew*k) ;
+ Fdst += drnew * (nb - k) ;
+
+ /* compact the rows of U (U' from dc-by-nb to dcnew-by-nb) */
+ Fsrc = Work->Fublock ;
+ ASSERT (Fdst == F1 + nb*nb + drnew*nb) ;
+ gap1 = dc - c ;
+ gap2 = dcnew - c ;
+ for (i = 0 ; i < k ; i++)
+ {
+ for (j = 0 ; j < c ; j++)
+ {
+ *Fdst++ = *Fsrc++ ;
+ }
+ Fsrc += gap1 ;
+ Fdst += gap2 ;
+ }
+ ASSERT (Fdst == F1 + nb*nb + drnew*nb + dcnew*k) ;
+ Fdst += dcnew * (nb - k) ;
+
+ /* compact the columns of C (from dr-by-dc to drnew-by-dcnew) */
+ Fsrc = Work->Fcblock ;
+ ASSERT (Fdst == F1 + nb*nb + drnew*nb + nb*dcnew) ;
+ gap1 = dr - r ;
+ gap2 = drnew - r ;
+ for (j = 0 ; j < c ; j++)
+ {
+ for (i = 0 ; i < r ; i++)
+ {
+ *Fdst++ = *Fsrc++ ;
+ }
+ Fsrc += gap1 ;
+ Fdst += gap2 ;
+ }
+ ASSERT (Fdst == F1 + nb*nb + drnew*nb + nb*dcnew + drnew*c) ;
+
+ /* recompute Fcpos, if necessary */
+ if (do_Fcpos)
+ {
+ Int *Fcols, *Fcpos ;
+ Fcols = Work->Fcols ;
+ Fcpos = Work->Fcpos ;
+ for (j = 0 ; j < c ; j++)
+ {
+ col = Fcols [j] ;
+ ASSERT (col >= 0 && col < Work->n_col) ;
+ ASSERT (Fcpos [col] == j * dr) ;
+ Fcpos [col] = j * drnew ;
+ }
+#ifndef NDEBUG
+ {
+ Int cnt = 0 ;
+ for (j = 0 ; j < Work->n_col ; j++)
+ {
+ if (Fcpos [j] != EMPTY) cnt++ ;
+ }
+ DEBUGm2 (("Recompute Fcpos cnt "ID" c "ID"\n", cnt, c)) ;
+ ASSERT (cnt == c) ;
+ }
+#endif
+ }
+
+#ifndef NDEBUG
+ DEBUGm2 (("Compacted front, drnew "ID" dcnew "ID"\n", drnew, dcnew)) ;
+ DEBUG7 (("C block: ")) ;
+ UMF_dump_dense (F1 + nb*nb + drnew*nb + nb*dcnew, drnew, r, c) ;
+ DEBUG7 (("L block: ")) ;
+ UMF_dump_dense (F1 + nb*nb, drnew, r, k) ;
+ DEBUG7 (("U block: ")) ;
+ UMF_dump_dense (F1 + nb*nb + drnew*nb, nb, k, c) ;
+ DEBUG7 (("LU block: ")) ;
+ UMF_dump_dense (F1, nb, k, k) ;
+#endif
+
+ /* Compacted dimensions of the new frontal matrix. */
+ Work->fnr_curr = drnew ;
+ Work->fnc_curr = dcnew ;
+ Work->fcurr_size = (drnew + nb) * (dcnew + nb) ;
+ size = UNITS (Entry, Work->fcurr_size) ;
+
+ /* make sure the object doesn't evaporate. The front can have
+ * zero size (Work->fcurr_size = 0), but the size of the memory
+ * block containing it cannot have zero size. */
+ size = MAX (1, size) ;
+
+ /* get the destination of frontal matrix */
+ pnext->header.prevsize = size ;
+ pdest -= (size + 1) ;
+ F2 = (Entry *) (pdest + 1) ;
+
+ ASSERT ((unsigned Int) psrc + 1 + size <= (unsigned Int) pnext) ;
+ ASSERT (psrc <= pdest) ;
+ ASSERT (F1 <= F2) ;
+
+ /* move the C block first */
+ Fsrc = F1 + nb*nb + drnew*nb + nb*dcnew + drnew*c ;
+ Fdst = F2 + nb*nb + drnew*nb + nb*dcnew + drnew*c ;
+ gap = drnew - r ;
+ for (j = c-1 ; j >= 0 ; j--)
+ {
+ Fsrc -= gap ;
+ Fdst -= gap ;
+ /* move column j of C */
+ for (i = r-1 ; i >= 0 ; i--)
+ {
+ *--Fdst = *--Fsrc ;
+ }
+ }
+ ASSERT (Fsrc == F1 + nb*nb + drnew*nb + nb*dcnew) ;
+ ASSERT (Fdst == F2 + nb*nb + drnew*nb + nb*dcnew) ;
+
+ /* move the U block */
+ Fsrc -= dcnew * (nb - k) ;
+ Fdst -= dcnew * (nb - k) ;
+ ASSERT (Fsrc == F1 + nb*nb + drnew*nb + dcnew*k) ;
+ ASSERT (Fdst == F2 + nb*nb + drnew*nb + dcnew*k) ;
+ gap = dcnew - c ;
+ for (i = k-1 ; i >= 0 ; i--)
+ {
+ Fsrc -= gap ;
+ Fdst -= gap ;
+ for (j = c-1 ; j >= 0 ; j--)
+ {
+ *--Fdst = *--Fsrc ;
+ }
+ }
+ ASSERT (Fsrc == F1 + nb*nb + drnew*nb) ;
+ ASSERT (Fdst == F2 + nb*nb + drnew*nb) ;
+
+ /* move the L block */
+ Fsrc -= drnew * (nb - k) ;
+ Fdst -= drnew * (nb - k) ;
+ ASSERT (Fsrc == F1 + nb*nb + drnew*k) ;
+ ASSERT (Fdst == F2 + nb*nb + drnew*k) ;
+ gap = drnew - r ;
+ for (j = k-1 ; j >= 0 ; j--)
+ {
+ Fsrc -= gap ;
+ Fdst -= gap ;
+ for (i = r-1 ; i >= 0 ; i--)
+ {
+ *--Fdst = *--Fsrc ;
+ }
+ }
+ ASSERT (Fsrc == F1 + nb*nb) ;
+ ASSERT (Fdst == F2 + nb*nb) ;
+
+ /* move the LU block */
+ Fsrc -= nb * (nb - k) ;
+ Fdst -= nb * (nb - k) ;
+ ASSERT (Fsrc == F1 + nb*k) ;
+ ASSERT (Fdst == F2 + nb*k) ;
+ gap = nb - k ;
+ for (j = k-1 ; j >= 0 ; j--)
+ {
+ Fsrc -= gap ;
+ Fdst -= gap ;
+ for (i = k-1 ; i >= 0 ; i--)
+ {
+ *--Fdst = *--Fsrc ;
+ }
+ }
+ ASSERT (Fsrc == F1) ;
+ ASSERT (Fdst == F2) ;
+
+ E [0] = (pdest + 1) - Numeric->Memory ;
+
+ Work->Flublock = (Entry *) (Numeric->Memory + E [0]) ;
+ ASSERT (Work->Flublock == F2) ;
+ Work->Flblock = Work->Flublock + nb * nb ;
+ Work->Fublock = Work->Flblock + drnew * nb ;
+ Work->Fcblock = Work->Fublock + nb * dcnew ;
+
+ pdest->header.prevsize = 0 ;
+ pdest->header.size = size ;
+
+#ifndef NDEBUG
+ DEBUG7 (("After moving compressed current frontal matrix:\n")) ;
+ DEBUG7 (("C block: ")) ;
+ UMF_dump_dense (Work->Fcblock, drnew, r, c) ;
+ DEBUG7 (("L block: ")) ;
+ UMF_dump_dense (Work->Flblock, drnew, r, k);
+ DEBUG7 (("U' block: ")) ;
+ UMF_dump_dense (Work->Fublock, dcnew, c, k) ;
+ DEBUG7 (("LU block: ")) ;
+ UMF_dump_dense (Work->Flublock, nb, k, k) ;
+#endif
+
+ }
+ else 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, (Int) (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) ;
+
+ ASSERT (size2 <= size) ;
+ ASSERT ((unsigned Int) psrc + 1 + size <= (unsigned Int) 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:\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",
+ (Int) (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 .. Work->elen - 1] */
+ /* ---------------------------------------------------------------------- */
+
+ for (e = nel+1 ; e < Work->elen ; e++)
+ {
+ E [e] = 0 ;
+ }
+
+#ifndef NDEBUG
+ UMF_dump_packed_memory (Numeric, Work) ;
+#endif
+
+ DEBUG8 (("::::GARBAGE COLLECTION DONE::::\n")) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_garbage_collection
+(
+ NumericType *Numeric,
+ WorkType *Work,
+ Int drnew,
+ Int dcnew,
+ Int do_Fcpos
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_get_memory ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 r2, /* compact current front to r2-by-c2 */
+ Int c2,
+ Int do_Fcpos
+)
+{
+ 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, tsize ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get and check parameters */
+ /* ---------------------------------------------------------------------- */
+
+#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, &tsize) ;
+ nsize += tsize ;
+ 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 ;
+
+ newsize = (Int) (UMF_REALLOC_INCREASE * ((double) minsize)) ;
+ nsize *= UMF_REALLOC_INCREASE ;
+ nsize += 1 ;
+
+ if (newsize < 0 || nsize > bsize)
+ {
+ /* :: realloc Numeric->Memory int overflow :: */
+ DEBUGm3 (("Realloc hit integer limit\n")) ;
+ newsize = (Int) bsize ; /* we cannot increase the size beyond bsize */
+ }
+ else
+ {
+ ASSERT (newsize <= nsize) ;
+ newsize = MAX (newsize, minsize) ;
+ }
+ newsize = MAX (newsize, Numeric->size) ;
+
+ 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 ;
+
+ DEBUG0 (("Before realloc E [0] "ID"\n", Work->E [0])) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* 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 != (Unit *) NULL) ;
+
+ /* 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 ;
+ if (Work->E [0])
+ {
+ Int nb, dr, dc ;
+ nb = Work->nb ;
+ dr = Work->fnr_curr ;
+ dc = Work->fnc_curr ;
+ Work->Flublock = (Entry *) (Numeric->Memory + Work->E [0]) ;
+ Work->Flblock = Work->Flublock + nb * nb ;
+ Work->Fublock = Work->Flblock + dr * nb ;
+ Work->Fcblock = Work->Fublock + nb * dc ;
+ DEBUG0 (("after realloc E [0] "ID"\n", Work->E [0])) ;
+ }
+ ASSERT (IMPLIES (!(Work->E [0]), Work->Flublock == (Entry *) NULL)) ;
+
+ 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, r2, c2, do_Fcpos) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* rebuild the tuples */
+ /* ---------------------------------------------------------------------- */
+
+ return (UMF_build_tuples (Numeric, Work)) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_get_memory
+(
+ NumericType *Numeric,
+ WorkType *Work,
+ Int needunits,
+ Int r2,
+ Int c2,
+ Int do_Fcpos
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_grow_front ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+/* Current frontal matrix is too small. Make it bigger. */
+
+#include "umf_internal.h"
+#include "umf_realloc.h"
+#include "umf_mem_free_tail_block.h"
+#include "umf_mem_alloc_tail_block.h"
+#include "umf_get_memory.h"
+
+GLOBAL Int UMF_grow_front
+(
+ NumericType *Numeric,
+ Int fnr2, /* desired size is fnr2-by-fnc2 */
+ Int fnc2,
+ WorkType *Work,
+ Int do_what /* -1: UMF_start_front
+ * 0: UMF_init_front, do not recompute Fcpos
+ * 1: UMF_extend_front
+ * 2: UMF_init_front, recompute Fcpos */
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Entry *Fcold, *Fcnew ;
+ Int j, i, col, *Fcpos, *Fcols, fnrows_max, fncols_max, fnr_curr, nb,
+ fnrows_new, fncols_new, fnr_min, fnc_min, minsize,
+ newsize, fnrows, fncols, *E, eloc ;
+ double s ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ if (do_what != -1) UMF_debug++ ;
+ DEBUG0 (("\n\n====================GROW FRONT: do_what: "ID"\n", do_what)) ;
+ if (do_what != -1) UMF_debug-- ;
+ ASSERT (Work->do_grow) ;
+ ASSERT (Work->fnpiv == 0) ;
+#endif
+
+ Fcols = Work->Fcols ;
+ Fcpos = Work->Fcpos ;
+ E = Work->E ;
+
+ /* ---------------------------------------------------------------------- */
+ /* The current front is too small, find the new size */
+ /* ---------------------------------------------------------------------- */
+
+ /* maximum size of frontal matrix for this chain */
+ nb = Work->nb ;
+ fnrows_max = Work->fnrows_max + nb ;
+ fncols_max = Work->fncols_max + nb ;
+ ASSERT (fnrows_max >= 0 && (fnrows_max % 2) == 1) ;
+ DEBUG0 (("Max size: "ID"-by-"ID" (incl. "ID" pivot block\n",
+ fnrows_max, fncols_max, nb)) ;
+
+ /* current dimensions of frontal matrix: fnr-by-fnc */
+ DEBUG0 (("Current : "ID"-by-"ID" (excl "ID" pivot blocks)\n",
+ Work->fnr_curr, Work->fnc_curr, nb)) ;
+ ASSERT (Work->fnr_curr >= 0) ;
+ ASSERT ((Work->fnr_curr % 2 == 1) || Work->fnr_curr == 0) ;
+
+ /* required dimensions of frontal matrix: fnr_min-by-fnc_min */
+ fnrows_new = Work->fnrows_new + 1 ;
+ fncols_new = Work->fncols_new + 1 ;
+ ASSERT (fnrows_new >= 0) ;
+ if (fnrows_new % 2 == 0) fnrows_new++ ;
+ fnrows_new += nb ;
+ fncols_new += nb ;
+ fnr_min = MIN (fnrows_new, fnrows_max) ;
+ fnc_min = MIN (fncols_new, fncols_max) ;
+ minsize = fnr_min * fnc_min ;
+ if (INT_OVERFLOW ((double) fnr_min * (double) fnc_min * sizeof (Entry)))
+ {
+ /* :: the minimum front size is bigger than the integer maximum :: */
+ return (FALSE) ;
+ }
+ ASSERT (fnr_min >= 0) ;
+ ASSERT (fnr_min % 2 == 1) ;
+
+ DEBUG0 (("Min : "ID"-by-"ID"\n", fnr_min, fnc_min)) ;
+
+ /* grow the front to fnr2-by-fnc2, but no bigger than the maximum,
+ * and no smaller than the minumum. */
+ DEBUG0 (("Desired : ("ID"+"ID")-by-("ID"+"ID")\n", fnr2, nb, fnc2, nb)) ;
+ fnr2 += nb ;
+ fnc2 += nb ;
+ ASSERT (fnr2 >= 0) ;
+ if (fnr2 % 2 == 0) fnr2++ ;
+ fnr2 = MAX (fnr2, fnr_min) ;
+ fnc2 = MAX (fnc2, fnc_min) ;
+ fnr2 = MIN (fnr2, fnrows_max) ;
+ fnc2 = MIN (fnc2, fncols_max) ;
+ DEBUG0 (("Try : "ID"-by-"ID"\n", fnr2, fnc2)) ;
+ ASSERT (fnr2 >= 0) ;
+ ASSERT (fnr2 % 2 == 1) ;
+
+ s = ((double) fnr2) * ((double) fnc2) ;
+ if (INT_OVERFLOW (s * sizeof (Entry)))
+ {
+ /* :: frontal matrix size int overflow :: */
+ /* the desired front size is bigger than the integer maximum */
+ /* compute a such that a*a*s < Int_MAX / sizeof (Entry) */
+ double a = 0.9 * sqrt ((Int_MAX / sizeof (Entry)) / s) ;
+ fnr2 = MAX (fnr_min, a * fnr2) ;
+ fnc2 = MAX (fnc_min, a * fnc2) ;
+ /* the new frontal size is a*r*a*c = a*a*s */
+ newsize = fnr2 * fnc2 ;
+ ASSERT (fnr2 >= 0) ;
+ if (fnr2 % 2 == 0) fnr2++ ;
+ fnc2 = newsize / fnr2 ;
+ }
+
+ fnr2 = MAX (fnr2, fnr_min) ;
+ fnc2 = MAX (fnc2, fnc_min) ;
+ newsize = fnr2 * fnc2 ;
+
+ ASSERT (fnr2 >= 0) ;
+ ASSERT (fnr2 % 2 == 1) ;
+ ASSERT (fnr2 >= fnr_min) ;
+ ASSERT (fnc2 >= fnc_min) ;
+ ASSERT (newsize >= minsize) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* free the current front if it is empty of any numerical values */
+ /* ---------------------------------------------------------------------- */
+
+ if (E [0] && do_what != 1)
+ {
+ /* free the current front, if it exists and has nothing in it */
+ DEBUG0 (("Freeing empty front\n")) ;
+ UMF_mem_free_tail_block (Numeric, E [0]) ;
+ E [0] = 0 ;
+ Work->Flublock = (Entry *) NULL ;
+ Work->Flblock = (Entry *) NULL ;
+ Work->Fublock = (Entry *) NULL ;
+ Work->Fcblock = (Entry *) NULL ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate the new front, doing garbage collection if necessary */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ UMF_allocfail = FALSE ;
+ if (UMF_gprob > 0) /* a double relop, but ignore NaN case */
+ {
+ double rrr = ((double) (rand ( ))) / (((double) RAND_MAX) + 1) ;
+ DEBUG1 (("Check random %e %e\n", rrr, UMF_gprob)) ;
+ UMF_allocfail = rrr < UMF_gprob ;
+ if (UMF_allocfail) DEBUGm2 (("Random garbage collection (grow)\n")) ;
+ }
+#endif
+
+ DEBUG0 (("Attempt size: "ID"-by-"ID"\n", fnr2, fnc2)) ;
+ eloc = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry, newsize)) ;
+
+ if (!eloc)
+ {
+ /* Do garbage collection, realloc, and try again. Compact the current
+ * contribution block in the front to fnrows-by-fncols. Note that
+ * there are no pivot rows/columns in current front. Do not recompute
+ * Fcpos in UMF_garbage_collection. */
+ DEBUGm3 (("get_memory from umf_grow_front\n")) ;
+ if (!UMF_get_memory (Numeric, Work, 1 + UNITS (Entry, newsize),
+ Work->fnrows, Work->fncols, FALSE))
+ {
+ /* :: out of memory in umf_grow_front :: */
+ return (FALSE) ; /* out of memory */
+ }
+ DEBUG0 (("Attempt size: "ID"-by-"ID" again\n", fnr2, fnc2)) ;
+ eloc = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry, newsize)) ;
+ }
+
+ /* try again with something smaller */
+ while ((fnr2 != fnr_min || fnc2 != fnc_min) && !eloc)
+ {
+ fnr2 = MIN (fnr2 - 2, fnr2 * UMF_REALLOC_REDUCTION) ;
+ fnc2 = MIN (fnc2 - 2, fnc2 * UMF_REALLOC_REDUCTION) ;
+ ASSERT (fnr_min >= 0) ;
+ ASSERT (fnr_min % 2 == 1) ;
+ fnr2 = MAX (fnr_min, fnr2) ;
+ fnc2 = MAX (fnc_min, fnc2) ;
+ ASSERT (fnr2 >= 0) ;
+ if (fnr2 % 2 == 0) fnr2++ ;
+ newsize = fnr2 * fnc2 ;
+ DEBUGm3 (("Attempt smaller size: "ID"-by-"ID" minsize "ID"-by-"ID"\n",
+ fnr2, fnc2, fnr_min, fnc_min)) ;
+ eloc = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry, newsize)) ;
+ }
+
+ /* try again with the smallest possible size */
+ if (!eloc)
+ {
+ fnr2 = fnr_min ;
+ fnc2 = fnc_min ;
+ newsize = minsize ;
+ DEBUG0 (("Attempt minsize: "ID"-by-"ID"\n", fnr2, fnc2)) ;
+ eloc = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry, newsize)) ;
+ }
+
+ if (!eloc)
+ {
+ /* out of memory */
+ return (FALSE) ;
+ }
+
+ ASSERT (fnr2 >= 0) ;
+ ASSERT (fnr2 % 2 == 1) ;
+ ASSERT (fnr2 >= fnr_min && fnc2 >= fnc_min) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* copy the old frontal matrix into the new one */
+ /* ---------------------------------------------------------------------- */
+
+ /* old contribution block (if any) */
+ fnr_curr = Work->fnr_curr ; /* garbage collection can change fn*_curr */
+ ASSERT (fnr_curr >= 0) ;
+ ASSERT ((fnr_curr % 2 == 1) || fnr_curr == 0) ;
+ fnrows = Work->fnrows ;
+ fncols = Work->fncols ;
+ Fcold = Work->Fcblock ;
+
+ /* remove nb from the sizes */
+ fnr2 -= nb ;
+ fnc2 -= nb ;
+
+ /* new frontal matrix */
+ Work->Flublock = (Entry *) (Numeric->Memory + eloc) ;
+ Work->Flblock = Work->Flublock + nb * nb ;
+ Work->Fublock = Work->Flblock + nb * fnr2 ;
+ Work->Fcblock = Work->Fublock + nb * fnc2 ;
+ Fcnew = Work->Fcblock ;
+
+ if (E [0])
+ {
+ /* copy the old contribution block into the new one */
+ for (j = 0 ; j < fncols ; j++)
+ {
+ col = Fcols [j] ;
+ DEBUG1 (("copy col "ID" \n",col)) ;
+ ASSERT (col >= 0 && col < Work->n_col) ;
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ Fcnew [i] = Fcold [i] ;
+ }
+ Fcnew += fnr2 ;
+ Fcold += fnr_curr ;
+ DEBUG1 (("new offset col "ID" "ID"\n",col, j * fnr2)) ;
+ Fcpos [col] = j * fnr2 ;
+ }
+ }
+ else if (do_what == 2)
+ {
+ /* just find the new column offsets */
+ for (j = 0 ; j < fncols ; j++)
+ {
+ col = Fcols [j] ;
+ DEBUG1 (("new offset col "ID" "ID"\n",col, j * fnr2)) ;
+ Fcpos [col] = j * fnr2 ;
+ }
+ }
+
+ /* free the old frontal matrix */
+ UMF_mem_free_tail_block (Numeric, E [0]) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* new frontal matrix size */
+ /* ---------------------------------------------------------------------- */
+
+ E [0] = eloc ;
+ Work->fnr_curr = fnr2 ; /* C block is fnr2-by-fnc2 */
+ Work->fnc_curr = fnc2 ;
+ Work->fcurr_size = newsize ; /* including LU, L, U, and C blocks */
+ Work->do_grow = FALSE ; /* the front has just been grown */
+
+ ASSERT (Work->fnr_curr >= 0) ;
+ ASSERT (Work->fnr_curr % 2 == 1) ;
+ DEBUG0 (("Newly grown front: "ID"+"ID" by "ID"+"ID"\n", Work->fnr_curr,
+ nb, Work->fnc_curr, nb)) ;
+ return (TRUE) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_grow_front
+(
+ NumericType *Numeric,
+ Int fnr2,
+ Int fnc2,
+ WorkType *Work,
+ Int do_what
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_init_front ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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"
+#include "umf_grow_front.h"
+
+/* ========================================================================== */
+/* === zero_init_front ====================================================== */
+/* ========================================================================== */
+
+/* Set the initial frontal matrix to zero. */
+
+PRIVATE void zero_init_front (Int m, Int n, Entry *Fcblock, Int d)
+{
+ Int i, j ;
+ Entry *F, *Fj = Fcblock ;
+ for (j = 0 ; j < m ; j++)
+ {
+ F = Fj ;
+ Fj += d ;
+ for (i = 0 ; i < n ; i++)
+ {
+ /* CLEAR (Fcblock [i + j*d]) ; */
+ CLEAR (*F) ;
+ F++ ;
+ }
+ }
+}
+
+/* ========================================================================== */
+/* === UMF_init_front ======================================================= */
+/* ========================================================================== */
+
+GLOBAL Int UMF_init_front
+(
+ NumericType *Numeric,
+ WorkType *Work
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int i, j, fnr_curr, row, col, *Frows, *Fcols,
+ *Fcpos, *Frpos, fncols, fnrows, *Wrow, fnr2, fnc2, rrdeg, ccdeg, *Wm,
+ fnrows_extended ;
+ Entry *Fcblock, *Fl, *Wy, *Wx ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get current frontal matrix and check for frontal growth */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ DEBUG0 (("INIT FRONT\n")) ;
+ DEBUG1 (("CURR before init:\n")) ;
+ UMF_dump_current_front (Numeric, Work, FALSE) ;
+#endif
+ if (Work->do_grow)
+ {
+ fnr2 = UMF_FRONTAL_GROWTH * Work->fnrows_new + 2 ;
+ fnc2 = UMF_FRONTAL_GROWTH * Work->fncols_new + 2 ;
+ if (!UMF_grow_front (Numeric, fnr2, fnc2, Work,
+ Work->pivrow_in_front ? 2 : 0))
+ {
+ /* :: out of memory in umf_init_front :: */
+ DEBUGm4 (("out of memory: init front\n")) ;
+ return (FALSE) ;
+ }
+ }
+#ifndef NDEBUG
+ DEBUG1 (("CURR after grow:\n")) ;
+ UMF_dump_current_front (Numeric, Work, FALSE) ;
+ DEBUG1 (("fnrows new "ID" fncols new "ID"\n",
+ Work->fnrows_new, Work->fncols_new)) ;
+#endif
+ ASSERT (Work->fnpiv == 0) ;
+ fnr_curr = Work->fnr_curr ;
+ ASSERT (Work->fnrows_new + 1 <= fnr_curr) ;
+ ASSERT (Work->fncols_new + 1 <= Work->fnc_curr) ;
+ ASSERT (fnr_curr >= 0) ;
+ ASSERT (fnr_curr % 2 == 1) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ /* current front is defined by pivot row and column */
+
+ Frows = Work->Frows ;
+ Fcols = Work->Fcols ;
+ Frpos = Work->Frpos ;
+ Fcpos = Work->Fcpos ;
+
+ Work->fnzeros = 0 ;
+
+ ccdeg = Work->ccdeg ;
+ rrdeg = Work->rrdeg ;
+
+ fnrows = Work->fnrows ;
+ fncols = Work->fncols ;
+
+ /* 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 && Work->pivcol_in_front)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* place pivot column pattern in frontal matrix */
+ /* ---------------------------------------------------------------------- */
+
+ Fl = Work->Flblock ;
+
+ 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 ... fnrows-1] (the old pattern), and
+ * Frows [fnrows ... fnrows + Work->ccdeg - 1] (the new
+ * pattern). Frpos is also properly defined. */
+ /* make a list of the new rows to scan */
+ Work->fscan_row = fnrows ; /* only scan the new rows */
+ Work->NewRows = Work->Wrp ;
+ Wy = Work->Wy ;
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ Fl [i] = Wy [i] ;
+ }
+ fnrows_extended = fnrows + ccdeg ;
+ for (i = fnrows ; i < fnrows_extended ; i++)
+ {
+ Fl [i] = Wy [i] ;
+ /* flip the row index, since Wrp must be < 0 */
+ row = Frows [i] ;
+ Work->NewRows [i] = FLIP (row) ;
+ }
+ fnrows = fnrows_extended ;
+ }
+ else
+ {
+ /* this is a completely new column */
+ Work->fscan_row = 0 ; /* scan all the rows */
+ Work->NewRows = Frows ;
+ Wm = Work->Wm ;
+ Wx = Work->Wx ;
+ for (i = 0 ; i < ccdeg ; i++)
+ {
+ Fl [i] = Wx [i] ;
+ row = Wm [i] ;
+ Frows [i] = row ;
+ Frpos [row] = i ;
+ }
+ fnrows = ccdeg ;
+ }
+
+ Work->fnrows = fnrows ;
+
+#ifndef NDEBUG
+ DEBUG3 (("New Pivot col "ID" now in front, length "ID"\n",
+ Work->pivcol, fnrows)) ;
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ DEBUG4 ((" "ID": row "ID"\n", i, Frows [i])) ;
+ ASSERT (Frpos [Frows [i]] == i) ;
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* place pivot row pattern in frontal matrix */
+ /* ---------------------------------------------------------------------- */
+
+ Wrow = Work->Wrow ;
+ if (Work->pivrow_in_front)
+ {
+ /* append the pivot row extension */
+ Work->fscan_col = fncols ; /* only scan the new columns */
+ Work->NewCols = Work->Wp ;
+#ifndef NDEBUG
+ for (j = 0 ; j < fncols ; j++)
+ {
+ col = Fcols [j] ;
+ ASSERT (col >= 0 && col < Work->n_col) ;
+ ASSERT (Fcpos [col] == j * fnr_curr) ;
+ }
+#endif
+ /* Wrow == Fcol for the IN_IN case, and for the OUT_IN case when
+ * the pivrow [IN][IN] happens to be the same as pivrow [OUT][IN].
+ * See UMF_local_search for more details. */
+ ASSERT (IMPLIES (Work->pivcol_in_front, Wrow == Fcols)) ;
+ if (Wrow == Fcols)
+ {
+ for (j = fncols ; j < rrdeg ; j++)
+ {
+ col = Wrow [j] ;
+ /* Fcols [j] = col ; not needed */
+ /* flip the col index, since Wp must be < 0 */
+ Work->NewCols [j] = FLIP (col) ;
+ Fcpos [col] = j * fnr_curr ;
+ }
+ }
+ else
+ {
+ for (j = fncols ; j < rrdeg ; j++)
+ {
+ col = Wrow [j] ;
+ Fcols [j] = col ;
+ /* flip the col index, since Wp must be < 0 */
+ Work->NewCols [j] = FLIP (col) ;
+ Fcpos [col] = j * fnr_curr ;
+ }
+ }
+ }
+ else
+ {
+ /* this is a completely new row */
+ Work->fscan_col = 0 ; /* scan all the columns */
+ Work->NewCols = Fcols ;
+ for (j = 0 ; j < rrdeg ; j++)
+ {
+ col = Wrow [j] ;
+ Fcols [j] = col ;
+ Fcpos [col] = j * fnr_curr ;
+ }
+ }
+
+ DEBUGm1 (("rrdeg "ID" fncols "ID"\n", rrdeg, fncols)) ;
+ fncols = rrdeg ;
+ Work->fncols = fncols ;
+
+ /* ---------------------------------------------------------------------- */
+ /* clear the frontal matrix */
+ /* ---------------------------------------------------------------------- */
+
+ ASSERT (fnrows == Work->fnrows_new + 1) ;
+ ASSERT (fncols == Work->fncols_new + 1) ;
+
+ Fcblock = Work->Fcblock ;
+ ASSERT (Fcblock != (Entry *) NULL) ;
+
+ zero_init_front (fncols, fnrows, Fcblock, fnr_curr) ;
+
+#ifndef NDEBUG
+ DEBUG3 (("New Pivot row "ID" now in front, length "ID" fnr_curr "ID"\n",
+ Work->pivrow, fncols, fnr_curr)) ;
+ for (j = 0 ; j < fncols ; j++)
+ {
+ DEBUG4 (("col "ID" position "ID"\n", j, Fcols [j])) ;
+ ASSERT (Fcpos [Fcols [j]] == j * fnr_curr) ;
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* current workspace usage: */
+ /* ---------------------------------------------------------------------- */
+
+ /* Fcblock [0..fnr_curr-1, 0..fnc_curr-1]: space for the new frontal
+ * matrix. Fcblock (i,j) is located at Fcblock [i+j*fnr_curr] */
+
+ return (TRUE) ;
+
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_init_front
+(
+ NumericType *Numeric,
+ WorkType *Work
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === umf_internal.h ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+/*
+ This file is for internal use in UMFPACK itself, and should not be included
+ in user code. Use umfpack.h instead. User-accessible file names and
+ routine names all start with the letters "umfpack_". Non-user-accessible
+ file names and routine names all start with "umf_".
+*/
+
+/* -------------------------------------------------------------------------- */
+/* ANSI standard include files */
+/* -------------------------------------------------------------------------- */
+
+/* from float.h: DBL_EPSILON */
+#include <float.h>
+
+/* from string.h: strcmp */
+#include <string.h>
+
+/* when debugging, assert.h and the assert macro are used (see umf_dump.h) */
+
+/* -------------------------------------------------------------------------- */
+/* Architecture */
+/* -------------------------------------------------------------------------- */
+
+#if defined (__sun) || defined (MSOL2) || defined (ARCH_SOL2)
+#define UMF_SOL2
+#define UMFPACK_ARCHITECTURE "Sun Solaris"
+
+#elif defined (__sgi) || defined (MSGI) || defined (ARCH_SGI)
+#define UMF_SGI
+#define UMFPACK_ARCHITECTURE "SGI Irix"
+
+#elif defined (__linux) || defined (MGLNX86) || defined (ARCH_GLNX86)
+#define UMF_LINUX
+#define UMFPACK_ARCHITECTURE "Linux"
+
+#elif defined (_AIX) || defined (MIBM_RS) || defined (ARCH_IBM_RS)
+#define UMF_AIX
+#define UMFPACK_ARCHITECTURE "IBM AIX"
+
+#elif defined (__alpha) || defined (MALPHA) || defined (ARCH_ALPHA)
+#define UMF_ALPHA
+#define UMFPACK_ARCHITECTURE "Compaq Alpha"
+
+#elif defined (__WIN32) || defined (_WIN32) || defined (_win32) || defined (__win32) || defined (WIN32)
+#define UMF_WINDOWS
+#define UMFPACK_ARCHITECTURE "Microsoft Windows"
+
+#elif defined (__hppa) || defined (__hpux) || defined (MHPUX) || defined (ARCH_HPUX)
+#define UMF_HP
+#define UMFPACK_ARCHITECTURE "HP Unix"
+
+#elif defined (__hp700) || defined (MHP700) || defined (ARCH_HP700)
+#define UMF_HP
+#define UMFPACK_ARCHITECTURE "HP 700 Unix"
+
+#else
+/* If the architecture is unknown, and you call the BLAS, you may need to */
+/* define BLAS_BY_VALUE, BLAS_NO_UNDERSCORE, and/or BLAS_CHAR_ARG yourself. */
+#define UMFPACK_ARCHITECTURE "unknown"
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* basic definitions (see also amd_internal.h) */
+/* -------------------------------------------------------------------------- */
+
+#define ONES_COMPLEMENT(r) (-(r)-1)
+
+/* -------------------------------------------------------------------------- */
+/* AMD include file */
+/* -------------------------------------------------------------------------- */
+
+/* stdio.h, stdlib.h, limits.h, and math.h, NDEBUG definition,
+ * assert.h, and MATLAB include files */
+#include "amd_internal.h"
+
+/* -------------------------------------------------------------------------- */
+/* Real/complex and int/long definitions, double relops */
+/* -------------------------------------------------------------------------- */
+
+#include "umf_version.h"
+
+/* -------------------------------------------------------------------------- */
+/* Compile-time configurations */
+/* -------------------------------------------------------------------------- */
+
+#include "umf_config.h"
+
+/* -------------------------------------------------------------------------- */
+/* umfpack include file */
+/* -------------------------------------------------------------------------- */
+
+#include "umfpack.h"
+
+/* -------------------------------------------------------------------------- */
+/* for contents of Info. This must correlate with umfpack.h */
+/* -------------------------------------------------------------------------- */
+
+#define ESTIMATE (UMFPACK_NUMERIC_SIZE_ESTIMATE - UMFPACK_NUMERIC_SIZE)
+#define ACTUAL 0
+
+/* -------------------------------------------------------------------------- */
+/* get a parameter from the Control array */
+/* -------------------------------------------------------------------------- */
+
+#define GET_CONTROL(i,default) \
+ ((Control != (double *) NULL) ? \
+ (SCALAR_IS_NAN (Control [i]) ? default : Control [i]) \
+ : default)
+
+/* -------------------------------------------------------------------------- */
+/* for clearing the external degree counters */
+/* -------------------------------------------------------------------------- */
+
+#define MAX_MARK(n) Int_MAX - (2*(n)+1)
+
+/* -------------------------------------------------------------------------- */
+/* convert number of Units to MBytes */
+/* -------------------------------------------------------------------------- */
+
+#define MBYTES(units) (((units) * sizeof (Unit)) / 1048576.0)
+
+/* -------------------------------------------------------------------------- */
+/* dense row/column macro */
+/* -------------------------------------------------------------------------- */
+
+/* In order for a row or column to be treated as "dense", it must have more */
+/* entries than the value returned by this macro. n is the dimension of the */
+/* matrix, and alpha is the dense row/column control parameter. */
+
+/* Note: this is not defined if alpha is NaN or Inf: */
+#define UMFPACK_DENSE_DEGREE_THRESHOLD(alpha,n) \
+ ((Int) MAX (16.0, (alpha) * 16.0 * sqrt ((double) (n))))
+
+/* -------------------------------------------------------------------------- */
+/* PRINTF */
+/* -------------------------------------------------------------------------- */
+
+#define PRINTFk(k,params) { if (prl >= (k)) { PRINTF (params) ; } }
+#define PRINTF1(params) PRINTFk (1, params)
+#define PRINTF2(params) PRINTFk (2, params)
+#define PRINTF3(params) PRINTFk (3, params)
+#define PRINTF4(params) PRINTFk (4, params)
+#define PRINTF5(params) PRINTFk (5, params)
+#define PRINTF6(params) PRINTFk (6, params)
+
+/* -------------------------------------------------------------------------- */
+/* Fixed control parameters */
+/* -------------------------------------------------------------------------- */
+
+/* maximum number of columns to consider at one time, in a single front */
+#define MAX_CANDIDATES 128
+
+/* reduce Numeric->Memory request by this ratio, if allocation fails */
+#define UMF_REALLOC_REDUCTION (0.95)
+
+/* increase Numeric->Memory request by this ratio, if we need more */
+#define UMF_REALLOC_INCREASE (1.2)
+
+/* increase the dimensions of the current frontal matrix by this factor
+ * when it needs to grow. */
+#define UMF_FRONTAL_GROWTH (1.2)
+
+/* largest BLAS block size permitted */
+#define MAXNB 64
+
+/* if abs (y) < RECIPROCAL_TOLERANCE, then compute x/y. Otherwise x*(1/y).
+ * Ignored if NRECIPROCAL is defined */
+#define RECIPROCAL_TOLERANCE 1e-12
+
+/* -------------------------------------------------------------------------- */
+/* Memory allocator */
+/* -------------------------------------------------------------------------- */
+
+/* The MATLAB mexFunction uses MATLAB's memory manager, while the C-callable
+ * AMD library uses the ANSI C malloc, free, and realloc routines. To use
+ * the mx* memory allocation routines, use -DNUTIL when compiling.
+ */
+
+#undef ALLOCATE
+#undef FREE
+#undef REALLOC
+
+#ifdef MATLAB_MEX_FILE
+
+#ifdef NUTIL
+
+/* These functions simply terminate the mexFunction if they fail to allocate
+ * memory. That's too restrictive for UMFPACK. */
+#define ALLOCATE mxMalloc
+#define FREE mxFree
+#define REALLOCATE mxRealloc
+
+#else
+
+/* Use internal MATLAB memory allocation routines, used by built-in MATLAB
+ * functions. These are not documented, but are available for use. Their
+ * prototypes are in util.h, but that file is not provided to the MATLAB user.
+ * The advantage of using these routines is that they return NULL if out of
+ * memory, instead of terminating the mexFunction. UMFPACK attempts to allocate
+ * extra space for "elbow room", and then reduces its request if the memory is
+ * not available. That strategy doesn't work with the mx* routines.
+ */
+void *utMalloc (size_t size) ;
+void utFree (void *p) ;
+void *utRealloc (void *p, size_t size) ;
+#define ALLOCATE utMalloc
+#define FREE utFree
+#define REALLOCATE utRealloc
+
+#endif
+#else
+#ifdef MATHWORKS
+
+/* Compiling as a built-in routine. Since out-of-memory conditions are checked
+ * after every allocation, we can use ut* routines here. */
+#define ALLOCATE utMalloc
+#define FREE utFree
+#define REALLOCATE utRealloc
+
+#else
+
+/* use the ANSI C memory allocation routines */
+#define ALLOCATE malloc
+#define FREE free
+#define REALLOCATE realloc
+
+#endif
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* Memory space definitions */
+/* -------------------------------------------------------------------------- */
+
+/* for memory alignment - assume double has worst case alignment */
+typedef double Align ;
+
+/* get number of bytes required to hold n items of a type: */
+/* note that this will not overflow, because sizeof (type) is always */
+/* greater than or equal to sizeof (Int) >= 2 */
+#define BYTES(type,n) (sizeof (type) * (n))
+
+/* ceiling of (b/u). Assumes b >= 0 and u > 0 */
+#define CEILING(b,u) (((b) + (u) - 1) / (u))
+
+/* get number of Units required to hold n items of a type: */
+#define UNITS(type,n) (CEILING (BYTES (type, n), sizeof (Unit)))
+
+/* same as DUNITS, but use double instead of int to avoid overflow */
+#define DUNITS(type,n) (ceil (BYTES (type, (double) n) / sizeof (Unit)))
+
+union Unit_union
+{ /* memory is allocated in multiples of Unit */
+ struct
+ {
+ Int
+ size, /* size, in Units, of the block, excl. header block */
+ /* size >= 0: block is in use */
+ /* size < 0: block is free, of |size| Units */
+ prevsize ; /* size, in Units, of preceding block in S->Memory */
+ /* during garbage_collection, prevsize is set to -e-1 */
+ /* for element e, or positive (and thus a free block) */
+ /* otherwise */
+ } header ; /* block header */
+ Align xxxxxx ; /* force alignment of blocks (xxxxxx is never used) */
+} ;
+
+typedef union Unit_union Unit ;
+
+/* get the size of an allocated block */
+#define GET_BLOCK_SIZE(p) (((p)-1)->header.size)
+
+/* -------------------------------------------------------------------------- */
+/* Numeric */
+/* -------------------------------------------------------------------------- */
+
+/*
+ NUMERIC_VALID and SYMBOLIC_VALID:
+ The different values of SYBOLIC_VALID and NUMERIC_VALID are chosen as a
+ first defense against corrupted *Symbolic or *Numeric pointers passed to an
+ UMFPACK routine. They also ensure that the objects are used only by the
+ same version that created them (umfpack_di_*, umfpack_dl_*, umfpack_zi_*,
+ or umfpack_zl_*). The values have also been changed since prior releases of
+ the code to ensure that all routines that operate on the objects are of the
+ same release. The values themselves are purely arbitrary. The are less
+ than the ANSI C required minimums of INT_MAX and LONG_MAX, respectively.
+*/
+
+#ifdef DINT
+#define NUMERIC_VALID 15977
+#define SYMBOLIC_VALID 41937
+#endif
+#ifdef DLONG
+#define NUMERIC_VALID 399789720
+#define SYMBOLIC_VALID 399192713
+#endif
+#ifdef ZINT
+#define NUMERIC_VALID 17957
+#define SYMBOLIC_VALID 40927
+#endif
+#ifdef ZLONG
+#define NUMERIC_VALID 129987754
+#define SYMBOLIC_VALID 110291734
+#endif
+
+typedef struct /* NumericType */
+{
+ double
+ flops, /* "true" flop count */
+ relpt, /* relative pivot tolerance used */
+ relpt2, /* relative pivot tolerance used for sym. */
+ droptol,
+ alloc_init, /* initial allocation of Numeric->memory */
+ front_alloc_init, /* frontal matrix allocation parameter */
+ rsmin, /* smallest row sum */
+ rsmax, /* largest row sum */
+ min_udiag, /* smallest abs value on diagonal of D */
+ max_udiag, /* smallest abs value on diagonal of D */
+ rcond ; /* min (D) / max (D) */
+
+ Int
+ scale ;
+
+ Int valid ; /* set to NUMERIC_VALID, for validity check */
+
+ /* Memory space for A and LU factors */
+ Unit
+ *Memory ; /* working memory for A and LU factors */
+ Int
+ ihead, /* pointer to tail of LU factors, in Numeric->Memory */
+ itail, /* pointer to top of elements & tuples, */
+ /* in Numeric->Memory */
+ ibig, /* pointer to largest free block seen in tail */
+ size ; /* size of Memory, in Units */
+
+ Int
+ *Rperm, /* pointer to row perm array, size: n+1 */
+ /* after UMF_kernel: Rperm [new] = old */
+ /* during UMF_kernel: Rperm [old] = new */
+ *Cperm, /* pointer to col perm array, size: n+1 */
+ /* after UMF_kernel: Cperm [new] = old */
+ /* during UMF_kernel: Cperm [old] = new */
+
+ *Upos, /* see UMFPACK_get_numeric for a description */
+ *Lpos,
+ *Lip,
+ *Lilen,
+ *Uip,
+ *Uilen,
+ *Upattern ; /* pattern of last row of U (if singular) */
+
+ Int
+ ulen, /* length of Upattern */
+ npiv, /* number of structural pivots found (sprank approx) */
+ nnzpiv ; /* number of numerical (nonzero) pivots found */
+
+ Entry
+ *D ; /* D [i] is the diagonal entry of U */
+
+ Int do_recip ;
+ double *Rs ; /* scale factors for the rows of A and b */
+ /* do_recip FALSE: Divide row i by Rs [i] */
+ /* do_recip TRUE: Multiply row i by Rs [i] */
+
+ Int
+ n_row, n_col, /* A is n_row-by-n_row */
+ n1 ; /* number of singletons */
+
+ /* for information only: */
+ Int
+ tail_usage, /* amount of memory allocated in tail */
+ /* head_usage is Numeric->ihead */
+ init_usage, /* memory usage just after UMF_kernel_init */
+ max_usage, /* peak memory usage (excludes internal and external */
+ /* fragmentation in the tail) */
+ ngarbage, /* number of garbage collections performed */
+ nrealloc, /* number of reallocations performed */
+ ncostly, /* number of costly reallocations performed */
+ isize, /* size of integer pattern of L and U */
+ nLentries, /* number of entries in L, excluding diagonal */
+ nUentries, /* number of entries in U, including diagonal */
+ /* Some entries may be numerically zero. */
+ lnz, /* number of nonzero entries in L, excl. diagonal */
+ all_lnz, /* lnz plus entries dropped from L */
+ unz, /* number of nonzero entries in U, excl. diagonal */
+ all_unz, /* unz plus entries dropped form U */
+ maxfrsize ; /* largest actual front size */
+
+ Int maxnrows, maxncols ; /* not the same as Symbolic->maxnrows/cols* */
+
+} NumericType ;
+
+
+
+/* -------------------------------------------------------------------------- */
+/* Element tuples for connecting elements together in a matrix */
+/* -------------------------------------------------------------------------- */
+
+typedef struct /* Tuple */
+{
+ /* The (e,f) tuples for the element lists */
+ Int
+ e, /* element */
+ f ; /* contribution to the row/col appears at this offset */
+
+} Tuple ;
+
+#define TUPLES(t) MAX (4, (t) + 1)
+
+/* Col_degree is aliased with Cperm, and Row_degree with Rperm */
+#define NON_PIVOTAL_COL(col) (Col_degree [col] >= 0)
+#define NON_PIVOTAL_ROW(row) (Row_degree [row] >= 0)
+
+/* -------------------------------------------------------------------------- */
+/* An element */
+/* -------------------------------------------------------------------------- */
+
+typedef struct /* Element */
+{
+ Int
+
+ cdeg, /* external column degree + cdeg0 offset */
+ rdeg, /* external row degree + rdeg0 offset */
+ nrowsleft, /* number of rows remaining */
+ ncolsleft, /* number of columns remaining */
+ nrows, /* number of rows */
+ ncols, /* number of columns */
+ next ; /* for list link of sons, used during assembly only */
+
+ /* followed in memory by:
+ Int
+ col [0..ncols-1], column indices of this element
+ row [0..nrows-1] ; row indices of this element
+ Entry (suitably aligned, see macro below)
+ C [0...nrows-1, 0...ncols-1] ;
+ size of C is nrows*ncols Entry's
+ */
+
+} Element ;
+
+/* macros for computing pointers to row/col indices, and contribution block: */
+
+#define GET_ELEMENT_SIZE(nr,nc) \
+(UNITS (Element, 1) + UNITS (Int, (nc) + (nr)) + UNITS (Entry, (nc) * (nr)))
+
+#define DGET_ELEMENT_SIZE(nr,nc) \
+(DUNITS (Element, 1) + DUNITS (Int, (nc) + (nr)) + DUNITS (Entry, (nc) * (nr)))
+
+#define GET_ELEMENT_COLS(ep,p,Cols) { \
+ ASSERT (p != (Unit *) NULL) ; \
+ ASSERT (p >= Numeric->Memory + Numeric->itail) ; \
+ ASSERT (p <= Numeric->Memory + Numeric->size) ; \
+ ep = (Element *) p ; \
+ p += UNITS (Element, 1) ; \
+ Cols = (Int *) p ; \
+}
+
+#define GET_ELEMENT_PATTERN(ep,p,Cols,Rows,ncm) { \
+ GET_ELEMENT_COLS (ep, p, Cols) ; \
+ ncm = ep->ncols ; \
+ Rows = Cols + ncm ; \
+}
+
+#define GET_ELEMENT(ep,p,Cols,Rows,ncm,nrm,C) { \
+ GET_ELEMENT_PATTERN (ep, p, Cols, Rows, ncm) ; \
+ nrm = ep->nrows ; \
+ p += UNITS (Int, ncm + nrm) ; \
+ C = (Entry *) p ; \
+}
+
+/* -------------------------------------------------------------------------- */
+/* Work data structure */
+/* -------------------------------------------------------------------------- */
+
+/*
+ This data structure holds items needed only during factorization.
+ All of this is freed when UMFPACK_numeric completes. Note that some of
+ it is stored in the tail end of Numeric->S (namely, the Tuples and the
+ Elements).
+*/
+
+typedef struct /* WorkType */
+{
+
+ /* ---------------------------------------------------------------------- */
+ /* information about each row and col of A */
+ /* ---------------------------------------------------------------------- */
+
+ /*
+ Row_tuples: pointer to tuple list (alias with Numeric->Uip)
+ Row_tlen: number of tuples (alias with Numeric->Uilen)
+ Col_tuples: pointer to tuple list (alias with Numeric->Lip)
+ Col_tlen: number of tuples (alias with Numeric->Lilen)
+ Row_degree: degree of the row or column (alias Numeric->Rperm)
+ Col_degree: degree of the row or column (alias Numeric->Cperm)
+
+ The Row_degree and Col_degree are MATLAB-style colmmd approximations,
+ are equal to the sum of the sizes of the elements (contribution blocks)
+ in each row and column. They are maintained when elements are created
+ and assembled. They are used only during the pivot row and column
+ search. They are not needed to represent the pattern of the remaining
+ matrix.
+ */
+
+ /* ---------------------------------------------------------------------- */
+ /* information about each element */
+ /* ---------------------------------------------------------------------- */
+
+ Int *E ; /* E [0 .. Work->elen-1] element "pointers" */
+ /* (offsets in Numeric->Memory) */
+
+ /* ---------------------------------------------------------------------- */
+ /* generic workspace */
+ /* ---------------------------------------------------------------------- */
+
+ Entry *Wx, *Wy ; /* each of size maxnrows+1 */
+
+ Int /* Sizes: nn = MAX (n_row, n_col) */
+ *Wp, /* nn+1 */
+ *Wrp, /* n_col+1 */
+ *Wm, /* maxnrows+1 */
+ *Wio, /* maxncols+1 */
+ *Woi, /* maxncols+1 */
+ *Woo, /* MAX (maxnrows,maxncols)+1 */
+ *Wrow, /* pointer to Fcols, Wio, or Woi */
+ *NewRows, /* list of rows to scan */
+ *NewCols ; /* list of cols to scan */
+
+ /* ---------------------------------------------------------------------- */
+
+ Int
+ *Lpattern, /* pattern of column of L, for one Lchain */
+ *Upattern, /* pattern of row of U, for one Uchain */
+ ulen, llen ; /* length of Upattern and Lpattern */
+
+ Int
+ *Diagonal_map, /* used for symmetric pivoting, of size nn+1 */
+ *Diagonal_imap ;/* used for symmetric pivoting, of size nn+1 */
+
+ /* ---------------------------------------------------------------------- */
+
+ Int
+ n_row, n_col, /* matrix is n_row-by-n_col */
+ nz, /* nonzeros in the elements for this matrix */
+ n1, /* number of row and col singletons */
+ elen, /* max possible number of elements */
+ npiv, /* number of pivot rows and columns so far */
+ ndiscard, /* number of discarded pivot columns */
+ Wrpflag,
+ nel, /* elements in use are in the range 1..nel */
+ noff_diagonal,
+ prior_element,
+ rdeg0, cdeg0,
+ rrdeg, ccdeg,
+ Candidates [MAX_CANDIDATES], /* current candidate pivot columns */
+ nCandidates, /* number of candidates in Candidate set */
+ ksuper,
+ firstsuper,
+ jsuper,
+ ncand, /* number of candidates (some not in Candidates[ ]) */
+ nextcand, /* next candidate to place in Candidate search set */
+ lo,
+ hi,
+ pivrow, /* current pivot row */
+ pivcol, /* current pivot column */
+ do_extend, /* true if the next pivot extends the current front */
+ do_update, /* true if update should be applied */
+ nforced, /* number of forced updates because of frontal growth */
+ any_skip,
+ do_scan2row,
+ do_scan2col,
+ do_grow,
+ pivot_case,
+ frontid, /* id of current frontal matrix */
+ nfr ; /* number of frontal matrices */
+
+ /* ---------------------------------------------------------------------- */
+ /* For row-merge tree */
+ /* ---------------------------------------------------------------------- */
+
+ Int
+ *Front_new1strow ;
+
+ /* ---------------------------------------------------------------------- */
+ /* current frontal matrix, F */
+ /* ---------------------------------------------------------------------- */
+
+ Int Pivrow [MAXNB],
+ Pivcol [MAXNB] ;
+
+ Entry
+ *Flublock, /* LU block, nb-by-nb */
+ *Flblock, /* L block, fnr_curr-by-nb */
+ *Fublock, /* U block, nb-by-fnc_curr, or U' fnc_curr-by-nb */
+ *Fcblock ; /* C block, fnr_curr-by-fnc_curr */
+
+ Int
+ *Frows, /* Frows [0.. ]: row indices of F */
+
+ *Fcols, /* Fcols [0.. ]: column indices of F */
+
+ *Frpos, /* position of row indices in F, or -1 if not present */
+ /* if Frows[i] == row, then Frpos[row] == i */
+
+ *Fcpos, /* position of col indices in F, or -1 if not present */
+ /* if Fcols[j] == col, then */
+ /* Fcpos[col] == j*Work->fnr_curr */
+
+ fnrows, /* number of rows in contribution block in F */
+ fncols, /* number of columns in contribution block in F */
+ fnr_curr, /* maximum # of rows in F (leading dimension) */
+ fnc_curr, /* maximum # of columns in F */
+ fcurr_size, /* current size of F */
+ fnrows_max, /* max possible column-dimension (max # of rows) of F */
+ fncols_max, /* max possible row-dimension (max # of columns) of F */
+ nb,
+ fnpiv, /* number of pivots in F */
+ fnzeros, /* number of explicit zero entries in LU block */
+ fscan_row, /* where to start scanning rows of F in UMF_assemble */
+ fscan_col, /* where to start scanning cols of F in UMF_assemble */
+ fnrows_new, /* number of new row indices in F after pivot added */
+ fncols_new, /* number of new col indices in F after pivot added */
+ pivrow_in_front, /* true if current pivot row in Frows */
+ pivcol_in_front ; /* true if current pivot column in Fcols */
+
+ /* ----------------------------------------------------------------------
+ * Current frontal matrix
+ * ----------------------------------------------------------------------
+ * The current frontal matrix is held as a single block of memory allocated
+ * from the "tail" end of Numeric->Memory. It is subdivided into four
+ * parts: an LU block, an L block, a U block, and a C block.
+ *
+ * Let k = fnpiv, r = fnrows, and c = fncols for the following discussion.
+ * Let dr = fnr_curr and dc = fnc_curr. Note that r <= dr and c <= dc.
+ *
+ * The LU block is of dimension nb-by-nb. The first k-by-k part holds the
+ * "diagonal" part of the LU factors for these k pivot rows and columns.
+ * The k pivot row and column indices in this part are Pivrow [0..k-1] and
+ * Pivcol [0..k-1], respectively.
+ *
+ * The L block is of dimension dr-by-nb. It holds the k pivot columns,
+ * except for the leading k-by-k part in the LU block. Only the leading
+ * r-by-k part is in use.
+ *
+ * The U block is of dimension dc-by-nb. It holds the k pivot rows,
+ * except for the leading k-by-k part in the LU block. It is stored in
+ * row-oriented form. Only the leading c-by-k part is in use.
+ *
+ * The C block is of dimension dr-by-dc. It holds the current contribution
+ * block. Only the leading r-by-c part is in use. The column indices in
+ * the C block are Fcols [0..c-1], and the row indices are Frows [0..r-1].
+ *
+ * dr is always odd, to avoid bad cache behavior.
+ */
+
+} WorkType ;
+
+
+/* -------------------------------------------------------------------------- */
+/* Symbolic */
+/* -------------------------------------------------------------------------- */
+
+/*
+ This is is constructed by UMFPACK_symbolic, and is needed by UMFPACK_numeric
+ to factor the matrix.
+*/
+
+typedef struct /* SymbolicType */
+{
+
+ double
+ num_mem_usage_est, /* estimated max Numeric->Memory size */
+ num_mem_size_est, /* estimated final Numeric->Memory size */
+ peak_sym_usage, /* peak Symbolic and SymbolicWork usage */
+ sym, /* symmetry of pattern */
+ dnum_mem_init_usage, /* min Numeric->Memory for UMF_kernel_init */
+ amd_lunz, /* nz in LU for AMD, with symmetric pivoting */
+ lunz_bound ; /* max nx in LU, for arbitrary row pivoting */
+
+ Int valid, /* set to SYMBOLIC_VALID, for validity check */
+ max_nchains,
+ nchains,
+ *Chain_start,
+ *Chain_maxrows,
+ *Chain_maxcols,
+ maxnrows, /* largest number of rows in any front */
+ maxncols, /* largest number of columns in any front */
+ *Front_npivcol, /* Front_npivcol [j] = size of jth supercolumn*/
+ *Front_1strow, /* first row index in front j */
+ *Front_leftmostdesc, /* leftmost desc of front j */
+ *Front_parent, /* super-column elimination tree */
+ *Cperm_init, /* initial column ordering */
+ *Rperm_init, /* initial row ordering */
+ *Cdeg, *Rdeg,
+ *Esize,
+ dense_row_threshold,
+ n1, /* number of singletons */
+ nempty, /* MIN (nempty_row, nempty_col) */
+ *Diagonal_map, /* initial "diagonal" (after 2by2) */
+ esize, /* size of Esize array */
+ nfr,
+ n_row, n_col, /* matrix A is n_row-by-n_col */
+ nz, /* nz of original matrix */
+ nb, /* block size for BLAS 3 */
+ num_mem_init_usage, /* min Numeric->Memory for UMF_kernel_init */
+ nempty_row, nempty_col,
+
+ strategy,
+ ordering,
+ fixQ,
+ prefer_diagonal,
+ nzaat,
+ nzdiag,
+ amd_dmax ;
+
+} SymbolicType ;
+
+
+/* -------------------------------------------------------------------------- */
+/* for debugging only: */
+/* -------------------------------------------------------------------------- */
+
+#include "umf_dump.h"
+
+/* -------------------------------------------------------------------------- */
+/* for statement coverage testing only: */
+/* -------------------------------------------------------------------------- */
+
+#ifdef TESTING
+
+/* for testing integer overflow: */
+#ifdef TEST_FOR_INTEGER_OVERFLOW
+#undef MAX_MARK
+#define MAX_MARK(n) (3*(n))
+#endif
+
+/* for testing out-of-memory conditions: */
+#define UMF_TCOV_TEST
+GLOBAL extern Int umf_fail, umf_fail_lo, umf_fail_hi ;
+GLOBAL extern Int umf_realloc_fail, umf_realloc_lo, umf_realloc_hi ;
+
+/* for testing malloc count: */
+#define UMF_MALLOC_COUNT
+
+#endif
--- /dev/null
+/* ========================================================================== */
+/* === UMF_is_permutation =================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 != (Int *) NULL) ;
+
+ for (i = 0 ; i < n ; i++)
+ {
+ W [i] = FALSE ;
+ }
+ for (k = 0 ; k < r ; k++)
+ {
+ i = P [k] ;
+ DEBUG5 (("k "ID" i "ID"\n", k, i)) ;
+ if (i < 0 || i >= n)
+ {
+ DEBUG0 (("i out of range "ID" "ID"\n", i, n)) ;
+ return (FALSE) ;
+ }
+ if (W [i])
+ {
+ DEBUG0 (("i duplicate "ID"\n", i)) ;
+ return (FALSE) ;
+ }
+ W [i] = TRUE ;
+ }
+ return (TRUE) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_is_permutation
+(
+ const Int P [ ],
+ Int W [ ],
+ Int n,
+ Int r
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_kernel =========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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_kernel_init.h"
+#include "umf_init_front.h"
+#include "umf_start_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_store_lu.h"
+#include "umf_kernel_wrapup.h"
+
+/* perform an action, and return if out of memory */
+#define DO(action) { if (! (action)) { return (UMFPACK_ERROR_out_of_memory) ; }}
+
+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, f1, f2, chain, nchains, *Chain_start, status, fixQ, evaporate,
+ *Front_npivcol, jmax, nb, drop ;
+
+ /* ---------------------------------------------------------------------- */
+ /* initialize memory space and load the matrix. Optionally scale. */
+ /* ---------------------------------------------------------------------- */
+
+ 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. */
+ DEBUGm4 (("kernel init failed\n")) ;
+ return (UMFPACK_ERROR_different_pattern) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* get the symbolic factorization */
+ /* ---------------------------------------------------------------------- */
+
+ nchains = Symbolic->nchains ;
+ Chain_start = Symbolic->Chain_start ;
+ Front_npivcol = Symbolic->Front_npivcol ;
+ nb = Symbolic->nb ;
+ fixQ = Symbolic->fixQ ;
+ drop = Numeric->droptol > 0.0 ;
+
+#ifndef NDEBUG
+ for (chain = 0 ; chain < nchains ; chain++)
+ {
+ Int i ;
+ f1 = Chain_start [chain] ;
+ f2 = Chain_start [chain+1] - 1 ;
+ DEBUG1 (("\nCHain: "ID" start "ID" end "ID"\n", chain, f1, f2)) ;
+ for (i = f1 ; i <= f2 ; i++)
+ {
+ DEBUG1 (("Front "ID", npivcol "ID"\n", i, Front_npivcol [i])) ;
+ }
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* factorize each chain of frontal matrices */
+ /* ---------------------------------------------------------------------- */
+
+ for (chain = 0 ; chain < nchains ; chain++)
+ {
+ f1 = Chain_start [chain] ;
+ f2 = Chain_start [chain+1] - 1 ;
+
+ /* ------------------------------------------------------------------ */
+ /* get the initial frontal matrix size for this chain */
+ /* ------------------------------------------------------------------ */
+
+ DO (UMF_start_front (chain, Numeric, Work, Symbolic)) ;
+
+ /* ------------------------------------------------------------------ */
+ /* factorize each front in the chain */
+ /* ------------------------------------------------------------------ */
+
+ for (Work->frontid = f1 ; Work->frontid <= f2 ; Work->frontid++)
+ {
+
+ /* -------------------------------------------------------------- */
+ /* Initialize the pivot column candidate set */
+ /* -------------------------------------------------------------- */
+
+ Work->ncand = Front_npivcol [Work->frontid] ;
+ Work->lo = Work->nextcand ;
+ Work->hi = Work->nextcand + Work->ncand - 1 ;
+ jmax = MIN (MAX_CANDIDATES, Work->ncand) ;
+ DEBUGm1 ((">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Starting front "
+ ID", npivcol: "ID"\n", Work->frontid, Work->ncand)) ;
+ if (fixQ)
+ {
+ /* do not modify the column order */
+ jmax = 1 ;
+ }
+ DEBUGm1 (("Initial candidates: ")) ;
+ for (j = 0 ; j < jmax ; j++)
+ {
+ DEBUGm1 ((" "ID, Work->nextcand)) ;
+ ASSERT (Work->nextcand <= Work->hi) ;
+ Work->Candidates [j] = Work->nextcand++ ;
+ }
+ Work->nCandidates = jmax ;
+ DEBUGm1 (("\n")) ;
+
+ /* -------------------------------------------------------------- */
+ /* 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)
+ {
+ /* :: pattern change detected in umf_local_search :: */
+ /* input matrix has changed since umfpack_*symbolic */
+ DEBUGm4 (("local search failed\n")) ;
+ return (UMFPACK_ERROR_different_pattern) ;
+ }
+ if (status == UMFPACK_WARNING_singular_matrix)
+ {
+ /* no pivot found, discard and try again */
+ continue ;
+ }
+
+ /* ---------------------------------------------------------- */
+ /* update if front not extended or too many zeros in L,U */
+ /* ---------------------------------------------------------- */
+
+ if (Work->do_update)
+ {
+ UMF_blas3_update (Work) ;
+ if (drop)
+ {
+ DO (UMF_store_lu_drop (Numeric, Work)) ;
+ }
+ else
+ {
+ DO (UMF_store_lu (Numeric, Work)) ;
+ }
+ }
+
+ /* ---------------------------------------------------------- */
+ /* extend the frontal matrix, or start a new one */
+ /* ---------------------------------------------------------- */
+
+ if (Work->do_extend)
+ {
+ /* extend the current front */
+ DO (UMF_extend_front (Numeric, Work)) ;
+ }
+ else
+ {
+ /* finish the current front (if any) and start a new one */
+ DO (UMF_create_element (Numeric, Work, Symbolic)) ;
+ DO (UMF_init_front (Numeric, Work)) ;
+ }
+
+ /* ---------------------------------------------------------- */
+ /* Numerical & symbolic assembly into current frontal matrix */
+ /* ---------------------------------------------------------- */
+
+ if (fixQ)
+ {
+ UMF_assemble_fixq (Numeric, Work) ;
+ }
+ else
+ {
+ UMF_assemble (Numeric, Work) ;
+ }
+
+ /* ---------------------------------------------------------- */
+ /* scale the pivot column */
+ /* ---------------------------------------------------------- */
+
+ UMF_scale_column (Numeric, Work) ;
+
+ /* ---------------------------------------------------------- */
+ /* Numerical update if enough pivots accumulated */
+ /* ---------------------------------------------------------- */
+
+ evaporate = Work->fnrows == 0 || Work->fncols == 0 ;
+ if (Work->fnpiv >= nb || evaporate)
+ {
+ UMF_blas3_update (Work) ;
+ if (drop)
+ {
+ DO (UMF_store_lu_drop (Numeric, Work)) ;
+ }
+ else
+ {
+ DO (UMF_store_lu (Numeric, Work)) ;
+ }
+
+ }
+
+ Work->pivrow_in_front = FALSE ;
+ Work->pivcol_in_front = FALSE ;
+
+ /* ---------------------------------------------------------- */
+ /* If front is empty, evaporate it */
+ /* ---------------------------------------------------------- */
+
+ if (evaporate)
+ {
+ /* This does not create an element, just evaporates it.
+ * It ensures that a front is not 0-by-c or r-by-0. No
+ * memory is allocated, so it is guaranteed to succeed. */
+ (void) UMF_create_element (Numeric, Work, Symbolic) ;
+ 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.
+ * ------------------------------------------------------------------ */
+
+ UMF_blas3_update (Work) ;
+ if (drop)
+ {
+ DO (UMF_store_lu_drop (Numeric, Work)) ;
+ }
+ else
+ {
+ DO (UMF_store_lu (Numeric, Work)) ;
+ }
+ Work->fnrows_new = Work->fnrows ;
+ Work->fncols_new = Work->fncols ;
+ DO (UMF_create_element (Numeric, Work, Symbolic)) ;
+
+ /* ------------------------------------------------------------------ */
+ /* 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 (this is OK) */
+ return (UMFPACK_OK) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+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
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_kernel_init ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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: scale the matrix, load the initial elements, and
+ build the tuple lists.
+
+ 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"
+#include "umf_mem_alloc_head_block.h"
+#include "umf_mem_alloc_tail_block.h"
+#include "umf_mem_free_tail_block.h"
+#include "umf_free.h"
+#include "umf_scale.h"
+
+/* ========================================================================== */
+/* === packsp =============================================================== */
+/* ========================================================================== */
+
+/* remove zero or small entries from a column of L or a row of U */
+
+PRIVATE Int packsp /* returns new value of pnew */
+(
+ Int pnew, /* index into Memory of next free space */
+ Int *p_p, /* ptr to index of old pattern in Memory on input,
+ new pattern on output */
+ Int *p_len, /* ptr to length of old pattern on input,
+ new pattern on output */
+ Int drop, /* TRUE if small nonzero entries are to be dropped */
+ double droptol, /* the drop tolerance */
+ Unit *Memory /* contains the sparse vector on input and output */
+)
+{
+ Entry x, *Bx, *Bx2 ;
+ Int p, i, len, len_new, *Bi, *Bi2 ;
+ double s ;
+
+ /* get the pointers to the sparse vector, and its length */
+ p = *p_p ;
+ len = *p_len ;
+ Bi = (Int *) (Memory + p) ; p += UNITS (Int, len) ;
+ Bx = (Entry *) (Memory + p) ; p += UNITS (Entry, len) ;
+ DEBUGm4 ((" p "ID" len "ID" pnew "ID"\n", p, len, pnew)) ;
+
+ /* the vector resides in Bi [0..len-1] and Bx [0..len-1] */
+
+ /* first, compact the vector in place */
+ len_new = 0 ;
+ for (p = 0 ; p < len ; p++)
+ {
+ i = Bi [p] ;
+ x = Bx [p] ;
+ DEBUGm4 ((" old vector: i "ID" value: ", i)) ;
+ EDEBUGk (-4, x) ;
+ DEBUGm4 (("\n")) ;
+ ASSERT (i >= 0) ;
+ /* skip if zero or below drop tolerance */
+ if (IS_ZERO (x)) continue ;
+ if (drop)
+ {
+ APPROX_ABS (s, x) ;
+ if (s <= droptol) continue ;
+ }
+ /* store the value back into the vector */
+ if (len_new != p)
+ {
+ Bi [len_new] = i ;
+ Bx [len_new] = x ;
+ }
+ len_new++ ;
+ }
+ ASSERT (len_new <= len) ;
+
+ /* the vector is now in Bi [0..len_new-1] and Bx [0..len_new-1] */
+
+#ifndef NDEBUG
+ for (p = 0 ; p < len_new ; p++)
+ {
+ DEBUGm4 ((" new vector: i "ID" value: ", Bi [p])) ;
+ EDEBUGk (-4, Bx [p]) ;
+ DEBUGm4 (("\n")) ;
+ ASSERT (Bi [p] >= 0) ;
+ }
+#endif
+
+ /* allocate new space for the compacted vector */
+ *p_p = pnew ;
+ *p_len = len_new ;
+ Bi2 = (Int *) (Memory + pnew) ; pnew += UNITS (Int, len_new) ;
+ Bx2 = (Entry *) (Memory + pnew) ; pnew += UNITS (Entry, len_new) ;
+ DEBUGm4 ((" pnew "ID" len_new "ID"\n", pnew, len_new)) ;
+
+ /* shift the vector upwards, into its new space */
+ for (p = 0 ; p < len_new ; p++)
+ {
+ Bi2 [p] = Bi [p] ;
+ }
+ for (p = 0 ; p < len_new ; p++)
+ {
+ Bx2 [p] = Bx [p] ;
+ }
+
+#ifndef NDEBUG
+ for (p = 0 ; p < len_new ; p++)
+ {
+ DEBUGm4 ((" packed vec: i "ID" value: ", Bi2 [p])) ;
+ EDEBUGk (-4, Bx2 [p]) ;
+ DEBUGm4 (("\n")) ;
+ ASSERT (Bi2 [p] >= 0) ;
+ }
+#endif
+
+ /* return the pointer to the space just after the new vector */
+ return (pnew) ;
+}
+
+
+/* ========================================================================== */
+/* === UMF_kernel_init ====================================================== */
+/* ========================================================================== */
+
+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, 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, oldrow, newrow, ilast, *Wrp,
+ *Rperm_init, col, n_inner, prefer_diagonal, *Diagonal_map, nempty,
+ *Diagonal_imap, fixQ, rdeg, cdeg, nempty_col, *Esize, esize, pnew,
+ *Lip, *Uip, *Lilen, *Uilen, llen, pa, *Cdeg, *Rdeg, n1, clen, do_scale,
+ lnz, unz, lip, uip, k1, *Rperm, *Cperm, pivcol, *Li, lilen, drop,
+ **Rpi, nempty_row, dense_row_threshold, empty_elements, rpi, rpx ;
+ double unused = 0, *Rs, rsmin, rsmax, rs, droptol ;
+ Entry *D, *C, x, *Lval, pivot_value, **Rpx ;
+ Element *ep ;
+ Unit *Memory ;
+
+#ifndef NRECIPROCAL
+ Int do_recip = FALSE ;
+#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) ;
+ nempty_col = Symbolic->nempty_col ;
+ nempty_row = Symbolic->nempty_row ;
+ nempty = MIN (nempty_row, nempty_col) ;
+ ASSERT (n_row > 0 && n_col > 0) ;
+ Cperm_init = Symbolic->Cperm_init ;
+ Rperm_init = Symbolic->Rperm_init ;
+ Cdeg = Symbolic->Cdeg ;
+ Rdeg = Symbolic->Rdeg ;
+ n1 = Symbolic->n1 ;
+ dense_row_threshold = Symbolic->dense_row_threshold ;
+ DEBUG0 (("Singletons: "ID"\n", n1)) ;
+ Work->nforced = 0 ;
+ Work->ndiscard = 0 ;
+ Work->noff_diagonal = 0 ;
+
+ nz = Ap [n_col] ;
+ if (nz < 0 || Ap [0] != 0 || nz != Symbolic->nz)
+ {
+ DEBUGm4 (("nz or Ap [0] bad\n")) ;
+ return (FALSE) ; /* pattern changed */
+ }
+
+ prefer_diagonal = Symbolic->prefer_diagonal ;
+ Diagonal_map = Work->Diagonal_map ;
+ Diagonal_imap = Work->Diagonal_imap ;
+
+ /* ---------------------------------------------------------------------- */
+ /* initialize the Numeric->Memory space for LU, elements, and tuples */
+ /* ---------------------------------------------------------------------- */
+
+ UMF_mem_init_memoryspace (Numeric) ;
+ DEBUG1 (("Kernel init head usage, before allocs: "ID"\n", Numeric->ihead)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* initialize the Work and Numeric objects */
+ /* ---------------------------------------------------------------------- */
+
+ /* current front is empty */
+ Work->fnpiv = 0 ;
+ Work->fncols = 0 ;
+ Work->fnrows = 0 ;
+ Work->fncols_max = 0 ;
+ Work->fnrows_max = 0 ;
+ Work->fnzeros = 0 ;
+ Work->fcurr_size = 0 ;
+ Work->fnr_curr = 0 ;
+ Work->fnc_curr = 0 ;
+
+ Work->nz = nz ;
+ Work->prior_element = EMPTY ;
+ Work->ulen = 0 ;
+ Work->llen = 0 ;
+ Work->npiv = n1 ;
+ Work->frontid = 0 ;
+ Work->nextcand = n1 ;
+
+ Memory = Numeric->Memory ;
+ Rperm = Numeric->Rperm ;
+ Cperm = Numeric->Cperm ;
+ Row_degree = Numeric->Rperm ;
+ Col_degree = Numeric->Cperm ;
+ /* Row_tuples = Numeric->Uip ; not needed */
+ Row_tlen = Numeric->Uilen ;
+ /* Col_tuples = Numeric->Lip ; not needed */
+ Col_tlen = Numeric->Lilen ;
+
+ Lip = Numeric->Lip ;
+ Uip = Numeric->Uip ;
+ Lilen = Numeric->Lilen ;
+ Uilen = Numeric->Uilen ;
+
+ Frpos = Work->Frpos ;
+ Fcpos = Work->Fcpos ;
+ Wp = Work->Wp ;
+ Wrp = Work->Wrp ;
+
+ D = Numeric->D ;
+ Upos = Numeric->Upos ;
+ Lpos = Numeric->Lpos ;
+ for (k = 0 ; k < n_inner ; k++)
+ {
+ CLEAR (D [k]) ;
+ }
+
+ Rs = Numeric->Rs ;
+
+ for (row = 0 ; row <= n_row ; row++)
+ {
+ Lpos [row] = EMPTY ;
+ /* Row_tuples [row] = 0 ; set in UMF_build_tuples */
+ /* Row_degree [row] = 0 ; initialized below */
+ 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 ;
+ Wrp [col] = 0 ;
+ }
+ Work->Wrpflag = 1 ;
+
+ /* When cleared, Wp [0..nn] is < 0 */
+ for (i = 0 ; i <= nn ; i++)
+ {
+ Wp [i] = EMPTY ;
+ }
+ /* In col search, Wp [row] is set to a position, which is >= 0. */
+
+ /* When cleared, Wrp [0..n_col] is < Wrpflag */
+ /* In row search, Wrp [col] is set to Wrpflag. */
+
+ /* no need to initialize Wm, Wio, Woi, and Woo */
+
+ /* clear the external degree counters */
+ Work->cdeg0 = 1 ;
+ Work->rdeg0 = 1 ;
+
+ fixQ = Symbolic->fixQ ;
+
+ 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->all_lnz = 0 ;
+ Numeric->all_unz = 0 ;
+ Numeric->maxfrsize = 0 ;
+ Numeric->maxnrows = 0 ;
+ Numeric->maxncols = 0 ;
+ Numeric->flops = 0. ;
+ Numeric->n1 = n1 ;
+ droptol = Numeric->droptol ;
+ drop = (droptol > 0) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* compute the scale factors, if requested, and check the input matrix */
+ /* ---------------------------------------------------------------------- */
+
+ /* UMFPACK_SCALE_SUM: Rs [i] = sum of the absolute values in row i.
+ * UMFPACK_SCALE_MAX: Rs [i] = max of the absolute values in row i.
+ *
+ * If A is complex, an approximate abs is used (|xreal| + |ximag|).
+ *
+ * If min (Rs [0..n_row]) >= RECIPROCAL_TOLERANCE, then the scale
+ * factors are inverted, and the rows of A are multiplied by the scale
+ * factors. Otherwise, the rows are divided by the scale factors. If
+ * NRECIPROCAL is defined, then the rows are always divided by the scale
+ * factors.
+ *
+ * For MATLAB (either built-in routine or mexFunction), or for gcc,
+ * the rows are always divided by the scale factors.
+ */
+
+ do_scale = (Numeric->scale != UMFPACK_SCALE_NONE) ;
+
+ if (do_scale)
+ {
+ int do_max = Numeric->scale == UMFPACK_SCALE_MAX ;
+ for (row = 0 ; row < n_row ; row++)
+ {
+ Rs [row] = 0.0 ;
+ }
+ for (col = 0 ; col < n_col ; col++)
+ {
+ ilast = EMPTY ;
+ p1 = Ap [col] ;
+ p2 = Ap [col+1] ;
+ if (p1 > p2)
+ {
+ /* invalid matrix */
+ DEBUGm4 (("invalid matrix (Ap)\n")) ;
+ return (FALSE) ;
+ }
+ for (p = p1 ; p < p2 ; p++)
+ {
+ double value ;
+ Entry aij ;
+ row = Ai [p] ;
+ if (row <= ilast || row >= n_row)
+ {
+ /* invalid matrix, columns must be sorted, no duplicates */
+ DEBUGm4 (("invalid matrix (Ai)\n")) ;
+ return (FALSE) ;
+ }
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ APPROX_ABS (value, aij) ;
+ rs = Rs [row] ;
+ if (!SCALAR_IS_NAN (rs))
+ {
+ if (SCALAR_IS_NAN (value))
+ {
+ /* if any entry in the row is NaN, then the scale factor
+ * is NaN too (for now) and then set to 1.0 below */
+ Rs [row] = value ;
+ }
+ else if (do_max)
+ {
+ Rs [row] = MAX (rs, value) ;
+ }
+ else
+ {
+ Rs [row] += value ;
+ }
+ }
+ DEBUG4 (("i "ID" j "ID" value %g, Rs[i]: %g\n",
+ row, col, value, Rs[row])) ;
+ ilast = row ;
+ }
+ }
+ DEBUG2 (("Rs[0] = %30.20e\n", Rs [0])) ;
+ for (row = 0 ; row < n_row ; row++)
+ {
+ rs = Rs [row] ;
+ if (SCALAR_IS_ZERO (rs) || SCALAR_IS_NAN (rs))
+ {
+ /* don't scale a completely zero row, or one with NaN's */
+ Rs [row] = 1.0 ;
+ }
+ }
+ rsmin = Rs [0] ;
+ rsmax = Rs [0] ;
+ for (row = 0 ; row < n_row ; row++)
+ {
+ DEBUG2 (("sum %30.20e ", Rs [row])) ;
+ rsmin = MIN (rsmin, Rs [row]) ;
+ rsmax = MAX (rsmax, Rs [row]) ;
+ DEBUG2 (("Rs["ID"] = %30.20e\n", row, Rs [row])) ;
+ }
+#ifndef NRECIPROCAL
+ /* multiply by the reciprocal if Rs is not too small */
+ do_recip = (rsmin >= RECIPROCAL_TOLERANCE) ;
+ if (do_recip)
+ {
+ /* invert the scale factors */
+ for (row = 0 ; row < n_row ; row++)
+ {
+ Rs [row] = 1.0 / Rs [row] ;
+ }
+ }
+#endif
+ }
+ else
+ {
+ /* no scaling, rsmin and rsmax not computed */
+ rsmin = -1 ;
+ rsmax = -1 ;
+#ifndef NRECIPROCAL
+ do_recip = FALSE ;
+#endif
+ /* check the input matrix */
+ if (!AMD_valid (n_row, n_col, Ap, Ai))
+ {
+ /* matrix is invalid */
+ return (FALSE) ;
+ }
+ }
+
+ Numeric->rsmin = rsmin ;
+ Numeric->rsmax = rsmax ;
+#ifndef NRECIPROCAL
+ Numeric->do_recip = do_recip ;
+#else
+ Numeric->do_recip = FALSE ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* construct the inverse row Rperm_init permutation (use Frpos as temp) */
+ /* ---------------------------------------------------------------------- */
+
+ DEBUG3 (("\n\n===================LOAD_MATRIX:\n")) ;
+
+ for (newrow = 0 ; newrow < n_row ; newrow++)
+ {
+ oldrow = Rperm_init [newrow] ;
+ ASSERT (oldrow >= 0 && oldrow < n_row) ;
+ Frpos [oldrow] = newrow ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* construct the diagonal imap if doing symmetric pivoting */
+ /* ---------------------------------------------------------------------- */
+
+ if (prefer_diagonal)
+ {
+ ASSERT (n_row == n_col) ;
+ ASSERT (nempty_col == Symbolic->nempty_row) ;
+ ASSERT (nempty_col == nempty) ;
+ for (i = 0 ; i < nn ; i++)
+ {
+ Diagonal_map [i] = EMPTY ;
+ Diagonal_imap [i] = EMPTY ;
+ }
+ for (k = n1 ; k < nn - nempty ; k++)
+ {
+ newrow = Symbolic->Diagonal_map [k] ;
+ Diagonal_map [k] = newrow ;
+ Diagonal_imap [newrow] = k ;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate O (n_row) workspace at the tail end of Memory */
+ /* ---------------------------------------------------------------------- */
+
+ rpi = UMF_mem_alloc_tail_block (Numeric, UNITS (Int *, n_row+1)) ;
+ rpx = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry *, n_row+1)) ;
+ if (!rpi || !rpx)
+ {
+ /* :: pattern change (out of memory for Rpx, Rpx) :: */
+ /* out of memory, which can only mean that the pattern has changed */
+ return (FALSE) ; /* pattern changed */
+ }
+ Rpi = (Int **) (Memory + rpx) ;
+ Rpx = (Entry **) (Memory + rpi) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate the LU factors for the columns of the singletons */
+ /* ---------------------------------------------------------------------- */
+
+ DEBUG1 (("Allocating singletons:\n")) ;
+ for (k = 0 ; k < n1 ; k++)
+ {
+ lnz = Cdeg [k] - 1 ;
+ unz = Rdeg [k] - 1 ;
+
+ DEBUG1 (("Singleton k "ID" pivrow "ID" pivcol "ID" cdeg "ID" rdeg "
+ ID"\n", k, Rperm_init [k], Cperm_init [k], Cdeg [k], Rdeg [k])) ;
+ ASSERT (unz >= 0 && lnz >= 0 && (lnz == 0 || unz == 0)) ;
+ DEBUG1 ((" lnz "ID" unz "ID"\n", lnz, unz)) ;
+
+ size = UNITS (Int, lnz) + UNITS (Entry, lnz)
+ + UNITS (Int, unz) + UNITS (Entry, unz) ;
+ p = UMF_mem_alloc_head_block (Numeric, size) ;
+ DEBUG1 (("Kernel init head usage: "ID"\n", Numeric->ihead)) ;
+ if (!p)
+ {
+ /* :: pattern change (out of memory for singletons) :: */
+ DEBUG0 (("Pattern has gotten larger - kernel init failed\n")) ;
+ return (FALSE) ; /* pattern changed */
+ }
+
+ Numeric->all_lnz += lnz ;
+ Numeric->all_unz += unz ;
+
+ /* allocate the column of L */
+ lip = p ;
+ p += UNITS (Int, lnz) ;
+ p += UNITS (Entry, lnz) ;
+
+ /* allocate the row of U */
+ uip = p ;
+ Rpi [k] = (Int *) (Memory + p) ;
+ p += UNITS (Int, unz) ;
+ Rpx [k] = (Entry *) (Memory + p) ;
+ /* p += UNITS (Entry, unz) ; (not needed) */
+
+ /* a single column of L (no Lchains) */
+ Lip [k] = lip ;
+ Lilen [k] = lnz ;
+
+ /* a single row of L (no Uchains) */
+ Uip [k] = uip ;
+ Uilen [k] = unz ;
+
+ Wp [k] = unz ;
+
+ /* save row and column inverse permutation */
+ k1 = ONES_COMPLEMENT (k) ;
+ Rperm [k] = k1 ; /* aliased with Row_degree */
+ Cperm [k] = k1 ; /* aliased with Col_degree */
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* current frontal matrix is empty */
+ /* ---------------------------------------------------------------------- */
+
+ e = 0 ;
+ E [e] = 0 ;
+ Work->Flublock = (Entry *) NULL ;
+ Work->Flblock = (Entry *) NULL ;
+ Work->Fublock = (Entry *) NULL ;
+ Work->Fcblock = (Entry *) NULL ;
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate the column elements */
+ /* ---------------------------------------------------------------------- */
+
+ Esize = Symbolic->Esize ;
+ empty_elements = FALSE ;
+ for (k = n1 ; k < n_col - nempty_col ; k++)
+ {
+ e = k - n1 + 1 ;
+ ASSERT (e < Work->elen) ;
+ esize = Esize ? Esize [k-n1] : Cdeg [k] ;
+ if (esize > 0)
+ {
+ /* allocate an element for this column */
+ E [e] = UMF_mem_alloc_element (Numeric, esize, 1, &Rows, &Cols, &C,
+ &size, &ep) ;
+ if (E [e] <= 0)
+ {
+ /* :: pattern change (out of memory for column elements) :: */
+ return (FALSE) ; /* pattern has changed */
+ }
+ Cols [0] = k ;
+ DEBUG0 (("Got column element e "ID" esize "ID"\n", e, esize)) ;
+ }
+ else
+ {
+ /* all rows in this column are dense, or empty */
+ E [e] = 0 ;
+ empty_elements = TRUE ;
+ DEBUG0 (("column element e is empty "ID"\n", e)) ;
+ }
+ }
+ DEBUG0 (("e "ID" n_col "ID" nempty_col "ID" n1 "ID"\n", e, n_col,
+ nempty_col, n1)) ;
+ ASSERT (e == n_col - nempty_col - n1) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate the row elements for dense rows of A (if any) */
+ /* ---------------------------------------------------------------------- */
+
+ if (Esize)
+ {
+ for (k = n1 ; k < n_row - nempty_row ; k++)
+ {
+ rdeg = Rdeg [k] ;
+ if (rdeg > dense_row_threshold)
+ {
+ /* allocate an element for this dense row */
+ e++ ;
+ ASSERT (e < Work->elen) ;
+ E [e] = UMF_mem_alloc_element (Numeric, 1, rdeg, &Rows, &Cols,
+ &C, &size, &ep) ;
+ if (E [e] <= 0)
+ {
+ /* :: pattern change (out of memory for row elements) :: */
+ return (FALSE) ; /* pattern has changed */
+ }
+ Rows [0] = k ;
+ Rpi [k] = Cols ;
+ Rpx [k] = C ;
+ Wp [k] = rdeg ;
+ DEBUG0 (("Got row element e "ID" rdeg "ID"\n", e, rdeg)) ;
+ }
+ }
+ }
+
+ /* elements are currently in the range 0 to e */
+ Work->nel = e ;
+
+ /* ---------------------------------------------------------------------- */
+ /* create the first n1 columns of L and U */
+ /* ---------------------------------------------------------------------- */
+
+ for (k = 0 ; k < n1 ; k++)
+ {
+ pivcol = Cperm_init [k] ;
+ p2 = Ap [pivcol+1] ;
+
+ /* get the kth column of L */
+ p = Lip [k] ;
+ Li = (Int *) (Memory + p) ;
+ lilen = Lilen [k] ;
+ p += UNITS (Int, lilen) ;
+ Lval = (Entry *) (Memory + p) ;
+
+ llen = 0 ;
+
+ for (pa = Ap [pivcol] ; pa < p2 ; pa++)
+ {
+ oldrow = Ai [pa] ;
+ newrow = Frpos [oldrow] ;
+ ASSIGN (x, Ax [pa], Az [pa]) ;
+
+ /* scale the value using the scale factors, Rs */
+ if (do_scale)
+ {
+#ifndef NRECIPROCAL
+ if (do_recip)
+ {
+ SCALE_RECIP (x, Rs [oldrow]) ;
+ }
+ else
+#endif
+ {
+ SCALE_DIV (x, Rs [oldrow]) ;
+ }
+ }
+
+ if (newrow == k)
+ {
+ /* this is the pivot entry itself */
+ ASSERT (oldrow == Rperm_init [k]) ;
+ D [k] = x ;
+ }
+ else if (newrow < k)
+ {
+ /* this entry goes in a row of U */
+ DEBUG1 (("Singleton row of U: k "ID" newrow "ID"\n",
+ k, newrow)) ;
+ if (--(Wp [newrow]) < 0)
+ {
+ /* :: pattern change (singleton row too long) :: */
+ DEBUGm4 (("bad U singleton row (too long)\n")) ;
+ return (FALSE) ; /* pattern changed */
+ }
+ *(Rpi [newrow]++) = k ;
+ *(Rpx [newrow]++) = x ;
+ }
+ else
+ {
+ /* this entry goes in a column of L */
+ DEBUG1 (("Singleton col of L: k "ID" newrow "ID"\n",
+ k, newrow)) ;
+ if (llen >= lilen)
+ {
+ DEBUGm4 (("bad L singleton col (too long)\n")) ;
+ return (FALSE) ; /* pattern changed */
+ }
+ Li [llen] = newrow ;
+ Lval [llen] = x ;
+ llen++ ;
+ }
+ }
+
+ if (llen != lilen)
+ {
+ /* :: pattern change (singleton column too long) :: */
+ DEBUGm4 (("bad L singleton col (too short)\n")) ;
+ return (FALSE) ; /* pattern changed */
+ }
+
+ /* scale the column of L */
+ if (llen > 0)
+ {
+ pivot_value = D [k] ;
+ UMF_scale (llen, pivot_value, Lval) ;
+ }
+
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate the elements and copy the columns of A */
+ /* ---------------------------------------------------------------------- */
+
+ /* also apply the row and column pre-ordering. */
+ for (k = n1 ; k < n_col ; k++)
+ {
+ /* The newcol is k, which is what the name of the column is in the
+ * UMFPACK kernel. The user's name for the column is oldcol. */
+ oldcol = Cperm_init [k] ;
+
+ ASSERT (oldcol >= 0 && oldcol < n_col) ;
+
+ p2 = Ap [oldcol+1] ;
+
+ cdeg = Cdeg [k] ;
+ ASSERT (cdeg >= 0) ;
+ ASSERT (IMPLIES (
+ (Symbolic->ordering != UMFPACK_ORDERING_GIVEN) && n1 > 0,
+ cdeg > 1 || cdeg == 0)) ;
+
+ /* if fixQ: set Col_degree to 0 for the NON_PIVOTAL_COL macro */
+ Col_degree [k] = fixQ ? 0 : cdeg ;
+
+ /* get the element for this column (if any) */
+ e = k - n1 + 1 ;
+ if (k < n_col - nempty_col)
+ {
+ esize = Esize ? Esize [k-n1] : cdeg ;
+ if (E [e])
+ {
+ Int ncols, nrows ;
+ Unit *pp ;
+ pp = Memory + E [e] ;
+ GET_ELEMENT (ep, pp, Cols, Rows, ncols, nrows, C) ;
+ ASSERT (ncols == 1) ;
+ ASSERT (nrows == esize) ;
+ ASSERT (Cols [0] == k) ;
+ }
+ }
+ else
+ {
+ ASSERT (cdeg == 0) ;
+ esize = 0 ;
+ }
+
+ clen = 0 ;
+
+ for (pa = Ap [oldcol] ; pa < p2 ; pa++)
+ {
+ oldrow = Ai [pa] ;
+ newrow = Frpos [oldrow] ;
+ ASSIGN (x, Ax [pa], Az [pa]) ;
+
+ /* scale the value using the scale factors, Rs */
+ if (do_scale)
+ {
+#ifndef NRECIPROCAL
+ if (do_recip)
+ {
+ /* multiply by the reciprocal */
+ SCALE_RECIP (x, Rs [oldrow]) ;
+ }
+ else
+#endif
+ {
+ /* divide instead */
+ SCALE_DIV (x, Rs [oldrow]) ;
+ }
+ }
+
+ rdeg = Rdeg [newrow] ;
+ if (newrow < n1 || rdeg > dense_row_threshold)
+ {
+ /* this entry goes in a row of U or into a dense row */
+ DEBUG1 (("Singleton/dense row of U: k "ID" newrow "ID"\n",
+ k, newrow)) ;
+ if (--(Wp [newrow]) < 0)
+ {
+ DEBUGm4 (("bad row of U or A (too long)\n")) ;
+ return (FALSE) ; /* pattern changed */
+ }
+ *(Rpi [newrow]++) = k ;
+ *(Rpx [newrow]++) = x ;
+ }
+ else
+ {
+ /* this entry goes in an initial element */
+ DEBUG1 (("In element k "ID" e "ID" newrow "ID"\n",
+ k, e, newrow)) ;
+ if (clen >= esize)
+ {
+ DEBUGm4 (("bad A column (too long)\n")) ;
+ return (FALSE) ; /* pattern changed */
+ }
+ ASSERT (E [e]) ;
+ ASSERT (k < n_col - nempty_col) ;
+ Rows [clen] = newrow ;
+ C [clen] = x ;
+ clen++ ;
+#ifndef NDEBUG
+ if (Diagonal_map && (newrow == Diagonal_map [k]))
+ {
+ DEBUG0 (("Diagonal: old: row "ID" col "ID" : "
+ "new: row "ID" col "ID" : ",
+ oldrow, oldcol, newrow, k)) ;
+ EDEBUGk (0, x) ;
+ }
+#endif
+ }
+ }
+
+ if (clen != esize)
+ {
+ /* :: pattern change (singleton column too short) :: */
+ DEBUGm4 (("bad A column (too short)\n")) ;
+ return (FALSE) ; /* pattern changed */
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* free the Rpi and Rpx workspace at the tail end of memory */
+ /* ---------------------------------------------------------------------- */
+
+ UMF_mem_free_tail_block (Numeric, rpi) ;
+ UMF_mem_free_tail_block (Numeric, rpx) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* prune zeros and small entries from the singleton rows and columns */
+ /* ---------------------------------------------------------------------- */
+
+ if (n1 > 0)
+ {
+ pnew = Lip [0] ;
+ ASSERT (pnew == 1) ;
+ for (k = 0 ; k < n1 ; k++)
+ {
+ DEBUGm4 (("\nPrune singleton L col "ID"\n", k)) ;
+ pnew = packsp (pnew, &Lip [k], &Lilen [k], drop, droptol, Memory) ;
+ Numeric->lnz += Lilen [k] ;
+ DEBUGm4 (("\nPrune singleton U row "ID"\n", k)) ;
+ pnew = packsp (pnew, &Uip [k], &Uilen [k], drop, droptol, Memory) ;
+ Numeric->unz += Uilen [k] ;
+ }
+ /* free the unused space at the head of memory */
+ Numeric->ihead = pnew ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* initialize row degrees */
+ /* ---------------------------------------------------------------------- */
+
+ for (k = 0 ; k < n1 ; k++)
+ {
+ if (Wp [k] != 0)
+ {
+ /* :: pattern change (singleton row too short) :: */
+ DEBUGm4 (("bad U singleton row (too short)\n")) ;
+ return (FALSE) ; /* pattern changed */
+ }
+ }
+
+ for (k = n1 ; k < n_row ; k++)
+ {
+ DEBUG1 (("Initial row degree k "ID" oldrow "ID" Rdeg "ID"\n",
+ k, Rperm_init [k], Rdeg [k])) ;
+ rdeg = Rdeg [k] ;
+ Row_degree [k] = rdeg ;
+ if (rdeg > dense_row_threshold && Wp [k] != 0)
+ {
+ /* :: pattern change (dense row too short) :: */
+ DEBUGm4 (("bad dense row (too short)\n")) ;
+ return (FALSE) ;
+ }
+ }
+
+#ifndef NDEBUG
+ if (prefer_diagonal)
+ {
+ Int *InvCperm, newcol ;
+ Entry aij ;
+ UMF_dump_diagonal_map (Diagonal_map, Diagonal_imap, n1, nn, nempty) ;
+ InvCperm = (Int *) malloc (n_col * sizeof (Int)) ;
+ ASSERT (InvCperm != (Int *) NULL) ;
+ for (newcol = 0 ; newcol < n_col ; newcol++)
+ {
+ oldcol = Cperm_init [newcol] ;
+ InvCperm [oldcol] = newcol ;
+ }
+ DEBUGm3 (("Diagonal of P2*A:\n")) ;
+ for (oldcol = 0 ; oldcol < n_col ; oldcol++)
+ {
+ newcol = InvCperm [oldcol] ;
+ for (p = Ap [oldcol] ; p < Ap [oldcol+1] ; p++)
+ {
+ oldrow = Ai [p] ;
+ newrow = Frpos [oldrow] ;
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ if (newrow == Diagonal_map [newcol])
+ {
+ DEBUG0 (("old row "ID" col "ID" new row "ID" col "ID,
+ oldrow, oldcol, newrow, newcol)) ;
+ EDEBUGk (0, aij) ;
+ DEBUG0 ((" scaled ")) ;
+ if (do_scale)
+ {
+#ifndef NRECIPROCAL
+ if (do_recip)
+ {
+ SCALE_RECIP (aij, Rs [oldrow]) ;
+ }
+ else
+#endif
+ {
+ SCALE_DIV (aij, Rs [oldrow]) ;
+ }
+ }
+ EDEBUGk (0, aij) ;
+ DEBUG0 (("\n")) ;
+ }
+ }
+ }
+ free (InvCperm) ;
+ }
+#endif
+
+ Col_degree [n_col] = 0 ;
+
+ /* ---------------------------------------------------------------------- */
+ /* pack the element name space */
+ /* ---------------------------------------------------------------------- */
+
+ if (empty_elements)
+ {
+ Int e2 = 0 ;
+ DEBUG0 (("\n\n============= Packing element space\n")) ;
+ for (e = 1 ; e <= Work->nel ; e++)
+ {
+ if (E [e])
+ {
+ e2++ ;
+ E [e2] = E [e] ;
+ }
+ }
+ Work->nel = e2 ;
+ }
+
+#ifndef NDEBUG
+ DEBUG0 (("Number of initial elements: "ID"\n", Work->nel)) ;
+ for (e = 0 ; e <= Work->nel ; e++) UMF_dump_element (Numeric, Work,e,TRUE) ;
+#endif
+
+ for (e = Work->nel + 1 ; e < Work->elen ; e++)
+ {
+ E [e] = 0 ;
+ }
+
+ /* Frpos no longer needed */
+ for (row = 0 ; row <= n_row ; row++)
+ {
+ Frpos [row] = EMPTY ;
+ }
+
+ /* clear Wp */
+ for (i = 0 ; i <= nn ; i++)
+ {
+ Wp [i] = EMPTY ;
+ }
+
+ DEBUG1 (("Kernel init head usage: "ID"\n", Numeric->ihead)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* 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))
+ {
+ /* :: pattern change (out of memory in umf_build_tuples) :: */
+ /* 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 ;
+
+ /* ---------------------------------------------------------------------- */
+ /* 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_dump_memory (Numeric) ;
+ UMF_dump_matrix (Numeric, Work, FALSE) ;
+ DEBUG0 (("kernel init done...\n")) ;
+#endif
+
+ return (TRUE) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_kernel_init
+(
+ const Int Ap [ ],
+ const Int Ai [ ],
+ const double Ax [ ],
+#ifdef COMPLEX
+ const double Az [ ],
+#endif
+ NumericType *Numeric,
+ WorkType *Work,
+ SymbolicType *Symbolic
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_kernel_wrapup ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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, zero_pivot, nan_pivot, n1 ;
+ Entry *D, pivot_value ;
+ double 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)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* find the smallest and largest entries in D */
+ /* ---------------------------------------------------------------------- */
+
+ for (k = 0 ; k < npiv ; k++)
+ {
+ pivot_value = D [k] ;
+ ABS (d, pivot_value) ;
+ zero_pivot = SCALAR_IS_ZERO (d) ;
+ nan_pivot = SCALAR_IS_NAN (d) ;
+
+ if (!zero_pivot)
+ {
+ /* the pivot is nonzero, but might be Inf or NaN */
+ Numeric->nnzpiv++ ;
+ }
+
+ 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) ;
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* 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 ;
+ DEBUGm3 (("Singular pivot rows "ID" to "ID"\n", k, n_row-1)) ;
+ for (row = 0 ; row < n_row ; row++)
+ {
+ if (NON_PIVOTAL_ROW (row))
+ {
+ Rperm [row] = ONES_COMPLEMENT (k) ;
+ DEBUGm3 (("Singular row "ID" is k: "ID" pivot row\n", row, 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 ;
+ DEBUGm3 (("Singular pivot cols "ID" to "ID"\n", k, n_col-1)) ;
+ for (col = 0 ; col < n_col ; col++)
+ {
+ if (NON_PIVOTAL_COL (col))
+ {
+ Cperm [col] = ONES_COMPLEMENT (k) ;
+ DEBUGm3 (("Singular col "ID" is k: "ID" pivot row\n", col, 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 */
+ DEBUGm3 (("Diag of U is zero, "ID" to "ID"\n", npiv, n_inner-1)) ;
+ for (k = npiv ; k < n_inner ; k++)
+ {
+ CLEAR (D [k]) ;
+ }
+ }
+
+ /* save the pattern of the last row of U */
+ if (Numeric->ulen > 0)
+ {
+ DEBUGm3 (("Last row of U is not empty\n")) ;
+ Numeric->Upattern = Work->Upattern ;
+ Work->Upattern = (Int *) NULL ;
+ }
+
+ DEBUG2 (("Nnzpiv: "ID" npiv "ID"\n", Numeric->nnzpiv, npiv)) ;
+ ASSERT (Numeric->nnzpiv <= npiv) ;
+ if (Numeric->nnzpiv < n_inner && !SCALAR_IS_NAN (Numeric->min_udiag))
+ {
+ /* the rest of the diagonal is zero, so min_udiag becomes 0,
+ * unless it is already NaN. */
+ 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->Wrp ; /* of size n_col+1 or bigger */
+
+ /* ---------------------------------------------------------------------- */
+ /* 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 */
+ /* ---------------------------------------------------------------------- */
+
+ n1 = Symbolic->n1 ;
+
+ for (k = 0 ; k < n1 ; k++)
+ {
+ /* this is a singleton row of U */
+ ulen = Uilen [k] ;
+ DEBUG4 (("K "ID" New U. ulen "ID" Singleton 1\n", k, ulen)) ;
+ if (ulen > 0)
+ {
+ up = Uip [k] ;
+ 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] ;
+ }
+ }
+ }
+
+ for (k = n1 ; 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", k)) ;
+ 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 < n1 ; k++)
+ {
+ llen = Lilen [k] ;
+ DEBUG4 (("K "ID" New L. llen "ID" Singleton col\n", k, llen)) ;
+ if (llen > 0)
+ {
+ lp = Lip [k] ;
+ 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] ;
+ }
+ }
+ }
+
+ for (k = n1 ; 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). */
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_kernel_wrapup
+(
+ NumericType *Numeric,
+ SymbolicType *Symbolic,
+ WorkType *Work
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_local_search ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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. The candidate set
+ corresponds to a supercolumn from colamd or UMF_analyze. The pivot column
+ is then removed from that set. Constructs the pivot column pattern and
+ values. Called by umf_kernel. 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"
+
+/* Version 4.1: relaxed amalgamation control parameters are now fixed, and
+ * cannot be changed via Control [..] settings, as they could in Version 4.0. */
+#define RELAX1 0.25 /* this was UMFPACK_DEFAULT_RELAXED_AMALGAMATION */
+#define SYM_RELAX1 0.0 /* this is new to Version 4.1 */
+#define RELAX2 0.1 /* this was UMFPACK_DEFAULT_RELAXED2_AMALGAMATION */
+#define RELAX3 0.125 /* this was UMFPACK_DEFAULT_RELAXED3_AMALGAMATION */
+
+/* ========================================================================== */
+/* === remove_candidate ===================================================== */
+/* ========================================================================== */
+
+/* Remove a column from the set of candidate pivot columns. */
+
+PRIVATE void remove_candidate (Int jj, WorkType *Work, SymbolicType *Symbolic)
+{
+
+#ifndef NDEBUG
+ Int j ;
+ DEBUGm2 (("pivot column Candidates before remove: nCand "ID" ncand "ID
+ " lo "ID" hi "ID" jj "ID"\n", Work->nCandidates, Work->ncand,
+ Work->lo, Work->hi, jj)) ;
+ for (j = 0 ; j < Work->nCandidates ; j++)
+ {
+ Int col = Work->Candidates [j] ;
+ DEBUGm2 ((ID" ", col));
+ ASSERT (col >= 0 && col < Work->n_col) ;
+ /* ASSERT (NON_PIVOTAL_COL (col)) ; */
+ ASSERT (col >= Work->lo && col <= Work->hi) ;
+ }
+ DEBUGm2 (("\n")) ;
+#endif
+
+ if (Symbolic->fixQ)
+ {
+ DEBUGm2 (("FixQ\n")) ;
+ /* do not modify the column ordering */
+ ASSERT (Work->nCandidates == 1) ;
+ ASSERT (jj == 0) ;
+ if (Work->ncand > 1)
+ {
+ Work->Candidates [0] = Work->nextcand++ ;
+ }
+ else
+ {
+ Work->nCandidates = 0 ;
+ }
+ }
+ else
+ {
+ /* place the next candidate in the set */
+ if (Work->ncand > MAX_CANDIDATES)
+ {
+ Work->Candidates [jj] = Work->nextcand++ ;
+ }
+ else
+ {
+ ASSERT (Work->nCandidates == Work->ncand) ;
+ Work->Candidates [jj] = Work->Candidates [Work->ncand - 1] ;
+ Work->Candidates [Work->ncand - 1] = EMPTY ;
+ Work->nCandidates-- ;
+ }
+ }
+ Work->ncand-- ;
+
+#ifndef NDEBUG
+ DEBUGm2 (("pivot column Candidates after remove: nCand "ID" ncand "ID
+ " lo "ID" hi "ID" jj "ID"\n", Work->nCandidates, Work->ncand, Work->lo,
+ Work->hi, jj)) ;
+ for (j = 0 ; j < Work->nCandidates ; j++)
+ {
+ Int col = Work->Candidates [j] ;
+ DEBUGm2 ((ID" ", col));
+ ASSERT (col >= 0 && col < Work->n_col) ;
+ /* ASSERT (NON_PIVOTAL_COL (col)) ; */
+ ASSERT (col >= Work->lo && col <= Work->hi) ;
+ }
+ DEBUGm2 (("\n")) ;
+ ASSERT (Work->ncand >= 0) ;
+ ASSERT (Work->nCandidates <= Work->ncand) ;
+#endif
+}
+
+/* ========================================================================== */
+/* === UMF_local_search ===================================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMF_local_search
+(
+ NumericType *Numeric,
+ WorkType *Work,
+ SymbolicType *Symbolic
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Entry *Flblock, *Fublock, *Fs, *Fcblock, *C, *Wx, *Wy, *Fu, *Flublock,
+ *Flu ;
+ double relax1 ;
+ Int pos, nrows, *Cols, *Rows, e, f, status, max_cdeg, fnzeros, nb, j, col,
+ i, row, cdeg_in, rdeg [2][2], fnpiv, nothing [2], new_LUsize,
+ pivrow [2][2], pivcol [2], *Wp, *Fcpos, *Frpos, new_fnzeros, cdeg_out,
+ *Wm, *Wio, *Woi, *Woo, *Frows, *Fcols, fnrows, fncols, *E, deg, nr_in,
+ nc, thiscost, bestcost, nr_out, do_update, extra_cols, extra_rows,
+ extra_zeros, relaxed_front, do_extend, fnr_curr, fnc_curr, tpi,
+ *Col_tuples, *Col_degree, *Col_tlen, jj, jcand [2], freebie [2],
+ did_rowmerge, fnrows_new [2][2], fncols_new [2][2], search_pivcol_out,
+ *Diagonal_map, *Diagonal_imap, row2, col2 ;
+ 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 ;
+
+ Wx = Work->Wx ;
+ Wy = Work->Wy ;
+ Wp = Work->Wp ;
+ Wm = Work->Wm ;
+ Woi = Work->Woi ;
+ Wio = Work->Wio ;
+ Woo = Work->Woo ;
+ Fcpos = Work->Fcpos ;
+ Frpos = Work->Frpos ;
+ Frows = Work->Frows ;
+ Fcols = Work->Fcols ;
+ fnrows = Work->fnrows ;
+ fncols = Work->fncols ;
+ nb = Work->nb ;
+ fnr_curr = Work->fnr_curr ;
+ fnc_curr = Work->fnc_curr ;
+ fnpiv = Work->fnpiv ;
+ nothing [0] = EMPTY ;
+ nothing [1] = EMPTY ;
+ relax1 = (Symbolic->prefer_diagonal) ? SYM_RELAX1 : RELAX1 ;
+ fnzeros = Work->fnzeros ;
+ new_fnzeros = fnzeros ;
+ jj = EMPTY ;
+
+ Fcblock = Work->Fcblock ; /* current contribution block */
+ Flblock = Work->Flblock ; /* current L block */
+ Fublock = Work->Fublock ; /* current U block */
+ Flublock = Work->Flublock ; /* current LU block */
+
+ /* The pivot column degree cannot exceed max_cdeg */
+ max_cdeg = Work->fnrows_max ;
+ ASSERT (Work->fnrows_max <= Symbolic->maxnrows) ;
+ ASSERT (Work->fncols_max <= Symbolic->maxncols) ;
+
+ if (fnrows == 0 && fncols == 0)
+ {
+ /* frontal matrix is empty */
+ Work->firstsuper = Work->ksuper ;
+ }
+
+#ifndef NDEBUG
+ n_row = Work->n_row ;
+ n_col = Work->n_col ;
+ DEBUG2 (("\n========LOCAL SEARCH: current frontal matrix: ========= \n")) ;
+ 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) ;
+ }
+ }
+
+ DEBUGm2 ((ID" pivot column Candidates: lo "ID" hi "ID"\n",
+ Work->nCandidates, Work->lo, Work->hi)) ;
+ for (j = 0 ; j < Work->nCandidates ; j++)
+ {
+ col = Work->Candidates [j] ;
+ DEBUGm2 ((ID" ", col));
+ ASSERT (col >= 0 && col < n_col) ;
+ ASSERT (NON_PIVOTAL_COL (col)) ;
+ ASSERT (col >= Work->lo && col <= Work->hi) ;
+ }
+
+ DEBUGm2 (("\n")) ;
+ /* 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" + fnpiv "ID" = "ID". "
+ "size "ID"-by-"ID"\n", Work->frontid,
+ Work->npiv, Work->fnpiv, Work->npiv + Work->fnpiv, fnrows, fncols)) ;
+ ASSERT ((fnrows == 0 && fncols == 0) ||(fnrows != 0 && fncols != 0)) ;
+#endif
+
+ /* ====================================================================== */
+ /* === PIVOT SEARCH ===================================================== */
+ /* ====================================================================== */
+
+ /* initialize */
+
+ pivcol [IN] = EMPTY ;
+ pivcol [OUT] = EMPTY ;
+
+ 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 ;
+
+ fnrows_new [IN][IN] = EMPTY ;
+ fnrows_new [IN][OUT] = EMPTY ;
+ fnrows_new [OUT][IN] = EMPTY ;
+ fnrows_new [OUT][OUT] = EMPTY ;
+
+ fncols_new [IN][IN] = EMPTY ;
+ fncols_new [IN][OUT] = EMPTY ;
+ fncols_new [OUT][IN] = EMPTY ;
+ fncols_new [OUT][OUT] = EMPTY ;
+
+#ifndef NDEBUG
+ /* check Frpos */
+ DEBUG4 (("Check Frpos : fnrows "ID" col "ID" maxcdeg "ID"\n",
+ fnrows, pivcol [IN], max_cdeg)) ;
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ row = Frows [i] ;
+ DEBUG4 ((" row: "ID"\n", row)) ;
+ ASSERT (row >= 0 && row < n_row) ;
+ ASSERT (Frpos [row] == i) ;
+ }
+ DEBUG4 (("All:\n")) ;
+ if (UMF_debug > 0 || n_row < 1000)
+ {
+ Int cnt = fnrows ;
+ for (row = 0 ; row < n_row ; row++)
+ {
+ if (Frpos [row] == EMPTY)
+ {
+ cnt++ ;
+ }
+ else
+ {
+ DEBUG4 ((" row: "ID" pos "ID"\n", row, Frpos [row])) ;
+ }
+ }
+ ASSERT (cnt == n_row) ;
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* 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. */
+
+ /* ------------------------------------------------------------------ */
+ /* look in the candidate set for the best column */
+ /* ------------------------------------------------------------------ */
+
+ DEBUG2 (("Max candidates %d, Work->ncand "ID" jmax "ID"\n",
+ MAX_CANDIDATES, Work->ncand, Work->nCandidates)) ;
+ col = Work->Candidates [0] ;
+ ASSERT (Work->nCandidates > 0) ;
+ DEBUG3 (("Pivot column candidate: "ID" j = "ID"\n", col, j)) ;
+ ASSERT (col >= 0 && col < n_col) ;
+
+ /* there is no Col_degree if fixQ is true */
+ deg = Symbolic->fixQ ? EMPTY : 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, !Symbolic->fixQ) ;
+ if (Symbolic->fixQ)
+ {
+ DEBUG1 (("FIXQ: Candidates "ID" pivcol "ID" npiv "ID" fnpiv "ID
+ " ndiscard "ID "\n", Work->nCandidates, col, Work->npiv,
+ Work->fnpiv, Work->ndiscard)) ;
+ ASSERT (Work->nCandidates == 1) ;
+ ASSERT (col == Work->npiv + Work->fnpiv + Work->ndiscard) ;
+ }
+#endif
+
+ if (Fcpos [col] >= 0)
+ {
+ /* best column in front, so far */
+ pivcol [IN] = col ;
+ cdeg_in = deg ; /* ignored, if fixQ is true */
+ jcand [IN] = 0 ;
+ }
+ else
+ {
+ /* best column not in front, so far */
+ pivcol [OUT] = col ;
+ cdeg_out = deg ; /* ignored, if fixQ is true */
+ jcand [OUT] = 0 ;
+ }
+
+ /* look at the rest of the candidates */
+ for (j = 1 ; j < Work->nCandidates ; j++)
+ {
+ col = Work->Candidates [j] ;
+
+ DEBUG3 (("Pivot col candidate: "ID" j = "ID"\n", col, j)) ;
+ ASSERT (col >= 0 && col < n_col) ;
+ ASSERT (!Symbolic->fixQ) ;
+ deg = Col_degree [col] ;
+#ifndef NDEBUG
+ DEBUG3 (("Pivot col candidate: "ID" cost: "ID" Fcpos[col] "ID"\n",
+ col, deg, Fcpos [col])) ;
+ UMF_dump_rowcol (1, Numeric, Work, col, !Symbolic->fixQ) ;
+#endif
+ if (Fcpos [col] >= 0)
+ {
+#ifndef NDEBUG
+ Int fs ;
+ fs = Fcpos [col] / fnr_curr ;
+ 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 */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ /* check Frpos */
+ DEBUG4 (("Prior to col update: fnrows "ID" col "ID" maxcdeg "ID"\n",
+ fnrows, pivcol [IN], max_cdeg)) ;
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ row = Frows [i] ;
+ DEBUG4 ((" row: "ID"\n", row)) ;
+ ASSERT (row >= 0 && row < n_row) ;
+ ASSERT (Frpos [row] == i) ;
+ }
+ DEBUG4 (("All:\n")) ;
+ if (UMF_debug > 0 || n_row < 1000)
+ {
+ Int cnt = fnrows ;
+ for (row = 0 ; row < n_row ; row++)
+ {
+ if (Frpos [row] == EMPTY)
+ {
+ cnt++ ;
+ }
+ else
+ {
+ DEBUG4 ((" row: "ID" pos "ID"\n", row, Frpos [row])) ;
+ }
+ }
+ ASSERT (cnt == n_row) ;
+ }
+#endif
+
+ 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], !Symbolic->fixQ) ;
+#endif
+
+ /* the only way we can have a pivcol[IN] is if the front is not empty */
+ ASSERT (fnrows > 0 && fncols > 0) ;
+
+ DEBUG4 (("Update pivot column:\n")) ;
+ Fs = Fcblock + Fcpos [pivcol [IN]] ;
+ Fu = Fublock + (Fcpos [pivcol [IN]] / fnr_curr) ;
+ Flu = Flublock + fnpiv * nb ;
+
+ /* ------------------------------------------------------------------ */
+ /* copy the pivot column from the U block into the LU block */
+ /* ------------------------------------------------------------------ */
+
+ /* This copy is permanent if the pivcol [IN] is chosen. */
+ for (i = 0 ; i < fnpiv ; i++)
+ {
+ Flu [i] = Fu [i*fnc_curr] ;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* update the pivot column in the LU block using a triangular solve */
+ /* ------------------------------------------------------------------ */
+
+ /* This work will be discarded if the pivcol [OUT] is chosen instead.
+ * It is permanent if the pivcol [IN] is chosen. */
+
+ if (fnpiv > 1)
+ {
+ /* solve Lx=b, where b = U (:,k), stored in the LU block */
+
+#ifdef USE_NO_BLAS
+
+ /* no BLAS available - use plain C code instead */
+ Entry *Flub = Flublock ;
+ for (j = 0 ; j < fnpiv ; j++)
+ {
+ Entry Fuj = Flu [j] ;
+#pragma ivdep
+ for (i = j+1 ; i < fnpiv ; i++)
+ {
+ /* Flu [i] -= Flublock [i + j*nb] * Flu [j] ; */
+ MULT_SUB (Flu [i], Flub [i], Fuj) ;
+ }
+ Flub += nb ;
+ }
+
+#else
+ BLAS_TRSV (fnpiv, Flublock, Flu, nb) ;
+#endif
+
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* copy the pivot column from the C block into Wy */
+ /* ------------------------------------------------------------------ */
+
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ Wy [i] = Fs [i] ;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* update the pivot column of L using a matrix-vector multiply */
+ /* ------------------------------------------------------------------ */
+
+ /* this work will be discarded if the pivcol [OUT] is chosen instead */
+
+#ifdef USE_NO_BLAS
+ /* no BLAS available - use plain C code instead */
+ for (j = 0 ; j < fnpiv ; j++)
+ {
+ Entry Fuj, *Flub = Flblock + j * fnr_curr ;
+ Fuj = Flu [j] ;
+ if (IS_NONZERO (Fuj))
+ {
+#pragma ivdep
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ /* Wy [i] -= Flblock [i+j*fnr_curr] * Fuj ; */
+ MULT_SUB (Wy [i], Flub [i], Fuj) ;
+ }
+ }
+ /* Flblock += fnr_curr ; */
+ }
+#else
+ /* Using 1-based notation:
+ * Wy (1:fnrows) -= Flblock (1:fnrows,1:fnpiv) * Flu (1:fnpiv) */
+ BLAS_GEMV (fnrows, fnpiv, Flblock, Flu, Wy, fnr_curr) ;
+#endif
+
+ /* ------------------------------------------------------------------ */
+
+#ifndef NDEBUG
+ DEBUG2 (("Wy after update: fnrows="ID"\n", fnrows)) ;
+ DEBUG4 ((" fnpiv="ID" \n", fnpiv)) ;
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ DEBUG4 ((ID" "ID" "ID, i, Frows [i], Frpos [Frows [i]])) ;
+ EDEBUG4 (Wy [i]) ;
+ DEBUG4 (("\n")) ;
+ }
+#endif
+
+ /* ------------------------------------------------------------------ */
+ /* construct the candidate column */
+ /* ------------------------------------------------------------------ */
+
+ cdeg_in = fnrows ;
+
+#ifndef NDEBUG
+ /* check Frpos */
+ DEBUG4 (("After col update: fnrows "ID" col "ID" maxcdeg "ID"\n",
+ fnrows, pivcol [IN], max_cdeg)) ;
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ row = Frows [i] ;
+ DEBUG4 ((" row: "ID"\n", row)) ;
+ ASSERT (row >= 0 && row < n_row) ;
+ ASSERT (Frpos [row] == i) ;
+ }
+ DEBUG4 (("All:\n")) ;
+ if (UMF_debug > 0 || n_row < 1000)
+ {
+ Int cnt = fnrows ;
+ for (row = 0 ; row < n_row ; row++)
+ {
+ if (Frpos [row] == EMPTY)
+ {
+ cnt++ ;
+ }
+ else
+ {
+ DEBUG4 ((" row: "ID" pos "ID"\n", row, Frpos [row])) ;
+ }
+ }
+ ASSERT (cnt == n_row) ;
+ }
+#endif
+
+#ifndef NDEBUG
+ /* check Frpos */
+ DEBUG4 (("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
+
+ /* assemble column into Wy */
+
+ 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)
+ {
+ /* new entry in the pattern - save Frpos */
+ ASSERT (cdeg_in < n_row) ;
+ if (cdeg_in >= max_cdeg)
+ {
+ /* :: pattern change (cdeg in failure) :: */
+ DEBUGm4 (("cdeg_in failure\n")) ;
+ return (UMFPACK_ERROR_different_pattern) ;
+ }
+ Frpos [row] = cdeg_in ;
+ Frows [cdeg_in] = row ;
+ Wy [cdeg_in++] = C [i] ;
+ }
+ else
+ {
+ /* entry already in pattern - sum values in Wy */
+ /* Wy [pos] += C [i] ; */
+ ASSERT (pos < max_cdeg) ;
+ ASSEMBLE (Wy [pos], C [i]) ;
+ }
+ }
+ }
+ *tp2++ = *tp ; /* leave the tuple in the list */
+ }
+ Col_tlen [pivcol [IN]] = tp2 - tp1 ;
+ }
+
+ /* ------------------------------------------------------------------ */
+
+#ifndef NDEBUG
+ /* check Frpos again */
+ DEBUG4 (("COL DONE: 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
+
+#ifndef NDEBUG
+ DEBUG4 (("Reduced column: cdeg in "ID" fnrows_max "ID"\n",
+ cdeg_in, Work->fnrows_max)) ;
+ for (i = 0 ; i < cdeg_in ; i++)
+ {
+ DEBUG4 ((" "ID" "ID" "ID, i, Frows [i], Frpos [Frows [i]])) ;
+ EDEBUG4 (Wy [i]) ;
+ DEBUG4 (("\n")) ;
+ ASSERT (i == Frpos [Frows [i]]) ;
+ }
+ ASSERT (cdeg_in <= Work->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,
+ fnrows, cdeg_in, Frows, Frpos, /* pattern of column to search */
+ pivrow [IN], rdeg [IN], Fcols, Wio, nothing, Wy,
+ pivcol [IN], freebie) ;
+ ASSERT (!freebie [IN] && !freebie [OUT]) ;
+
+ /* ------------------------------------------------------------------ */
+ /* fatal error if matrix pattern has changed since symbolic analysis */
+ /* ------------------------------------------------------------------ */
+
+ if (status == UMFPACK_ERROR_different_pattern)
+ {
+ /* :: pattern change (row search IN failure) :: */
+ DEBUGm4 (("row search IN failure\n")) ;
+ 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.
+ * Both candidate pivot row and column are in the current front.
+ * Cost is how much the current front would expand */
+
+ /* pivrow[IN][IN] candidates are not found via row merge search */
+
+ ASSERT (fnrows >= 0 && fncols >= 0) ;
+
+ 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]) ;
+
+ /* size of relaxed front (after pivot row column removed): */
+ fnrows_new [IN][IN] = (fnrows-1) + nr_in ;
+ fncols_new [IN][IN] = (fncols-1) + nc ;
+ /* relaxed_front = fnrows_new [IN][IN] * fncols_new [IN][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)) ;
+
+ /* There are fnpiv pivots currently in the front. This one
+ * will be the (fnpiv+1)st pivot, if it is extended. */
+
+ /* RELAX2 parameter uses a double relop, but ignore NaN case: */
+ do_update = fnpiv > 0 &&
+ (((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.
+ * Candidate pivot column is in the current front, but the
+ * candidate pivot row is not. */
+
+ ASSERT (fnrows >= 0 && fncols > 0) ;
+ 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] ;
+ DEBUG4 (("counting col "ID" Fcpos[] = "ID"\n", col,
+ Fcpos [col])) ;
+ ASSERT (col >= 0 && col < n_col && 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 (after pivot column removed): */
+ fnrows_new [IN][OUT] = fnrows + (nr_in-1) ;
+ fncols_new [IN][OUT] = (fncols-1) + nc ;
+ relaxed_front = fnrows_new [IN][OUT] * fncols_new [IN][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 */
+
+ /* relax parameter uses a double relop, but ignore NaN case: */
+ if (extra_zeros == 0)
+ {
+ do_extend = TRUE ;
+ }
+ else
+ {
+ do_extend = ((double) extra_zeros) <
+ (relax1 * (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)) ;
+
+ /* RELAX3 parameter uses a double relop, ignore NaN case: */
+ do_update = fnpiv > 0 &&
+ (((double) fnzeros) / ((double) new_LUsize)) > RELAX3 ;
+ DEBUG2 (("do_update "ID"\n", do_update))
+
+ }
+ else
+ {
+ /* the current front would not be extended */
+ do_update = fnpiv > 0 ;
+ fnzeros = 0 ;
+ DEBUG2 (("IN-OUT do_update forced true: "ID"\n", do_update)) ;
+
+ /* The new front would be just big enough to hold the new
+ * pivot row and column. */
+ fnrows_new [IN][OUT] = cdeg_in - 1 ;
+ fncols_new [IN][OUT] = rdeg [IN][OUT] - 1 ;
+
+ }
+
+ 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 */
+ /* ---------------------------------------------------------------------- */
+
+ search_pivcol_out = (bestcost != 0 && pivcol [OUT] != EMPTY) ;
+ if (Symbolic->prefer_diagonal)
+ {
+ search_pivcol_out = search_pivcol_out && (pivrow [IN][IN] == EMPTY) ;
+ }
+
+ if (search_pivcol_out)
+ {
+
+#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], !Symbolic->fixQ) ;
+ DEBUG2 (("fncols "ID" fncols_max "ID"\n", fncols, Work->fncols_max)) ;
+ ASSERT (fncols < Work->fncols_max) ;
+#endif
+
+ /* Use Wx as temporary workspace to construct the pivcol [OUT] */
+
+
+ /* ------------------------------------------------------------------ */
+ /* construct the candidate column (currently not in the front) */
+ /* ------------------------------------------------------------------ */
+
+ /* Construct the column in Wx, Wm, using Wp for the positions: */
+ /* Wm [0..cdeg_out-1] list of row indices in the column */
+ /* Wx [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 */
+ DEBUG4 (("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) ;
+ }
+ }
+ DEBUG4 (("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)
+ {
+ /* new entry in the pattern - save Wp */
+ ASSERT (cdeg_out < n_row) ;
+ if (cdeg_out >= max_cdeg)
+ {
+ /* :: pattern change (cdeg out failure) :: */
+ DEBUGm4 (("cdeg out failure\n")) ;
+ return (UMFPACK_ERROR_different_pattern) ;
+ }
+ Wp [row] = cdeg_out ;
+ Wm [cdeg_out] = row ;
+ Wx [cdeg_out++] = C [i] ;
+ }
+ else
+ {
+ /* entry already in pattern - sum the values */
+ /* Wx [pos] += C [i] ; */
+ ASSEMBLE (Wx [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++)
+ {
+ DEBUG4 ((" "ID" "ID" "ID, i, Wm [i], Wp [Wm [i]])) ;
+ EDEBUG4 (Wx [i]) ;
+ DEBUG4 (("\n")) ;
+ ASSERT (i == Wp [Wm [i]]) ;
+ }
+#endif
+
+ /* ------------------------------------------------------------------ */
+ /* new degree of pivcol [OUT] is cdeg_out */
+ /* ------------------------------------------------------------------ */
+
+ /* search for two candidate pivot rows */
+ status = UMF_row_search (Numeric, Work, Symbolic,
+ 0, cdeg_out, Wm, Wp, /* pattern of column to search */
+ pivrow [OUT], rdeg [OUT], Woi, Woo, pivrow [IN], Wx,
+ pivcol [OUT], freebie) ;
+
+ /* ------------------------------------------------------------------ */
+ /* fatal error if matrix pattern has changed since symbolic analysis */
+ /* ------------------------------------------------------------------ */
+
+ if (status == UMFPACK_ERROR_different_pattern)
+ {
+ /* :: pattern change detected in umf_local_search :: */
+ return (UMFPACK_ERROR_different_pattern) ;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* Clear Wp */
+ /* ------------------------------------------------------------------ */
+
+ for (i = 0 ; i < cdeg_out ; i++)
+ {
+ Wp [Wm [i]] = EMPTY ; /* clear Wp */
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* 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. The current frontal matrix must
+ * be empty, too. It it weren't, and pivcol [OUT] exists, then
+ * there would be at least one row that could be selected. Since
+ * the current front is empty, pivcol [IN] must also be EMPTY.
+ */
+
+ DEBUGm4 (("Note: pivcol [OUT]: "ID" discard\n", pivcol [OUT])) ;
+ ASSERT ((Work->fnrows == 0 && Work->fncols == 0)) ;
+ ASSERT (pivcol [IN] == EMPTY) ;
+
+ /* remove the failed pivcol [OUT] from candidate set */
+ ASSERT (pivcol [OUT] == Work->Candidates [jcand [OUT]]) ;
+ remove_candidate (jcand [OUT], Work, Symbolic) ;
+ Work->ndiscard++ ;
+
+ /* 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 ;
+
+ /* no pivot found at all */
+ return (UMFPACK_WARNING_singular_matrix) ;
+ }
+
+ /* ------------------------------------------------------------------ */
+
+ 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.
+ * The candidate pivot row is in the current front, but the
+ * candidate pivot column is not. */
+
+ ASSERT (fnrows > 0 && fncols >= 0) ;
+
+ 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) */
+ DEBUGm4 (("did row merge OUT col, IN row\n")) ;
+ Wm [0] = pivrow [OUT][IN] ;
+ CLEAR (Wx [0]) ;
+ 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 && 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 (after pivot row removed): */
+ fnrows_new [OUT][IN] = (fnrows-1) + nr_out ;
+ fncols_new [OUT][IN] = fncols + (nc-1) ;
+ relaxed_front = fnrows_new [OUT][IN] * fncols_new [OUT][IN] ;
+
+ /* 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: */
+ if (extra_zeros == 0)
+ {
+ do_extend = TRUE ;
+ }
+ else
+ {
+ do_extend = ((double) extra_zeros) <
+ (relax1 * (double) relaxed_front) ;
+ }
+ }
+
+ if (do_extend)
+ {
+ /* count the cost of relaxed amalgamation */
+ thiscost += extra_zeros ;
+
+ 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)) ;
+
+ /* 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)) ;
+
+ /* RELAX3 parameter uses a double relop, ignore NaN case: */
+ do_update = fnpiv > 0 &&
+ (((double) fnzeros) / ((double) new_LUsize)) > RELAX3 ;
+ DEBUG2 (("do_update "ID"\n", do_update))
+ }
+ else
+ {
+ /* the current front would not be extended */
+ do_update = fnpiv > 0 ;
+ fnzeros = 0 ;
+ DEBUG2 (("OUT-IN do_update forced true: "ID"\n", do_update)) ;
+
+ /* The new front would be just big enough to hold the new
+ * pivot row and column. */
+ fnrows_new [OUT][IN] = cdeg_out - 1 ;
+ fncols_new [OUT][IN] = rdeg [OUT][IN] - 1 ;
+ }
+
+ 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)
+ {
+ /* Neither the candidate pivot row nor the candidate pivot column
+ * are in the current front. */
+
+ ASSERT (fnrows >= 0 && fncols >= 0) ;
+
+ 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) */
+ DEBUGm4 (("did row merge OUT col, OUT row\n")) ;
+ Wm [0] = pivrow [OUT][OUT] ;
+ CLEAR (Wx [0]) ;
+ cdeg_out = 1 ;
+ ASSERT (nr_out == EMPTY) ;
+ nr_out = 1 ;
+ }
+
+ if (fnrows == 0 && fncols == 0)
+ {
+ /* the current front is completely empty */
+ ASSERT (fnpiv == 0) ;
+ nc = rdeg [OUT][OUT] ;
+ extra_cols = 0 ;
+ nr_out = cdeg_out ;
+ extra_rows = 0 ;
+ extra_zeros = 0 ;
+
+ thiscost = (nc-1) * (cdeg_out-1) ; /* new columns only */
+
+ /* size of new front: */
+ fnrows_new [OUT][OUT] = nr_out-1 ;
+ fncols_new [OUT][OUT] = nc-1 ;
+ relaxed_front = fnrows_new [OUT][OUT] * fncols_new [OUT][OUT] ;
+ }
+ else
+ {
+
+ /* 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 && 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: */
+ fnrows_new [OUT][OUT] = fnrows + (nr_out-1) ;
+ fncols_new [OUT][OUT] = fncols + (nc-1) ;
+ relaxed_front = fnrows_new [OUT][OUT] * fncols_new [OUT][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: */
+ if (extra_zeros == 0)
+ {
+ do_extend = TRUE ;
+ }
+ else
+ {
+ do_extend = ((double) extra_zeros) <
+ (relax1 * (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)) ;
+
+ /* RELAX3 parameter uses a double relop, ignore NaN case: */
+ do_update = fnpiv > 0 &&
+ (((double) fnzeros) / ((double) new_LUsize)) > RELAX3 ;
+ DEBUG2 (("do_update "ID"\n", do_update))
+ }
+ else
+ {
+ /* the current front would not be extended */
+ do_update = fnpiv > 0 ;
+ fnzeros = 0 ;
+ DEBUG2 (("OUT-OUT do_update forced true: "ID"\n", do_update)) ;
+
+ /* The new front would be just big enough to hold the new
+ * pivot row and column. */
+ fnrows_new [OUT][OUT] = cdeg_out - 1 ;
+ fncols_new [OUT][OUT] = rdeg [OUT][OUT] - 1 ;
+ }
+
+ 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 search, 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")) ;
+ ASSERT (fnrows > 0 && fncols > 0) ;
+ Work->pivcol_in_front = TRUE ;
+ Work->pivrow_in_front = TRUE ;
+ Work->pivcol = pivcol [IN] ;
+ Work->pivrow = pivrow [IN][IN] ;
+ Work->ccdeg = nr_in ;
+ Work->Wrow = Fcols ;
+ Work->rrdeg = rdeg [IN][IN] ;
+ jj = jcand [IN] ;
+ Work->fnrows_new = fnrows_new [IN][IN] ;
+ Work->fncols_new = fncols_new [IN][IN] ;
+ break ;
+
+ case IN_OUT:
+ DEBUG2 (("IN-OUT option selected\n")) ;
+ ASSERT (fnrows >= 0 && fncols > 0) ;
+ Work->pivcol_in_front = TRUE ;
+ Work->pivrow_in_front = FALSE ;
+ Work->pivcol = pivcol [IN] ;
+ Work->pivrow = pivrow [IN][OUT] ;
+ Work->ccdeg = nr_in ;
+ Work->Wrow = Wio ;
+ Work->rrdeg = rdeg [IN][OUT] ;
+ jj = jcand [IN] ;
+ Work->fnrows_new = fnrows_new [IN][OUT] ;
+ Work->fncols_new = fncols_new [IN][OUT] ;
+ break ;
+
+ case OUT_IN:
+ DEBUG2 (("OUT-IN option selected\n")) ;
+ ASSERT (fnrows > 0 && fncols >= 0) ;
+ Work->pivcol_in_front = FALSE ;
+ Work->pivrow_in_front = TRUE ;
+ Work->pivcol = pivcol [OUT] ;
+ Work->pivrow = pivrow [OUT][IN] ;
+ 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] ;
+ Work->fnrows_new = fnrows_new [OUT][IN] ;
+ Work->fncols_new = fncols_new [OUT][IN] ;
+ break ;
+
+ case OUT_OUT:
+ DEBUG2 (("OUT-OUT option selected\n")) ;
+ ASSERT (fnrows >= 0 && fncols >= 0) ;
+ Work->pivcol_in_front = FALSE ;
+ Work->pivrow_in_front = FALSE ;
+ Work->pivcol = pivcol [OUT] ;
+ Work->pivrow = pivrow [OUT][OUT] ;
+ Work->ccdeg = cdeg_out ;
+ /* Wrow might be equivalenced to Wio (Freebie out): */
+ Work->Wrow = Woo ;
+ Work->rrdeg = rdeg [OUT][OUT] ;
+ jj = jcand [OUT] ;
+ Work->fnrows_new = fnrows_new [OUT][OUT] ;
+ Work->fncols_new = fncols_new [OUT][OUT] ;
+ break ;
+
+ }
+
+ ASSERT (IMPLIES (fnrows == 0 && fncols == 0, Work->pivot_case == OUT_OUT)) ;
+
+ 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;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* Pivot row and column have been found */
+ /* ---------------------------------------------------------------------- */
+
+ /* ---------------------------------------------------------------------- */
+ /* remove pivot column from candidate pivot column set */
+ /* ---------------------------------------------------------------------- */
+
+ ASSERT (jj >= 0 && jj < Work->nCandidates) ;
+ ASSERT (Work->pivcol == Work->Candidates [jj]) ;
+ remove_candidate (jj, Work, Symbolic) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* check for frontal matrix growth */
+ /* ---------------------------------------------------------------------- */
+
+ DEBUG1 (("Check frontal growth:\n")) ;
+ DEBUG1 (("fnrows_new "ID" + 1 = "ID", fnr_curr "ID"\n",
+ Work->fnrows_new, Work->fnrows_new + 1, fnr_curr)) ;
+ DEBUG1 (("fncols_new "ID" + 1 = "ID", fnc_curr "ID"\n",
+ Work->fncols_new, Work->fncols_new + 1, fnc_curr)) ;
+
+ Work->do_grow = (Work->fnrows_new + 1 > fnr_curr
+ || Work->fncols_new + 1 > fnc_curr) ;
+ if (Work->do_grow)
+ {
+ DEBUG0 (("\nNeed to grow frontal matrix, force do_update true\n")) ;
+ /* If the front must grow, then apply the pending updates and remove
+ * the current pivot rows/columns from the front prior to growing the
+ * front. This frees up as much space as possible for the new front. */
+ if (!Work->do_update && fnpiv > 0)
+ {
+ /* This update would not have to be done if the current front
+ * was big enough. */
+ Work->nforced++ ;
+ Work->do_update = TRUE ;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* current pivot column */
+ /* ---------------------------------------------------------------------- */
+
+ /*
+ c1) If pivot column index is in the current front:
+
+ The pivot column pattern is in Frows [0 .. fnrows-1] and
+ the extension is in Frows [fnrows ... fnrows+ccdeg-1].
+
+ Frpos [Frows [0 .. fnrows+ccdeg-1]] is
+ equal to 0 .. fnrows+ccdeg-1. Wm is not needed.
+
+ The values are in Wy [0 .. fnrows+ccdeg-1].
+
+ c2) Otherwise, if the pivot column index is not in the current front:
+
+ c2a) If the front is being extended, old row indices in the the
+ pivot column pattern are in Frows [0 .. fnrows-1].
+
+ All entries are in Wm [0 ... ccdeg-1], with values in
+ Wx [0 .. ccdeg-1]. These may include entries already in
+ Frows [0 .. fnrows-1].
+
+ Frpos [Frows [0 .. fnrows-1]] is equal to 0 .. fnrows-1.
+ Frpos [Wm [0 .. ccdeg-1]] for new entries is < 0.
+
+ c2b) If the front is not being extended, then the entire pivot
+ column pattern is in Wm [0 .. ccdeg-1]. It includes
+ the pivot row index. It is does not contain the pattern
+ Frows [0..fnrows-1]. The intersection of these two
+ sets may or may not be empty. The values are in Wx [0..ccdeg-1]
+
+ In both cases c1 and c2, Frpos [Frows [0 .. fnrows-1]] is equal
+ to 0 .. fnrows-1, which is the pattern of the current front.
+ Any entry of Frpos that is not specified above is < 0.
+ */
+
+
+#ifndef NDEBUG
+ DEBUG2 (("\n\nSEARCH DONE: Pivot col "ID" in: ("ID") pivot row "ID" in: ("ID
+ ") extend: "ID"\n\n", Work->pivcol, Work->pivcol_in_front,
+ Work->pivrow, Work->pivrow_in_front, Work->do_extend)) ;
+ UMF_dump_rowcol (1, Numeric, Work, Work->pivcol, !Symbolic->fixQ) ;
+ DEBUG2 (("Pivot col "ID": fnrows "ID" ccdeg "ID"\n", Work->pivcol, fnrows,
+ Work->ccdeg)) ;
+ if (Work->pivcol_in_front) /* case c1 */
+ {
+ Int found = FALSE ;
+ DEBUG3 (("Pivcol in front\n")) ;
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ row = Frows [i] ;
+ DEBUG3 ((ID": row:: "ID" in front ", i, row)) ;
+ ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;
+ ASSERT (Frpos [row] == i) ;
+ EDEBUG3 (Wy [i]) ;
+ if (row == Work->pivrow)
+ {
+ DEBUG3 ((" <- pivrow")) ;
+ found = TRUE ;
+ }
+ DEBUG3 (("\n")) ;
+ }
+ ASSERT (found == Work->pivrow_in_front) ;
+ found = FALSE ;
+ for (i = fnrows ; i < fnrows + Work->ccdeg ; i++)
+ {
+ row = Frows [i] ;
+ DEBUG3 ((ID": row:: "ID" (new)", i, row)) ;
+ ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;
+ ASSERT (Frpos [row] == i) ;
+ EDEBUG3 (Wy [i]) ;
+ if (row == Work->pivrow)
+ {
+ DEBUG3 ((" <- pivrow")) ;
+ found = TRUE ;
+ }
+ DEBUG3 (("\n")) ;
+ }
+ ASSERT (found == !Work->pivrow_in_front) ;
+ }
+ else
+ {
+ if (Work->do_extend)
+ {
+ Int found = FALSE ;
+ DEBUG3 (("Pivcol not in front (extend)\n")) ;
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ row = Frows [i] ;
+ DEBUG3 ((ID": row:: "ID" in front ", i, row)) ;
+ ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;
+ ASSERT (Frpos [row] == i) ;
+ if (row == Work->pivrow)
+ {
+ DEBUG3 ((" <- pivrow")) ;
+ found = TRUE ;
+ }
+ DEBUG3 (("\n")) ;
+ }
+ ASSERT (found == Work->pivrow_in_front) ;
+ found = FALSE ;
+ DEBUG3 (("----\n")) ;
+ for (i = 0 ; i < Work->ccdeg ; i++)
+ {
+ row = Wm [i] ;
+ ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;
+ DEBUG3 ((ID": row:: "ID" ", i, row)) ;
+ EDEBUG3 (Wx [i]) ;
+ if (Frpos [row] < 0)
+ {
+ DEBUG3 ((" (new) ")) ;
+ }
+ if (row == Work->pivrow)
+ {
+ DEBUG3 ((" <- pivrow")) ;
+ found = TRUE ;
+ /* ... */
+ if (Work->pivrow_in_front) ASSERT (Frpos [row] >= 0) ;
+ else ASSERT (Frpos [row] < 0) ;
+ }
+ DEBUG3 (("\n")) ;
+ }
+ ASSERT (found) ;
+ }
+ else
+ {
+ Int found = FALSE ;
+ DEBUG3 (("Pivcol not in front (no extend)\n")) ;
+ for (i = 0 ; i < Work->ccdeg ; i++)
+ {
+ row = Wm [i] ;
+ ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ;
+ DEBUG3 ((ID": row:: "ID" ", i, row)) ;
+ EDEBUG3 (Wx [i]) ;
+ DEBUG3 ((" (new) ")) ;
+ if (row == Work->pivrow)
+ {
+ DEBUG3 ((" <- pivrow")) ;
+ found = TRUE ;
+ }
+ DEBUG3 (("\n")) ;
+ }
+ ASSERT (found) ;
+ }
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* current pivot row */
+ /* ---------------------------------------------------------------------- */
+
+ /*
+ r1) If the pivot row index is in the current front:
+
+ The pivot row pattern is in Fcols [0..fncols-1] and the extenson is
+ in Wrow [fncols .. rrdeg-1]. If the pivot column is in the current
+ front, then Fcols and Wrow are equivalenced.
+
+ r2) If the pivot row index is not in the current front:
+
+ r2a) If the front is being extended, the pivot row pattern is in
+ Fcols [0 .. fncols-1]. New entries are in Wrow [0 .. rrdeg-1],
+ but these may include entries already in Fcols [0 .. fncols-1].
+
+ r2b) Otherwise, the pivot row pattern is Wrow [0 .. rrdeg-1].
+
+ Fcpos [Fcols [0..fncols-1]] is (0..fncols-1) * fnr_curr.
+ All other entries in Fcpos are < 0.
+
+ These conditions are asserted below.
+
+ ------------------------------------------------------------------------
+ Other items in Work structure that are relevant:
+
+ pivcol: the pivot column index
+ pivrow: the pivot column index
+
+ rrdeg:
+ ccdeg:
+
+ fnrows: the number of rows in the currnt contribution block
+ fncols: the number of columns in the current contribution block
+
+ fnrows_new: the number of rows in the new contribution block
+ fncols_new: the number of rows in the new contribution block
+
+ ------------------------------------------------------------------------
+ */
+
+
+#ifndef NDEBUG
+ UMF_dump_rowcol (0, Numeric, Work, Work->pivrow, TRUE) ;
+ DEBUG2 (("Pivot row "ID":\n", Work->pivrow)) ;
+ if (Work->pivrow_in_front)
+ {
+ Int found = FALSE ;
+ for (i = 0 ; i < fncols ; i++)
+ {
+ col = Fcols [i] ;
+ DEBUG3 ((" col:: "ID" in front\n", col)) ;
+ ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;
+ ASSERT (Fcpos [col] == i * fnr_curr) ;
+ if (col == Work->pivcol) found = TRUE ;
+ }
+ ASSERT (found == Work->pivcol_in_front) ;
+ found = FALSE ;
+ ASSERT (IMPLIES (Work->pivcol_in_front, Fcols == Work->Wrow)) ;
+ for (i = fncols ; i < Work->rrdeg ; i++)
+ {
+ col = Work->Wrow [i] ;
+ ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;
+ ASSERT (Fcpos [col] < 0) ;
+ if (col == Work->pivcol) found = TRUE ;
+ else DEBUG3 ((" col:: "ID" (new)\n", col)) ;
+ }
+ ASSERT (found == !Work->pivcol_in_front) ;
+ }
+ else
+ {
+ if (Work->do_extend)
+ {
+ Int found = FALSE ;
+ for (i = 0 ; i < fncols ; i++)
+ {
+ col = Fcols [i] ;
+ DEBUG3 ((" col:: "ID" in front\n", col)) ;
+ ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;
+ ASSERT (Fcpos [col] == i * fnr_curr) ;
+ if (col == Work->pivcol) found = TRUE ;
+ }
+ ASSERT (found == Work->pivcol_in_front) ;
+ found = FALSE ;
+ for (i = 0 ; i < Work->rrdeg ; i++)
+ {
+ col = Work->Wrow [i] ;
+ ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;
+ if (Fcpos [col] >= 0) continue ;
+ if (col == Work->pivcol) found = TRUE ;
+ else DEBUG3 ((" col:: "ID" (new, extend)\n", col)) ;
+ }
+ ASSERT (found == !Work->pivcol_in_front) ;
+ }
+ else
+ {
+ Int found = FALSE ;
+ for (i = 0 ; i < Work->rrdeg ; i++)
+ {
+ col = Work->Wrow [i] ;
+ ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ;
+ if (col == Work->pivcol) found = TRUE ;
+ else DEBUG3 ((" col:: "ID" (all new)\n", col)) ;
+ }
+ ASSERT (found) ;
+ }
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* 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 ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+
+ DEBUG2 (("LOCAL SEARCH DONE: pivot column "ID" pivot row: "ID"\n",
+ Work->pivcol, Work->pivrow)) ;
+ DEBUG2 (("do_extend: "ID"\n", Work->do_extend)) ;
+ DEBUG2 (("do_update: "ID"\n", Work->do_update)) ;
+ DEBUG2 (("do_grow: "ID"\n", Work->do_grow)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* keep track of the diagonal */
+ /* ---------------------------------------------------------------------- */
+
+ if (Symbolic->prefer_diagonal
+ && Work->pivcol < Work->n_col - Symbolic->nempty_col)
+ {
+ Diagonal_map = Work->Diagonal_map ;
+ Diagonal_imap = Work->Diagonal_imap ;
+ ASSERT (Diagonal_map != (Int *) NULL) ;
+ ASSERT (Diagonal_imap != (Int *) NULL) ;
+
+ row2 = Diagonal_map [Work->pivcol] ;
+ col2 = Diagonal_imap [Work->pivrow] ;
+
+ if (row2 < 0)
+ {
+ /* this was an off-diagonal pivot row */
+ Work->noff_diagonal++ ;
+ row2 = UNFLIP (row2) ;
+ }
+
+ ASSERT (Diagonal_imap [row2] == Work->pivcol) ;
+ ASSERT (UNFLIP (Diagonal_map [col2]) == Work->pivrow) ;
+
+ if (row2 != Work->pivrow)
+ {
+ /* swap the diagonal map to attempt to maintain symmetry later on.
+ * Also mark the map for col2 (via FLIP) to denote that the entry
+ * now on the diagonal is not the original entry on the diagonal. */
+
+ DEBUG0 (("Unsymmetric pivot\n")) ;
+ Diagonal_map [Work->pivcol] = FLIP (Work->pivrow) ;
+ Diagonal_imap [Work->pivrow] = Work->pivcol ;
+
+ Diagonal_map [col2] = FLIP (row2) ;
+ Diagonal_imap [row2] = col2 ;
+
+ }
+ ASSERT (n_row == n_col) ;
+#ifndef NDEBUG
+ UMF_dump_diagonal_map (Diagonal_map, Diagonal_imap, Symbolic->n1,
+ Symbolic->n_col, Symbolic->nempty_col) ;
+#endif
+ }
+
+ return (UMFPACK_OK) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_local_search
+(
+ NumericType *Numeric,
+ WorkType *Work,
+ SymbolicType *Symbolic
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_lsolve =========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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, n1, *Li ;
+ Entry *xp, xk, *Lval ;
+
+ /* ---------------------------------------------------------------------- */
+
+ if (Numeric->n_row != Numeric->n_col) return (0.) ;
+ npiv = Numeric->npiv ;
+ Lpos = Numeric->Lpos ;
+ Lilen = Numeric->Lilen ;
+ Lip = Numeric->Lip ;
+ n1 = Numeric->n1 ;
+
+#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
+
+ /* ---------------------------------------------------------------------- */
+ /* singletons */
+ /* ---------------------------------------------------------------------- */
+
+ for (k = 0 ; k < n1 ; k++)
+ {
+ DEBUG4 (("Singleton k "ID"\n", k)) ;
+ xk = X [k] ;
+ deg = Lilen [k] ;
+ if (deg > 0 && IS_NONZERO (xk))
+ {
+ lp = Lip [k] ;
+ Li = (Int *) (Numeric->Memory + lp) ;
+ lp += UNITS (Int, deg) ;
+ Lval = (Entry *) (Numeric->Memory + lp) ;
+ for (j = 0 ; j < deg ; j++)
+ {
+ DEBUG4 ((" row "ID" k "ID" value", Li [j], k)) ;
+ EDEBUG4 (Lval [j]) ;
+ DEBUG4 (("\n")) ;
+ /* X [Li [j]] -= xk * Lval [j] ; */
+ MULT_SUB (X [Li [j]], xk, Lval [j]) ;
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* rest of L */
+ /* ---------------------------------------------------------------------- */
+
+ deg = 0 ;
+
+ for (k = n1 ; 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)) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL double UMF_lsolve
+(
+ NumericType *Numeric,
+ Entry X [ ],
+ Int Pattern [ ]
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_ltsolve ========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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, n1, *Li ;
+ Entry *xp, xk, *Lval ;
+
+ /* ---------------------------------------------------------------------- */
+
+ if (Numeric->n_row != Numeric->n_col) return (0.) ;
+ npiv = Numeric->npiv ;
+ Lpos = Numeric->Lpos ;
+ Lilen = Numeric->Lilen ;
+ Lip = Numeric->Lip ;
+ kstart = npiv ;
+ n1 = Numeric->n1 ;
+
+#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
+
+ /* ---------------------------------------------------------------------- */
+ /* non-singletons */
+ /* ---------------------------------------------------------------------- */
+
+ for (kend = npiv-1 ; kend >= n1 ; 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 ;
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* singletons */
+ /* ---------------------------------------------------------------------- */
+
+ for (k = n1 - 1 ; k >= 0 ; k--)
+ {
+ DEBUG4 (("Singleton k "ID"\n", k)) ;
+ deg = Lilen [k] ;
+ if (deg > 0)
+ {
+ xk = X [k] ;
+ lp = Lip [k] ;
+ Li = (Int *) (Numeric->Memory + lp) ;
+ lp += UNITS (Int, deg) ;
+ Lval = (Entry *) (Numeric->Memory + lp) ;
+ for (j = 0 ; j < deg ; j++)
+ {
+ DEBUG4 ((" row "ID" k "ID" value", Li [j], k)) ;
+ EDEBUG4 (Lval [j]) ;
+ DEBUG4 (("\n")) ;
+#ifdef CONJUGATE_SOLVE
+ /* xk -= X [Li [j]] * conjugate (Lval [j]) ; */
+ MULT_SUB_CONJ (xk, X [Li [j]], Lval [j]) ;
+#else
+ /* xk -= X [Li [j]] * Lval [j] ; */
+ MULT_SUB (xk, X [Li [j]], Lval [j]) ;
+#endif
+ }
+ X [k] = xk ;
+ }
+ }
+
+#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)) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL double UMF_ltsolve
+(
+ NumericType *Numeric,
+ Entry X [ ],
+ Int Pattern [ ]
+) ;
+
+GLOBAL double UMF_lhsolve
+(
+ NumericType *Numeric,
+ Entry X [ ],
+ Int Pattern [ ]
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_malloc =========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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. 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
+
+#ifdef UMF_TCOV_TEST
+/* For exhaustive statement coverage testing only! */
+GLOBAL Int umf_fail, umf_fail_lo, umf_fail_hi ;
+GLOBAL Int umf_realloc_fail, umf_realloc_lo, umf_realloc_hi ;
+#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)
+ {
+ DEBUG0 (("umf_malloc: Pretend to fail %d %d %d\n",
+ umf_fail, umf_fail_hi, umf_fail_lo)) ;
+ return ((void *) NULL) ;
+ }
+#endif
+
+ DEBUG0 (("UMF_malloc: ")) ;
+
+ /* 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) ;
+
+ DEBUG0 ((ID"\n", (Int) p)) ;
+
+#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++ ;
+ DEBUG0 ((" successful, new malloc count: "ID"\n", UMF_malloc_count)) ;
+ }
+#endif
+
+ return (p) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+#if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG)
+GLOBAL extern Int UMF_malloc_count ;
+#endif
+
+GLOBAL void *UMF_malloc
+(
+ Int n_objects,
+ size_t size_of_object
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_mem_alloc_element ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 != (NumericType *) NULL) ;
+ ASSERT (Numeric->Memory != (Unit *) NULL) ;
+
+ *size = GET_ELEMENT_SIZE (nrows, ncols) ;
+ if (INT_OVERFLOW (DGET_ELEMENT_SIZE (nrows, ncols) + 1))
+ {
+ /* :: allocate element, int overflow :: */
+ 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, (Int) (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) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_mem_alloc_element
+(
+ NumericType *Numeric,
+ Int nrows,
+ Int ncols,
+ Int **Rows,
+ Int **Cols,
+ Entry **C,
+ Int *size,
+ Element **epout
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_mem_alloc_head_block ============================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 != (NumericType *) NULL) ;
+ ASSERT (Numeric->Memory != (Unit *) NULL) ;
+
+#ifndef NDEBUG
+ if (UMF_allocfail)
+ {
+ /* pretend to fail, to test garbage_collection */
+ DEBUGm2 (("UMF_mem_alloc_head_block: pretend to fail\n")) ;
+ UMF_allocfail = FALSE ; /* don't fail the next time */
+ return (0) ;
+ }
+#endif
+
+ 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 (("p: "ID"\n", p)) ;
+ usage = Numeric->ihead + Numeric->tail_usage ;
+ Numeric->max_usage = MAX (Numeric->max_usage, usage) ;
+ return (p) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_mem_alloc_head_block
+(
+ NumericType *Numeric,
+ Int nunits
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_mem_alloc_tail_block ============================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 != (NumericType *) NULL) ;
+ ASSERT (Numeric->Memory != (Unit *) NULL) ;
+
+#ifndef NDEBUG
+ if (UMF_allocfail)
+ {
+ /* pretend to fail, to test garbage_collection */
+ DEBUGm2 (("UMF_mem_alloc_tail_block: pretend to fail\n")) ;
+ 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", (Int) (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", (Int) (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",
+ (Int) (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) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_mem_alloc_tail_block
+(
+ NumericType *Numeric,
+ Int nunits
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_mem_free_tail_block ============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 != (NumericType *) NULL) ;
+ ASSERT (Numeric->Memory != (Unit *) NULL) ;
+ 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, (Int) (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,
+ (Int) (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" ", (Int) (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", (Int) (p-Numeric->Memory),
+ -(p->header.size))) ;
+
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_mem_free_tail_block
+(
+ NumericType *Numeric,
+ Int i
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_mem_init_memoryspace ============================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 != (NumericType *) NULL) ;
+ ASSERT (Numeric->Memory != (Unit *) NULL) ;
+ ASSERT (Numeric->size >= 3) ;
+ 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", (Int) (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
+
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_mem_init_memoryspace
+(
+ NumericType *Numeric
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_realloc ========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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"
+
+#if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG)
+#include "umf_malloc.h"
+#endif
+
+GLOBAL void *UMF_realloc
+(
+ void *p,
+ Int n_objects,
+ size_t size_of_object
+)
+{
+ size_t size ;
+ void *p2 ;
+
+#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)
+ {
+ /* :: int overflow in umf_realloc :: */
+ return ((void *) NULL) ;
+ }
+ size *= size_of_object ;
+
+ DEBUG0 (("UMF_realloc: "ID" n_objects "ID" size_of_object "ID"\n",
+ (Int) p, n_objects, (Int) size_of_object)) ;
+
+ /* see umf_config.h for the memory allocator selection */
+ p2 = REALLOCATE (p, size) ;
+
+#if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG)
+ /* If p didn't exist on input, and p2 exists, then a new object has been
+ * allocated. */
+ if (p == (void *) NULL && p2 != (void *) NULL)
+ {
+ UMF_malloc_count++ ;
+ }
+#endif
+
+ DEBUG0 (("UMF_realloc: "ID" new malloc count "ID"\n",
+ (Int) p2, UMF_malloc_count)) ;
+
+ return (p2) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void *UMF_realloc
+(
+ void *p,
+ Int n_objects,
+ size_t size_of_object
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_report_perm ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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"
+
+#define PRINTF4U(params) { if (user || prl >= 4) PRINTF (params) ; }
+
+GLOBAL Int UMF_report_perm
+(
+ Int n,
+ const Int P [ ],
+ Int W [ ], /* workspace of size n */
+ Int prl,
+ Int user
+)
+{
+ Int i, k, valid, prl1 ;
+
+ ASSERT (prl >= 3) ;
+
+ PRINTF4U (("permutation vector, n = "ID". ", n)) ;
+
+ if (n <= 0)
+ {
+ PRINTF (("ERROR: length of permutation is <= 0\n\n")) ;
+ return (UMFPACK_ERROR_n_nonpositive) ;
+ }
+
+ if (!P)
+ {
+ /* if P is (Int *) NULL, this is the identity permutation */
+ PRINTF (("(not present)\n\n")) ;
+ return (UMFPACK_OK) ;
+ }
+
+ if (!W)
+ {
+ PRINTF (("ERROR: out of memory\n\n")) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+
+ PRINTF4 (("\n")) ;
+
+ for (i = 0 ; i < n ; i++)
+ {
+ W [i] = TRUE ;
+ }
+
+ prl1 = prl ;
+ for (k = 0 ; k < n ; k++)
+ {
+ i = P [k] ;
+ PRINTF4 ((" "ID" : "ID" ", INDEX (k), INDEX (i))) ;
+ valid = (i >= 0 && i < n) ;
+ if (valid)
+ {
+ valid = W [i] ;
+ W [i] = FALSE ;
+ }
+ if (!valid)
+ {
+ /* out of range or duplicate entry */
+ PRINTF (("ERROR: invalid\n\n")) ;
+ return (UMFPACK_ERROR_invalid_permutation) ;
+ }
+ PRINTF4 (("\n")) ;
+ if (prl == 4 && k == 9 && n > 10)
+ {
+ PRINTF ((" ...\n")) ;
+ prl-- ;
+ }
+ }
+ prl = prl1 ;
+
+ PRINTF4 ((" permutation vector ")) ;
+ PRINTF4U (("OK\n\n")) ;
+ return (UMFPACK_OK) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_report_perm
+(
+ Int n,
+ const Int P [ ],
+ Int W [ ],
+ Int prl,
+ Int user
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_report_vector ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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"
+
+/* ========================================================================== */
+/* === print_value ========================================================== */
+/* ========================================================================== */
+
+PRIVATE void print_value
+(
+ Int i,
+ const double Xx [ ],
+ const double Xz [ ],
+ Int scalar /* if true, then print real part only */
+)
+{
+ Entry *X, xi ;
+ /* if Xz is null, then X is in "merged" format (compatible with Entry, */
+ /* and ANSI C99 double _Complex type). */
+ X = (Entry *) Xx ;
+ PRINTF ((" "ID" :", INDEX (i))) ;
+ if (scalar)
+ {
+ PRINT_SCALAR (Xx [i]) ;
+ }
+ else
+ {
+ if (Xz != (double *) NULL)
+ {
+ ASSIGN (xi, Xx [i], Xz [i]) ;
+ }
+ else
+ {
+ xi = X [i] ;
+ }
+ PRINT_ENTRY (xi) ;
+ }
+ PRINTF (("\n")) ;
+}
+
+/* ========================================================================== */
+/* === UMF_report_vector ==================================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMF_report_vector
+(
+ Int n,
+ const double Xx [ ],
+ const double Xz [ ],
+ Int prl,
+ Int user,
+ Int scalar
+)
+{
+ Int n2, i ;
+
+ if (user || prl >= 4)
+ {
+ PRINTF (("dense vector, n = "ID". ", n)) ;
+ }
+
+ if (user)
+ {
+ if (!Xx)
+ {
+ PRINTF (("ERROR: vector not present\n\n")) ;
+ return (UMFPACK_ERROR_argument_missing) ;
+ }
+ if (n < 0)
+ {
+ PRINTF (("ERROR: length of vector is < 0\n\n")) ;
+ return (UMFPACK_ERROR_n_nonpositive) ;
+ }
+ }
+
+ if (user || prl >= 4)
+ {
+ PRINTF4 (("\n")) ;
+ }
+
+ if (prl == 4)
+ {
+ /* print level of 4 */
+ n2 = MIN (10, n) ;
+ for (i = 0 ; i < n2 ; i++)
+ {
+ print_value (i, Xx, Xz, scalar) ;
+ }
+ if (n2 < n)
+ {
+ PRINTF ((" ...\n")) ;
+ print_value (n-1, Xx, Xz, scalar) ;
+ }
+ }
+ else if (prl > 4)
+ {
+ /* print level 4 or more */
+ for (i = 0 ; i < n ; i++)
+ {
+ print_value (i, Xx, Xz, scalar) ;
+ }
+ }
+
+ PRINTF4 ((" dense vector ")) ;
+ if (user || prl >= 4)
+ {
+ PRINTF (("OK\n\n")) ;
+ }
+ return (UMFPACK_OK) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_report_vector
+(
+ Int n,
+ const double Xx [ ],
+ const double Xz [ ],
+ Int prl,
+ Int user,
+ Int scalar
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_row_search ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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"
+#include "umf_row_search.h"
+
+GLOBAL Int UMF_row_search
+(
+ NumericType *Numeric,
+ WorkType *Work,
+ SymbolicType *Symbolic,
+ Int cdeg0, /* length of column in Front */
+ Int cdeg1, /* length of column outside Front */
+ const Int Pattern [ ], /* pattern of column, Pattern [0..cdeg1 -1] */
+ const Int Pos [ ], /* Pos [Pattern [0..cdeg1 -1]] = 0..cdeg1 -1 */
+ 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 Wxy [ ], /* numerical values Wxy [0..cdeg1-1],
+ either Wx or Wy */
+
+ Int pivcol, /* the candidate column being searched */
+ Int freebie [ ]
+)
+{
+
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ double maxval, toler, toler2, value, pivot [2] ;
+ Int i, row, deg, col, *Frpos, fnrows, *E, j, ncols, *Cols, *Rows,
+ e, f, Wrpflag, *Fcpos, fncols, tpi, max_rdeg, nans_in_col, was_offdiag,
+ diag_row, prefer_diagonal, *Wrp, found, *Diagonal_map ;
+ Tuple *tp, *tpend, *tp1, *tp2 ;
+ Unit *Memory, *p ;
+ Element *ep ;
+ Int *Row_tuples, *Row_degree, *Row_tlen ;
+
+#ifndef NDEBUG
+ Int *Col_degree ;
+ DEBUG2 (("Row_search:\n")) ;
+ for (i = 0 ; i < cdeg1 ; i++)
+ {
+ row = Pattern [i] ;
+ DEBUG4 ((" row: "ID"\n", row)) ;
+ ASSERT (row >= 0 && row < Numeric->n_row) ;
+ ASSERT (i == Pos [row]) ;
+ }
+ /* If row is not in Pattern [0..cdeg1-1], then Pos [row] == EMPTY */
+ if (UMF_debug > 0 || Numeric->n_row < 1000)
+ {
+ Int cnt = cdeg1 ;
+ DEBUG4 (("Scan all rows:\n")) ;
+ for (row = 0 ; row < Numeric->n_row ; row++)
+ {
+ if (Pos [row] < 0)
+ {
+ cnt++ ;
+ }
+ else
+ {
+ DEBUG4 ((" row: "ID" pos "ID"\n", row, Pos [row])) ;
+ }
+ }
+ ASSERT (cnt == Numeric->n_row) ;
+ }
+ Col_degree = Numeric->Cperm ; /* for NON_PIVOTAL_COL macro only */
+ ASSERT (pivcol >= 0 && pivcol < Work->n_col) ;
+ ASSERT (NON_PIVOTAL_COL (pivcol)) ;
+#endif
+
+ pivot [IN] = 0. ;
+ pivot [OUT] = 0. ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ Row_degree = Numeric->Rperm ;
+ Row_tuples = Numeric->Uip ;
+ Row_tlen = Numeric->Uilen ;
+ Wrp = Work->Wrp ;
+ Frpos = Work->Frpos ;
+ E = Work->E ;
+ Memory = Numeric->Memory ;
+ fnrows = Work->fnrows ;
+
+ prefer_diagonal = Symbolic->prefer_diagonal ;
+ Diagonal_map = Work->Diagonal_map ;
+
+ if (Diagonal_map)
+ {
+ diag_row = Diagonal_map [pivcol] ;
+ was_offdiag = diag_row < 0 ;
+ if (was_offdiag)
+ {
+ /* the "diagonal" entry in this column was permuted here by an
+ * earlier pivot choice. The tighter off-diagonal tolerance will
+ * be used instead of the symmetric tolerance. */
+ diag_row = FLIP (diag_row) ;
+ }
+ ASSERT (diag_row >= 0 && diag_row < Numeric->n_row) ;
+ }
+ else
+ {
+ diag_row = EMPTY ; /* unused */
+ was_offdiag = EMPTY ; /* unused */
+ }
+
+ /* pivot row degree cannot exceed max_rdeg */
+ max_rdeg = Work->fncols_max ;
+
+ /* ---------------------------------------------------------------------- */
+ /* scan pivot column for candidate rows */
+ /* ---------------------------------------------------------------------- */
+
+ maxval = 0.0 ;
+ nans_in_col = FALSE ;
+
+ for (i = 0 ; i < cdeg1 ; i++)
+ {
+ APPROX_ABS (value, Wxy [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 ;
+ toler2 = Numeric->relpt2 * maxval ;
+ toler2 = was_offdiag ? toler : toler2 ;
+
+ DEBUG5 (("Row_search begins [ maxval %g toler %g %g\n",
+ maxval, toler, toler2)) ;
+ if (SCALAR_IS_NAN (toler) || SCALAR_IS_NAN (toler2))
+ {
+ nans_in_col = TRUE ;
+ }
+
+ if (!nans_in_col)
+ {
+
+ /* look for the diagonal entry, if it exists */
+ found = FALSE ;
+ ASSERT (!SCALAR_IS_NAN (toler)) ;
+
+ if (prefer_diagonal)
+ {
+ ASSERT (diag_row != EMPTY) ;
+ i = Pos [diag_row] ;
+ if (i >= 0)
+ {
+ double a ;
+ ASSERT (i < cdeg1) ;
+ ASSERT (diag_row == Pattern [i]) ;
+
+ APPROX_ABS (a, Wxy [i]) ;
+
+ ASSERT (!SCALAR_IS_NAN (a)) ;
+ ASSERT (!SCALAR_IS_NAN (toler2)) ;
+
+ if (SCALAR_IS_NONZERO (a) && a >= toler2)
+ {
+ /* found it! */
+ DEBUG3 (("Symmetric pivot: "ID" "ID"\n", pivcol, diag_row));
+ found = TRUE ;
+ if (Frpos [diag_row] >= 0 && Frpos [diag_row] < fnrows)
+ {
+ pivrow [IN] = diag_row ;
+ pivrow [OUT] = EMPTY ;
+ }
+ else
+ {
+ pivrow [IN] = EMPTY ;
+ pivrow [OUT] = diag_row ;
+ }
+ }
+ }
+ }
+
+ /* either no diagonal found, or we didn't look for it */
+ if (!found)
+ {
+ if (cdeg0 > 0)
+ {
+
+ /* this is a column in the front */
+ for (i = 0 ; i < cdeg0 ; i++)
+ {
+ double a ;
+ APPROX_ABS (a, Wxy [i]) ;
+ ASSERT (!SCALAR_IS_NAN (a)) ;
+ ASSERT (!SCALAR_IS_NAN (toler)) ;
+ if (SCALAR_IS_NONZERO (a) && a >= toler)
+ {
+ 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
+ ASSERT (Frpos [row] >= 0 && Frpos [row] < fnrows) ;
+ ASSERT (Frpos [row] == i) ;
+ /* row is in the current front */
+ DEBUG4 ((" in front\n")) ;
+ if (deg < rdeg [IN]
+ /* break ties by picking the largest entry: */
+ || (deg == rdeg [IN] && a > pivot [IN])
+ /* break ties by picking the diagonal entry: */
+ /* || (deg == rdeg [IN] && row == diag_row) */
+ )
+ {
+ /* best row in front, so far */
+ pivrow [IN] = row ;
+ rdeg [IN] = deg ;
+ pivot [IN] = a ;
+ }
+ }
+ }
+ for ( ; i < cdeg1 ; i++)
+ {
+ double a ;
+ APPROX_ABS (a, Wxy [i]) ;
+ ASSERT (!SCALAR_IS_NAN (a)) ;
+ ASSERT (!SCALAR_IS_NAN (toler)) ;
+ if (SCALAR_IS_NONZERO (a) && a >= toler)
+ {
+ 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
+ ASSERT (Frpos [row] == i) ;
+ /* row is not in the current front */
+ DEBUG4 ((" NOT in front\n")) ;
+ if (deg < rdeg [OUT]
+ /* break ties by picking the largest entry: */
+ || (deg == rdeg [OUT] && a > pivot [OUT])
+ /* break ties by picking the diagonal entry: */
+ /* || (deg == rdeg [OUT] && row == diag_row) */
+ )
+ {
+ /* best row not in front, so far */
+ pivrow [OUT] = row ;
+ rdeg [OUT] = deg ;
+ pivot [OUT] = a ;
+ }
+ }
+ }
+
+ }
+ else
+ {
+
+ /* this column is not in the front */
+ for (i = 0 ; i < cdeg1 ; i++)
+ {
+ double a ;
+ APPROX_ABS (a, Wxy [i]) ;
+ ASSERT (!SCALAR_IS_NAN (a)) ;
+ ASSERT (!SCALAR_IS_NAN (toler)) ;
+ if (SCALAR_IS_NONZERO (a) && a >= toler)
+ {
+ 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]
+ /* break ties by picking the largest entry: */
+ || (deg == rdeg [IN] && a > pivot [IN])
+ /* break ties by picking the diagonal entry: */
+ /* || (deg == rdeg [IN] && row == diag_row) */
+ )
+ {
+ /* best row in front, so far */
+ pivrow [IN] = row ;
+ rdeg [IN] = deg ;
+ pivot [IN] = a ;
+ }
+ }
+ else
+ {
+ /* row is not in the current front */
+ DEBUG4 ((" NOT in front\n")) ;
+ if (deg < rdeg [OUT]
+ /* break ties by picking the largest entry: */
+ || (deg == rdeg[OUT] && a > pivot [OUT])
+ /* break ties by picking the diagonal entry: */
+ /* || (deg == rdeg[OUT] && row == diag_row) */
+ )
+ {
+ /* best row not in front, so far */
+ pivrow [OUT] = row ;
+ rdeg [OUT] = deg ;
+ pivot [OUT] = a ;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* NaN handling */
+ /* ---------------------------------------------------------------------- */
+
+ /* if cdeg1 > 0 then we must have found a pivot row ... unless NaN's */
+ /* exist. Try with no numerical tests if no pivot found. */
+
+ if (cdeg1 > 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, */
+ /* numerical stability, and symmetric preference */
+ 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 < cdeg1 ; 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 == diag_row))
+ {
+ /* 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 == diag_row))
+ {
+ /* 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 (cdeg1 > 0, pivrow[IN] != EMPTY || pivrow[OUT] != EMPTY)) ;
+
+ /* If there are no entries in the pivot column, then no pivot is found */
+ ASSERT (IMPLIES (cdeg1 == 0, pivrow[IN] == EMPTY && pivrow[OUT] == EMPTY)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* check for singular matrix */
+ /* ---------------------------------------------------------------------- */
+
+ if (cdeg1 == 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] ;
+ DEBUGm4 (("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 ;
+
+ DEBUGm4 (("Note: 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++)
+ {
+ DEBUG3 ((" Row: "ID"\n", row)) ;
+ if (NON_PIVOTAL_ROW (row))
+ {
+ /* found it */
+ DEBUG3 ((" Row: "ID" found\n", row)) ;
+ ASSERT (Frpos [row] == EMPTY) ;
+ pivrow [OUT] = row ;
+ DEBUGm4 (("got row merge pivrow %d\n", pivrow [OUT])) ;
+ 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 ;
+ DEBUG3 (("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++)
+ {
+ DEBUG3 ((" Empty Row: "ID"\n", row)) ;
+ if (NON_PIVOTAL_ROW (row))
+ {
+ /* found it */
+ DEBUG3 ((" Empty Row: "ID" found\n", row)) ;
+ ASSERT (Frpos [row] == EMPTY) ;
+ pivrow [OUT] = row ;
+ DEBUGm4 (("got dummy row pivrow %d\n", pivrow [OUT])) ;
+ break ;
+ }
+ }
+ Front_new1strow [nfr] = row ;
+ }
+
+ if (pivrow [OUT] == EMPTY)
+ {
+ /* Row-merge set is empty. We can just discard */
+ /* the candidate pivot column. */
+ DEBUG0 (("Note: row-merge set empty\n")) ;
+ DEBUGm4 (("got no pivrow \n")) ;
+ return (UMFPACK_WARNING_singular_matrix) ;
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* construct the candidate row in the front, if any */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ /* check Wrp */
+ ASSERT (Work->Wrpflag > 0) ;
+ if (UMF_debug > 0 || Work->n_col < 1000)
+ {
+ for (i = 0 ; i < Work->n_col ; i++)
+ {
+ ASSERT (Wrp [i] < Work->Wrpflag) ;
+ }
+ }
+#endif
+
+#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]) && (cdeg1 > 0) ;
+ ASSERT (cdeg1 >= 0) ;
+
+ if (!freebie [IN])
+ {
+ /* include current front in the degree of this row */
+
+ Fcpos = Work->Fcpos ;
+ fncols = Work->fncols ;
+
+ Wrpflag = Work->Wrpflag ;
+
+ /* -------------------------------------------------------------- */
+ /* 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) ;
+ }
+#endif
+
+ rdeg [IN] = fncols ;
+
+ ASSERT (pivrow [IN] >= 0 && pivrow [IN] < Work->n_row) ;
+ ASSERT (NON_PIVOTAL_ROW (pivrow [IN])) ;
+
+ /* add the pivot column itself */
+ ASSERT (Wrp [pivcol] != Wrpflag) ;
+ if (Fcpos [pivcol] < 0)
+ {
+ DEBUG3 (("Adding pivot col to pivrow [IN] pattern\n")) ;
+ if (rdeg [IN] >= max_rdeg)
+ {
+ /* :: pattern change (in) :: */
+ return (UMFPACK_ERROR_different_pattern) ;
+ }
+ Wrp [pivcol] = Wrpflag ;
+ 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] ;
+ ASSERT (col >= EMPTY && col < Work->n_col) ;
+ if ((col >= 0) && (Wrp [col] != Wrpflag)
+ && Fcpos [col] <0)
+ {
+ ASSERT (NON_PIVOTAL_COL (col)) ;
+ if (rdeg [IN] >= max_rdeg)
+ {
+ /* :: pattern change (rdeg in failure) :: */
+ DEBUGm4 (("rdeg [IN] >= max_rdeg failure\n")) ;
+ return (UMFPACK_ERROR_different_pattern) ;
+ }
+ Wrp [col] = Wrpflag ;
+ 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], Wrp [W_i [j]]));
+ ASSERT (W_i [j] >= 0 && W_i [j] < Work->n_col) ;
+ ASSERT (Wrp [W_i [j]] == Wrpflag) ;
+ }
+ /* 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->Wrp. */
+ Work->Wrpflag++ ;
+ /* All Wrp [0..n_col] is now < Wrpflag */
+ }
+ }
+
+#ifndef NDEBUG
+ /* check Wrp */
+ if (UMF_debug > 0 || Work->n_col < 1000)
+ {
+ for (i = 0 ; i < Work->n_col ; i++)
+ {
+ ASSERT (Wrp [i] < Work->Wrpflag) ;
+ }
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* 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]) && cdeg1 > 0 ;
+ ASSERT (cdeg1 >= 0) ;
+
+ if (!freebie [OUT])
+ {
+
+ Wrpflag = Work->Wrpflag ;
+
+ /* -------------------------------------------------------------- */
+ /* construct the pattern of the row */
+ /* -------------------------------------------------------------- */
+
+ rdeg [OUT] = 0 ;
+
+ ASSERT (pivrow [OUT] >= 0 && pivrow [OUT] < Work->n_row) ;
+ ASSERT (NON_PIVOTAL_ROW (pivrow [OUT])) ;
+
+ /* add the pivot column itself */
+ ASSERT (Wrp [pivcol] != Wrpflag) ;
+ DEBUG3 (("Adding pivot col to pivrow [OUT] pattern\n")) ;
+ if (rdeg [OUT] >= max_rdeg)
+ {
+ /* :: pattern change (out) :: */
+ return (UMFPACK_ERROR_different_pattern) ;
+ }
+ Wrp [pivcol] = Wrpflag ;
+ 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] ;
+ ASSERT (col >= EMPTY && col < Work->n_col) ;
+ if ((col >= 0) && (Wrp [col] != Wrpflag))
+ {
+ ASSERT (NON_PIVOTAL_COL (col)) ;
+ if (rdeg [OUT] >= max_rdeg)
+ {
+ /* :: pattern change (rdeg out failure) :: */
+ DEBUGm4 (("rdeg [OUT] failure\n")) ;
+ return (UMFPACK_ERROR_different_pattern) ;
+ }
+ Wrp [col] = Wrpflag ;
+ 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], Wrp [W_o [j]])) ;
+ ASSERT (W_o [j] >= 0 && W_o [j] < Work->n_col) ;
+ ASSERT (Wrp [W_o [j]] == Wrpflag) ;
+ }
+ /* 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->Wrp. */
+ Work->Wrpflag++ ;
+ /* All Wrp [0..n] is now < Wrpflag */
+
+ }
+
+ }
+ DEBUG5 (("Row_search end ] \n")) ;
+
+#ifndef NDEBUG
+ /* check Wrp */
+ if (UMF_debug > 0 || Work->n_col < 1000)
+ {
+ for (i = 0 ; i < Work->n_col ; i++)
+ {
+ ASSERT (Wrp [i] < Work->Wrpflag) ;
+ }
+ }
+#endif
+
+ return (UMFPACK_OK) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_row_search
+(
+ NumericType *Numeric,
+ WorkType *Work,
+ SymbolicType *Symbolic,
+ Int cdeg0,
+ Int cdeg1,
+ const Int Pattern [ ],
+ const Int Pos [ ],
+ Int pivrow [2],
+ Int rdeg [2],
+ Int W_i [ ],
+ Int W_o [ ],
+ Int prior_pivrow [2],
+ const Entry Wxy [ ],
+ Int pivcol,
+ Int freebie [2]
+) ;
+
+#define IN 0
+#define OUT 1
+
+#define IN_IN 0
+#define IN_OUT 1
+#define OUT_IN 2
+#define OUT_OUT 3
--- /dev/null
+/* ========================================================================== */
+/* === UMF_scale ============================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+/* Divide a vector of stride 1 by the pivot value. */
+
+#include "umf_internal.h"
+
+GLOBAL void UMF_scale
+(
+ Int n,
+ Entry pivot,
+ Entry X [ ]
+)
+{
+ Int i ;
+ Entry x ;
+ double s ;
+
+ /* ---------------------------------------------------------------------- */
+ /* compute the approximate absolute value of the pivot, and select method */
+ /* ---------------------------------------------------------------------- */
+
+ APPROX_ABS (s, pivot) ;
+
+ if (s < RECIPROCAL_TOLERANCE || IS_NAN (pivot))
+ {
+ /* ------------------------------------------------------------------ */
+ /* tiny, or zero, pivot case */
+ /* ------------------------------------------------------------------ */
+
+ /* The pivot is tiny, or NaN. Do not divide zero by the pivot value,
+ * and do not multiply by 1/pivot, either. */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ /* X [i] /= pivot ; */
+ x = X [i] ;
+
+#ifndef NO_DIVIDE_BY_ZERO
+ if (IS_NONZERO (x))
+ {
+ DIV (X [i], x, pivot) ;
+ }
+#else
+ /* Do not divide by zero */
+ if (IS_NONZERO (x) && IS_NONZERO (pivot))
+ {
+ DIV (X [i], x, pivot) ;
+ }
+#endif
+
+ }
+
+ }
+ else
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* normal case. select the x/pivot or x * (1/pivot) method */
+ /* ------------------------------------------------------------------ */
+
+ /* The pivot is not tiny, and is not NaN. Don't bother to check for
+ * zeros in the pivot column, X. */
+
+#if !defined (NRECIPROCAL) && !(defined (__GNUC__) && defined (COMPLEX))
+
+ /* -------------------------------------------------------------- */
+ /* multiply x by (1/pivot) */
+ /* -------------------------------------------------------------- */
+
+ /* Slightly less accurate, but faster. It allows the use of
+ * the level-1 BLAS dscal or zscal routine. This not used when
+ * UMFPACK is used in MATLAB (either as a built-in routine, or as
+ * a mexFunction).
+ *
+ * Using gcc version 3.2 can cause the following code to fail for
+ * some complex matrices (not all), with or without the BLAS. This
+ * was found in Red Hat Linux 7.3 on a Dell Latitude C840 with a
+ * Pentium 4M. Thus, this code is not used when gcc is used, for
+ * the complex case.
+ *
+ * It works just fine with Intel's icc compiler, version 7.0.
+ */
+
+ /* pivot = 1 / pivot */
+ RECIPROCAL (pivot) ;
+
+#if defined (USE_NO_BLAS)
+ for (i = 0 ; i < n ; i++)
+ {
+ /* X [i] *= pivot ; */
+ x = X [i] ;
+ MULT (X [i], x, pivot) ;
+ }
+#else
+ BLAS_SCAL (n, pivot, X) ;
+#endif
+
+#else
+
+ /* -------------------------------------------------------------- */
+ /* divide x by the pivot */
+ /* -------------------------------------------------------------- */
+
+ /* This is slightly more accurate, particularly if the pivot column
+ * consists of only IEEE subnormals. Always do this if UMFPACK is
+ * being compiled as a built-in routine or mexFunction in MATLAB,
+ * or if gcc is being used with complex matrices. */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ /* X [i] /= pivot ; */
+ x = X [i] ;
+ DIV (X [i], x, pivot) ;
+ }
+
+#endif
+
+ }
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_scale
+(
+ Int n,
+ Entry alpha,
+ Entry X [ ]
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_scale_column ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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, move the pivot row and column into place,
+ and log the permutation.
+*/
+
+#include "umf_internal.h"
+#include "umf_mem_free_tail_block.h"
+#include "umf_scale.h"
+
+/* ========================================================================== */
+/* === shift_pivot_row ====================================================== */
+/* ========================================================================== */
+
+/* Except for the BLAS, most of the time is typically spent in the following
+ * shift_pivot_row routine. It copies the pivot row into the U block, and
+ * then fills in the whole in the C block by shifting the last row of C into
+ * the row vacated by the pivot row.
+ */
+
+PRIVATE void shift_pivot_row (Entry *Fd, Entry *Fs, Entry *Fe, Int len, Int d)
+{
+ Int j ;
+#pragma ivdep
+ for (j = 0 ; j < len ; j++)
+ {
+ Fd [j] = Fs [j*d] ;
+ Fs [j*d] = Fe [j*d] ;
+ }
+}
+
+/* ========================================================================== */
+/* === UMF_scale_column ===================================================== */
+/* ========================================================================== */
+
+GLOBAL void UMF_scale_column
+(
+ NumericType *Numeric,
+ WorkType *Work
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int k, k1, fnr_curr, fnrows, fncols, *Frpos, *Fcpos, pivrow, pivcol,
+ *Frows, *Fcols, fnc_curr, fnpiv, *Row_tuples, nb,
+ *Col_tuples, *Rperm, *Cperm, fspos, col2, row2 ;
+ Entry pivot_value, *Fcol,
+ *Flublock, *Flblock, *Fublock, *Fcblock ;
+#ifndef NDEBUG
+ Int *Col_degree, *Row_degree ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ fnrows = Work->fnrows ;
+ fncols = Work->fncols ;
+ fnpiv = Work->fnpiv ;
+
+ /* ---------------------------------------------------------------------- */
+
+ Rperm = Numeric->Rperm ;
+ Cperm = Numeric->Cperm ;
+
+ /* ---------------------------------------------------------------------- */
+
+ Flublock = Work->Flublock ;
+ Flblock = Work->Flblock ;
+ Fublock = Work->Fublock ;
+ Fcblock = Work->Fcblock ;
+
+ fnr_curr = Work->fnr_curr ;
+ fnc_curr = Work->fnc_curr ;
+ 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) ;
+
+#ifndef NDEBUG
+ Col_degree = Numeric->Cperm ; /* for NON_PIVOTAL_COL macro */
+ Row_degree = Numeric->Rperm ; /* for NON_PIVOTAL_ROW macro */
+#endif
+
+ Row_tuples = Numeric->Uip ;
+ Col_tuples = Numeric->Lip ;
+ nb = Work->nb ;
+
+#ifndef NDEBUG
+ ASSERT (fnrows == Work->fnrows_new + 1) ;
+ ASSERT (fncols == Work->fncols_new + 1) ;
+ DEBUG1 (("SCALE COL: fnrows "ID" fncols "ID"\n", fnrows, fncols)) ;
+ DEBUG2 (("\nFrontal matrix, including all space:\n"
+ "fnr_curr "ID" fnc_curr "ID" nb "ID"\n"
+ "fnrows "ID" fncols "ID" fnpiv "ID"\n",
+ fnr_curr, fnc_curr, nb, fnrows, fncols, fnpiv)) ;
+ DEBUG2 (("\nJust the active part:\n")) ;
+ DEBUG7 (("C block: ")) ;
+ UMF_dump_dense (Fcblock, fnr_curr, fnrows, fncols) ;
+ DEBUG7 (("L block: ")) ;
+ UMF_dump_dense (Flblock, fnr_curr, fnrows, fnpiv);
+ DEBUG7 (("U' block: ")) ;
+ UMF_dump_dense (Fublock, fnc_curr, fncols, fnpiv) ;
+ DEBUG7 (("LU block: ")) ;
+ UMF_dump_dense (Flublock, nb, fnpiv, fnpiv) ;
+#endif
+
+ /* ====================================================================== */
+ /* === Shift pivot row and column ======================================= */
+ /* ====================================================================== */
+
+ /* ---------------------------------------------------------------------- */
+ /* move pivot column into place */
+ /* ---------------------------------------------------------------------- */
+
+ /* Note that the pivot column is already in place. Just shift the last
+ * column into the position vacated by the pivot column. */
+
+ fspos = Fcpos [pivcol] ;
+
+ /* one less column in the contribution block */
+ fncols = --(Work->fncols) ;
+
+ if (fspos != fncols * fnr_curr)
+ {
+
+ Int fs = fspos / fnr_curr ;
+
+ DEBUG6 (("Shift pivot column in front\n")) ;
+ DEBUG6 (("fspos: "ID" flpos: "ID"\n", fspos, fncols * fnr_curr)) ;
+
+ /* ------------------------------------------------------------------ */
+ /* move Fe => Fs */
+ /* ------------------------------------------------------------------ */
+
+ /* column of the contribution block: */
+ {
+ /* Fs: current position of pivot column in contribution block */
+ /* Fe: position of last column in contribution block */
+ Int i ;
+ Entry *Fs, *Fe ;
+ Fs = Fcblock + fspos ;
+ Fe = Fcblock + fncols * fnr_curr ;
+#pragma ivdep
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ Fs [i] = Fe [i] ;
+ }
+ }
+
+ /* column of the U2 block */
+ {
+ /* Fs: current position of pivot column in U block */
+ /* Fe: last column in U block */
+ Int i ;
+ Entry *Fs, *Fe ;
+ Fs = Fublock + fs ;
+ Fe = Fublock + fncols ;
+#pragma ivdep
+ for (i = 0 ; i < fnpiv ; i++)
+ {
+ Fs [i * fnc_curr] = Fe [i * fnc_curr] ;
+ }
+ }
+
+ /* move column Fe to Fs in the Fcols pattern */
+ col2 = Fcols [fncols] ;
+ Fcols [fs] = col2 ;
+ Fcpos [col2] = fspos ;
+ }
+
+ /* pivot column is no longer in the frontal matrix */
+ Fcpos [pivcol] = EMPTY ;
+
+#ifndef NDEBUG
+ DEBUG2 (("\nFrontal matrix after col swap, including all space:\n"
+ "fnr_curr "ID" fnc_curr "ID" nb "ID"\n"
+ "fnrows "ID" fncols "ID" fnpiv "ID"\n",
+ fnr_curr, fnc_curr, nb,
+ fnrows, fncols, fnpiv)) ;
+ DEBUG2 (("\nJust the active part:\n")) ;
+ DEBUG7 (("C block: ")) ;
+ UMF_dump_dense (Fcblock, fnr_curr, fnrows, fncols) ;
+ DEBUG7 (("L block: ")) ;
+ UMF_dump_dense (Flblock, fnr_curr, fnrows, fnpiv+1);
+ DEBUG7 (("U' block: ")) ;
+ UMF_dump_dense (Fublock, fnc_curr, fncols, fnpiv) ;
+ DEBUG7 (("LU block: ")) ;
+ UMF_dump_dense (Flublock, nb, fnpiv, fnpiv+1) ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* move pivot row into place */
+ /* ---------------------------------------------------------------------- */
+
+ fspos = Frpos [pivrow] ;
+
+ /* one less row in the contribution block */
+ fnrows = --(Work->fnrows) ;
+
+ DEBUG6 (("Swap/shift pivot row in front:\n")) ;
+ DEBUG6 (("fspos: "ID" flpos: "ID"\n", fspos, fnrows)) ;
+
+ if (fspos == fnrows)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* move Fs => Fd */
+ /* ------------------------------------------------------------------ */
+
+ DEBUG6 (("row case 1\n")) ;
+
+ /* row of the contribution block: */
+ {
+ Int j ;
+ Entry *Fd, *Fs ;
+ Fd = Fublock + fnpiv * fnc_curr ;
+ Fs = Fcblock + fspos ;
+#pragma ivdep
+ for (j = 0 ; j < fncols ; j++)
+ {
+ Fd [j] = Fs [j * fnr_curr] ;
+ }
+ }
+
+ /* row of the L2 block: */
+ if (Work->pivrow_in_front)
+ {
+ Int j ;
+ Entry *Fd, *Fs ;
+ Fd = Flublock + fnpiv ;
+ Fs = Flblock + fspos ;
+#pragma ivdep
+ for (j = 0 ; j <= fnpiv ; j++)
+ {
+ Fd [j * nb] = Fs [j * fnr_curr] ;
+ }
+ }
+ else
+ {
+ Int j ;
+ Entry *Fd, *Fs ;
+ Fd = Flublock + fnpiv ;
+ Fs = Flblock + fspos ;
+#pragma ivdep
+ for (j = 0 ; j < fnpiv ; j++)
+ {
+ ASSERT (IS_ZERO (Fs [j * fnr_curr])) ;
+ CLEAR (Fd [j * nb]) ;
+ }
+ Fd [fnpiv * nb] = Fs [fnpiv * fnr_curr] ;
+ }
+ }
+ else
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* move Fs => Fd */
+ /* move Fe => Fs */
+ /* ------------------------------------------------------------------ */
+
+ DEBUG6 (("row case 2\n")) ;
+ /* this is the most common case, by far */
+
+ /* row of the contribution block: */
+ {
+ /* Fd: destination of pivot row on U block */
+ /* Fs: current position of pivot row in contribution block */
+ /* Fe: position of last row in contribution block */
+ Entry *Fd, *Fs, *Fe ;
+ Fd = Fublock + fnpiv * fnc_curr ;
+ Fs = Fcblock + fspos ;
+ Fe = Fcblock + fnrows ;
+ shift_pivot_row (Fd, Fs, Fe, fncols, fnr_curr) ;
+ }
+
+ /* row of the L2 block: */
+ if (Work->pivrow_in_front)
+ {
+ /* Fd: destination of pivot row in LU block */
+ /* Fs: current position of pivot row in L block */
+ /* Fe: last row in L block */
+ Int j ;
+ Entry *Fd, *Fs, *Fe ;
+ Fd = Flublock + fnpiv ;
+ Fs = Flblock + fspos ;
+ Fe = Flblock + fnrows ;
+#pragma ivdep
+ for (j = 0 ; j <= fnpiv ; j++)
+ {
+ Fd [j * nb] = Fs [j * fnr_curr] ;
+ Fs [j * fnr_curr] = Fe [j * fnr_curr] ;
+ }
+ }
+ else
+ {
+ Int j ;
+ Entry *Fd, *Fs, *Fe ;
+ Fd = Flublock + fnpiv ;
+ Fs = Flblock + fspos ;
+ Fe = Flblock + fnrows ;
+#pragma ivdep
+ for (j = 0 ; j < fnpiv ; j++)
+ {
+ ASSERT (IS_ZERO (Fs [j * fnr_curr])) ;
+ CLEAR (Fd [j * nb]) ;
+ Fs [j * fnr_curr] = Fe [j * fnr_curr] ;
+ }
+ Fd [fnpiv * nb] = Fs [fnpiv * fnr_curr] ;
+ Fs [fnpiv * fnr_curr] = Fe [fnpiv * fnr_curr] ;
+ }
+
+ /* move row Fe to Fs in the Frows pattern */
+ row2 = Frows [fnrows] ;
+ Frows [fspos] = row2 ;
+ Frpos [row2] = fspos ;
+
+ }
+ /* pivot row is no longer in the frontal matrix */
+ Frpos [pivrow] = EMPTY ;
+
+#ifndef NDEBUG
+ DEBUG2 (("\nFrontal matrix after row swap, including all space:\n"
+ "fnr_curr "ID" fnc_curr "ID" nb "ID"\n"
+ "fnrows "ID" fncols "ID" fnpiv "ID"\n",
+ Work->fnr_curr, Work->fnc_curr, Work->nb,
+ Work->fnrows, Work->fncols, Work->fnpiv)) ;
+ DEBUG2 (("\nJust the active part:\n")) ;
+ DEBUG7 (("C block: ")) ;
+ UMF_dump_dense (Fcblock, fnr_curr, fnrows, fncols) ;
+ DEBUG7 (("L block: ")) ;
+ UMF_dump_dense (Flblock, fnr_curr, fnrows, fnpiv+1);
+ DEBUG7 (("U' block: ")) ;
+ UMF_dump_dense (Fublock, fnc_curr, fncols, fnpiv+1) ;
+ DEBUG7 (("LU block: ")) ;
+ UMF_dump_dense (Flublock, nb, fnpiv+1, fnpiv+1) ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* Frpos [row] >= 0 for each row in pivot column pattern. */
+ /* offset into pattern is given by: */
+ /* Frpos [row] == offset - 1 */
+ /* Frpos [pivrow] is EMPTY */
+
+ /* Fcpos [col] >= 0 for each col in pivot row pattern. */
+ /* Fcpos [col] == (offset - 1) * fnr_curr */
+ /* Fcpos [pivcol] is EMPTY */
+
+ /* Fcols [0..fncols-1] is the pivot row pattern (excl pivot cols) */
+ /* Frows [0..fnrows-1] is the pivot col pattern (excl pivot rows) */
+
+ /* ====================================================================== */
+ /* === scale pivot column =============================================== */
+ /* ====================================================================== */
+
+ /* pivot column (except for pivot entry itself) */
+ Fcol = Flblock + fnpiv * fnr_curr ;
+ /* fnpiv-th pivot in frontal matrix located in Flublock (fnpiv, fnpiv) */
+ pivot_value = Flublock [fnpiv + fnpiv * nb] ;
+
+ /* this is the kth global pivot */
+ k = Work->npiv + fnpiv ;
+
+ DEBUG4 (("Pivot value: ")) ;
+ EDEBUG4 (pivot_value) ;
+ DEBUG4 (("\n")) ;
+
+ UMF_scale (fnrows, pivot_value, Fcol) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* 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]) ;
+
+ Row_tuples [pivrow] = 0 ;
+ Col_tuples [pivcol] = 0 ;
+
+ 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)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* Keep track of the pivot order. This is the kth pivot row and column. */
+ /* ---------------------------------------------------------------------- */
+
+ /* keep track of pivot rows and columns in the LU, L, and U blocks */
+ ASSERT (fnpiv < MAXNB) ;
+ Work->Pivrow [fnpiv] = pivrow ;
+ Work->Pivcol [fnpiv] = pivcol ;
+
+ /* ====================================================================== */
+ /* === one step in the factorization is done ============================ */
+ /* ====================================================================== */
+
+ /* One more step is done, except for pending updates to the U and C blocks
+ * of this frontal matrix. Those are saved up, and applied by
+ * UMF_blas3_update when enough pivots have accumulated. Also, the
+ * LU factors for these pending pivots have not yet been stored. */
+
+ Work->fnpiv++ ;
+
+#ifndef NDEBUG
+ DEBUG7 (("Current frontal matrix: (after pivcol scale)\n")) ;
+ UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_scale_column
+(
+ NumericType *Numeric,
+ WorkType *Work
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_set_stats ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+ double maxnrows, /* largest #rows in front */
+ double maxncols, /* largest #cols in front */
+ Int scale, /* true if scaling the rows of A */
+ Int prefer_diagonal, /* true if diagonal pivoting (only square A) */
+ 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, sym_maxncols, sym_maxnrows, elen, n1 ;
+
+ n_col = Symbolic->n_col ;
+ n_row = Symbolic->n_row ;
+ n1 = Symbolic->n1 ;
+ nn = MAX (n_row, n_col) ;
+ n_inner = MIN (n_row, n_col) ;
+ sym_maxncols = MIN (Symbolic->maxncols + Symbolic->nb, n_col) ;
+ sym_maxnrows = MIN (Symbolic->maxnrows + Symbolic->nb, n_row) ;
+ elen = (n_col - n1) + (n_row - n1) + MIN (n_col - n1, n_row - n1) + 1 ;
+
+ /* final Symbolic object size */
+ sym_size = UMF_symbolic_usage (Symbolic->n_row, Symbolic->n_col,
+ Symbolic->nchains, Symbolic->nfr, Symbolic->esize, prefer_diagonal) ;
+
+ /* 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 */
+ + (scale ? DUNITS (Entry, n_row) : 0) ; /* Rs, row scale factors */
+
+ /* 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 */
+ + 6 * DUNITS (Int, npiv+1) /* Lpos, Uilen, Uip, Upos, Lilen, Lip */
+ + (scale ? DUNITS (Entry, n_row) : 0) ; /* Rs, row scale factors */
+
+ DEBUG1 (("num O(n) size2: %g\n", num_On_size2)) ;
+
+ /* peak size of Numeric->Memory, including LU factors, current frontal
+ * matrix, elements, and tuple lists. */
+ Info [UMFPACK_VARIABLE_PEAK + what] = max_usage ;
+
+ /* final size of Numeric->Memory (LU factors only) */
+ 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+1) ;/* Numeric->Upattern (from Work->Upattern) */
+
+ DEBUG1 (("num mem size: %g\n", num_mem_size)) ;
+ DEBUG1 (("ulen units %g\n", DUNITS (Int, ulen))) ;
+ DEBUG1 (("numeric size %g\n", Info [UMFPACK_NUMERIC_SIZE + what])) ;
+
+ /* largest front size (working array size, or actual size used) */
+ Info [UMFPACK_MAX_FRONT_SIZE + what] = maxfrsize ;
+ Info [UMFPACK_MAX_FRONT_NROWS + what] = maxnrows ;
+ Info [UMFPACK_MAX_FRONT_NCOLS + what] = maxncols ;
+ DEBUGm4 (("maxnrows %g maxncols %g\n", maxnrows, maxncols)) ;
+ DEBUGm4 (("maxfrsize %g\n", maxfrsize)) ;
+
+ /* UMF_kernel usage, from work_alloc routine in umf_kernel.c */
+ work_usage =
+ /* Work-> arrays, except for current frontal matrix which is allocated
+ * inside Numeric->Memory. */
+ 2 * DUNITS (Entry, sym_maxnrows + 1) /* Wx, Wy */
+ + 2 * DUNITS (Int, n_row+1) /* Frpos, Lpattern */
+ + 2 * DUNITS (Int, n_col+1) /* Fcpos, Upattern */
+ + DUNITS (Int, nn + 1) /* Wp */
+ + DUNITS (Int, MAX (n_col, sym_maxnrows) + 1) /* Wrp */
+ + 2 * DUNITS (Int, sym_maxnrows + 1) /* Frows, Wm */
+ + 3 * DUNITS (Int, sym_maxncols + 1) /* Fcols, Wio, Woi */
+ + DUNITS (Int, MAX (sym_maxnrows, sym_maxncols) + 1) /* Woo */
+ + DUNITS (Int, elen) /* E */
+ + DUNITS (Int, Symbolic->nfr + 1) /* Front_new1strow */
+ + ((n_row == n_col) ? (2 * DUNITS (Int, nn)) : 0) ; /* Diag map,imap */
+
+ /* Peak memory for just UMFPACK_numeric. */
+ num_usage =
+ sym_size /* size of Symbolic object */
+ + num_On_size1 /* O(n) part of Numeric object (excl. Upattern) */
+ + work_usage /* Work-> arrays (including Upattern) */
+ + max_usage ; /* peak size of Numeric->Memory */
+
+ /* 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 ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL void UMF_set_stats
+(
+ double Info [ ],
+ SymbolicType *Symbolic,
+ double max_usage,
+ double num_mem_size,
+ double flops,
+ double lnz,
+ double unz,
+ double maxfrsize,
+ double ulen,
+ double npiv,
+ double maxnrows,
+ double maxncols,
+ Int scale,
+ Int prefer_diagonal,
+ Int what
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_singletons ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 and order the row and column singletons of a matrix A. If there are
+ * row and column singletons, the output is a row and column permutation such
+ * that the matrix is in the following form:
+ *
+ * x x x x x x x x x
+ * 0 x x x x x x x x
+ * 0 0 x x x x x x x
+ * 0 0 0 x 0 0 0 0 0
+ * 0 0 0 x x 0 0 0 0
+ * 0 0 0 x x s s s s
+ * 0 0 0 x x s s s s
+ * 0 0 0 x x s s s s
+ * 0 0 0 x x s s s s
+ *
+ * The above example has 3 column singletons (the first three columns and
+ * their corresponding pivot rows) and 2 row singletons. The singletons are
+ * ordered first, because they have zero Markowitz cost. The LU factorization
+ * for these first five rows and columns is free - there is no work to do
+ * (except to scale the pivot columns for the 2 row singletons), and no
+ * fill-in occurs. * The remaining * submatrix (4-by-4 in the above example)
+ * has no rows or columns with degree one. It may have empty rows or columns.
+ *
+ * This algorithm does not perform a full permutation to block triangular
+ * form. If there are one or more singletons, then the matrix can be
+ * permuted to block triangular form, but UMFPACK does not perform the full
+ * BTF permutation (see also "dmperm" in MATLAB).
+ */
+
+#include "umf_internal.h"
+
+#ifndef NDEBUG
+
+/* ========================================================================== */
+/* === debug routines ======================================================= */
+/* ========================================================================== */
+
+/* Dump the singleton queue */
+
+PRIVATE void dump_singletons
+(
+ Int head, /* head of the queue */
+ Int tail, /* tail of the queue */
+ Int Next [ ], /* Next [i] is the next object after i */
+ char *name, /* "row" or "col" */
+ Int Deg [ ], /* Deg [i] is the degree of object i */
+ Int n /* objects are in the range 0 to n-1 */
+)
+{
+ Int i, next, cnt ;
+ DEBUG6 (("%s Singleton list: head "ID" tail "ID"\n", name, head, tail)) ;
+ i = head ;
+ ASSERT (head >= EMPTY && head < n) ;
+ ASSERT (tail >= EMPTY && tail < n) ;
+ cnt = 0 ;
+ while (i != EMPTY)
+ {
+ DEBUG7 ((" "ID": "ID" deg: "ID"\n", cnt, i, Deg [i])) ;
+ ASSERT (i >= 0 && i < n) ;
+ next = Next [i] ;
+ if (i == tail) ASSERT (next == EMPTY) ;
+ i = next ;
+ cnt++ ;
+ ASSERT (cnt <= n) ;
+ }
+}
+
+PRIVATE void dump_mat
+(
+ char *xname,
+ char *yname,
+ Int nx,
+ Int ny,
+ const Int Xp [ ],
+ const Int Xi [ ],
+ Int Xdeg [ ],
+ Int Ydeg [ ]
+)
+{
+ Int x, y, p, p1, p2, xdeg, do_xdeg, ydeg ;
+ DEBUG6 (("\n ==== Dump %s mat:\n", xname)) ;
+ for (x = 0 ; x < nx ; x++)
+ {
+ p1 = Xp [x] ;
+ p2 = Xp [x+1] ;
+ xdeg = Xdeg [x] ;
+ DEBUG6 (("Dump %s "ID" p1 "ID" p2 "ID" deg "ID"\n",
+ xname, x, p1, p2, xdeg)) ;
+ do_xdeg = (xdeg >= 0) ;
+ for (p = p1 ; p < p2 ; p++)
+ {
+ y = Xi [p] ;
+ DEBUG7 ((" %s "ID" deg: ", yname, y)) ;
+ ASSERT (y >= 0 && y < ny) ;
+ ydeg = Ydeg [y] ;
+ DEBUG7 ((ID"\n", ydeg)) ;
+ if (do_xdeg && ydeg >= 0)
+ {
+ xdeg-- ;
+ }
+ }
+ ASSERT (IMPLIES (do_xdeg, xdeg == 0)) ;
+ }
+}
+#endif
+
+/* ========================================================================== */
+/* === create_row_form ====================================================== */
+/* ========================================================================== */
+
+/* Create the row-form R of the column-form input matrix A. This could be done
+ * by UMF_transpose, except that Rdeg has already been computed.
+ */
+
+PRIVATE void create_row_form
+(
+ /* input, not modified: */
+ Int n_row, /* A is n_row-by-n_col, nz = Ap [n_col] */
+ Int n_col,
+ const Int Ap [ ], /* Ap [0..n_col]: column pointers for A */
+ const Int Ai [ ], /* Ai [0..nz-1]: row indices for A */
+ Int Rdeg [ ], /* Rdeg [0..n_row-1]: row degrees */
+
+ /* output, not defined on input: */
+ Int Rp [ ], /* Rp [0..n_row]: row pointers for R */
+ Int Ri [ ], /* Ri [0..nz-1]: column indices for R */
+
+ /* workspace, not defined on input or output */
+ Int W [ ] /* size n_row */
+)
+{
+ Int row, col, p, p2 ;
+
+ /* create the row pointers */
+ Rp [0] = 0 ;
+ W [0] = 0 ;
+ for (row = 0 ; row < n_row ; row++)
+ {
+ Rp [row+1] = Rp [row] + Rdeg [row] ;
+ W [row] = Rp [row] ;
+ }
+
+ /* create the indices for the row-form */
+ for (col = 0 ; col < n_col ; col++)
+ {
+ p2 = Ap [col+1] ;
+ for (p = Ap [col] ; p < p2 ; p++)
+ {
+ Ri [W [Ai [p]]++] = col ;
+ }
+ }
+}
+
+/* ========================================================================== */
+/* === order_singletons ===================================================== */
+/* ========================================================================== */
+
+PRIVATE int order_singletons /* return new number of singletons */
+(
+ Int k, /* the number of singletons so far */
+ Int head,
+ Int tail,
+ Int Next [ ],
+ Int Xdeg [ ], Int Xperm [ ], const Int Xp [ ], const Int Xi [ ],
+ Int Ydeg [ ], Int Yperm [ ], const Int Yp [ ], const Int Yi [ ]
+#ifndef NDEBUG
+ , char *xname, char *yname, Int nx, Int ny
+#endif
+)
+{
+ Int xpivot, x, y, ypivot, p, p2, deg ;
+
+#ifndef NDEBUG
+ Int i, k1 = k ;
+ dump_singletons (head, tail, Next, xname, Xdeg, nx) ;
+ dump_mat (xname, yname, nx, ny, Xp, Xi, Xdeg, Ydeg) ;
+ dump_mat (yname, xname, ny, nx, Yp, Yi, Ydeg, Xdeg) ;
+#endif
+
+ while (head != EMPTY)
+ {
+ /* remove the singleton at the head of the queue */
+ xpivot = head ;
+ DEBUG1 (("------ Order %s singleton: "ID"\n", xname, xpivot)) ;
+ head = Next [xpivot] ;
+ if (head == EMPTY) tail = EMPTY ;
+
+#ifndef NDEBUG
+ if (k % 100 == 0) dump_singletons (head, tail, Next, xname, Xdeg, nx) ;
+#endif
+
+ ASSERT (Xdeg [xpivot] >= 0) ;
+ if (Xdeg [xpivot] != 1)
+ {
+ /* This row/column x is empty. The matrix is singular.
+ * x will be ordered last in Xperm. */
+ DEBUG1 (("empty %s, after singletons removed\n", xname)) ;
+ continue ;
+ }
+
+ /* find the ypivot to match with this xpivot */
+#ifndef NDEBUG
+ /* there can only be one ypivot, since the degree of x is 1 */
+ deg = 0 ;
+ p2 = Xp [xpivot+1] ;
+ for (p = Xp [xpivot] ; p < p2 ; p++)
+ {
+ y = Xi [p] ;
+ DEBUG1 (("%s: "ID"\n", yname, y)) ;
+ if (Ydeg [y] >= 0)
+ {
+ /* this is a live index in this xpivot vector */
+ deg++ ;
+ }
+ }
+ ASSERT (deg == 1) ;
+#endif
+
+ ypivot = EMPTY ;
+ p2 = Xp [xpivot+1] ;
+ for (p = Xp [xpivot] ; p < p2 ; p++)
+ {
+ y = Xi [p] ;
+ DEBUG1 (("%s: "ID"\n", yname, y)) ;
+ if (Ydeg [y] >= 0)
+ {
+ /* this is a live index in this xpivot vector */
+ ypivot = y ;
+ break ;
+ }
+ }
+
+ DEBUG1 (("Pivot %s: "ID"\n", yname, ypivot)) ;
+ ASSERT (ypivot != EMPTY) ;
+ DEBUG1 (("deg "ID"\n", Ydeg [ypivot])) ;
+ ASSERT (Ydeg [ypivot] >= 0) ;
+
+ /* decrement the degrees after removing this singleton */
+ DEBUG1 (("p1 "ID"\n", Yp [ypivot])) ;
+ DEBUG1 (("p2 "ID"\n", Yp [ypivot+1])) ;
+ p2 = Yp [ypivot+1] ;
+ for (p = Yp [ypivot] ; p < p2 ; p++)
+ {
+ x = Yi [p] ;
+ DEBUG1 ((" %s: "ID" deg: "ID"\n", xname, x, Xdeg [x])) ;
+ if (Xdeg [x] < 0) continue ;
+ ASSERT (Xdeg [x] > 0) ;
+ if (x == xpivot) continue ;
+ deg = --(Xdeg [x]) ;
+ ASSERT (Xdeg [x] >= 0) ;
+ if (deg == 1)
+ {
+ /* this is a new singleton, put at the end of the queue */
+ Next [x] = EMPTY ;
+ if (head == EMPTY)
+ {
+ head = x ;
+ }
+ else
+ {
+ ASSERT (tail != EMPTY) ;
+ Next [tail] = x ;
+ }
+ tail = x ;
+ DEBUG1 ((" New %s singleton: "ID"\n", xname, x)) ;
+#ifndef NDEBUG
+ if (k % 100 == 0)
+ {
+ dump_singletons (head, tail, Next, xname, Xdeg, nx) ;
+ }
+#endif
+ }
+ }
+
+ /* flag the xpivot and ypivot by FLIP'ing the degrees */
+ Xdeg [xpivot] = FLIP (1) ;
+ Ydeg [ypivot] = FLIP (Ydeg [ypivot]) ;
+
+ /* keep track of the pivot row and column */
+ Xperm [k] = xpivot ;
+ Yperm [k] = ypivot ;
+ k++ ;
+
+#ifndef NDEBUG
+ if (k % 1000 == 0)
+ {
+ dump_mat (xname, yname, nx, ny, Xp, Xi, Xdeg, Ydeg) ;
+ dump_mat (yname, xname, ny, nx, Yp, Yi, Ydeg, Xdeg) ;
+ }
+#endif
+ }
+
+#ifndef NDEBUG
+ DEBUGm4 (("%s singletons: k = "ID"\n", xname, k)) ;
+ for (i = k1 ; i < k ; i++)
+ {
+ DEBUG1 ((" %s: "ID" %s: "ID"\n", xname, Xperm [i], yname, Yperm [i])) ;
+ }
+ ASSERT (k > 0) ;
+#endif
+
+ return (k) ;
+}
+
+/* ========================================================================== */
+/* === find_any_singletons ================================================== */
+/* ========================================================================== */
+
+PRIVATE Int find_any_singletons /* returns # of singletons found */
+(
+ /* input, not modified: */
+ Int n_row,
+ Int n_col,
+ const Int Ap [ ], /* size n_col+1 */
+ const Int Ai [ ], /* size nz = Ap [n_col] */
+
+ /* input, modified on output: */
+ Int Cdeg [ ], /* size n_col */
+ Int Rdeg [ ], /* size n_row */
+
+ /* output, not defined on input: */
+ Int Cperm [ ], /* size n_col */
+ Int Rperm [ ], /* size n_row */
+ Int *p_n1r, /* # of row singletons */
+ Int *p_n1c, /* # of col singletons */
+
+ /* workspace, not defined on input or output */
+ Int Rp [ ], /* size n_row+1 */
+ Int Ri [ ], /* size nz */
+ Int W [ ], /* size n_row */
+ Int Next [ ] /* size MAX (n_row, n_col) */
+)
+{
+ Int n1, col, row, row_form, head, tail, n1r, n1c ;
+
+ /* ---------------------------------------------------------------------- */
+ /* eliminate column singletons */
+ /* ---------------------------------------------------------------------- */
+
+ n1 = 0 ;
+ n1r = 0 ;
+ n1c = 0 ;
+ row_form = FALSE ;
+
+ head = EMPTY ;
+ tail = EMPTY ;
+ for (col = n_col-1 ; col >= 0 ; col--)
+ {
+ if (Cdeg [col] == 1)
+ {
+ /* put the column singleton in the queue */
+ if (head == EMPTY) tail = col ;
+ Next [col] = head ;
+ head = col ;
+ DEBUG1 (("Column singleton: "ID"\n", col)) ;
+ }
+ }
+
+ if (head != EMPTY)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* create the row-form of A */
+ /* ------------------------------------------------------------------ */
+
+ create_row_form (n_row, n_col, Ap, Ai, Rdeg, Rp, Ri, W) ;
+ row_form = TRUE ;
+
+ /* ------------------------------------------------------------------ */
+ /* find and order the column singletons */
+ /* ------------------------------------------------------------------ */
+
+ n1 = order_singletons (0, head, tail, Next,
+ Cdeg, Cperm, Ap, Ai,
+ Rdeg, Rperm, Rp, Ri
+#ifndef NDEBUG
+ , "col", "row", n_col, n_row
+#endif
+ ) ;
+ n1c = n1 ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* eliminate row singletons */
+ /* ---------------------------------------------------------------------- */
+
+ head = EMPTY ;
+ tail = EMPTY ;
+ for (row = n_row-1 ; row >= 0 ; row--)
+ {
+ if (Rdeg [row] == 1)
+ {
+ /* put the row singleton in the queue */
+ if (head == EMPTY) tail = row ;
+ Next [row] = head ;
+ head = row ;
+ DEBUG1 (("Row singleton: "ID"\n", row)) ;
+ }
+ }
+
+ if (head != EMPTY)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* create the row-form of A, if not already created */
+ /* ------------------------------------------------------------------ */
+
+ if (!row_form)
+ {
+ create_row_form (n_row, n_col, Ap, Ai, Rdeg, Rp, Ri, W) ;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* find and order the row singletons */
+ /* ------------------------------------------------------------------ */
+
+ n1 = order_singletons (n1, head, tail, Next,
+ Rdeg, Rperm, Rp, Ri,
+ Cdeg, Cperm, Ap, Ai
+#ifndef NDEBUG
+ , "row", "col", n_row, n_col
+#endif
+ ) ;
+ n1r = n1 - n1c ;
+ }
+
+ DEBUG0 (("n1 "ID"\n", n1)) ;
+ *p_n1r = n1r ;
+ *p_n1c = n1c ;
+ return (n1) ;
+}
+
+/* ========================================================================== */
+/* === find_user_singletons ================================================= */
+/* ========================================================================== */
+
+PRIVATE Int find_user_singletons /* returns # singletons found */
+(
+ /* input, not modified: */
+ Int n_row,
+ Int n_col,
+ const Int Ap [ ], /* size n_col+1 */
+ const Int Ai [ ], /* size nz = Ap [n_col] */
+ const Int Quser [ ], /* size n_col if present */
+
+ /* input, modified on output: */
+ Int Cdeg [ ], /* size n_col */
+ Int Rdeg [ ], /* size n_row */
+
+ /* output, not defined on input */
+ Int Cperm [ ], /* size n_col */
+ Int Rperm [ ], /* size n_row */
+ Int *p_n1r, /* # of row singletons */
+ Int *p_n1c, /* # of col singletons */
+
+ /* workspace, not defined on input or output */
+ Int Rp [ ], /* size n_row+1 */
+ Int Ri [ ], /* size nz */
+ Int W [ ] /* size n_row */
+)
+{
+ Int n1, col, row, p, p2, pivcol, pivrow, found, k, n1r, n1c ;
+
+ n1 = 0 ;
+ n1r = 0 ;
+ n1c = 0 ;
+ *p_n1r = 0 ;
+ *p_n1c = 0 ;
+
+ /* find singletons in the user column permutation, Quser */
+ pivcol = Quser [0] ;
+ found = (Cdeg [pivcol] == 1) ;
+ DEBUG0 (("Is first col: "ID" a col singleton?: "ID"\n", pivcol, found)) ;
+ if (!found)
+ {
+ /* the first column is not a column singleton, check for a row
+ * singleton in the first column. */
+ for (p = Ap [pivcol] ; p < Ap [pivcol+1] ; p++)
+ {
+ if (Rdeg [Ai [p]] == 1)
+ {
+ DEBUG0 (("Row singleton in first col: "ID" row: "ID"\n",
+ pivcol, Ai [p])) ;
+ found = TRUE ;
+ break ;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ /* no singletons in the leading part of A (:,Quser) */
+ return (0) ;
+ }
+
+ /* there is at least one row or column singleton. Look for more. */
+ create_row_form (n_row, n_col, Ap, Ai, Rdeg, Rp, Ri, W) ;
+
+ n1 = 0 ;
+
+ for (k = 0 ; k < n_col ; k++)
+ {
+ pivcol = Quser [k] ;
+ pivrow = EMPTY ;
+
+ /* ------------------------------------------------------------------ */
+ /* check if col is a column singleton, or contains a row singleton */
+ /* ------------------------------------------------------------------ */
+
+ found = (Cdeg [pivcol] == 1) ;
+
+ if (found)
+ {
+
+ /* -------------------------------------------------------------- */
+ /* pivcol is a column singleton */
+ /* -------------------------------------------------------------- */
+
+ DEBUG0 (("Found a col singleton: k "ID" pivcol "ID"\n", k, pivcol));
+
+ /* find the pivrow to match with this pivcol */
+#ifndef NDEBUG
+ /* there can only be one pivrow, since the degree of pivcol is 1 */
+ {
+ Int deg = 0 ;
+ p2 = Ap [pivcol+1] ;
+ for (p = Ap [pivcol] ; p < p2 ; p++)
+ {
+ row = Ai [p] ;
+ DEBUG1 (("row: "ID"\n", row)) ;
+ if (Rdeg [row] >= 0)
+ {
+ /* this is a live index in this column vector */
+ deg++ ;
+ }
+ }
+ ASSERT (deg == 1) ;
+ }
+#endif
+
+ p2 = Ap [pivcol+1] ;
+ for (p = Ap [pivcol] ; p < p2 ; p++)
+ {
+ row = Ai [p] ;
+ DEBUG1 (("row: "ID"\n", row)) ;
+ if (Rdeg [row] >= 0)
+ {
+ /* this is a live index in this pivcol vector */
+ pivrow = row ;
+ break ;
+ }
+ }
+
+ DEBUG1 (("Pivot row: "ID"\n", pivrow)) ;
+ ASSERT (pivrow != EMPTY) ;
+ DEBUG1 (("deg "ID"\n", Rdeg [pivrow])) ;
+ ASSERT (Rdeg [pivrow] >= 0) ;
+
+ /* decrement the degrees after removing this col singleton */
+ DEBUG1 (("p1 "ID"\n", Rp [pivrow])) ;
+ DEBUG1 (("p2 "ID"\n", Rp [pivrow+1])) ;
+ p2 = Rp [pivrow+1] ;
+ for (p = Rp [pivrow] ; p < p2 ; p++)
+ {
+ col = Ri [p] ;
+ DEBUG1 ((" col: "ID" deg: "ID"\n", col, Cdeg [col])) ;
+ if (Cdeg [col] < 0) continue ;
+ ASSERT (Cdeg [col] > 0) ;
+ Cdeg [col]-- ;
+ ASSERT (Cdeg [col] >= 0) ;
+ }
+
+ /* flag the pivcol and pivrow by FLIP'ing the degrees */
+ Cdeg [pivcol] = FLIP (1) ;
+ Rdeg [pivrow] = FLIP (Rdeg [pivrow]) ;
+ n1c++ ;
+
+ }
+ else
+ {
+
+ /* -------------------------------------------------------------- */
+ /* pivcol may contain a row singleton */
+ /* -------------------------------------------------------------- */
+
+ p2 = Ap [pivcol+1] ;
+ for (p = Ap [pivcol] ; p < p2 ; p++)
+ {
+ pivrow = Ai [p] ;
+ if (Rdeg [pivrow] == 1)
+ {
+ DEBUG0 (("Row singleton in pivcol: "ID" row: "ID"\n",
+ pivcol, pivrow)) ;
+ found = TRUE ;
+ break ;
+ }
+ }
+
+ if (!found)
+ {
+ DEBUG0 (("End of user singletons\n")) ;
+ break ;
+ }
+
+#ifndef NDEBUG
+ /* there can only be one pivrow, since the degree of pivcol is 1 */
+ {
+ Int deg = 0 ;
+ p2 = Rp [pivrow+1] ;
+ for (p = Rp [pivrow] ; p < p2 ; p++)
+ {
+ col = Ri [p] ;
+ DEBUG1 (("col: "ID" cdeg::: "ID"\n", col, Cdeg [col])) ;
+ if (Cdeg [col] >= 0)
+ {
+ /* this is a live index in this column vector */
+ ASSERT (col == pivcol) ;
+ deg++ ;
+ }
+ }
+ ASSERT (deg == 1) ;
+ }
+#endif
+
+ DEBUG1 (("Pivot row: "ID"\n", pivrow)) ;
+ DEBUG1 (("pivcol deg "ID"\n", Cdeg [pivcol])) ;
+ ASSERT (Cdeg [pivcol] > 1) ;
+
+ /* decrement the degrees after removing this row singleton */
+ DEBUG1 (("p1 "ID"\n", Ap [pivcol])) ;
+ DEBUG1 (("p2 "ID"\n", Ap [pivcol+1])) ;
+ p2 = Ap [pivcol+1] ;
+ for (p = Ap [pivcol] ; p < p2 ; p++)
+ {
+ row = Ai [p] ;
+ DEBUG1 ((" row: "ID" deg: "ID"\n", row, Rdeg [row])) ;
+ if (Rdeg [row] < 0) continue ;
+ ASSERT (Rdeg [row] > 0) ;
+ Rdeg [row]-- ;
+ ASSERT (Rdeg [row] >= 0) ;
+ }
+
+ /* flag the pivcol and pivrow by FLIP'ing the degrees */
+ Cdeg [pivcol] = FLIP (Cdeg [pivcol]) ;
+ Rdeg [pivrow] = FLIP (1) ;
+ n1r++ ;
+ }
+
+ /* keep track of the pivot row and column */
+ Cperm [k] = pivcol ;
+ Rperm [k] = pivrow ;
+ n1++ ;
+
+#ifndef NDEBUG
+ dump_mat ("col", "row", n_col, n_row, Ap, Ai, Cdeg, Rdeg) ;
+ dump_mat ("row", "col", n_row, n_col, Rp, Ri, Rdeg, Cdeg) ;
+#endif
+
+ }
+
+ DEBUGm4 (("User singletons found: "ID"\n", n1)) ;
+ ASSERT (n1 > 0) ;
+
+ *p_n1r = n1r ;
+ *p_n1c = n1c ;
+ return (n1) ;
+}
+
+/* ========================================================================== */
+/* === finish_permutation =================================================== */
+/* ========================================================================== */
+
+/* Complete the permutation for the pruned submatrix. The singletons are
+ * already ordered, but remove their flags. Place rows/columns that are empty
+ * in the pruned submatrix at the end of the output permutation. This can only
+ * occur if the matrix is singular.
+ */
+
+PRIVATE Int finish_permutation
+(
+ Int n1,
+ Int nx,
+ Int Xdeg [ ],
+ const Int Xuser [ ],
+ Int Xperm [ ],
+ Int *p_max_deg
+)
+{
+ Int nempty, x, deg, s, max_deg, k ;
+ nempty = 0 ;
+ s = n1 ;
+ max_deg = 0 ;
+ DEBUG0 (("n1 "ID" nempty "ID"\n", n1, nempty)) ;
+ for (k = 0 ; k < nx ; k++)
+ {
+ x = (Xuser != (Int *) NULL) ? Xuser [k] : k ;
+ DEBUG0 (("finish perm k "ID" x "ID" nx "ID"\n", k, x, nx)) ;
+ deg = Xdeg [x] ;
+ if (deg == 0)
+ {
+ /* this row/col is empty in the pruned submatrix */
+ ASSERT (s < nx - nempty) ;
+ nempty++ ;
+ Xperm [nx - nempty] = x ;
+ }
+ else if (deg > 0)
+ {
+ /* this row/col is nonempty in the pruned submatrix */
+ ASSERT (s < nx - nempty) ;
+ Xperm [s++] = x ;
+ max_deg = MAX (max_deg, deg) ;
+ }
+ else
+ {
+ /* This is a singleton row/column - it is already ordered.
+ * Just clear the flag. */
+ Xdeg [x] = FLIP (deg) ;
+ }
+ }
+ ASSERT (s == nx - nempty) ;
+ *p_max_deg = max_deg ;
+ return (nempty) ;
+}
+
+/* ========================================================================== */
+/* === UMF_singletons ======================================================= */
+/* ========================================================================== */
+
+GLOBAL Int UMF_singletons
+(
+
+ /* input, not modified: */
+ Int n_row,
+ Int n_col,
+ const Int Ap [ ], /* size n_col+1 */
+ const Int Ai [ ], /* size nz = Ap [n_col] */
+ const Int Quser [ ], /* size n_col if present */
+
+ /* output, not defined on input: */
+ Int Cdeg [ ], /* size n_col */
+ Int Cperm [ ], /* size n_col */
+ Int Rdeg [ ], /* size n_row */
+ Int Rperm [ ], /* size n_row */
+ Int InvRperm [ ], /* size n_row, the inverse of Rperm */
+ Int *p_n1, /* # of col and row singletons */
+ Int *p_n1c, /* # of col singletons */
+ Int *p_n1r, /* # of row singletons */
+ Int *p_nempty_col, /* # of empty columns in pruned submatrix */
+ Int *p_nempty_row, /* # of empty columns in pruned submatrix */
+ Int *p_is_sym, /* TRUE if pruned submatrix is square and has been
+ * symmetrically permuted by Cperm and Rperm */
+ Int *p_max_rdeg, /* maximum Rdeg in pruned submatrix */
+
+ /* workspace, not defined on input or output */
+ Int Rp [ ], /* size n_row+1 */
+ Int Ri [ ], /* size nz */
+ Int W [ ], /* size n_row */
+ Int Next [ ] /* size MAX (n_row, n_col) */
+)
+{
+ Int n1, s, col, row, p, p1, p2, cdeg, last_row, is_sym, k,
+ nempty_row, nempty_col, max_cdeg, max_rdeg, n1c, n1r ;
+
+ /* ---------------------------------------------------------------------- */
+ /* initializations */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ UMF_dump_start ( ) ;
+ DEBUGm4 (("Starting umf_singletons\n")) ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* scan the columns, check for errors and count row degrees */
+ /* ---------------------------------------------------------------------- */
+
+ if (Ap [0] != 0 || Ap [n_col] < 0)
+ {
+ return (UMFPACK_ERROR_invalid_matrix) ;
+ }
+ for (row = 0 ; row < n_row ; row++)
+ {
+ Rdeg [row] = 0 ;
+ }
+ for (col = 0 ; col < n_col ; col++)
+ {
+ p1 = Ap [col] ;
+ p2 = Ap [col+1] ;
+ cdeg = p2 - p1 ;
+ if (cdeg < 0)
+ {
+ return (UMFPACK_ERROR_invalid_matrix) ;
+ }
+ last_row = EMPTY ;
+ for (p = p1 ; p < p2 ; p++)
+ {
+ row = Ai [p] ;
+ if (row <= last_row || row >= n_row)
+ {
+ return (UMFPACK_ERROR_invalid_matrix) ;
+ }
+ Rdeg [row]++ ;
+ last_row = row ;
+ }
+ Cdeg [col] = cdeg ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* find singletons */
+ /* ---------------------------------------------------------------------- */
+
+ if (Quser != (Int *) NULL)
+ {
+ /* look for singletons, but respect the user's input permutation */
+ n1 = find_user_singletons (n_row, n_col, Ap, Ai, Quser,
+ Cdeg, Rdeg, Cperm, Rperm, &n1r, &n1c, Rp, Ri, W) ;
+ }
+ else
+ {
+ /* look for singletons anywhere */
+ n1 = find_any_singletons (n_row, n_col, Ap, Ai,
+ Cdeg, Rdeg, Cperm, Rperm, &n1r, &n1c, Rp, Ri, W, Next) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* eliminate empty columns and complete the column permutation */
+ /* ---------------------------------------------------------------------- */
+
+ nempty_col = finish_permutation (n1, n_col, Cdeg, Quser, Cperm, &max_cdeg) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* eliminate empty rows and complete the row permutation */
+ /* ---------------------------------------------------------------------- */
+
+ nempty_row = finish_permutation (n1, n_row, Rdeg, (Int *) NULL, Rperm,
+ &max_rdeg) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* compute the inverse of Rperm */
+ /* ---------------------------------------------------------------------- */
+
+ for (k = 0 ; k < n_row ; k++)
+ {
+ ASSERT (Rperm [k] >= 0 && Rperm [k] < n_row) ;
+ InvRperm [Rperm [k]] = k ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* see if pruned submatrix is square and has been symmetrically permuted */
+ /* ---------------------------------------------------------------------- */
+
+ if (n_row == n_col && nempty_row == nempty_col)
+ {
+ /* is_sym is true if the submatrix is square, and
+ * Rperm [n1..n_row-nempty_row-1] = Cperm [n1..n_col-nempty_col-1] */
+ is_sym = TRUE ;
+ for (s = n1 ; s < n_col - nempty_col ; s++)
+ {
+ if (Cperm [s] != Rperm [s])
+ {
+ is_sym = FALSE ;
+ break ;
+ }
+ }
+ }
+ else
+ {
+ is_sym = FALSE ;
+ }
+ DEBUGm4 (("Submatrix square and symmetrically permuted? "ID"\n", is_sym)) ;
+ DEBUGm4 (("singletons "ID" row "ID" col "ID"\n", n1, n1r, n1c)) ;
+ DEBUGm4 (("Empty cols "ID" rows "ID"\n", nempty_col, nempty_row)) ;
+ *p_n1 = n1 ;
+ *p_n1r = n1r ;
+ *p_n1c = n1c ;
+ *p_is_sym = is_sym ;
+ *p_nempty_col = nempty_col ;
+ *p_nempty_row = nempty_row ;
+ *p_max_rdeg = max_rdeg ;
+ return (UMFPACK_OK) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_singletons
+(
+ Int n_row,
+ Int n_col,
+ const Int Ap [ ],
+ const Int Ai [ ],
+ const Int Quser [ ],
+ Int Cdeg [ ],
+ Int Cperm [ ],
+ Int Rdeg [ ],
+ Int Rperm [ ],
+ Int InvRperm [ ],
+ Int *n1,
+ Int *n1c,
+ Int *n1r,
+ Int *nempty_col,
+ Int *nempty_row,
+ Int *is_sym,
+ Int *max_rdeg,
+ Int Rp [ ],
+ Int Ri [ ],
+ Int W [ ],
+ Int Next [ ]
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_solve ============================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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"
+#include "umf_report_vector.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, p2, do_scale ;
+ Entry axx, wi, xj, zi, xi, aij, *W, *Z, *S, *X, bi ;
+ double omega [3], d, *Z2, *Y, z2i, yi, *B2, *Rs, flops ;
+
+#ifndef NRECIPROCAL
+ Int do_recip = Numeric->do_recip ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* 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 ;
+ Rs = Numeric->Rs ; /* row scale factors */
+ do_scale = (Rs != (double *) NULL) ;
+ flops = 0 ;
+ 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). */
+ DEBUGm4 (("Note, 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 A x = 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) = ||R A_i||, 1-norm of row i of R A */
+ for (i = 0 ; i < n ; i++)
+ {
+ Y [i] = 0. ;
+ }
+ flops += (ABS_FLOPS + 1) * nz ;
+ p2 = Ap [n] ;
+ for (p = 0 ; p < p2 ; p++)
+ {
+ /* Y [Ai [p]] += ABS (Ax [p]) ; */
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ ABS (d, aij) ;
+ Y [Ai [p]] += d ;
+ }
+
+ /* B2 = abs (B) */
+ 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) ;
+ }
+
+ /* scale Y and B2. */
+ if (do_scale)
+ {
+ /* Y = R Y */
+ /* B2 = R B2 */
+#ifndef NRECIPROCAL
+ if (do_recip)
+ {
+ /* multiply by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ Y [i] *= Rs [i] ;
+ B2 [i] *= Rs [i] ;
+ }
+ }
+ else
+#endif
+ {
+ /* divide by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ Y [i] /= Rs [i] ;
+ B2 [i] /= Rs [i] ;
+ }
+ }
+
+ flops += 2 * n ;
+ }
+
+ }
+
+ for (step = 0 ; step <= irstep ; step++)
+ {
+
+ /* -------------------------------------------------------------- */
+ /* Solve A x = b (step 0): */
+ /* x = Q (U \ (L \ (P R b))) */
+ /* and then perform iterative refinement (step > 0): */
+ /* x = x + Q (U \ (L \ (P R (b - A x)))) */
+ /* -------------------------------------------------------------- */
+
+ if (step == 0)
+ {
+ if (do_scale)
+ {
+ /* W = P R b, using X as workspace, since Z is not
+ * allocated if irstep = 0. */
+#ifndef NRECIPROCAL
+ if (do_recip)
+ {
+ /* multiply by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ ASSIGN (X [i], Bx [i], Bz [i]) ;
+ SCALE_RECIP (X [i], Rs [i]) ;
+ }
+ }
+ else
+#endif
+ {
+ /* divide by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ ASSIGN (X [i], Bx [i], Bz [i]) ;
+ SCALE_DIV (X [i], Rs [i]) ;
+ }
+ }
+ flops += SCALE_FLOPS * n ;
+ for (i = 0 ; i < n ; i++)
+ {
+ W [i] = X [Rperm [i]] ;
+ }
+ }
+ else
+ {
+ /* W = P b, since the row scaling R = I */
+ 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]) ;
+ }
+ flops += MULTSUB_FLOPS * nz ;
+ for (i = 0 ; i < n ; i++)
+ {
+ xi = X [i] ;
+ p2 = Ap [i+1] ;
+ for (p = Ap [i] ; p < p2 ; p++)
+ {
+ /* Z [Ai [p]] -= Ax [p] * xi ; */
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ MULT_SUB (Z [Ai [p]], aij, xi) ;
+ }
+ }
+ /* scale, Z = R Z */
+ if (do_scale)
+ {
+#ifndef NRECIPROCAL
+ if (do_recip)
+ {
+ /* multiply by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ SCALE_RECIP (Z [i], Rs [i]) ;
+ }
+ }
+ else
+#endif
+ {
+ /* divide by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ SCALE_DIV (Z [i], Rs [i]) ;
+ }
+ }
+ flops += SCALE_FLOPS * n ;
+ }
+ for (i = 0 ; i < n ; i++)
+ {
+ W [i] = Z [Rperm [i]] ;
+ }
+ }
+
+ flops += UMF_lsolve (Numeric, W, Pattern) ;
+ flops += UMF_usolve (Numeric, W, Pattern) ;
+
+ if (step == 0)
+ {
+ for (i = 0 ; i < n ; i++)
+ {
+ X [Cperm [i]] = W [i] ;
+ }
+ }
+ else
+ {
+ 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) = R (b - A x)_i, residual */
+ /* Z2 (i) = R (|A||x|)_i */
+ /* ---------------------------------------------------------- */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ /* W [i] = B [i] ; */
+ ASSIGN (W [i], Bx [i], Bz [i]) ;
+ Z2 [i] = 0. ;
+ }
+ flops += (MULT_FLOPS + DECREMENT_FLOPS + ABS_FLOPS + 1) * nz ;
+ for (j = 0 ; j < n ; j++)
+ {
+ xj = X [j] ;
+ p2 = Ap [j+1] ;
+ for (p = Ap [j] ; p < p2 ; 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 ;
+ }
+ }
+
+ /* scale W and Z2 */
+ if (do_scale)
+ {
+ /* Z2 = R Z2 */
+ /* W = R W */
+#ifndef NRECIPROCAL
+ if (do_recip)
+ {
+ /* multiply by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ SCALE_RECIP (W [i], Rs [i]) ;
+ Z2 [i] *= Rs [i] ;
+ }
+ }
+ else
+#endif
+ {
+ /* divide by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ SCALE_DIV (W [i], Rs [i]) ;
+ Z2 [i] /= Rs [i] ;
+ }
+ }
+ flops += (SCALE_FLOPS + 1) * n ;
+ }
+
+ flops += (2*ABS_FLOPS + 5) * n ;
+ 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' R)_i||, 1-norm of row i of A' R */
+
+ if (do_scale)
+ {
+ flops += (ABS_FLOPS + 2) * nz ;
+#ifndef NRECIPROCAL
+ if (do_recip)
+ {
+ /* multiply by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ yi = 0. ;
+ p2 = Ap [i+1] ;
+ for (p = Ap [i] ; p < p2 ; p++)
+ {
+ /* yi += ABS (Ax [p]) * Rs [Ai [p]] ; */
+ /* note that abs (aij) is the same as
+ * abs (conj (aij)) */
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ ABS (d, aij) ;
+ yi += (d * Rs [Ai [p]]) ;
+ }
+ Y [i] = yi ;
+ }
+ }
+ else
+#endif
+ {
+ /* divide by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ yi = 0. ;
+ p2 = Ap [i+1] ;
+ for (p = Ap [i] ; p < p2 ; p++)
+ {
+ /* yi += ABS (Ax [p]) / Rs [Ai [p]] ; */
+ /* note that abs (aij) is the same as
+ * abs (conj (aij)) */
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ ABS (d, aij) ;
+ yi += (d / Rs [Ai [p]]) ;
+ }
+ Y [i] = yi ;
+ }
+ }
+ }
+ else
+ {
+ /* no scaling */
+ flops += (ABS_FLOPS + 1) * nz ;
+ for (i = 0 ; i < n ; i++)
+ {
+ yi = 0. ;
+ p2 = Ap [i+1] ;
+ for (p = Ap [i] ; p < p2 ; 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 = R P' (L' \ (U' \ (Q' b))) */
+ /* and then perform iterative refinement (step > 0): */
+ /* x = x + R P' (L' \ (U' \ (Q' (b - A' x)))) */
+ /* -------------------------------------------------------------- */
+
+ if (step == 0)
+ {
+ /* W = Q' b */
+ for (i = 0 ; i < n ; i++)
+ {
+ /* W [i] = B [Cperm [i]] ; */
+ ASSIGN (W [i], Bx [Cperm [i]], Bz [Cperm [i]]) ;
+ }
+ }
+ else
+ {
+ /* Z = b - A' x */
+ for (i = 0 ; i < n ; i++)
+ {
+ /* Z [i] = B [i] ; */
+ ASSIGN (Z [i], Bx [i], Bz [i]) ;
+ }
+ flops += MULTSUB_FLOPS * nz ;
+ for (i = 0 ; i < n ; i++)
+ {
+ zi = Z [i] ;
+ p2 = Ap [i+1] ;
+ for (p = Ap [i] ; p < p2 ; 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 ;
+ }
+ /* W = Q' Z */
+ for (i = 0 ; i < n ; i++)
+ {
+ W [i] = Z [Cperm [i]] ;
+ }
+ }
+
+ flops += UMF_uhsolve (Numeric, W, Pattern) ;
+ flops += UMF_lhsolve (Numeric, W, Pattern) ;
+
+ if (step == 0)
+ {
+
+ /* X = R P' W */
+ /* do not use Z, since it isn't allocated if irstep = 0 */
+
+ /* X = P' W */
+ for (i = 0 ; i < n ; i++)
+ {
+ X [Rperm [i]] = W [i] ;
+ }
+ if (do_scale)
+ {
+ /* X = R X */
+#ifndef NRECIPROCAL
+ if (do_recip)
+ {
+ /* multiply by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ SCALE_RECIP (X [i], Rs [i]) ;
+ }
+ }
+ else
+#endif
+ {
+ /* divide by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ SCALE_DIV (X [i], Rs [i]) ;
+ }
+ }
+ flops += SCALE_FLOPS * n ;
+ }
+
+ }
+ else
+ {
+
+ /* Z = P' W */
+ for (i = 0 ; i < n ; i++)
+ {
+ Z [Rperm [i]] = W [i] ;
+ }
+ if (do_scale)
+ {
+ /* Z = R Z */
+#ifndef NRECIPROCAL
+ if (do_recip)
+ {
+ /* multiply by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ SCALE_RECIP (Z [i], Rs [i]) ;
+ }
+ }
+ else
+#endif
+ {
+ /* divide by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ SCALE_DIV (Z [i], Rs [i]) ;
+ }
+ }
+ flops += SCALE_FLOPS * n ;
+ }
+
+ flops += ASSEMBLE_FLOPS * n ;
+ /* X += Z */
+ for (i = 0 ; i < n ; i++)
+ {
+ /* X [i] += W [i] ; */
+ ASSEMBLE (X [i], W [i]) ;
+ }
+ }
+
+ /* -------------------------------------------------------------- */
+ /* sparse backward error estimate */
+ /* -------------------------------------------------------------- */
+
+ if (irstep > 0)
+ {
+
+ /* ---------------------------------------------------------- */
+ /* A' is stored by row */
+ /* W (i) = (b - A' x)_i, residual */
+ /* Z2 (i) = (|A'||x|)_i */
+ /* ---------------------------------------------------------- */
+
+ 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. ;
+ p2 = Ap [i+1] ;
+ for (p = Ap [i] ; p < p2 ; 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 ;
+ }
+
+ flops += (2*ABS_FLOPS + 5) * n ;
+ 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.' R)_i||, 1-norm of row i of A.' R */
+
+ if (do_scale)
+ {
+ flops += (ABS_FLOPS + 2) * nz ;
+#ifndef NRECIPROCAL
+ if (do_recip)
+ {
+ /* multiply by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ yi = 0. ;
+ p2 = Ap [i+1] ;
+ for (p = Ap [i] ; p < p2 ; p++)
+ {
+ /* yi += ABS (Ax [p]) * Rs [Ai [p]] ; */
+ /* note that A.' is the array transpose,
+ * so no conjugate */
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ ABS (d, aij) ;
+ yi += (d * Rs [Ai [p]]) ;
+ }
+ Y [i] = yi ;
+ }
+ }
+ else
+#endif
+ {
+ /* divide by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ yi = 0. ;
+ p2 = Ap [i+1] ;
+ for (p = Ap [i] ; p < p2 ; p++)
+ {
+ /* yi += ABS (Ax [p]) / Rs [Ai [p]] ; */
+ /* note that A.' is the array transpose,
+ * so no conjugate */
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ ABS (d, aij) ;
+ yi += (d / Rs [Ai [p]]) ;
+ }
+ Y [i] = yi ;
+ }
+ }
+ }
+ else
+ {
+ /* no scaling */
+ flops += (ABS_FLOPS + 1) * nz ;
+ for (i = 0 ; i < n ; i++)
+ {
+ yi = 0. ;
+ p2 = Ap [i+1] ;
+ for (p = Ap [i] ; p < p2 ; p++)
+ {
+ /* yi += ABS (Ax [p]) */
+ /* note that A.' is the array transpose,
+ * so no conjugate */
+ 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 = R P' (L.' \ (U.' \ (Q' b))) */
+ /* and then perform iterative refinement (step > 0): */
+ /* x = x + R P' (L.' \ (U.' \ (Q' (b - A.' x)))) */
+ /* -------------------------------------------------------------- */
+
+ if (step == 0)
+ {
+ /* W = Q' b */
+ for (i = 0 ; i < n ; i++)
+ {
+ /* W [i] = B [Cperm [i]] ; */
+ ASSIGN (W [i], Bx [Cperm [i]], Bz [Cperm [i]]) ;
+ }
+ }
+ else
+ {
+ /* Z = b - A.' x */
+ for (i = 0 ; i < n ; i++)
+ {
+ /* Z [i] = B [i] ; */
+ ASSIGN (Z [i], Bx [i], Bz [i]) ;
+ }
+ flops += MULTSUB_FLOPS * nz ;
+ for (i = 0 ; i < n ; i++)
+ {
+ zi = Z [i] ;
+ p2 = Ap [i+1] ;
+ for (p = Ap [i] ; p < p2 ; p++)
+ {
+ /* zi -= Ax [p] * X [Ai [p]] ; */
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ MULT_SUB (zi, aij, X [Ai [p]]) ;
+ }
+ Z [i] = zi ;
+ }
+ /* W = Q' Z */
+ for (i = 0 ; i < n ; i++)
+ {
+ W [i] = Z [Cperm [i]] ;
+ }
+ }
+
+ flops += UMF_utsolve (Numeric, W, Pattern) ;
+ flops += UMF_ltsolve (Numeric, W, Pattern) ;
+
+ if (step == 0)
+ {
+
+ /* X = R P' W */
+ /* do not use Z, since it isn't allocated if irstep = 0 */
+
+ /* X = P' W */
+ for (i = 0 ; i < n ; i++)
+ {
+ X [Rperm [i]] = W [i] ;
+ }
+ if (do_scale)
+ {
+ /* X = R X */
+#ifndef NRECIPROCAL
+ if (do_recip)
+ {
+ /* multiply by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ SCALE_RECIP (X [i], Rs [i]) ;
+ }
+ }
+ else
+#endif
+ {
+ /* divide by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ SCALE_DIV (X [i], Rs [i]) ;
+ }
+ }
+ flops += SCALE_FLOPS * n ;
+ }
+
+ }
+ else
+ {
+
+ /* Z = P' W */
+ for (i = 0 ; i < n ; i++)
+ {
+ Z [Rperm [i]] = W [i] ;
+ }
+ if (do_scale)
+ {
+ /* Z = R Z */
+#ifndef NRECIPROCAL
+ if (do_recip)
+ {
+ /* multiply by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ SCALE_RECIP (Z [i], Rs [i]) ;
+ }
+ }
+ else
+#endif
+ {
+ /* divide by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ SCALE_DIV (Z [i], Rs [i]) ;
+ }
+ }
+ flops += SCALE_FLOPS * n ;
+ }
+
+ flops += ASSEMBLE_FLOPS * n ;
+ /* X += Z */
+ for (i = 0 ; i < n ; i++)
+ {
+ /* X [i] += W [i] ; */
+ ASSEMBLE (X [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 */
+ /* ---------------------------------------------------------- */
+
+ 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. ;
+ p2 = Ap [i+1] ;
+ for (p = Ap [i] ; p < p2 ; 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 ;
+ }
+
+ flops += (2*ABS_FLOPS + 5) * n ;
+ 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]]) ;
+ }
+ 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]) ;
+ }
+ 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]) ;
+ }
+ 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]) ;
+ }
+ 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]) ;
+ }
+ 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]) ;
+ }
+ 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]) ;
+ }
+ 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]) ;
+ }
+ 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]]) ;
+ }
+ 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]]) ;
+ }
+ 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]) ;
+ }
+ 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]) ;
+ }
+ 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 */
+ Info [UMFPACK_SOLVE_FLOPS] = flops ;
+ return (status) ;
+}
+
+
+/* ========================================================================== */
+/* === do_step ============================================================== */
+/* ========================================================================== */
+
+/* Perform one step of iterative refinement, for A x = 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 (("do_step start: nctau = %30.20e\n", nctau)) ;
+ ASSERT (UMF_report_vector (n, (double *) X, (double *) NULL, UMF_debug,
+ FALSE, FALSE) == UMFPACK_OK) ;
+
+ /* for approximate flop count, assume d1 > tau is always true */
+ /* flops += (2*ABS_FLOPS + 5) * n ; (done in UMF_solve, above) */
+
+ /* ---------------------------------------------------------------------- */
+ /* 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 ;
+ 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 ;
+ 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")) ;
+ ASSERT (UMF_report_vector (n, (double *) X, (double *) NULL, UMF_debug,
+ FALSE, FALSE) == UMFPACK_OK) ;
+ return (TRUE) ;
+ }
+
+ if (omega [0] < DBL_EPSILON) /* double relop, but no NaN case here */
+ {
+ DEBUG0 (("omega[0] too small - done.\n")) ;
+ ASSERT (UMF_report_vector (n, (double *) X, (double *) NULL, UMF_debug,
+ FALSE, FALSE) == UMFPACK_OK) ;
+ 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 ;
+ ASSERT (UMF_report_vector (n, (double *) X, (double *) NULL, UMF_debug,
+ FALSE, FALSE) == UMFPACK_OK) ;
+ return (TRUE) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* save current solution in case we need to reinstate */
+ /* ---------------------------------------------------------------------- */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ S [i] = X [i] ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* iterative refinement continues */
+ /* ---------------------------------------------------------------------- */
+
+ ASSERT (UMF_report_vector (n, (double *) X, (double *) NULL, UMF_debug,
+ FALSE, FALSE) == UMFPACK_OK) ;
+ return (FALSE) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+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 [ ],
+ double SolveWork [ ]
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_start_front ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 the initial frontal matrix working array for a single chain. The
+ * front does not have to be big enough, since if it's too small it will get
+ * reallocated. The size computed here is just an estimate. */
+
+#include "umf_internal.h"
+#include "umf_grow_front.h"
+
+GLOBAL Int UMF_start_front /* returns TRUE if successful, FALSE otherwise */
+(
+ Int chain,
+ NumericType *Numeric,
+ WorkType *Work,
+ SymbolicType *Symbolic
+)
+{
+ Int fnrows_max, fncols_max, fnr2, fnc2, fsize, fcurr_size, maxfrsize,
+ overflow, nb, f, cdeg ;
+ double maxbytes ;
+
+ nb = Symbolic->nb ;
+ fnrows_max = Symbolic->Chain_maxrows [chain] ;
+ fncols_max = Symbolic->Chain_maxcols [chain] ;
+
+ DEBUGm2 (("Start Front for chain "ID". fnrows_max "ID" fncols_max "ID"\n",
+ chain, fnrows_max, fncols_max)) ;
+
+ Work->fnrows_max = fnrows_max ;
+ Work->fncols_max = fncols_max ;
+ Work->any_skip = FALSE ;
+
+ maxbytes = sizeof (Entry) *
+ (double) (fnrows_max + nb) * (double) (fncols_max + nb) ;
+ fcurr_size = Work->fcurr_size ;
+
+ if (Symbolic->prefer_diagonal)
+ {
+ /* Get a rough upper bound on the degree of the first pivot column in
+ * this front. Note that Col_degree is not maintained if diagonal
+ * pivoting is preferred. For most matrices, the first pivot column
+ * of the first frontal matrix of a new chain has only one tuple in
+ * it anyway, so this bound is exact in that case. */
+ Int col, tpi, e, *E, *Col_tuples, *Col_tlen, *Cols ;
+ Tuple *tp, *tpend ;
+ Unit *Memory, *p ;
+ Element *ep ;
+ E = Work->E ;
+ Memory = Numeric->Memory ;
+ Col_tuples = Numeric->Lip ;
+ Col_tlen = Numeric->Lilen ;
+ col = Work->nextcand ;
+ tpi = Col_tuples [col] ;
+ tp = (Tuple *) Memory + tpi ;
+ tpend = tp + Col_tlen [col] ;
+ cdeg = 0 ;
+ DEBUGm3 (("\n=============== start front: col "ID" tlen "ID"\n",
+ col, Col_tlen [col])) ;
+ for ( ; tp < tpend ; tp++)
+ {
+ DEBUG1 (("Tuple ("ID","ID")\n", tp->e, tp->f)) ;
+ e = tp->e ;
+ if (!E [e]) continue ;
+ f = tp->f ;
+ p = Memory + E [e] ;
+ ep = (Element *) p ;
+ p += UNITS (Element, 1) ;
+ Cols = (Int *) p ;
+ if (Cols [f] == EMPTY) continue ;
+ DEBUG1 ((" nrowsleft "ID"\n", ep->nrowsleft)) ;
+ cdeg += ep->nrowsleft ;
+ }
+#ifndef NDEBUG
+ DEBUGm3 (("start front cdeg: "ID" col "ID"\n", cdeg, col)) ;
+ UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ;
+#endif
+
+ /* cdeg is now the rough upper bound on the degree of the next pivot
+ * column. */
+
+ /* If AMD was called, we know the maximum number of nonzeros in any
+ * column of L. Use this as an upper bound for cdeg, but add 2 to
+ * account for a small amount of off-diagonal pivoting. */
+ if (Symbolic->amd_dmax > 0)
+ {
+ cdeg = MIN (cdeg, Symbolic->amd_dmax) ;
+ }
+
+ /* Increase it to account for larger columns later on.
+ * Also ensure that it's larger than zero. */
+ cdeg += 2 ;
+
+ /* cdeg cannot be larger than fnrows_max */
+ cdeg = MIN (cdeg, fnrows_max) ;
+
+ }
+ else
+ {
+ /* don't do the above cdeg computation */
+ cdeg = 0 ;
+ }
+
+ DEBUGm2 (("fnrows max "ID" fncols_max "ID"\n", fnrows_max, fncols_max)) ;
+
+ /* the current frontal matrix is empty */
+ ASSERT (Work->fnrows == 0 && Work->fncols == 0 && Work->fnpiv == 0) ;
+
+ /* maximum row dimension is always odd, to avoid bad cache effects */
+ ASSERT (fnrows_max >= 0) ;
+ ASSERT (fnrows_max % 2 == 1) ;
+
+ /* ----------------------------------------------------------------------
+ * allocate working array for current frontal matrix:
+ * minimum size: 1-by-1
+ * maximum size: fnrows_max-by-fncols_max
+ * desired size:
+ *
+ * if Numeric->front_alloc_init >= 0:
+ *
+ * for unsymmetric matrices:
+ * Numeric->front_alloc_init * (fnrows_max-by-fncols_max)
+ *
+ * for symmetric matrices (diagonal pivoting preference, actually):
+ * Numeric->front_alloc_init * (fnrows_max-by-fncols_max), or
+ * cdeg*cdeg, whichever is smaller.
+ *
+ * if Numeric->front_alloc_init < 0:
+ * allocate a front of size -Numeric->front_alloc_init.
+ *
+ * Allocate the whole thing if it's small (less than 2*nb^2). Make sure the
+ * leading dimension of the frontal matrix is odd.
+ *
+ * Also allocate the nb-by-nb LU block, the dr-by-nb L block, and the
+ * nb-by-dc U block.
+ * ---------------------------------------------------------------------- */
+
+ /* get the maximum front size, avoiding integer overflow */
+ overflow = INT_OVERFLOW (maxbytes) ;
+ if (overflow)
+ {
+ /* :: int overflow, max front size :: */
+ maxfrsize = Int_MAX / sizeof (Entry) ;
+ }
+ else
+ {
+ maxfrsize = (fnrows_max + nb) * (fncols_max + nb) ;
+ }
+ ASSERT (!INT_OVERFLOW ((double) maxfrsize * sizeof (Entry))) ;
+
+ if (Numeric->front_alloc_init < 0)
+ {
+ /* allocate a front of -Numeric->front_alloc_init entries */
+ fsize = -Numeric->front_alloc_init ;
+ fsize = MAX (1, fsize) ;
+ }
+ else
+ {
+ if (INT_OVERFLOW (Numeric->front_alloc_init * maxbytes))
+ {
+ /* :: int overflow, requested front size :: */
+ fsize = Int_MAX / sizeof (Entry) ;
+ }
+ else
+ {
+ fsize = Numeric->front_alloc_init * maxfrsize ;
+ }
+
+ if (cdeg > 0)
+ {
+ /* diagonal pivoting is in use. cdeg was computed above */
+ Int fsize2 ;
+
+ /* add the L and U blocks */
+ cdeg += nb ;
+
+ if (INT_OVERFLOW (((double) cdeg * (double) cdeg) * sizeof (Entry)))
+ {
+ /* :: int overflow, symmetric front size :: */
+ fsize2 = Int_MAX / sizeof (Entry) ;
+ }
+ else
+ {
+ fsize2 = MAX (cdeg * cdeg, fcurr_size) ;
+ }
+ fsize = MIN (fsize, fsize2) ;
+ }
+ }
+
+ fsize = MAX (fsize, 2*nb*nb) ;
+
+ /* fsize and maxfrsize are now safe from integer overflow. They both
+ * include the size of the pivot blocks. */
+ ASSERT (!INT_OVERFLOW ((double) fsize * sizeof (Entry))) ;
+
+ Work->fnrows_new = 0 ;
+ Work->fncols_new = 0 ;
+
+ /* desired size is fnr2-by-fnc2 (includes L and U blocks): */
+ DEBUGm2 ((" fsize "ID" fcurr_size "ID"\n", fsize, fcurr_size)) ;
+ DEBUGm2 ((" maxfrsize "ID" fnr_curr "ID" fnc_curr "ID"\n", maxfrsize,
+ Work->fnr_curr, Work->fnc_curr)) ;
+
+ if (fsize >= maxfrsize && !overflow)
+ {
+ /* max working array is small, allocate all of it */
+ fnr2 = fnrows_max + nb ;
+ fnc2 = fncols_max + nb ;
+ fsize = maxfrsize ;
+ DEBUGm1 ((" sufficient for ("ID"+"ID")-by-("ID"+"ID")\n",
+ fnrows_max, nb, fncols_max, nb)) ;
+ }
+ else
+ {
+ /* allocate a smaller working array */
+ if (fnrows_max <= fncols_max)
+ {
+ fnr2 = (Int) sqrt ((double) fsize) ;
+ /* make sure fnr2 is odd */
+ fnr2 = MAX (fnr2, 1) ;
+ if (fnr2 % 2 == 0) fnr2++ ;
+ fnr2 = MIN (fnr2, fnrows_max + nb) ;
+ fnc2 = fsize / fnr2 ;
+ }
+ else
+ {
+ fnc2 = (Int) sqrt ((double) fsize) ;
+ fnc2 = MIN (fnc2, fncols_max + nb) ;
+ fnr2 = fsize / fnc2 ;
+ /* make sure fnr2 is odd */
+ fnr2 = MAX (fnr2, 1) ;
+ if (fnr2 % 2 == 0)
+ {
+ fnr2++ ;
+ fnc2 = fsize / fnr2 ;
+ }
+ }
+ DEBUGm1 ((" smaller "ID"-by-"ID"\n", fnr2, fnc2)) ;
+ }
+ fnr2 = MIN (fnr2, fnrows_max + nb) ;
+ fnc2 = MIN (fnc2, fncols_max + nb) ;
+ ASSERT (fnr2 % 2 == 1) ;
+ ASSERT (fnr2 * fnc2 <= fsize) ;
+
+ fnr2 -= nb ;
+ fnc2 -= nb ;
+ ASSERT (fnr2 >= 0) ;
+ ASSERT (fnc2 >= 0) ;
+
+ if (fsize > fcurr_size)
+ {
+ DEBUGm1 ((" Grow front \n")) ;
+ Work->do_grow = TRUE ;
+ if (!UMF_grow_front (Numeric, fnr2, fnc2, Work, -1))
+ {
+ /* since the minimum front size is 1-by-1, it would be nearly
+ * impossible to run out of memory here. */
+ DEBUGm4 (("out of memory: start front\n")) ;
+ return (FALSE) ;
+ }
+ }
+ else
+ {
+ /* use the existing front */
+ DEBUGm1 ((" existing front ok\n")) ;
+ Work->fnr_curr = fnr2 ;
+ Work->fnc_curr = fnc2 ;
+ Work->Flblock = Work->Flublock + nb * nb ;
+ Work->Fublock = Work->Flblock + nb * fnr2 ;
+ Work->Fcblock = Work->Fublock + nb * fnc2 ;
+ }
+ ASSERT (Work->Flblock == Work->Flublock + Work->nb*Work->nb) ;
+ ASSERT (Work->Fublock == Work->Flblock + Work->fnr_curr*Work->nb) ;
+ ASSERT (Work->Fcblock == Work->Fublock + Work->nb*Work->fnc_curr) ;
+ return (TRUE) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_start_front
+(
+ Int chain,
+ NumericType *Numeric,
+ WorkType *Work,
+ SymbolicType *Symbolic
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_store_lu ========================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+/*
+ 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"
+
+/* ========================================================================== */
+
+#ifdef DROP
+GLOBAL Int UMF_store_lu_drop
+#else
+GLOBAL Int UMF_store_lu
+#endif
+(
+ NumericType *Numeric,
+ WorkType *Work
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int i, k, fnr_curr, fnrows, fncols, row, col, pivrow, pivcol, *Frows,
+ *Fcols, *Lpattern, *Upattern, *Lpos, *Upos, llen, ulen, fnc_curr, fnpiv,
+ uilen, lnz, unz, nb, *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, *Pivrow, *Pivcol, kk,
+ Lnz [MAXNB] ;
+ Entry *D, pivot_value, *Lval, *Uval, *Fl1, *Fl2, *Fu1, *Fu2,
+ *Flublock, *Flblock, *Fublock ;
+
+#ifndef NDEBUG
+ Int *Col_degree, *Row_degree ;
+#endif
+
+#ifdef DROP
+ Int all_lnz, all_unz ;
+ double droptol ;
+ droptol = Numeric->droptol ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ fnrows = Work->fnrows ;
+ fncols = Work->fncols ;
+ fnpiv = Work->fnpiv ;
+
+ Lpos = Numeric->Lpos ;
+ Upos = Numeric->Upos ;
+ Lilen = Numeric->Lilen ;
+ Uilen = Numeric->Uilen ;
+
+ Lip = Numeric->Lip ;
+ Uip = Numeric->Uip ;
+ D = Numeric->D ;
+
+ Flublock = Work->Flublock ;
+ Flblock = Work->Flblock ;
+ Fublock = Work->Fublock ;
+
+ fnr_curr = Work->fnr_curr ;
+ fnc_curr = Work->fnc_curr ;
+ Frows = Work->Frows ;
+ Fcols = Work->Fcols ;
+
+#ifndef NDEBUG
+ Col_degree = Numeric->Cperm ; /* for NON_PIVOTAL_COL macro */
+ Row_degree = Numeric->Rperm ; /* for NON_PIVOTAL_ROW macro */
+#endif
+
+ Lpattern = Work->Lpattern ;
+ llen = Work->llen ;
+ Upattern = Work->Upattern ;
+ ulen = Work->ulen ;
+
+ nb = Work->nb ;
+
+#ifndef NDEBUG
+ DEBUG1 (("\n##################################### STORE LU: fnrows "ID
+ " fncols "ID"\n", fnrows, fncols)) ;
+
+ DEBUG2 (("\nFrontal matrix, including all space:\n"
+ "fnr_curr "ID" fnc_curr "ID" nb "ID"\n"
+ "fnrows "ID" fncols "ID" fnpiv "ID"\n",
+ fnr_curr, fnc_curr, nb, fnrows, fncols, fnpiv)) ;
+
+ DEBUG2 (("\nJust the active part:\n")) ;
+ DEBUG7 (("C block: ")) ;
+ UMF_dump_dense (Work->Fcblock, fnr_curr, fnrows, fncols) ;
+ DEBUG7 (("L block: ")) ;
+ UMF_dump_dense (Work->Flblock, fnr_curr, fnrows, fnpiv);
+ DEBUG7 (("U' block: ")) ;
+ UMF_dump_dense (Work->Fublock, fnc_curr, fncols, fnpiv) ;
+ DEBUG7 (("LU block: ")) ;
+ UMF_dump_dense (Work->Flublock, nb, fnpiv, fnpiv) ;
+ DEBUG7 (("Current frontal matrix: (prior to store LU)\n")) ;
+ UMF_dump_current_front (Numeric, Work, TRUE) ;
+#endif
+
+ Pivrow = Work->Pivrow ;
+ Pivcol = Work->Pivcol ;
+
+ /* ---------------------------------------------------------------------- */
+ /* store the columns of L */
+ /* ---------------------------------------------------------------------- */
+
+ for (kk = 0 ; kk < fnpiv ; kk++)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* one more pivot row and column is being stored into L and U */
+ /* ------------------------------------------------------------------ */
+
+ k = Work->npiv + kk ;
+
+ /* ------------------------------------------------------------------ */
+ /* find the kth pivot row and pivot column */
+ /* ------------------------------------------------------------------ */
+
+ pivrow = Pivrow [kk] ;
+ pivcol = Pivcol [kk] ;
+
+#ifndef NDEBUG
+ ASSERT (pivrow >= 0 && pivrow < Work->n_row) ;
+ ASSERT (pivcol >= 0 && pivcol < Work->n_col) ;
+
+ DEBUGm4 ((
+ "\n -------------------------------------------------------------"
+ "Store LU: step " ID"\n", k)) ;
+ ASSERT (k < MIN (Work->n_row, Work->n_col)) ;
+ 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 (i == Lpos [row]) ;
+ }
+#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 */
+ /* ------------------------------------------------------------------ */
+
+ /* kk-th column of LU block */
+ Fl1 = Flublock + kk * nb ;
+
+ /* kk-th column of L in the L block */
+ Fl2 = Flblock + kk * fnr_curr ;
+
+ /* kk-th pivot in frontal matrix located in Flublock [kk, kk] */
+ pivot_value = Fl1 [kk] ;
+
+ D [k] = pivot_value ;
+ zero_pivot = IS_ZERO (pivot_value) ;
+
+ DEBUG4 (("Pivot D["ID"]=", k)) ;
+ EDEBUG4 (pivot_value) ;
+ DEBUG4 (("\n")) ;
+
+ /* ------------------------------------------------------------------ */
+ /* count nonzeros in kth column of L */
+ /* ------------------------------------------------------------------ */
+
+ lnz = 0 ;
+ lnz2i = 0 ;
+ lnz2x = llen ;
+
+#ifdef DROP
+ all_lnz = 0 ;
+
+ for (i = kk + 1 ; i < fnpiv ; i++)
+ {
+ double s ;
+ Entry x = Fl1 [i] ;
+ if (IS_ZERO (x)) continue ;
+ all_lnz++ ;
+ APPROX_ABS (s, x) ;
+ if (s <= droptol) continue ;
+ lnz++ ;
+ if (Lpos [Pivrow [i]] == EMPTY) lnz2i++ ;
+ }
+
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ double s ;
+ Entry x = Fl2 [i] ;
+ if (IS_ZERO (x)) continue ;
+ all_lnz++ ;
+ APPROX_ABS (s, x) ;
+ if (s <= droptol) continue ;
+ lnz++ ;
+ if (Lpos [Frows [i]] == EMPTY) lnz2i++ ;
+ }
+
+#else
+
+ for (i = kk + 1 ; i < fnpiv ; i++)
+ {
+ if (IS_ZERO (Fl1 [i])) continue ;
+ lnz++ ;
+ if (Lpos [Pivrow [i]] == EMPTY) lnz2i++ ;
+ }
+
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ if (IS_ZERO (Fl2 [i])) continue ;
+ lnz++ ;
+ if (Lpos [Frows [i]] == EMPTY) lnz2i++ ;
+ }
+
+#endif
+
+ lnz2x += lnz2i ;
+
+ /* 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] ;
+ 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 ;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* allocate space for the column of L */
+ /* ------------------------------------------------------------------ */
+
+ size = UNITS (Int, lnzi) + UNITS (Entry, lnzx) ;
+
+#ifndef NDEBUG
+ UMF_allocfail = FALSE ;
+ if (UMF_gprob > 0)
+ {
+ double rrr = ((double) (rand ( ))) / (((double) RAND_MAX) + 1) ;
+ DEBUG4 (("Check random %e %e\n", rrr, UMF_gprob)) ;
+ UMF_allocfail = rrr < UMF_gprob ;
+ if (UMF_allocfail) DEBUGm2 (("Random garbage coll. (store LU)\n"));
+ }
+#endif
+
+ p = UMF_mem_alloc_head_block (Numeric, size) ;
+ if (!p)
+ {
+ Int r2, c2 ;
+ /* Do garbage collection, realloc, and try again. */
+ /* Note that there are pivot rows/columns in current front. */
+ if (Work->do_grow)
+ {
+ /* full compaction of current frontal matrix, since
+ * UMF_grow_front will be called next anyway. */
+ r2 = fnrows ;
+ c2 = fncols ;
+ }
+ else
+ {
+ /* partial compaction. */
+ r2 = MAX (fnrows, Work->fnrows_new + 1) ;
+ c2 = MAX (fncols, Work->fncols_new + 1) ;
+ }
+ DEBUGm3 (("get_memory from umf_store_lu:\n")) ;
+ if (!UMF_get_memory (Numeric, Work, size, r2, c2, TRUE))
+ {
+ DEBUGm4 (("out of memory: store LU (1)\n")) ;
+ return (FALSE) ; /* out of memory */
+ }
+ p = UMF_mem_alloc_head_block (Numeric, size) ;
+ if (!p)
+ {
+ DEBUGm4 (("out of memory: store LU (2)\n")) ;
+ return (FALSE) ; /* out of memory */
+ }
+ /* garbage collection may have moved the current front */
+ fnc_curr = Work->fnc_curr ;
+ fnr_curr = Work->fnr_curr ;
+ Flublock = Work->Flublock ;
+ Flblock = Work->Flblock ;
+ Fublock = Work->Fublock ;
+ Fl1 = Flublock + kk * nb ;
+ Fl2 = Flblock + kk * fnr_curr ;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* 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) ;
+
+#ifdef DROP
+
+ for (i = kk + 1 ; i < fnpiv ; i++)
+ {
+ double s ;
+ Int row2, pos ;
+ Entry x = Fl1 [i] ;
+ APPROX_ABS (s, x) ;
+ if (s <= droptol) continue ;
+ row2 = Pivrow [i] ;
+ pos = llen++ ;
+ Lpattern [pos] = row2 ;
+ Lpos [row2] = pos ;
+ Li [pos] = row2 ;
+ Lval [pos] = x ;
+ }
+
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ double s ;
+ Int row2, pos ;
+ Entry x = Fl2 [i] ;
+ APPROX_ABS (s, x) ;
+ if (s <= droptol) continue ;
+ row2 = Frows [i] ;
+ pos = llen++ ;
+ Lpattern [pos] = row2 ;
+ Lpos [row2] = pos ;
+ Li [pos] = row2 ;
+ Lval [pos] = x ;
+ }
+
+#else
+
+ for (i = kk + 1 ; i < fnpiv ; i++)
+ {
+ Int row2, pos ;
+ Entry x = Fl1 [i] ;
+ if (IS_ZERO (x)) continue ;
+ row2 = Pivrow [i] ;
+ pos = llen++ ;
+ Lpattern [pos] = row2 ;
+ Lpos [row2] = pos ;
+ Li [pos] = row2 ;
+ Lval [pos] = x ;
+ }
+
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ Int row2, pos ;
+ Entry x = Fl2 [i] ;
+ if (IS_ZERO (x)) continue ;
+ row2 = Frows [i] ;
+ pos = llen++ ;
+ Lpattern [pos] = row2 ;
+ Lpos [row2] = pos ;
+ Li [pos] = row2 ;
+ Lval [pos] = x ;
+ }
+
+#endif
+
+ }
+ else
+ {
+ ASSERT (llen > 0) ;
+
+#ifdef DROP
+
+ for (i = kk + 1 ; i < fnpiv ; i++)
+ {
+ double s ;
+ Int row2, pos ;
+ Entry x = Fl1 [i] ;
+ APPROX_ABS (s, x) ;
+ if (s <= droptol) continue ;
+ row2 = Pivrow [i] ;
+ pos = Lpos [row2] ;
+ if (pos == EMPTY)
+ {
+ pos = llen++ ;
+ Lpattern [pos] = row2 ;
+ Lpos [row2] = pos ;
+ *Li++ = row2 ;
+ }
+ Lval [pos] = x ;
+ }
+
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ double s ;
+ Int row2, pos ;
+ Entry x = Fl2 [i] ;
+ APPROX_ABS (s, x) ;
+ if (s <= droptol) continue ;
+ row2 = Frows [i] ;
+ pos = Lpos [row2] ;
+ if (pos == EMPTY)
+ {
+ pos = llen++ ;
+ Lpattern [pos] = row2 ;
+ Lpos [row2] = pos ;
+ *Li++ = row2 ;
+ }
+ Lval [pos] = x ;
+ }
+
+#else
+
+ for (i = kk + 1 ; i < fnpiv ; i++)
+ {
+ Int row2, pos ;
+ Entry x = Fl1 [i] ;
+ if (IS_ZERO (x)) continue ;
+ row2 = Pivrow [i] ;
+ pos = Lpos [row2] ;
+ if (pos == EMPTY)
+ {
+ pos = llen++ ;
+ Lpattern [pos] = row2 ;
+ Lpos [row2] = pos ;
+ *Li++ = row2 ;
+ }
+ Lval [pos] = x ;
+ }
+
+ for (i = 0 ; i < fnrows ; i++)
+ {
+ Int row2, pos ;
+ Entry x = Fl2 [i] ;
+ if (IS_ZERO (x)) continue ;
+ row2 = Frows [i] ;
+ pos = Lpos [row2] ;
+ if (pos == EMPTY)
+ {
+ pos = llen++ ;
+ Lpattern [pos] = row2 ;
+ Lpos [row2] = pos ;
+ *Li++ = row2 ;
+ }
+ Lval [pos] = x ;
+ }
+
+#endif
+
+ }
+ DEBUG4 (("llen "ID" lnzx "ID"\n", llen, lnzx)) ;
+ ASSERT (llen == lnzx) ;
+ ASSERT (lnz <= llen) ;
+ DEBUG4 (("lnz "ID" \n", lnz)) ;
+
+#ifdef DROP
+
+ DEBUG4 (("all_lnz "ID" \n", all_lnz)) ;
+ ASSERT (lnz <= all_lnz) ;
+ Numeric->lnz += lnz ;
+ Numeric->all_lnz += all_lnz ;
+ Lnz [kk] = all_lnz ;
+
+#else
+
+ Numeric->lnz += lnz ;
+ Numeric->all_lnz += lnz ;
+ Lnz [kk] = lnz ;
+#endif
+
+ Numeric->nLentries += lnzx ;
+ Work->llen = llen ;
+ Numeric->isize += lnzi ;
+
+ /* ------------------------------------------------------------------ */
+ /* the pivot column is fully assembled and scaled, and is now the */
+ /* k-th column of L */
+ /* ------------------------------------------------------------------ */
+
+ Lpos [pivrow] = pivrow_position ; /* not aliased */
+ Lip [pivcol] = lip ; /* aliased with Col_tuples */
+ Lilen [pivcol] = lnzi ; /* aliased with Col_tlen */
+
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* store the rows of U */
+ /* ---------------------------------------------------------------------- */
+
+ for (kk = 0 ; kk < fnpiv ; kk++)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* one more pivot row and column is being stored into L and U */
+ /* ------------------------------------------------------------------ */
+
+ k = Work->npiv + kk ;
+
+ /* ------------------------------------------------------------------ */
+ /* find the kth pivot row and pivot column */
+ /* ------------------------------------------------------------------ */
+
+ pivrow = Pivrow [kk] ;
+ pivcol = Pivcol [kk] ;
+
+#ifndef NDEBUG
+ ASSERT (pivrow >= 0 && pivrow < Work->n_row) ;
+ ASSERT (pivcol >= 0 && pivcol < Work->n_col) ;
+
+ 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 (i == Upos [col]) ;
+ }
+#endif
+
+ /* ------------------------------------------------------------------ */
+ /* get the pivot value, for the diagonal matrix D */
+ /* ------------------------------------------------------------------ */
+
+ zero_pivot = IS_ZERO (D [k]) ;
+
+ /* ------------------------------------------------------------------ */
+ /* count the nonzeros in the row of U */
+ /* ------------------------------------------------------------------ */
+
+ /* kk-th row of U in the LU block */
+ Fu1 = Flublock + kk ;
+
+ /* kk-th row of U in the U block */
+ Fu2 = Fublock + kk * fnc_curr ;
+
+ unz = 0 ;
+ unz2i = 0 ;
+ unz2x = ulen ;
+ DEBUG2 (("unz2x is "ID", lnzx "ID"\n", unz2x, lnzx)) ;
+
+ /* if row k does not end a Uchain, pivcol not 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) ;
+
+#ifdef DROP
+ all_unz = 0 ;
+
+ for (i = kk + 1 ; i < fnpiv ; i++)
+ {
+ double s ;
+ Entry x = Fu1 [i*nb] ;
+ if (IS_ZERO (x)) continue ;
+ all_unz++ ;
+ APPROX_ABS (s, x) ;
+ if (s <= droptol) continue ;
+ unz++ ;
+ if (Upos [Pivcol [i]] == EMPTY) unz2i++ ;
+ }
+
+ for (i = 0 ; i < fncols ; i++)
+ {
+ double s ;
+ Entry x = Fu2 [i] ;
+ if (IS_ZERO (x)) continue ;
+ all_unz++ ;
+ APPROX_ABS (s, x) ;
+ if (s <= droptol) continue ;
+ unz++ ;
+ if (Upos [Fcols [i]] == EMPTY) unz2i++ ;
+ }
+
+#else
+
+ for (i = kk + 1 ; i < fnpiv ; i++)
+ {
+ if (IS_ZERO (Fu1 [i*nb])) continue ;
+ unz++ ;
+ if (Upos [Pivcol [i]] == EMPTY) unz2i++ ;
+ }
+
+ for (i = 0 ; i < fncols ; i++)
+ {
+ if (IS_ZERO (Fu2 [i])) continue ;
+ unz++ ;
+ if (Upos [Fcols [i]] == EMPTY) unz2i++ ;
+ }
+
+#endif
+
+ unz2x += unz2i ;
+
+ 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 row of U */
+ /* ------------------------------------------------------------------ */
+
+ size = 0 ;
+ 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) ;
+
+#ifndef NDEBUG
+ UMF_allocfail = FALSE ;
+ if (UMF_gprob > 0)
+ {
+ double rrr = ((double) (rand ( ))) / (((double) RAND_MAX) + 1) ;
+ DEBUG4 (("Check random %e %e\n", rrr, UMF_gprob)) ;
+ UMF_allocfail = rrr < UMF_gprob ;
+ if (UMF_allocfail) DEBUGm2 (("Random garbage coll. (store LU)\n"));
+ }
+#endif
+
+ p = UMF_mem_alloc_head_block (Numeric, size) ;
+ if (!p)
+ {
+ Int r2, c2 ;
+ /* Do garbage collection, realloc, and try again. */
+ /* Note that there are pivot rows/columns in current front. */
+ if (Work->do_grow)
+ {
+ /* full compaction of current frontal matrix, since
+ * UMF_grow_front will be called next anyway. */
+ r2 = fnrows ;
+ c2 = fncols ;
+ }
+ else
+ {
+ /* partial compaction. */
+ r2 = MAX (fnrows, Work->fnrows_new + 1) ;
+ c2 = MAX (fncols, Work->fncols_new + 1) ;
+ }
+ DEBUGm3 (("get_memory from umf_store_lu:\n")) ;
+ if (!UMF_get_memory (Numeric, Work, size, r2, c2, TRUE))
+ {
+ /* :: get memory, column of L :: */
+ DEBUGm4 (("out of memory: store LU (1)\n")) ;
+ return (FALSE) ; /* out of memory */
+ }
+ p = UMF_mem_alloc_head_block (Numeric, size) ;
+ if (!p)
+ {
+ /* :: out of memory, column of U :: */
+ DEBUGm4 (("out of memory: store LU (2)\n")) ;
+ return (FALSE) ; /* out of memory */
+ }
+ /* garbage collection may have moved the current front */
+ fnc_curr = Work->fnc_curr ;
+ fnr_curr = Work->fnr_curr ;
+ Flublock = Work->Flublock ;
+ Flblock = Work->Flblock ;
+ Fublock = Work->Fublock ;
+ Fu1 = Flublock + kk ;
+ Fu2 = Fublock + kk * fnc_curr ;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* 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) ;
+ 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) ;
+ 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) ;
+
+#ifdef DROP
+
+ for (i = kk + 1 ; i < fnpiv ; i++)
+ {
+ double s ;
+ Int col2, pos ;
+ Entry x = Fu1 [i*nb] ;
+ APPROX_ABS (s, x) ;
+ if (s <= droptol) continue ;
+ col2 = Pivcol [i] ;
+ pos = ulen++ ;
+ Upattern [pos] = col2 ;
+ Upos [col2] = pos ;
+ Uval [pos] = x ;
+ }
+
+ for (i = 0 ; i < fncols ; i++)
+ {
+ double s ;
+ Int col2, pos ;
+ Entry x = Fu2 [i] ;
+ APPROX_ABS (s, x) ;
+ if (s <= droptol) continue ;
+ col2 = Fcols [i] ;
+ pos = ulen++ ;
+ Upattern [pos] = col2 ;
+ Upos [col2] = pos ;
+ Uval [pos] = x ;
+ }
+
+#else
+
+ for (i = kk + 1 ; i < fnpiv ; i++)
+ {
+ Int col2, pos ;
+ Entry x = Fu1 [i*nb] ;
+ if (IS_ZERO (x)) continue ;
+ col2 = Pivcol [i] ;
+ pos = ulen++ ;
+ Upattern [pos] = col2 ;
+ Upos [col2] = pos ;
+ Uval [pos] = x ;
+ }
+
+ for (i = 0 ; i < fncols ; i++)
+ {
+ Int col2, pos ;
+ Entry x = Fu2 [i] ;
+ if (IS_ZERO (x)) continue ;
+ col2 = Fcols [i] ;
+ pos = ulen++ ;
+ Upattern [pos] = col2 ;
+ Upos [col2] = pos ;
+ Uval [pos] = x ;
+ }
+
+#endif
+
+ }
+ else
+ {
+
+ ASSERT (ulen > 0) ;
+
+ /* store the numerical entries and find new nonzeros */
+
+#ifdef DROP
+
+ for (i = kk + 1 ; i < fnpiv ; i++)
+ {
+ double s ;
+ Int col2, pos ;
+ Entry x = Fu1 [i*nb] ;
+ APPROX_ABS (s, x) ;
+ if (s <= droptol) continue ;
+ col2 = Pivcol [i] ;
+ pos = Upos [col2] ;
+ if (pos == EMPTY)
+ {
+ pos = ulen++ ;
+ Upattern [pos] = col2 ;
+ Upos [col2] = pos ;
+ }
+ Uval [pos] = x ;
+ }
+
+ for (i = 0 ; i < fncols ; i++)
+ {
+ double s ;
+ Int col2, pos ;
+ Entry x = Fu2 [i] ;
+ APPROX_ABS (s, x) ;
+ if (s <= droptol) continue ;
+ col2 = Fcols [i] ;
+ pos = Upos [col2] ;
+ if (pos == EMPTY)
+ {
+ pos = ulen++ ;
+ Upattern [pos] = col2 ;
+ Upos [col2] = pos ;
+ }
+ Uval [pos] = x ;
+ }
+
+#else
+
+ for (i = kk + 1 ; i < fnpiv ; i++)
+ {
+ Int col2, pos ;
+ Entry x = Fu1 [i*nb] ;
+ if (IS_ZERO (x)) continue ;
+ col2 = Pivcol [i] ;
+ pos = Upos [col2] ;
+ if (pos == EMPTY)
+ {
+ pos = ulen++ ;
+ Upattern [pos] = col2 ;
+ Upos [col2] = pos ;
+ }
+ Uval [pos] = x ;
+ }
+
+ for (i = 0 ; i < fncols ; i++)
+ {
+ Int col2, pos ;
+ Entry x = Fu2 [i] ;
+ if (IS_ZERO (x)) continue ;
+ col2 = Fcols [i] ;
+ pos = Upos [col2] ;
+ if (pos == EMPTY)
+ {
+ pos = ulen++ ;
+ Upattern [pos] = col2 ;
+ Upos [col2] = pos ;
+ }
+ Uval [pos] = x ;
+ }
+
+#endif
+
+ }
+
+ ASSERT (ulen == unzx) ;
+ ASSERT (unz <= ulen) ;
+ DEBUG4 (("unz "ID" \n", unz)) ;
+
+#ifdef DROP
+
+ DEBUG4 (("all_unz "ID" \n", all_unz)) ;
+ ASSERT (unz <= all_unz) ;
+ Numeric->unz += unz ;
+ Numeric->all_unz += all_unz ;
+ /* count the "true" flops, based on LU pattern only */
+ Numeric->flops += DIV_FLOPS * Lnz [kk] /* scale pivot column */
+ + MULTSUB_FLOPS * (Lnz [kk] * all_unz) ; /* outer product */
+
+#else
+
+ Numeric->unz += unz ;
+ Numeric->all_unz += unz ;
+ /* count the "true" flops, based on LU pattern only */
+ Numeric->flops += DIV_FLOPS * Lnz [kk] /* scale pivot column */
+ + MULTSUB_FLOPS * (Lnz [kk] * unz) ; /* outer product */
+#endif
+
+ Numeric->nUentries += unzx ;
+ Work->ulen = ulen ;
+ DEBUG1 (("Work->ulen = "ID" at end of pivot step, k: "ID"\n", ulen, k));
+
+ /* ------------------------------------------------------------------ */
+ /* the pivot row is the k-th row of U */
+ /* ------------------------------------------------------------------ */
+
+ Upos [pivcol] = pivcol_position ; /* not aliased */
+ Uip [pivrow] = uip ; /* aliased with Row_tuples */
+ Uilen [pivrow] = uilen ; /* aliased with Row_tlen */
+
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* no more pivots in frontal working array */
+ /* ---------------------------------------------------------------------- */
+
+ Work->npiv += fnpiv ;
+ Work->fnpiv = 0 ;
+ Work->fnzeros = 0 ;
+ return (TRUE) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_store_lu
+(
+ NumericType *Numeric,
+ WorkType *Work
+) ;
+
+GLOBAL Int UMF_store_lu_drop
+(
+ NumericType *Numeric,
+ WorkType *Work
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_symbolic_usage =================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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,
+ Int esize, /* zero if no dense rows. Otherwise, equal to the
+ * number of non-singleton, non-empty columns */
+ Int prefer_diagonal
+)
+{
+ double units ;
+
+ units =
+ DUNITS (SymbolicType, 1) /* Symbolic structure */
+ + 2 * DUNITS (Int, n_col+1) /* Cperm_init, Cdeg */
+ + 2 * DUNITS (Int, n_row+1) /* Rperm_init, Rdeg */
+ + 3 * DUNITS (Int, nchains+1) /* Chain_ */
+ + 4 * DUNITS (Int, nfr+1) ; /* Front_ */
+
+ /* if dense rows are present */
+ units += DUNITS (Int, esize) ; /* Esize */
+
+ /* for diagonal pivoting */
+ if (prefer_diagonal)
+ {
+ units += DUNITS (Int, n_col+1) ; /* Diagonal_map */
+ }
+
+ return (units) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL double UMF_symbolic_usage
+(
+ Int n_row,
+ Int n_col,
+ Int nchains,
+ Int nfr,
+ Int esize,
+ Int prefer_diagonal
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_transpose ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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, newj, do_values ;
+
+ /* ---------------------------------------------------------------------- */
+ /* check inputs */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ Int nz ;
+ ASSERT (n_col >= 0) ;
+ nz = (Ap != (Int *) NULL) ? Ap [n_col] : 0 ;
+ DEBUG2 (("UMF_transpose: "ID"-by-"ID" nz "ID"\n", n_row, n_col, nz)) ;
+#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) ;
+ }
+ if (!UMF_is_permutation (P, W, n_row, n_row) ||
+ !UMF_is_permutation (Q, W, nq, nq))
+ {
+ return (UMFPACK_ERROR_invalid_permutation) ;
+ }
+ if (!AMD_valid (n_row, n_col, Ap, Ai))
+ {
+ return (UMFPACK_ERROR_invalid_matrix) ;
+ }
+ }
+
+#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 != (Int *) NULL)
+ {
+ 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 != (Int *) NULL)
+ {
+ 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 != (Int *) NULL)
+ {
+
+ /* 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 != (Int *) NULL)
+ {
+ 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 != (Int *) NULL)
+ {
+ 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]) ;
+ ASSERT (AMD_valid (n_col, n_row, Rp, Ri)) ;
+#endif
+
+ return (UMFPACK_OK) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_transpose
+(
+ Int n_row,
+ Int n_col,
+ const Int Ap [ ],
+ const Int Ai [ ],
+ const double Ax [ ],
+ const Int P [ ],
+ const Int Q [ ],
+ Int nq,
+ Int Rp [ ],
+ Int Ri [ ],
+ double Rx [ ],
+ Int W [ ],
+ Int check
+#ifdef COMPLEX
+ , const double Az [ ]
+ , double Rz [ ]
+ , Int do_conjugate
+#endif
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_triplet ========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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. Converts triplet input to column-oriented form.
+ Duplicate entries may exist (they are summed in the output). The columns
+ of the column-oriented form are in sorted order. The input is not modified.
+ Returns 1 if OK, 0 if an error occured.
+
+ Compiled into four different routines for each version (di, dl, zi, zl),
+ for a total of 16 different routines.
+*/
+
+#include "umf_internal.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+#ifdef DO_MAP
+#ifdef DO_VALUES
+GLOBAL Int UMF_triplet_map_x
+#else
+GLOBAL Int UMF_triplet_map_nox
+#endif
+#else
+#ifdef DO_VALUES
+GLOBAL Int UMF_triplet_nomap_x
+#else
+GLOBAL Int UMF_triplet_nomap_nox
+#endif
+#endif
+(
+ Int n_row,
+ Int n_col,
+ Int nz,
+ const Int Ti [ ], /* size nz */
+ const Int Tj [ ], /* size nz */
+ Int Ap [ ], /* size n_col + 1 */
+ Int Ai [ ], /* size nz */
+ Int Rp [ ], /* size n_row + 1 */
+ Int Rj [ ], /* size nz */
+ Int W [ ], /* size max (n_row, n_col) */
+ Int RowCount [ ] /* size n_row */
+#ifdef DO_VALUES
+ , const double Tx [ ] /* size nz */
+ , double Ax [ ] /* size nz */
+ , double Rx [ ] /* size nz */
+#ifdef COMPLEX
+ , const double Tz [ ] /* size nz */
+ , double Az [ ] /* size nz */
+ , double Rz [ ] /* size nz */
+#endif
+#endif
+#ifdef DO_MAP
+ , Int Map [ ] /* size nz */
+ , Int Map2 [ ] /* size nz */
+#endif
+)
+{
+
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int i, j, k, p, cp, p1, p2, pdest, pj ;
+#ifdef DO_MAP
+ Int duplicates ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* count the entries in each row (also counting duplicates) */
+ /* ---------------------------------------------------------------------- */
+
+ /* use W as workspace for row counts (including duplicates) */
+ for (i = 0 ; i < n_row ; i++)
+ {
+ W [i] = 0 ;
+ }
+
+ for (k = 0 ; k < nz ; k++)
+ {
+ i = Ti [k] ;
+ j = Tj [k] ;
+ if (i < 0 || i >= n_row || j < 0 || j >= n_col)
+ {
+ return (UMFPACK_ERROR_invalid_matrix) ;
+ }
+ W [i]++ ;
+#ifndef NDEBUG
+ DEBUG1 ((ID " triplet: "ID" "ID" ", k, i, j)) ;
+#ifdef DO_VALUES
+ {
+ Entry tt ;
+ ASSIGN (tt, Tx [k], Tz [k]) ;
+ EDEBUG2 (tt) ;
+ DEBUG1 (("\n")) ;
+ }
+#endif
+#endif
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* compute the row pointers */
+ /* ---------------------------------------------------------------------- */
+
+ Rp [0] = 0 ;
+ for (i = 0 ; i < n_row ; i++)
+ {
+ Rp [i+1] = Rp [i] + W [i] ;
+ W [i] = Rp [i] ;
+ }
+
+ /* W is now equal to the row pointers */
+
+ /* ---------------------------------------------------------------------- */
+ /* construct the row form */
+ /* ---------------------------------------------------------------------- */
+
+ for (k = 0 ; k < nz ; k++)
+ {
+ p = W [Ti [k]]++ ;
+#ifdef DO_MAP
+ Map [k] = p ;
+#endif
+ Rj [p] = Tj [k] ;
+#ifdef DO_VALUES
+ Rx [p] = Tx [k] ;
+#ifdef COMPLEX
+ Rz [p] = Tz [k] ;
+#endif
+#endif
+ }
+
+ /* Rp stays the same, but W [i] is advanced to the start of row i+1 */
+
+#ifndef NDEBUG
+ for (i = 0 ; i < n_row ; i++)
+ {
+ ASSERT (W [i] == Rp [i+1]) ;
+ }
+#ifdef DO_MAP
+ for (k = 0 ; k < nz ; k++)
+ {
+ /* make sure that kth triplet is mapped correctly */
+ p = Map [k] ;
+ DEBUG1 (("First row map: Map ["ID"] = "ID"\n", k, p)) ;
+ i = Ti [k] ;
+ j = Tj [k] ;
+ ASSERT (j == Rj [p]) ;
+ ASSERT (Rp [i] <= p && p < Rp [i+1]) ;
+ }
+#endif
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* sum up duplicates */
+ /* ---------------------------------------------------------------------- */
+
+ /* use W [j] to hold position in Ri/Rx/Rz of a_ij, for row i [ */
+
+ for (j = 0 ; j < n_col ; j++)
+ {
+ W [j] = EMPTY ;
+ }
+
+#ifdef DO_MAP
+ duplicates = FALSE ;
+#endif
+
+ for (i = 0 ; i < n_row ; i++)
+ {
+ p1 = Rp [i] ;
+ p2 = Rp [i+1] ;
+ pdest = p1 ;
+ /* At this point, W [j] < p1 holds true for all columns j, */
+ /* because Ri/Rx/Rz is stored in row oriented order. */
+#ifndef NDEBUG
+ if (UMF_debug >= -2)
+ {
+ for (j = 0 ; j < n_col ; j++)
+ {
+ ASSERT (W [j] < p1) ;
+ }
+ }
+#endif
+ for (p = p1 ; p < p2 ; p++)
+ {
+ j = Rj [p] ;
+ ASSERT (j >= 0 && j < n_col) ;
+ pj = W [j] ;
+ if (pj >= p1)
+ {
+ /* this column index, j, is already in row i, at position pj */
+ ASSERT (pj < p) ;
+ ASSERT (Rj [pj] == j) ;
+#ifdef DO_MAP
+ Map2 [p] = pj ;
+ duplicates = TRUE ;
+#endif
+#ifdef DO_VALUES
+ /* sum the entry */
+ Rx [pj] += Rx [p] ;
+#ifdef COMPLEX
+ Rz [pj] += Rz [p] ;
+#endif
+#endif
+ }
+ else
+ {
+ /* keep the entry */
+ /* also keep track in W[j] of position of a_ij for case above */
+ W [j] = pdest ;
+#ifdef DO_MAP
+ Map2 [p] = pdest ;
+#endif
+ /* no need to move the entry if pdest is equal to p */
+ if (pdest != p)
+ {
+ Rj [pdest] = j ;
+#ifdef DO_VALUES
+ Rx [pdest] = Rx [p] ;
+#ifdef COMPLEX
+ Rz [pdest] = Rz [p] ;
+#endif
+#endif
+ }
+ pdest++ ;
+ }
+ }
+ RowCount [i] = pdest - p1 ;
+ }
+
+ /* done using W for position of a_ij ] */
+
+ /* ---------------------------------------------------------------------- */
+ /* merge Map and Map2 into a single Map */
+ /* ---------------------------------------------------------------------- */
+
+#ifdef DO_MAP
+ if (duplicates)
+ {
+ for (k = 0 ; k < nz ; k++)
+ {
+ Map [k] = Map2 [Map [k]] ;
+ }
+ }
+#ifndef NDEBUG
+ else
+ {
+ /* no duplicates, so no need to recompute Map */
+ for (k = 0 ; k < nz ; k++)
+ {
+ ASSERT (Map2 [k] == k) ;
+ }
+ }
+ for (k = 0 ; k < nz ; k++)
+ {
+ /* make sure that kth triplet is mapped correctly */
+ p = Map [k] ;
+ DEBUG1 (("Second row map: Map ["ID"] = "ID"\n", k, p)) ;
+ i = Ti [k] ;
+ j = Tj [k] ;
+ ASSERT (j == Rj [p]) ;
+ ASSERT (Rp [i] <= p && p < Rp [i+1]) ;
+ }
+#endif
+#endif
+
+ /* now the kth triplet maps to p = Map [k], and thus to Rj/Rx [p] */
+
+ /* ---------------------------------------------------------------------- */
+ /* count the entries in each column */
+ /* ---------------------------------------------------------------------- */
+
+ /* [ use W as work space for column counts of A */
+ for (j = 0 ; j < n_col ; j++)
+ {
+ W [j] = 0 ;
+ }
+
+ for (i = 0 ; i < n_row ; i++)
+ {
+ for (p = Rp [i] ; p < Rp [i] + RowCount [i] ; p++)
+ {
+ j = Rj [p] ;
+ ASSERT (j >= 0 && j < n_col) ;
+ W [j]++ ;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* create the column pointers */
+ /* ---------------------------------------------------------------------- */
+
+ Ap [0] = 0 ;
+ for (j = 0 ; j < n_col ; j++)
+ {
+ Ap [j+1] = Ap [j] + W [j] ;
+ }
+ /* done using W as workspace for column counts of A ] */
+
+ for (j = 0 ; j < n_col ; j++)
+ {
+ W [j] = Ap [j] ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* construct the column form */
+ /* ---------------------------------------------------------------------- */
+
+ for (i = 0 ; i < n_row ; i++)
+ {
+ for (p = Rp [i] ; p < Rp [i] + RowCount [i] ; p++)
+ {
+ cp = W [Rj [p]]++ ;
+#ifdef DO_MAP
+ Map2 [p] = cp ;
+#endif
+ Ai [cp] = i ;
+#ifdef DO_VALUES
+ Ax [cp] = Rx [p] ;
+#ifdef COMPLEX
+ Az [cp] = Rz [p] ;
+#endif
+#endif
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* merge Map and Map2 into a single Map */
+ /* ---------------------------------------------------------------------- */
+
+#ifdef DO_MAP
+ for (k = 0 ; k < nz ; k++)
+ {
+ Map [k] = Map2 [Map [k]] ;
+ }
+#endif
+
+ /* now the kth triplet maps to p = Map [k], and thus to Ai/Ax [p] */
+
+#ifndef NDEBUG
+ for (j = 0 ; j < n_col ; j++)
+ {
+ ASSERT (W [j] == Ap [j+1]) ;
+ }
+
+ UMF_dump_col_matrix (
+#ifdef DO_VALUES
+ Ax,
+#ifdef COMPLEX
+ Az,
+#endif
+#else
+ (double *) NULL,
+#ifdef COMPLEX
+ (double *) NULL,
+#endif
+#endif
+ Ai, Ap, n_row, n_col, nz) ;
+
+#ifdef DO_MAP
+ for (k = 0 ; k < nz ; k++)
+ {
+ /* make sure that kth triplet is mapped correctly */
+ p = Map [k] ;
+ DEBUG1 (("Col map: Map ["ID"] = "ID"\t", k, p)) ;
+ i = Ti [k] ;
+ j = Tj [k] ;
+ ASSERT (i == Ai [p]) ;
+ DEBUG1 ((" i "ID" j "ID" Ap[j] "ID" p "ID" Ap[j+1] "ID"\n",
+ i, j, Ap [j], p, Ap [j+1])) ;
+ ASSERT (Ap [j] <= p && p < Ap [j+1]) ;
+ }
+#endif
+#endif
+
+ return (UMFPACK_OK) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_triplet_map_x
+(
+ Int n_row,
+ Int n_col,
+ Int nz,
+ const Int Ti [ ],
+ const Int Tj [ ],
+ Int Ap [ ],
+ Int Ai [ ],
+ Int Rp [ ],
+ Int Rj [ ],
+ Int W [ ],
+ Int RowCount [ ]
+ , const double Tx [ ]
+ , double Ax [ ]
+ , double Rx [ ]
+#ifdef COMPLEX
+ , const double Tz [ ]
+ , double Az [ ]
+ , double Rz [ ]
+#endif
+ , Int Map [ ]
+ , Int Map2 [ ]
+) ;
+
+GLOBAL Int UMF_triplet_map_nox
+(
+ Int n_row,
+ Int n_col,
+ Int nz,
+ const Int Ti [ ],
+ const Int Tj [ ],
+ Int Ap [ ],
+ Int Ai [ ],
+ Int Rp [ ],
+ Int Rj [ ],
+ Int W [ ],
+ Int RowCount [ ]
+ , Int Map [ ]
+ , Int Map2 [ ]
+) ;
+
+GLOBAL Int UMF_triplet_nomap_x
+(
+ Int n_row,
+ Int n_col,
+ Int nz,
+ const Int Ti [ ],
+ const Int Tj [ ],
+ Int Ap [ ],
+ Int Ai [ ],
+ Int Rp [ ],
+ Int Rj [ ],
+ Int W [ ],
+ Int RowCount [ ]
+ , const double Tx [ ]
+ , double Ax [ ]
+ , double Rx [ ]
+#ifdef COMPLEX
+ , const double Tz [ ]
+ , double Az [ ]
+ , double Rz [ ]
+#endif
+) ;
+
+GLOBAL Int UMF_triplet_nomap_nox
+(
+ Int n_row,
+ Int n_col,
+ Int nz,
+ const Int Ti [ ],
+ const Int Tj [ ],
+ Int Ap [ ],
+ Int Ai [ ],
+ Int Rp [ ],
+ Int Rj [ ],
+ Int W [ ],
+ Int RowCount [ ]
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_tuple_lengths ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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"
+
+GLOBAL Int UMF_tuple_lengths /* return memory usage */
+(
+ NumericType *Numeric,
+ WorkType *Work,
+ double *p_dusage /* output argument */
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* 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, n1 ;
+ double dusage ;
+ Element *ep ;
+ Unit *p ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ E = Work->E ;
+ Row_degree = Numeric->Rperm ; /* for NON_PIVOTAL_ROW macro only */
+ Col_degree = Numeric->Cperm ; /* for NON_PIVOTAL_COL macro only */
+ Row_tlen = Numeric->Uilen ;
+ Col_tlen = Numeric->Lilen ;
+ n_row = Work->n_row ;
+ n_col = Work->n_col ;
+ n1 = Work->n1 ;
+ nel = Work->nel ;
+
+ DEBUG3 (("TUPLE_LENGTHS: n_row "ID" n_col "ID" nel "ID"\n",
+ n_row, n_col, nel)) ;
+ ASSERT (nel < Work->elen) ;
+
+ /* tuple list lengths already initialized to zero */
+
+ /* ---------------------------------------------------------------------- */
+ /* scan each element: count tuple list lengths (include element 0) */
+ /* ---------------------------------------------------------------------- */
+
+ for (e = 1 ; 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 ;
+ for (i = 0 ; i < nrows ; i++)
+ {
+ row = Rows [i] ;
+ ASSERT (row == EMPTY || (row >= n1 && row < n_row)) ;
+ if (row >= n1)
+ {
+ ASSERT (NON_PIVOTAL_ROW (row)) ;
+ Row_tlen [row] ++ ;
+ }
+ }
+ for (i = 0 ; i < ncols ; i++)
+ {
+ col = Cols [i] ;
+ ASSERT (col == EMPTY || (col >= n1 && col < n_col)) ;
+ if (col >= n1)
+ {
+ 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 */
+ /* ---------------------------------------------------------------------- */
+
+ DEBUG0 (("UMF_build_tuples_usage\n")) ;
+
+ usage = 0 ;
+ dusage = 0 ;
+
+ ASSERT (Col_tlen && Col_degree) ;
+
+ for (col = n1 ; col < n_col ; col++)
+ {
+ if (NON_PIVOTAL_COL (col))
+ {
+ usage += 1 + UNITS (Tuple, TUPLES (Col_tlen [col])) ;
+ dusage += 1 + DUNITS (Tuple, TUPLES (Col_tlen [col])) ;
+ DEBUG0 ((" col: "ID" tlen "ID" usage so far: "ID"\n",
+ col, Col_tlen [col], usage)) ;
+ }
+ }
+
+ ASSERT (Row_tlen && Row_degree) ;
+
+ for (row = n1 ; row < n_row ; row++)
+ {
+ if (NON_PIVOTAL_ROW (row))
+ {
+ usage += 1 + UNITS (Tuple, TUPLES (Row_tlen [row])) ;
+ dusage += 1 + DUNITS (Tuple, TUPLES (Row_tlen [row])) ;
+ DEBUG0 ((" row: "ID" tlen "ID" usage so far: "ID"\n",
+ row, Row_tlen [row], usage)) ;
+ }
+ }
+
+ DEBUG0 (("UMF_build_tuples_usage "ID" %g\n", usage, dusage)) ;
+
+ *p_dusage = dusage ;
+ return (usage) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_tuple_lengths
+(
+ NumericType *Numeric,
+ WorkType *Work,
+ double *dusage
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_usolve =========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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, n1, *Ui ;
+ Entry *xp, xk, *D, *Uval ;
+
+ /* ---------------------------------------------------------------------- */
+ /* 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 ;
+ n1 = Numeric->n1 ;
+
+#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
+
+ /* ---------------------------------------------------------------------- */
+ /* singular case */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NO_DIVIDE_BY_ZERO
+ /* handle the singular part of D, up to just before the last pivot */
+ for (k = n-1 ; k >= npiv ; k--)
+ {
+ /* This is an *** intentional *** divide-by-zero, to get Inf or Nan,
+ * as appropriate. It is not a bug. */
+ ASSERT (IS_ZERO (D [k])) ;
+ xk = X [k] ;
+ /* X [k] = xk / D [k] ; */
+ DIV (X [k], xk, D [k]) ;
+ }
+#else
+ /* Do not divide by zero */
+#endif
+
+ 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] ;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* nonsingletons */
+ /* ---------------------------------------------------------------------- */
+
+ for (k = npiv-1 ; k >= n1 ; 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] ;
+ 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++ ;
+ }
+
+#ifndef NO_DIVIDE_BY_ZERO
+ /* Go ahead and divide by zero if D [k] is zero */
+ /* X [k] = xk / D [k] ; */
+ DIV (X [k], xk, D [k]) ;
+#else
+ /* Do not divide by zero */
+ if (IS_NONZERO (D [k]))
+ {
+ /* X [k] = xk / D [k] ; */
+ DIV (X [k], xk, D [k]) ;
+ }
+#endif
+
+ /* ------------------------------------------------------------------ */
+ /* make row k-1 of U in Pattern [0..deg-1] */
+ /* ------------------------------------------------------------------ */
+
+ if (k == n1) break ;
+
+ 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 ;
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* singletons */
+ /* ---------------------------------------------------------------------- */
+
+ for (k = n1 - 1 ; k >= 0 ; k--)
+ {
+ deg = Uilen [k] ;
+ xk = X [k] ;
+ DEBUG4 (("Singleton k "ID"\n", k)) ;
+ if (deg > 0)
+ {
+ up = Uip [k] ;
+ Ui = (Int *) (Numeric->Memory + up) ;
+ up += UNITS (Int, deg) ;
+ Uval = (Entry *) (Numeric->Memory + up) ;
+ for (j = 0 ; j < deg ; j++)
+ {
+ DEBUG4 ((" k "ID" col "ID" value", k, Ui [j])) ;
+ EDEBUG4 (Uval [j]) ;
+ DEBUG4 (("\n")) ;
+ /* xk -= X [Ui [j]] * Uval [j] ; */
+ ASSERT (Ui [j] >= 0 && Ui [j] < n) ;
+ MULT_SUB (xk, X [Ui [j]], Uval [j]) ;
+ }
+ }
+
+#ifndef NO_DIVIDE_BY_ZERO
+ /* Go ahead and divide by zero if D [k] is zero */
+ /* X [k] = xk / D [k] ; */
+ DIV (X [k], xk, D [k]) ;
+#else
+ /* Do not divide by zero */
+ if (IS_NONZERO (D [k]))
+ {
+ /* X [k] = xk / D [k] ; */
+ DIV (X [k], xk, D [k]) ;
+ }
+#endif
+
+ }
+
+#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));
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL double UMF_usolve
+(
+ NumericType *Numeric,
+ Entry X [ ],
+ Int Pattern [ ]
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_utsolve ========================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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, n1, *Ui ;
+ Entry *xp, xk, *D, *Uval ;
+
+ /* ---------------------------------------------------------------------- */
+ /* 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 ;
+ n1 = Numeric->n1 ;
+
+#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
+
+ /* ---------------------------------------------------------------------- */
+ /* singletons */
+ /* ---------------------------------------------------------------------- */
+
+ for (k = 0 ; k < n1 ; k++)
+ {
+ DEBUG4 (("Singleton k "ID"\n", k)) ;
+
+#ifndef NO_DIVIDE_BY_ZERO
+ /* 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
+#else
+ /* Do not divide by zero */
+ if (IS_NONZERO (D [k]))
+ {
+#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
+ }
+#endif
+
+ X [k] = xk ;
+ deg = Uilen [k] ;
+ if (deg > 0 && IS_NONZERO (xk))
+ {
+ up = Uip [k] ;
+ Ui = (Int *) (Numeric->Memory + up) ;
+ up += UNITS (Int, deg) ;
+ Uval = (Entry *) (Numeric->Memory + up) ;
+ for (j = 0 ; j < deg ; j++)
+ {
+ DEBUG4 ((" k "ID" col "ID" value", k, Ui [j])) ;
+ EDEBUG4 (Uval [j]) ;
+ DEBUG4 (("\n")) ;
+#ifdef CONJUGATE_SOLVE
+ /* X [Ui [j]] -= xk * conjugate (Uval [j]) ; */
+ MULT_SUB_CONJ (X [Ui [j]], xk, Uval [j]) ;
+#else
+ /* X [Ui [j]] -= xk * Uval [j] ; */
+ MULT_SUB (X [Ui [j]], xk, Uval [j]) ;
+#endif
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* nonsingletons */
+ /* ---------------------------------------------------------------------- */
+
+ for (kstart = n1 ; 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 */
+ /* -------------------------------------------------------------- */
+
+#ifndef NO_DIVIDE_BY_ZERO
+ /* 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
+#else
+ /* Do not divide by zero */
+ if (IS_NONZERO (D [k]))
+ {
+#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
+ }
+#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) ;
+ }
+
+#ifndef NO_DIVIDE_BY_ZERO
+ for (k = npiv ; k < n ; k++)
+ {
+ /* This is an *** intentional *** divide-by-zero, to get Inf or Nan,
+ * as appropriate. It is not a bug. */
+ 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 ;
+ }
+#endif
+
+#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));
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL double UMF_utsolve
+(
+ NumericType *Numeric,
+ Entry X [ ],
+ Int Pattern [ ]
+) ;
+
+
+GLOBAL double UMF_uhsolve
+(
+ NumericType *Numeric,
+ Entry X [ ],
+ Int Pattern [ ]
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_valid_numeric ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_valid_numeric
+(
+ NumericType *Numeric
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === UMF_valid_symbolic =================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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) ;
+}
--- /dev/null
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+GLOBAL Int UMF_valid_symbolic
+(
+ SymbolicType *Symbolic
+) ;
--- /dev/null
+/* ========================================================================== */
+/* === umf_version.h ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 */
+/* -------------------------------------------------------------------------- */
+
+/*
+ Define routine names, depending on version being compiled.
+
+ DINT: double precision, int's as integers
+ DLONG: double precision, long's as integers
+ ZLONG: complex double precision, long's as integers
+ ZINT: complex double precision, int's as integers
+*/
+
+/* Set DINT as the default, if nothing is defined */
+#if !defined (DLONG) && !defined (DINT) && !defined (ZLONG) && !defined (ZINT)
+#define DINT
+#endif
+
+/* Determine if this is a real or complex version */
+#if defined (ZLONG) || defined (ZINT)
+#define COMPLEX
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* integer type (Int is int or long) now defined in amd_internal.h */
+/* -------------------------------------------------------------------------- */
+
+#if defined (DLONG) || defined (ZLONG)
+#define LONG_INTEGER
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* Numerical relop macros for correctly handling the NaN case */
+/* -------------------------------------------------------------------------- */
+
+/*
+SCALAR_IS_NAN(x):
+ True if x is NaN. False otherwise. The commonly-existing isnan(x)
+ function could be used, but it's not in Kernighan & Ritchie 2nd edition
+ (ANSI C). It may appear in <math.h>, but I'm not certain about
+ portability. The expression x != x is true if and only if x is NaN,
+ according to the IEEE 754 floating-point standard.
+
+SCALAR_IS_ZERO(x):
+ True if x is zero. False if x is nonzero, NaN, or +/- Inf.
+ This is (x == 0) if the compiler is IEEE 754 compliant.
+
+SCALAR_IS_NONZERO(x):
+ True if x is nonzero, NaN, or +/- Inf. False if x zero.
+ This is (x != 0) if the compiler is IEEE 754 compliant.
+
+SCALAR_IS_LTZERO(x):
+ True if x is < zero or -Inf. False if x is >= 0, NaN, or +Inf.
+ This is (x < 0) if the compiler is IEEE 754 compliant.
+*/
+
+#if defined (MATHWORKS)
+
+/* The MathWorks has their own macros in util.h that handle NaN's properly. */
+#define SCALAR_IS_NAN(x) (utIsNaN (x))
+#define SCALAR_IS_ZERO(x) (utEQZero (x))
+#define SCALAR_IS_NONZERO(x) (utNEZero (x))
+#define SCALAR_IS_LTZERO(x) (utLTZero (x))
+
+#elif defined (UMF_WINDOWS)
+
+/* Yes, this is exceedingly ugly. Blame Microsoft, which hopelessly */
+/* violates the IEEE 754 floating-point standard in a bizarre way. */
+/* If you're using an IEEE 754-compliant compiler, then x != x is true */
+/* iff x is NaN. For Microsoft, (x < x) is true iff x is NaN. */
+/* So either way, this macro safely detects a NaN. */
+#define SCALAR_IS_NAN(x) (((x) != (x)) || (((x) < (x))))
+#define SCALAR_IS_ZERO(x) (((x) == 0.) && !SCALAR_IS_NAN(x))
+#define SCALAR_IS_NONZERO(x) (((x) != 0.) || SCALAR_IS_NAN(x))
+#define SCALAR_IS_LTZERO(x) (((x) < 0.) && !SCALAR_IS_NAN(x))
+
+#else
+
+/* These all work properly, according to the IEEE 754 standard ... except on */
+/* a PC with windows. Works fine in Linux on the same PC... */
+#define SCALAR_IS_NAN(x) ((x) != (x))
+#define SCALAR_IS_ZERO(x) ((x) == 0.)
+#define SCALAR_IS_NONZERO(x) ((x) != 0.)
+#define SCALAR_IS_LTZERO(x) ((x) < 0.)
+
+#endif
+
+/* scalar absolute value macro. If x is NaN, the result is NaN: */
+#define SCALAR_ABS(x) ((SCALAR_IS_LTZERO (x)) ? -(x) : (x))
+
+/* true if an integer (stored in double x) would overflow (or if x is NaN) */
+#define INT_OVERFLOW(x) ((!((x) * (1.0+1e-8) <= (double) Int_MAX)) \
+ || SCALAR_IS_NAN (x))
+
+/* print a scalar (avoid printing "-0" for negative zero). */
+#define PRINT_SCALAR(a) \
+{ \
+ if (SCALAR_IS_NONZERO (a)) \
+ { \
+ PRINTF ((" (%g)", (a))) ; \
+ } \
+ else \
+ { \
+ PRINTF ((" (0)")) ; \
+ } \
+}
+
+/* -------------------------------------------------------------------------- */
+/* Real floating-point arithmetic */
+/* -------------------------------------------------------------------------- */
+
+#ifndef COMPLEX
+
+#define Entry double
+
+#define REAL_COMPONENT(c) (c)
+#define IMAG_COMPONENT(c) (0.)
+#define ASSIGN(c,s1,s2) { (c) = (s1) ; }
+#define CLEAR(c) { (c) = 0. ; }
+#define CLEAR_AND_INCREMENT(p) { *p++ = 0. ; }
+#define IS_NAN(a) SCALAR_IS_NAN (a)
+#define IS_ZERO(a) SCALAR_IS_ZERO (a)
+#define IS_NONZERO(a) SCALAR_IS_NONZERO (a)
+#define SCALE_DIV(c,s) { (c) /= (s) ; }
+#ifndef NRECIPROCAL
+#define SCALE_RECIP(c,s) { (c) *= (s) ; }
+#endif
+#define ASSEMBLE(c,a) { (c) += (a) ; }
+#define ASSEMBLE_AND_INCREMENT(c,p) { (c) += *p++ ; }
+#define DECREMENT(c,a) { (c) -= (a) ; }
+#define MULT(c,a,b) { (c) = (a) * (b) ; }
+#define MULT_CONJ(c,a,b) { (c) = (a) * (b) ; }
+#define MULT_SUB(c,a,b) { (c) -= (a) * (b) ; }
+#define MULT_SUB_CONJ(c,a,b) { (c) -= (a) * (b) ; }
+#define DIV(c,a,b) { (c) = (a) / (b) ; }
+#define RECIPROCAL(c) { (c) = 1.0 / (c) ; }
+#define DIV_CONJ(c,a,b) { (c) = (a) / (b) ; }
+#define APPROX_ABS(s,a) { (s) = SCALAR_ABS (a) ; }
+#define ABS(s,a) { (s) = SCALAR_ABS (a) ; }
+#define PRINT_ENTRY(a) PRINT_SCALAR (a)
+
+/* for flop counts */
+#define MULTSUB_FLOPS 2. /* c -= a*b */
+#define DIV_FLOPS 1. /* c = a/b */
+#define ABS_FLOPS 0. /* c = abs (a) */
+#define ASSEMBLE_FLOPS 1. /* c += a */
+#define DECREMENT_FLOPS 1. /* c -= a */
+#define MULT_FLOPS 1. /* c = a*b */
+#define SCALE_FLOPS 1. /* c = a/s */
+
+#else
+
+/* -------------------------------------------------------------------------- */
+/* Complex floating-point arithmetic */
+/* -------------------------------------------------------------------------- */
+
+/*
+ Note: An alternative to this DoubleComplex type would be to use a
+ struct { double r ; double i ; }. The problem with that method
+ (used by the Sun Performance Library, for example) is that ANSI C provides
+ no guarantee about the layout of a struct. It is possible that the sizeof
+ the struct above would be greater than 2 * sizeof (double). This would
+ mean that the complex BLAS could not be used. The method used here avoids
+ that possibility. ANSI C *does* guarantee that an array of structs has
+ the same size as n times the size of one struct.
+
+ The ANSI C99 version of the C language includes a "double _Complex" type.
+ It should be possible in that case to do the following:
+
+ #define Entry double _Complex
+
+ and remove the DoubleComplex struct. The macros, below, could then be
+ replaced with instrinsic operators. Note that the #define Real and
+ #define Imag should also be removed (they only appear in this file).
+
+ For the MULT, MULT_SUB, MULT_SUB_CONJ, and MULT_CONJ macros,
+ the output argument c cannot be the same as any input argument.
+
+*/
+
+typedef struct
+{
+ double component [2] ; /* real and imaginary parts */
+
+} DoubleComplex ;
+
+#define Entry DoubleComplex
+#define Real component [0]
+#define Imag component [1]
+
+/* for flop counts */
+#define MULTSUB_FLOPS 8. /* c -= a*b */
+#define DIV_FLOPS 9. /* c = a/b */
+#define ABS_FLOPS 6. /* c = abs (a), count sqrt as one flop */
+#define ASSEMBLE_FLOPS 2. /* c += a */
+#define DECREMENT_FLOPS 2. /* c -= a */
+#define MULT_FLOPS 6. /* c = a*b */
+#define SCALE_FLOPS 2. /* c = a/s or c = a*s */
+
+/* -------------------------------------------------------------------------- */
+
+/* real part of c */
+#define REAL_COMPONENT(c) ((c).Real)
+
+/* -------------------------------------------------------------------------- */
+
+/* imag part of c */
+#define IMAG_COMPONENT(c) ((c).Imag)
+
+/* -------------------------------------------------------------------------- */
+
+/* c = (s1) + (s2)i */
+#define ASSIGN(c,s1,s2) \
+{ \
+ (c).Real = (s1) ; \
+ (c).Imag = (s2) ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c = 0 */
+#define CLEAR(c) \
+{ \
+ (c).Real = 0. ; \
+ (c).Imag = 0. ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* *p++ = 0 */
+#define CLEAR_AND_INCREMENT(p) \
+{ \
+ p->Real = 0. ; \
+ p->Imag = 0. ; \
+ p++ ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* True if a == 0 */
+#define IS_ZERO(a) \
+ (SCALAR_IS_ZERO ((a).Real) && SCALAR_IS_ZERO ((a).Imag))
+
+/* -------------------------------------------------------------------------- */
+
+/* True if a is NaN */
+#define IS_NAN(a) \
+ (SCALAR_IS_NAN ((a).Real) || SCALAR_IS_NAN ((a).Imag))
+
+/* -------------------------------------------------------------------------- */
+
+/* True if a != 0 */
+#define IS_NONZERO(a) \
+ (SCALAR_IS_NONZERO ((a).Real) || SCALAR_IS_NONZERO ((a).Imag))
+
+/* -------------------------------------------------------------------------- */
+
+/* c /= s */
+#define SCALE_DIV(c,s) \
+{ \
+ (c).Real /= (s) ; \
+ (c).Imag /= (s) ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c *= s, where s is the reciprocal scale factor. Not used if
+ * NRECIPROCAL is defined at compile time. */
+#ifndef NRECIPROCAL
+#define SCALE_RECIP(c,s) \
+{ \
+ (c).Real *= (s) ; \
+ (c).Imag *= (s) ; \
+}
+#endif
+
+/* -------------------------------------------------------------------------- */
+
+/* c += a */
+#define ASSEMBLE(c,a) \
+{ \
+ (c).Real += (a).Real ; \
+ (c).Imag += (a).Imag ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c += *p++ */
+#define ASSEMBLE_AND_INCREMENT(c,p) \
+{ \
+ (c).Real += p->Real ; \
+ (c).Imag += p->Imag ; \
+ p++ ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c -= a */
+#define DECREMENT(c,a) \
+{ \
+ (c).Real -= (a).Real ; \
+ (c).Imag -= (a).Imag ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c = a*b, assert because c cannot be the same as a or b */
+#define MULT(c,a,b) \
+{ \
+ ASSERT (&(c) != &(a) && &(c) != &(b)) ; \
+ (c).Real = (a).Real * (b).Real - (a).Imag * (b).Imag ; \
+ (c).Imag = (a).Imag * (b).Real + (a).Real * (b).Imag ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c = a*conjugate(b), assert because c cannot be the same as a or b */
+#define MULT_CONJ(c,a,b) \
+{ \
+ ASSERT (&(c) != &(a) && &(c) != &(b)) ; \
+ (c).Real = (a).Real * (b).Real + (a).Imag * (b).Imag ; \
+ (c).Imag = (a).Imag * (b).Real - (a).Real * (b).Imag ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c -= a*b, assert because c cannot be the same as a or b */
+#define MULT_SUB(c,a,b) \
+{ \
+ ASSERT (&(c) != &(a) && &(c) != &(b)) ; \
+ (c).Real -= (a).Real * (b).Real - (a).Imag * (b).Imag ; \
+ (c).Imag -= (a).Imag * (b).Real + (a).Real * (b).Imag ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c -= a*conjugate(b), assert because c cannot be the same as a or b */
+#define MULT_SUB_CONJ(c,a,b) \
+{ \
+ ASSERT (&(c) != &(a) && &(c) != &(b)) ; \
+ (c).Real -= (a).Real * (b).Real + (a).Imag * (b).Imag ; \
+ (c).Imag -= (a).Imag * (b).Real - (a).Real * (b).Imag ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* c = a/b, be careful to avoid underflow and overflow */
+#ifdef MATHWORKS
+#define DIV(c,a,b) \
+{ \
+ (void) utDivideComplex ((a).Real, (a).Imag, (b).Real, (b).Imag, \
+ &((c).Real), &((c).Imag)) ; \
+}
+#else
+/* This uses ACM Algo 116, by R. L. Smith, 1962. */
+/* c can be the same variable as a or b. */
+/* Ignore NaN case for double relop br>=bi. */
+#define DIV(c,a,b) \
+{ \
+ double r, den, ar, ai, br, bi ; \
+ br = (b).Real ; \
+ bi = (b).Imag ; \
+ ar = (a).Real ; \
+ ai = (a).Imag ; \
+ if (SCALAR_ABS (br) >= SCALAR_ABS (bi)) \
+ { \
+ r = bi / br ; \
+ den = br + r * bi ; \
+ (c).Real = (ar + ai * r) / den ; \
+ (c).Imag = (ai - ar * r) / den ; \
+ } \
+ else \
+ { \
+ r = br / bi ; \
+ den = r * br + bi ; \
+ (c).Real = (ar * r + ai) / den ; \
+ (c).Imag = (ai * r - ar) / den ; \
+ } \
+}
+#endif
+
+/* -------------------------------------------------------------------------- */
+
+/* c = 1/c, be careful to avoid underflow and overflow */
+/* Not used if MATHWORKS is defined. */
+/* This uses ACM Algo 116, by R. L. Smith, 1962. */
+/* Ignore NaN case for double relop cr>=ci. */
+#define RECIPROCAL(c) \
+{ \
+ double r, den, cr, ci ; \
+ cr = (c).Real ; \
+ ci = (c).Imag ; \
+ if (SCALAR_ABS (cr) >= SCALAR_ABS (ci)) \
+ { \
+ r = ci / cr ; \
+ den = cr + r * ci ; \
+ (c).Real = 1.0 / den ; \
+ (c).Imag = - r / den ; \
+ } \
+ else \
+ { \
+ r = cr / ci ; \
+ den = r * cr + ci ; \
+ (c).Real = r / den ; \
+ (c).Imag = - 1.0 / den ; \
+ } \
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+/* c = a/conjugate(b), be careful to avoid underflow and overflow */
+#ifdef MATHWORKS
+#define DIV_CONJ(c,a,b) \
+{ \
+ (void) utDivideComplex ((a).Real, (a).Imag, (b).Real, (-(b).Imag), \
+ &((c).Real), &((c).Imag)) ; \
+}
+#else
+/* This uses ACM Algo 116, by R. L. Smith, 1962. */
+/* c can be the same variable as a or b. */
+/* Ignore NaN case for double relop br>=bi. */
+#define DIV_CONJ(c,a,b) \
+{ \
+ double r, den, ar, ai, br, bi ; \
+ br = (b).Real ; \
+ bi = (b).Imag ; \
+ ar = (a).Real ; \
+ ai = (a).Imag ; \
+ if (SCALAR_ABS (br) >= SCALAR_ABS (bi)) \
+ { \
+ r = (-bi) / br ; \
+ den = br - r * bi ; \
+ (c).Real = (ar + ai * r) / den ; \
+ (c).Imag = (ai - ar * r) / den ; \
+ } \
+ else \
+ { \
+ r = br / (-bi) ; \
+ den = r * br - bi; \
+ (c).Real = (ar * r + ai) / den ; \
+ (c).Imag = (ai * r - ar) / den ; \
+ } \
+}
+#endif
+
+/* -------------------------------------------------------------------------- */
+
+/* approximate absolute value, s = |r|+|i| */
+#define APPROX_ABS(s,a) \
+{ \
+ (s) = SCALAR_ABS ((a).Real) + SCALAR_ABS ((a).Imag) ; \
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* exact absolute value, s = sqrt (a.real^2 + amag^2) */
+#ifdef MATHWORKS
+#define ABS(s,a) \
+{ \
+ (s) = utFdlibm_hypot ((a).Real, (a).Imag) ; \
+}
+#else
+/* Ignore NaN case for the double relops ar>=ai and ar+ai==ar. */
+#define ABS(s,a) \
+{ \
+ double r, ar, ai ; \
+ ar = SCALAR_ABS ((a).Real) ; \
+ ai = SCALAR_ABS ((a).Imag) ; \
+ if (ar >= ai) \
+ { \
+ if (ar + ai == ar) \
+ { \
+ (s) = ar ; \
+ } \
+ else \
+ { \
+ r = ai / ar ; \
+ (s) = ar * sqrt (1.0 + r*r) ; \
+ } \
+ } \
+ else \
+ { \
+ if (ai + ar == ai) \
+ { \
+ (s) = ai ; \
+ } \
+ else \
+ { \
+ r = ar / ai ; \
+ (s) = ai * sqrt (1.0 + r*r) ; \
+ } \
+ } \
+}
+#endif
+
+/* -------------------------------------------------------------------------- */
+
+/* print an entry (avoid printing "-0" for negative zero). */
+#define PRINT_ENTRY(a) \
+{ \
+ if (SCALAR_IS_NONZERO ((a).Real)) \
+ { \
+ PRINTF ((" (%g", (a).Real)) ; \
+ } \
+ else \
+ { \
+ PRINTF ((" (0")) ; \
+ } \
+ if (SCALAR_IS_LTZERO ((a).Imag)) \
+ { \
+ PRINTF ((" - %gi)", -(a).Imag)) ; \
+ } \
+ else if (SCALAR_IS_ZERO ((a).Imag)) \
+ { \
+ PRINTF ((" + 0i)")) ; \
+ } \
+ else \
+ { \
+ PRINTF ((" + %gi)", (a).Imag)) ; \
+ } \
+}
+
+/* -------------------------------------------------------------------------- */
+
+#endif /* #ifndef COMPLEX */
+
+/* -------------------------------------------------------------------------- */
+/* Double precision, with int's as integers */
+/* -------------------------------------------------------------------------- */
+
+#ifdef DINT
+
+#define UMF_analyze umf_i_analyze
+#define UMF_apply_order umf_i_apply_order
+#define UMF_assemble umfdi_assemble
+#define UMF_assemble_fixq umfdi_assemble_fixq
+#define UMF_blas3_update umfdi_blas3_update
+#define UMF_build_tuples umfdi_build_tuples
+#define UMF_build_tuples_usage umfdi_build_tuples_usage
+#define UMF_colamd umf_i_colamd
+#define UMF_colamd_set_defaults umf_i_colamd_set_defaults
+#define UMF_create_element umfdi_create_element
+#define UMF_extend_front umfdi_extend_front
+#define UMF_free umf_i_free
+#define UMF_fsize umf_i_fsize
+#define UMF_garbage_collection umfdi_garbage_collection
+#define UMF_get_memory umfdi_get_memory
+#define UMF_grow_front umfdi_grow_front
+#define UMF_init_front umfdi_init_front
+#define UMF_is_permutation umf_i_is_permutation
+#define UMF_kernel umfdi_kernel
+#define UMF_kernel_init umfdi_kernel_init
+#define UMF_kernel_init_usage umfdi_kernel_init_usage
+#define UMF_kernel_wrapup umfdi_kernel_wrapup
+#define UMF_local_search umfdi_local_search
+#define UMF_lsolve umfdi_lsolve
+#define UMF_ltsolve umfdi_ltsolve
+#define UMF_lhsolve umfdi_lhsolve
+#define UMF_malloc umf_i_malloc
+#define UMF_mem_alloc_element umfdi_mem_alloc_element
+#define UMF_mem_alloc_head_block umfdi_mem_alloc_head_block
+#define UMF_mem_alloc_tail_block umfdi_mem_alloc_tail_block
+#define UMF_mem_free_tail_block umfdi_mem_free_tail_block
+#define UMF_mem_init_memoryspace umfdi_mem_init_memoryspace
+#define UMF_realloc umf_i_realloc
+#define UMF_report_perm umf_i_report_perm
+#define UMF_report_vector umfdi_report_vector
+#define UMF_row_search umfdi_row_search
+#define UMF_scale umfdi_scale
+#define UMF_scale_column umfdi_scale_column
+#define UMF_set_stats umf_i_set_stats
+#define UMF_singletons umf_i_singletons
+#define UMF_solve umfdi_solve
+#define UMF_start_front umfdi_start_front
+#define UMF_store_lu umfdi_store_lu
+#define UMF_store_lu_drop umfdi_store_lu_drop
+#define UMF_symbolic_usage umfdi_symbolic_usage
+#define UMF_transpose umfdi_transpose
+#define UMF_tuple_lengths umfdi_tuple_lengths
+#define UMF_usolve umfdi_usolve
+#define UMF_utsolve umfdi_utsolve
+#define UMF_uhsolve umfdi_uhsolve
+#define UMF_valid_numeric umfdi_valid_numeric
+#define UMF_valid_symbolic umfdi_valid_symbolic
+#define UMF_triplet_map_x umfdi_triplet_map_x
+#define UMF_triplet_map_nox umfdi_triplet_map_nox
+#define UMF_triplet_nomap_x umfdi_triplet_nomap_x
+#define UMF_triplet_nomap_nox umfdi_triplet_nomap_nox
+#define UMF_2by2 umfdi_2by2
+
+#define UMFPACK_col_to_triplet umfpack_di_col_to_triplet
+#define UMFPACK_defaults umfpack_di_defaults
+#define UMFPACK_free_numeric umfpack_di_free_numeric
+#define UMFPACK_free_symbolic umfpack_di_free_symbolic
+#define UMFPACK_get_lunz umfpack_di_get_lunz
+#define UMFPACK_get_numeric umfpack_di_get_numeric
+#define UMFPACK_get_symbolic umfpack_di_get_symbolic
+#define UMFPACK_numeric umfpack_di_numeric
+#define UMFPACK_qsymbolic umfpack_di_qsymbolic
+#define UMFPACK_report_control umfpack_di_report_control
+#define UMFPACK_report_info umfpack_di_report_info
+#define UMFPACK_report_matrix umfpack_di_report_matrix
+#define UMFPACK_report_numeric umfpack_di_report_numeric
+#define UMFPACK_report_perm umfpack_di_report_perm
+#define UMFPACK_report_status umfpack_di_report_status
+#define UMFPACK_report_symbolic umfpack_di_report_symbolic
+#define UMFPACK_report_triplet umfpack_di_report_triplet
+#define UMFPACK_report_vector umfpack_di_report_vector
+#define UMFPACK_save_numeric umfpack_di_save_numeric
+#define UMFPACK_save_symbolic umfpack_di_save_symbolic
+#define UMFPACK_load_numeric umfpack_di_load_numeric
+#define UMFPACK_load_symbolic umfpack_di_load_symbolic
+#define UMFPACK_scale umfpack_di_scale
+#define UMFPACK_solve umfpack_di_solve
+#define UMFPACK_symbolic umfpack_di_symbolic
+#define UMFPACK_transpose umfpack_di_transpose
+#define UMFPACK_triplet_to_col umfpack_di_triplet_to_col
+#define UMFPACK_wsolve umfpack_di_wsolve
+
+/* for debugging only: */
+#define UMF_malloc_count umf_i_malloc_count
+#define UMF_debug umfdi_debug
+#define UMF_allocfail umfdi_allocfail
+#define UMF_gprob umfdi_gprob
+#define UMF_dump_dense umfdi_dump_dense
+#define UMF_dump_element umfdi_dump_element
+#define UMF_dump_rowcol umfdi_dump_rowcol
+#define UMF_dump_matrix umfdi_dump_matrix
+#define UMF_dump_current_front umfdi_dump_current_front
+#define UMF_dump_lu umfdi_dump_lu
+#define UMF_dump_memory umfdi_dump_memory
+#define UMF_dump_packed_memory umfdi_dump_packed_memory
+#define UMF_dump_col_matrix umfdi_dump_col_matrix
+#define UMF_dump_chain umfdi_dump_chain
+#define UMF_dump_start umfdi_dump_start
+#define UMF_dump_rowmerge umfdi_dump_rowmerge
+#define UMF_dump_diagonal_map umfdi_dump_diagonal_map
+
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* Double precision, with long's as integers */
+/* -------------------------------------------------------------------------- */
+
+#ifdef DLONG
+
+#define UMF_analyze umf_l_analyze
+#define UMF_apply_order umf_l_apply_order
+#define UMF_assemble umfdl_assemble
+#define UMF_assemble_fixq umfdl_assemble_fixq
+#define UMF_blas3_update umfdl_blas3_update
+#define UMF_build_tuples umfdl_build_tuples
+#define UMF_build_tuples_usage umfdl_build_tuples_usage
+#define UMF_colamd umf_l_colamd
+#define UMF_colamd_set_defaults umf_l_colamd_set_defaults
+#define UMF_create_element umfdl_create_element
+#define UMF_extend_front umfdl_extend_front
+#define UMF_free umf_l_free
+#define UMF_fsize umf_l_fsize
+#define UMF_garbage_collection umfdl_garbage_collection
+#define UMF_get_memory umfdl_get_memory
+#define UMF_grow_front umfdl_grow_front
+#define UMF_init_front umfdl_init_front
+#define UMF_is_permutation umf_l_is_permutation
+#define UMF_kernel umfdl_kernel
+#define UMF_kernel_init umfdl_kernel_init
+#define UMF_kernel_init_usage umfdl_kernel_init_usage
+#define UMF_kernel_wrapup umfdl_kernel_wrapup
+#define UMF_local_search umfdl_local_search
+#define UMF_lsolve umfdl_lsolve
+#define UMF_ltsolve umfdl_ltsolve
+#define UMF_lhsolve umfdl_lhsolve
+#define UMF_malloc umf_l_malloc
+#define UMF_mem_alloc_element umfdl_mem_alloc_element
+#define UMF_mem_alloc_head_block umfdl_mem_alloc_head_block
+#define UMF_mem_alloc_tail_block umfdl_mem_alloc_tail_block
+#define UMF_mem_free_tail_block umfdl_mem_free_tail_block
+#define UMF_mem_init_memoryspace umfdl_mem_init_memoryspace
+#define UMF_realloc umf_l_realloc
+#define UMF_report_perm umf_l_report_perm
+#define UMF_report_vector umfdl_report_vector
+#define UMF_row_search umfdl_row_search
+#define UMF_scale umfdl_scale
+#define UMF_scale_column umfdl_scale_column
+#define UMF_set_stats umf_l_set_stats
+#define UMF_singletons umf_l_singletons
+#define UMF_solve umfdl_solve
+#define UMF_start_front umfdl_start_front
+#define UMF_store_lu umfdl_store_lu
+#define UMF_store_lu_drop umfdl_store_lu_drop
+#define UMF_symbolic_usage umfdl_symbolic_usage
+#define UMF_transpose umfdl_transpose
+#define UMF_tuple_lengths umfdl_tuple_lengths
+#define UMF_usolve umfdl_usolve
+#define UMF_utsolve umfdl_utsolve
+#define UMF_uhsolve umfdl_uhsolve
+#define UMF_valid_numeric umfdl_valid_numeric
+#define UMF_valid_symbolic umfdl_valid_symbolic
+#define UMF_triplet_map_x umfdl_triplet_map_x
+#define UMF_triplet_map_nox umfdl_triplet_map_nox
+#define UMF_triplet_nomap_x umfdl_triplet_nomap_x
+#define UMF_triplet_nomap_nox umfdl_triplet_nomap_nox
+#define UMF_2by2 umfdl_2by2
+
+#define UMFPACK_col_to_triplet umfpack_dl_col_to_triplet
+#define UMFPACK_defaults umfpack_dl_defaults
+#define UMFPACK_free_numeric umfpack_dl_free_numeric
+#define UMFPACK_free_symbolic umfpack_dl_free_symbolic
+#define UMFPACK_get_lunz umfpack_dl_get_lunz
+#define UMFPACK_get_numeric umfpack_dl_get_numeric
+#define UMFPACK_get_symbolic umfpack_dl_get_symbolic
+#define UMFPACK_numeric umfpack_dl_numeric
+#define UMFPACK_qsymbolic umfpack_dl_qsymbolic
+#define UMFPACK_report_control umfpack_dl_report_control
+#define UMFPACK_report_info umfpack_dl_report_info
+#define UMFPACK_report_matrix umfpack_dl_report_matrix
+#define UMFPACK_report_numeric umfpack_dl_report_numeric
+#define UMFPACK_report_perm umfpack_dl_report_perm
+#define UMFPACK_report_status umfpack_dl_report_status
+#define UMFPACK_report_symbolic umfpack_dl_report_symbolic
+#define UMFPACK_report_triplet umfpack_dl_report_triplet
+#define UMFPACK_report_vector umfpack_dl_report_vector
+#define UMFPACK_save_numeric umfpack_dl_save_numeric
+#define UMFPACK_save_symbolic umfpack_dl_save_symbolic
+#define UMFPACK_load_numeric umfpack_dl_load_numeric
+#define UMFPACK_load_symbolic umfpack_dl_load_symbolic
+#define UMFPACK_scale umfpack_dl_scale
+#define UMFPACK_solve umfpack_dl_solve
+#define UMFPACK_symbolic umfpack_dl_symbolic
+#define UMFPACK_transpose umfpack_dl_transpose
+#define UMFPACK_triplet_to_col umfpack_dl_triplet_to_col
+#define UMFPACK_wsolve umfpack_dl_wsolve
+
+/* for debugging only: */
+#define UMF_malloc_count umf_l_malloc_count
+#define UMF_debug umfdl_debug
+#define UMF_allocfail umfdl_allocfail
+#define UMF_gprob umfdl_gprob
+#define UMF_dump_dense umfdl_dump_dense
+#define UMF_dump_element umfdl_dump_element
+#define UMF_dump_rowcol umfdl_dump_rowcol
+#define UMF_dump_matrix umfdl_dump_matrix
+#define UMF_dump_current_front umfdl_dump_current_front
+#define UMF_dump_lu umfdl_dump_lu
+#define UMF_dump_memory umfdl_dump_memory
+#define UMF_dump_packed_memory umfdl_dump_packed_memory
+#define UMF_dump_col_matrix umfdl_dump_col_matrix
+#define UMF_dump_chain umfdl_dump_chain
+#define UMF_dump_start umfdl_dump_start
+#define UMF_dump_rowmerge umfdl_dump_rowmerge
+#define UMF_dump_diagonal_map umfdl_dump_diagonal_map
+
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* Complex double precision, with int's as integers */
+/* -------------------------------------------------------------------------- */
+
+#ifdef ZINT
+
+#define UMF_analyze umf_i_analyze
+#define UMF_apply_order umf_i_apply_order
+#define UMF_assemble umfzi_assemble
+#define UMF_assemble_fixq umfzi_assemble_fixq
+#define UMF_blas3_update umfzi_blas3_update
+#define UMF_build_tuples umfzi_build_tuples
+#define UMF_build_tuples_usage umfzi_build_tuples_usage
+#define UMF_colamd umf_i_colamd
+#define UMF_colamd_set_defaults umf_i_colamd_set_defaults
+#define UMF_create_element umfzi_create_element
+#define UMF_extend_front umfzi_extend_front
+#define UMF_free umf_i_free
+#define UMF_fsize umf_i_fsize
+#define UMF_garbage_collection umfzi_garbage_collection
+#define UMF_get_memory umfzi_get_memory
+#define UMF_grow_front umfzi_grow_front
+#define UMF_init_front umfzi_init_front
+#define UMF_is_permutation umf_i_is_permutation
+#define UMF_kernel umfzi_kernel
+#define UMF_kernel_init umfzi_kernel_init
+#define UMF_kernel_init_usage umfzi_kernel_init_usage
+#define UMF_kernel_wrapup umfzi_kernel_wrapup
+#define UMF_local_search umfzi_local_search
+#define UMF_lsolve umfzi_lsolve
+#define UMF_ltsolve umfzi_ltsolve
+#define UMF_lhsolve umfzi_lhsolve
+#define UMF_malloc umf_i_malloc
+#define UMF_mem_alloc_element umfzi_mem_alloc_element
+#define UMF_mem_alloc_head_block umfzi_mem_alloc_head_block
+#define UMF_mem_alloc_tail_block umfzi_mem_alloc_tail_block
+#define UMF_mem_free_tail_block umfzi_mem_free_tail_block
+#define UMF_mem_init_memoryspace umfzi_mem_init_memoryspace
+#define UMF_realloc umf_i_realloc
+#define UMF_report_perm umf_i_report_perm
+#define UMF_report_vector umfzi_report_vector
+#define UMF_row_search umfzi_row_search
+#define UMF_scale umfzi_scale
+#define UMF_scale_column umfzi_scale_column
+#define UMF_set_stats umfzi_set_stats
+#define UMF_singletons umf_i_singletons
+#define UMF_solve umfzi_solve
+#define UMF_start_front umfzi_start_front
+#define UMF_store_lu umfzi_store_lu
+#define UMF_store_lu_drop umfzi_store_lu_drop
+#define UMF_symbolic_usage umfzi_symbolic_usage
+#define UMF_transpose umfzi_transpose
+#define UMF_tuple_lengths umfzi_tuple_lengths
+#define UMF_usolve umfzi_usolve
+#define UMF_utsolve umfzi_utsolve
+#define UMF_uhsolve umfzi_uhsolve
+#define UMF_valid_numeric umfzi_valid_numeric
+#define UMF_valid_symbolic umfzi_valid_symbolic
+#define UMF_triplet_map_x umfzi_triplet_map_x
+#define UMF_triplet_map_nox umfzi_triplet_map_nox
+#define UMF_triplet_nomap_x umfzi_triplet_nomap_x
+#define UMF_triplet_nomap_nox umfzi_triplet_nomap_nox
+#define UMF_2by2 umfzi_2by2
+
+#define UMFPACK_col_to_triplet umfpack_zi_col_to_triplet
+#define UMFPACK_defaults umfpack_zi_defaults
+#define UMFPACK_free_numeric umfpack_zi_free_numeric
+#define UMFPACK_free_symbolic umfpack_zi_free_symbolic
+#define UMFPACK_get_lunz umfpack_zi_get_lunz
+#define UMFPACK_get_numeric umfpack_zi_get_numeric
+#define UMFPACK_get_symbolic umfpack_zi_get_symbolic
+#define UMFPACK_numeric umfpack_zi_numeric
+#define UMFPACK_qsymbolic umfpack_zi_qsymbolic
+#define UMFPACK_report_control umfpack_zi_report_control
+#define UMFPACK_report_info umfpack_zi_report_info
+#define UMFPACK_report_matrix umfpack_zi_report_matrix
+#define UMFPACK_report_numeric umfpack_zi_report_numeric
+#define UMFPACK_report_perm umfpack_zi_report_perm
+#define UMFPACK_report_status umfpack_zi_report_status
+#define UMFPACK_report_symbolic umfpack_zi_report_symbolic
+#define UMFPACK_report_triplet umfpack_zi_report_triplet
+#define UMFPACK_report_vector umfpack_zi_report_vector
+#define UMFPACK_save_numeric umfpack_zi_save_numeric
+#define UMFPACK_save_symbolic umfpack_zi_save_symbolic
+#define UMFPACK_load_numeric umfpack_zi_load_numeric
+#define UMFPACK_load_symbolic umfpack_zi_load_symbolic
+#define UMFPACK_scale umfpack_zi_scale
+#define UMFPACK_solve umfpack_zi_solve
+#define UMFPACK_symbolic umfpack_zi_symbolic
+#define UMFPACK_transpose umfpack_zi_transpose
+#define UMFPACK_triplet_to_col umfpack_zi_triplet_to_col
+#define UMFPACK_wsolve umfpack_zi_wsolve
+
+/* for debugging only: */
+#define UMF_malloc_count umf_i_malloc_count
+#define UMF_debug umfzi_debug
+#define UMF_allocfail umfzi_allocfail
+#define UMF_gprob umfzi_gprob
+#define UMF_dump_dense umfzi_dump_dense
+#define UMF_dump_element umfzi_dump_element
+#define UMF_dump_rowcol umfzi_dump_rowcol
+#define UMF_dump_matrix umfzi_dump_matrix
+#define UMF_dump_current_front umfzi_dump_current_front
+#define UMF_dump_lu umfzi_dump_lu
+#define UMF_dump_memory umfzi_dump_memory
+#define UMF_dump_packed_memory umfzi_dump_packed_memory
+#define UMF_dump_col_matrix umfzi_dump_col_matrix
+#define UMF_dump_chain umfzi_dump_chain
+#define UMF_dump_start umfzi_dump_start
+#define UMF_dump_rowmerge umfzi_dump_rowmerge
+#define UMF_dump_diagonal_map umfzi_dump_diagonal_map
+
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* Complex double precision, with long's as integers */
+/* -------------------------------------------------------------------------- */
+
+#ifdef ZLONG
+
+#define UMF_analyze umf_l_analyze
+#define UMF_apply_order umf_l_apply_order
+#define UMF_assemble umfzl_assemble
+#define UMF_assemble_fixq umfzl_assemble_fixq
+#define UMF_blas3_update umfzl_blas3_update
+#define UMF_build_tuples umfzl_build_tuples
+#define UMF_build_tuples_usage umfzl_build_tuples_usage
+#define UMF_colamd umf_l_colamd
+#define UMF_colamd_set_defaults umf_l_colamd_set_defaults
+#define UMF_create_element umfzl_create_element
+#define UMF_extend_front umfzl_extend_front
+#define UMF_free umf_l_free
+#define UMF_fsize umf_l_fsize
+#define UMF_garbage_collection umfzl_garbage_collection
+#define UMF_get_memory umfzl_get_memory
+#define UMF_grow_front umfzl_grow_front
+#define UMF_init_front umfzl_init_front
+#define UMF_is_permutation umf_l_is_permutation
+#define UMF_kernel umfzl_kernel
+#define UMF_kernel_init umfzl_kernel_init
+#define UMF_kernel_init_usage umfzl_kernel_init_usage
+#define UMF_kernel_wrapup umfzl_kernel_wrapup
+#define UMF_local_search umfzl_local_search
+#define UMF_lsolve umfzl_lsolve
+#define UMF_ltsolve umfzl_ltsolve
+#define UMF_lhsolve umfzl_lhsolve
+#define UMF_malloc umf_l_malloc
+#define UMF_mem_alloc_element umfzl_mem_alloc_element
+#define UMF_mem_alloc_head_block umfzl_mem_alloc_head_block
+#define UMF_mem_alloc_tail_block umfzl_mem_alloc_tail_block
+#define UMF_mem_free_tail_block umfzl_mem_free_tail_block
+#define UMF_mem_init_memoryspace umfzl_mem_init_memoryspace
+#define UMF_realloc umf_l_realloc
+#define UMF_report_perm umf_l_report_perm
+#define UMF_report_vector umfzl_report_vector
+#define UMF_row_search umfzl_row_search
+#define UMF_scale umfzl_scale
+#define UMF_scale_column umfzl_scale_column
+#define UMF_set_stats umfzl_set_stats
+#define UMF_singletons umf_l_singletons
+#define UMF_solve umfzl_solve
+#define UMF_start_front umfzl_start_front
+#define UMF_store_lu umfzl_store_lu
+#define UMF_store_lu_drop umfzl_store_lu_drop
+#define UMF_symbolic_usage umfzl_symbolic_usage
+#define UMF_transpose umfzl_transpose
+#define UMF_tuple_lengths umfzl_tuple_lengths
+#define UMF_usolve umfzl_usolve
+#define UMF_utsolve umfzl_utsolve
+#define UMF_uhsolve umfzl_uhsolve
+#define UMF_valid_numeric umfzl_valid_numeric
+#define UMF_valid_symbolic umfzl_valid_symbolic
+#define UMF_triplet_map_x umfzl_triplet_map_x
+#define UMF_triplet_map_nox umfzl_triplet_map_nox
+#define UMF_triplet_nomap_x umfzl_triplet_nomap_x
+#define UMF_triplet_nomap_nox umfzl_triplet_nomap_nox
+#define UMF_2by2 umfzl_2by2
+
+#define UMFPACK_col_to_triplet umfpack_zl_col_to_triplet
+#define UMFPACK_defaults umfpack_zl_defaults
+#define UMFPACK_free_numeric umfpack_zl_free_numeric
+#define UMFPACK_free_symbolic umfpack_zl_free_symbolic
+#define UMFPACK_get_lunz umfpack_zl_get_lunz
+#define UMFPACK_get_numeric umfpack_zl_get_numeric
+#define UMFPACK_get_symbolic umfpack_zl_get_symbolic
+#define UMFPACK_numeric umfpack_zl_numeric
+#define UMFPACK_qsymbolic umfpack_zl_qsymbolic
+#define UMFPACK_report_control umfpack_zl_report_control
+#define UMFPACK_report_info umfpack_zl_report_info
+#define UMFPACK_report_matrix umfpack_zl_report_matrix
+#define UMFPACK_report_numeric umfpack_zl_report_numeric
+#define UMFPACK_report_perm umfpack_zl_report_perm
+#define UMFPACK_report_status umfpack_zl_report_status
+#define UMFPACK_report_symbolic umfpack_zl_report_symbolic
+#define UMFPACK_report_triplet umfpack_zl_report_triplet
+#define UMFPACK_report_vector umfpack_zl_report_vector
+#define UMFPACK_save_numeric umfpack_zl_save_numeric
+#define UMFPACK_save_symbolic umfpack_zl_save_symbolic
+#define UMFPACK_load_numeric umfpack_zl_load_numeric
+#define UMFPACK_load_symbolic umfpack_zl_load_symbolic
+#define UMFPACK_scale umfpack_zl_scale
+#define UMFPACK_solve umfpack_zl_solve
+#define UMFPACK_symbolic umfpack_zl_symbolic
+#define UMFPACK_transpose umfpack_zl_transpose
+#define UMFPACK_triplet_to_col umfpack_zl_triplet_to_col
+#define UMFPACK_wsolve umfpack_zl_wsolve
+
+/* for debugging only: */
+#define UMF_malloc_count umf_l_malloc_count
+#define UMF_debug umfzl_debug
+#define UMF_allocfail umfzl_allocfail
+#define UMF_gprob umfzl_gprob
+#define UMF_dump_dense umfzl_dump_dense
+#define UMF_dump_element umfzl_dump_element
+#define UMF_dump_rowcol umfzl_dump_rowcol
+#define UMF_dump_matrix umfzl_dump_matrix
+#define UMF_dump_current_front umfzl_dump_current_front
+#define UMF_dump_lu umfzl_dump_lu
+#define UMF_dump_memory umfzl_dump_memory
+#define UMF_dump_packed_memory umfzl_dump_packed_memory
+#define UMF_dump_col_matrix umfzl_dump_col_matrix
+#define UMF_dump_chain umfzl_dump_chain
+#define UMF_dump_start umfzl_dump_start
+#define UMF_dump_rowmerge umfzl_dump_rowmerge
+#define UMF_dump_diagonal_map umfzl_dump_diagonal_map
+
+#endif
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_col_to_triplet =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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. Converts a column-oriented input matrix to triplet form by
+ constructing the column indices Tj from the column pointers Ap. The matrix
+ may be singular. See umfpack_col_to_triplet.h for details.
+
+*/
+
+#include "umf_internal.h"
+
+GLOBAL Int UMFPACK_col_to_triplet
+(
+ Int n_col,
+ const Int Ap [ ],
+ Int Tj [ ]
+)
+{
+
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int nz, j, p, p1, p2, length ;
+
+ /* ---------------------------------------------------------------------- */
+ /* construct the column indices */
+ /* ---------------------------------------------------------------------- */
+
+ if (!Ap || !Tj)
+ {
+ return (UMFPACK_ERROR_argument_missing) ;
+ }
+ if (n_col <= 0)
+ {
+ return (UMFPACK_ERROR_n_nonpositive) ;
+ }
+ if (Ap [0] != 0)
+ {
+ return (UMFPACK_ERROR_invalid_matrix) ;
+ }
+ nz = Ap [n_col] ;
+ if (nz < 0)
+ {
+ return (UMFPACK_ERROR_invalid_matrix) ;
+ }
+
+ for (j = 0 ; j < n_col ; j++)
+ {
+ p1 = Ap [j] ;
+ p2 = Ap [j+1] ;
+ length = p2 - p1 ;
+ if (length < 0 || p2 > nz)
+ {
+ return (UMFPACK_ERROR_invalid_matrix) ;
+ }
+ for (p = p1 ; p < p2 ; p++)
+ {
+ Tj [p] = j ;
+ }
+ }
+
+ return (UMFPACK_OK) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_defaults ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 ;
+ Control [UMFPACK_AMD_DENSE] = UMFPACK_DEFAULT_AMD_DENSE ;
+ Control [UMFPACK_STRATEGY] = UMFPACK_DEFAULT_STRATEGY ;
+ Control [UMFPACK_2BY2_TOLERANCE] = UMFPACK_DEFAULT_2BY2_TOLERANCE ;
+ Control [UMFPACK_AGGRESSIVE] = UMFPACK_DEFAULT_AGGRESSIVE ;
+
+ /* used in UMFPACK_numeric: */
+ Control [UMFPACK_PIVOT_TOLERANCE] = UMFPACK_DEFAULT_PIVOT_TOLERANCE ;
+ Control [UMFPACK_SYM_PIVOT_TOLERANCE] = UMFPACK_DEFAULT_SYM_PIVOT_TOLERANCE;
+ Control [UMFPACK_BLOCK_SIZE] = UMFPACK_DEFAULT_BLOCK_SIZE ;
+ Control [UMFPACK_ALLOC_INIT] = UMFPACK_DEFAULT_ALLOC_INIT ;
+ Control [UMFPACK_FRONT_ALLOC_INIT] = UMFPACK_DEFAULT_FRONT_ALLOC_INIT ;
+ Control [UMFPACK_SCALE] = UMFPACK_DEFAULT_SCALE ;
+
+ /* used in UMFPACK_*solve: */
+ Control [UMFPACK_IRSTEP] = UMFPACK_DEFAULT_IRSTEP ;
+
+ /* ---------------------------------------------------------------------- */
+ /* compile-time settings: cannot be modified at run-time */
+ /* ---------------------------------------------------------------------- */
+
+#ifdef USE_NO_BLAS
+ /* do not use the BLAS - use in-line C code instead */
+ Control [UMFPACK_COMPILED_WITH_BLAS] = 0 ;
+#else
+ /* use externally-provided BLAS (dgemm, dger, dgemv, zgemm, zgeru, zgemv) */
+ Control [UMFPACK_COMPILED_WITH_BLAS] = 1 ;
+#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 NO_TIMER
+ /* no timer used */
+ Control [UMFPACK_COMPILED_WITH_GETRUSAGE] = 3 ;
+#ifndef NPOSIX
+ /* uses the POSIX sysconf ( ) and times ( ) routines in UMFPACK_tic, toc */
+ Control [UMFPACK_COMPILED_WITH_GETRUSAGE] = 2 ;
+#else
+#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
+#endif
+#endif
+
+#ifndef NDEBUG
+ /* UMFPACK is compiled in debug mode. */
+ /* This is exceedingly slow. */
+ DEBUG0 (("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
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_free_numeric ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 (consists of 11 to 13
+ * malloc'd objects. 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 ;
+ }
+
+ /* these 9 objects always exist */
+ (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) ;
+
+ /* Rs does not exist if scaling was not performed */
+ (void) UMF_free ((void *) Numeric->Rs) ;
+
+ /* Upattern can only exist for singular or rectangular matrices */
+ (void) UMF_free ((void *) Numeric->Upattern) ;
+
+ /* these 2 objects always exist */
+ (void) UMF_free ((void *) Numeric->Memory) ;
+ (void) UMF_free ((void *) Numeric) ;
+
+ *NumericHandle = (void *) NULL ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_free_symbolic ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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->Cdeg) ;
+ (void) UMF_free ((void *) Symbolic->Rdeg) ;
+
+ /* only when dense rows are present */
+ (void) UMF_free ((void *) Symbolic->Esize) ;
+
+ /* only when diagonal pivoting is prefered */
+ (void) UMF_free ((void *) Symbolic->Diagonal_map) ;
+
+ (void) UMF_free ((void *) Symbolic) ;
+ *SymbolicHandle = (void *) NULL ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_get_lunz ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_get_numeric ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 [ ]
+) ;
+
+/* ========================================================================== */
+/* === UMFPACK_get_numeric ================================================== */
+/* ========================================================================== */
+
+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
+ Int *p_do_recip,
+ double Rs [ ],
+ void *NumericHandle
+)
+{
+
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ NumericType *Numeric ;
+ Int getL, getU, *Rperm, *Cperm, k, nn, n_row, n_col, *Wi, *Pattern,
+ n_inner ;
+ double *Rs1 ;
+ Entry *D ;
+
+#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) ;
+ DEBUGm4 (("out of memory: get numeric\n")) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+ ASSERT (UMF_malloc_count == init_count + 2) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* get contents of Numeric */
+ /* ---------------------------------------------------------------------- */
+
+ if (P != (Int *) NULL)
+ {
+ Rperm = Numeric->Rperm ;
+ for (k = 0 ; k < n_row ; k++)
+ {
+ P [k] = Rperm [k] ;
+ }
+ }
+
+ if (Q != (Int *) NULL)
+ {
+ 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 != (double *) NULL)
+ {
+ D = Numeric->D ;
+ for (k = 0 ; k < n_inner ; k++)
+ {
+ Dx [k] = REAL_COMPONENT (D [k]) ;
+ }
+ }
+
+#ifdef COMPLEX
+ if (Dz != (double *) NULL)
+ {
+ D = Numeric->D ;
+ for (k = 0 ; k < n_inner ; k++)
+ {
+ Dz [k] = IMAG_COMPONENT (D [k]) ;
+ }
+ }
+#endif
+
+ /* return the flag stating whether the scale factors are to be multiplied,
+ * or divided. If do_recip is TRUE, multiply. Otherwise, divided.
+ * If NRECIPROCAL is defined at compile time, the scale factors are always
+ * to be used by dividing.
+ */
+ if (p_do_recip != (Int *) NULL)
+ {
+#ifndef NRECIPROCAL
+ *p_do_recip = Numeric->do_recip ;
+#else
+ *p_do_recip = FALSE ;
+#endif
+ }
+
+ if (Rs != (double *) NULL)
+ {
+ Rs1 = Numeric->Rs ;
+ if (Rs1 == (double *) NULL)
+ {
+ /* R is the identity matrix. */
+ for (k = 0 ; k < n_row ; k++)
+ {
+ Rs [k] = 1.0 ;
+ }
+ }
+ else
+ {
+ for (k = 0 ; k < n_row ; k++)
+ {
+ Rs [k] = Rs1 [k] ;
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* 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, *Li, n1 ;
+ Entry *xp, value, *Lval ;
+
+ /* ---------------------------------------------------------------------- */
+ /* 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 ;
+ n1 = Numeric->n1 ;
+ Lpos = Numeric->Lpos ;
+ Lilen = Numeric->Lilen ;
+ Lip = Numeric->Lip ;
+ deg = 0 ;
+
+ /* ---------------------------------------------------------------------- */
+ /* count the nonzeros in each row of L */
+ /* ---------------------------------------------------------------------- */
+
+#pragma ivdep
+ for (row = 0 ; row < n_inner ; row++)
+ {
+ /* include the diagonal entry in the row counts */
+ Wi [row] = 1 ;
+ }
+#pragma ivdep
+ for (row = n_inner ; row < n_row ; row++)
+ {
+ Wi [row] = 0 ;
+ }
+
+ /* singletons */
+ for (k = 0 ; k < n1 ; k++)
+ {
+ DEBUG4 (("Singleton k "ID"\n", k)) ;
+ deg = Lilen [k] ;
+ if (deg > 0)
+ {
+ lp = Lip [k] ;
+ Li = (Int *) (Numeric->Memory + lp) ;
+ lp += UNITS (Int, deg) ;
+ Lval = (Entry *) (Numeric->Memory + lp) ;
+ for (j = 0 ; j < deg ; j++)
+ {
+ row = Li [j] ;
+ value = Lval [j] ;
+ DEBUG4 ((" row "ID" k "ID" value", row, k)) ;
+ EDEBUG4 (value) ;
+ DEBUG4 (("\n")) ;
+ if (IS_NONZERO (value))
+ {
+ Wi [row]++ ;
+ }
+ }
+ }
+ }
+
+ /* non-singletons */
+ for (k = n1 ; 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 (singletons) */
+ for (k = 0 ; k < n1 ; k++)
+ {
+ DEBUG4 (("Singleton k "ID"\n", k)) ;
+ deg = Lilen [k] ;
+ if (deg > 0)
+ {
+ lp = Lip [k] ;
+ Li = (Int *) (Numeric->Memory + lp) ;
+ lp += UNITS (Int, deg) ;
+ Lval = (Entry *) (Numeric->Memory + lp) ;
+ for (j = 0 ; j < deg ; j++)
+ {
+ row = Li [j] ;
+ value = Lval [j] ;
+ DEBUG4 ((" row "ID" k "ID" value", row, k)) ;
+ 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 entries from the rows of L (non-singletons) */
+ for (k = n1 ; 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, *Usi,
+ unz2, p, k, up, newUchain, pos, npiv, n1 ;
+ Entry *xp, *D, value, *Uval ;
+
+#ifndef NDEBUG
+ Int nnzpiv = 0 ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ DEBUG4 (("get_U start:\n")) ;
+ n_col = Numeric->n_col ;
+ n1 = Numeric->n1 ;
+ 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])) ;
+ }
+ }
+
+ /* non-singletons */
+ for (k = npiv-1 ; k >= n1 ; 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 (k == n1) break ;
+
+ 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 ;
+ }
+ }
+ }
+
+ /* singletons */
+ for (k = n1 - 1 ; k >= 0 ; k--)
+ {
+ deg = Uilen [k] ;
+ DEBUG4 (("Singleton k "ID"\n", k)) ;
+ if (deg > 0)
+ {
+ up = Uip [k] ;
+ Usi = (Int *) (Numeric->Memory + up) ;
+ up += UNITS (Int, deg) ;
+ Uval = (Entry *) (Numeric->Memory + up) ;
+ for (j = 0 ; j < deg ; j++)
+ {
+ col = Usi [j] ;
+ value = Uval [j] ;
+ DEBUG4 ((" k "ID" col "ID" value", k, col)) ;
+ EDEBUG4 (value) ;
+ DEBUG4 (("\n")) ;
+ if (IS_NONZERO (value))
+ {
+ Wi [col]++ ;
+ }
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* 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] ;
+ }
+ }
+
+ /* non-singletons */
+ for (k = npiv-1 ; k >= n1 ; 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 ;
+ }
+ }
+ }
+
+ /* singletons */
+ for (k = n1 - 1 ; k >= 0 ; k--)
+ {
+ deg = Uilen [k] ;
+ DEBUG4 (("Singleton k "ID"\n", k)) ;
+ if (deg > 0)
+ {
+ up = Uip [k] ;
+ Usi = (Int *) (Numeric->Memory + up) ;
+ up += UNITS (Int, deg) ;
+ Uval = (Entry *) (Numeric->Memory + up) ;
+ for (j = 0 ; j < deg ; j++)
+ {
+ col = Usi [j] ;
+ value = Uval [j] ;
+ DEBUG4 ((" k "ID" col "ID" value", k, col)) ;
+ 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
+ }
+ }
+ }
+ }
+
+#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
+
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_get_symbolic ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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_n1, /* number of singletons */
+ Int *p_nz,
+ Int *p_nfr,
+ Int *p_nchains,
+ Int P [ ],
+ Int Q [ ],
+ 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, n1, 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 ;
+ n1 = Symbolic->n1 ;
+ 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_n1)
+ {
+ *p_n1 = n1 ;
+ }
+
+ if (p_nz)
+ {
+ *p_nz = Symbolic->nz ;
+ }
+
+ if (p_nfr)
+ {
+ *p_nfr = nfr ;
+ }
+
+ if (p_nchains)
+ {
+ *p_nchains = nchains ;
+ }
+
+ if (P != (Int *) NULL)
+ {
+ Int *Rperm_init, *Diagonal_map ;
+ Rperm_init = Symbolic->Rperm_init ;
+ Diagonal_map = Symbolic->Diagonal_map ;
+ if (Diagonal_map != (Int *) NULL)
+ {
+ ASSERT (n_row == n_col) ;
+ /* next pivot rows are found in the diagonal map */
+ for (k = 0 ; k < n_row ; k++)
+ {
+ P [k] = Rperm_init [Diagonal_map [k]] ;
+ }
+ }
+ else
+ {
+ /* there is no diagonal map. */
+ for (k = 0 ; k < n_row ; k++)
+ {
+ P [k] = Rperm_init [k] ;
+ }
+ }
+ }
+
+ if (Q != (Int *) NULL)
+ {
+ p = Symbolic->Cperm_init ;
+ for (k = 0 ; k < n_col ; k++)
+ {
+ Q [k] = p [k] ;
+ }
+ }
+
+ if (Front_npivcol != (Int *) NULL)
+ {
+ p = Symbolic->Front_npivcol ;
+ for (k = 0 ; k <= nfr ; k++)
+ {
+ Front_npivcol [k] = p [k] ;
+ }
+ }
+
+ if (Front_parent != (Int *) NULL)
+ {
+ p = Symbolic->Front_parent ;
+ for (k = 0 ; k <= nfr ; k++)
+ {
+ Front_parent [k] = p [k] ;
+ }
+ }
+
+ if (Front_1strow != (Int *) NULL)
+ {
+ p = Symbolic->Front_1strow ;
+ for (k = 0 ; k <= nfr ; k++)
+ {
+ Front_1strow [k] = p [k] ;
+ }
+ }
+
+ if (Front_leftmostdesc != (Int *) NULL)
+ {
+ p = Symbolic->Front_leftmostdesc ;
+ for (k = 0 ; k <= nfr ; k++)
+ {
+ Front_leftmostdesc [k] = p [k] ;
+ }
+ }
+
+ if (Chain_start != (Int *) NULL)
+ {
+ p = Symbolic->Chain_start ;
+ for (k = 0 ; k <= nchains ; k++)
+ {
+ Chain_start [k] = p [k] ;
+ }
+ }
+
+ if (Chain_maxrows != (Int *) NULL)
+ {
+ p = Symbolic->Chain_maxrows ;
+ for (k = 0 ; k < nchains ; k++)
+ {
+ Chain_maxrows [k] = p [k] ;
+ }
+ Chain_maxrows [nchains] = 0 ;
+ }
+
+ if (Chain_maxcols != (Int *) NULL)
+ {
+ p = Symbolic->Chain_maxcols ;
+ for (k = 0 ; k < nchains ; k++)
+ {
+ Chain_maxcols [k] = p [k] ;
+ }
+ Chain_maxcols [nchains] = 0 ;
+ }
+
+ return (UMFPACK_OK) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_load_numeric ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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. Loads a Numeric object from a file created by
+ umfpack_*_save_numeric.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+#define READ(object,type,n) \
+{ \
+ object = (type *) UMF_malloc (n, sizeof (type)) ; \
+ if (object == (type *) NULL) \
+ { \
+ UMFPACK_free_numeric ((void **) &Numeric) ; \
+ fclose (f) ; \
+ return (UMFPACK_ERROR_out_of_memory) ; \
+ } \
+ if (fread (object, sizeof (type), n, f) != n) \
+ { \
+ UMFPACK_free_numeric ((void **) &Numeric) ; \
+ fclose (f) ; \
+ return (UMFPACK_ERROR_file_IO) ; \
+ } \
+ if (ferror (f)) \
+ { \
+ UMFPACK_free_numeric ((void **) &Numeric) ; \
+ fclose (f) ; \
+ return (UMFPACK_ERROR_file_IO) ; \
+ } \
+}
+
+/* ========================================================================== */
+/* === UMFPACK_load_numeric ================================================= */
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_load_numeric
+(
+ void **NumericHandle,
+ char *user_filename
+)
+{
+ NumericType *Numeric ;
+ char *filename ;
+ FILE *f ;
+
+ *NumericHandle = (void *) NULL ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get the filename, or use the default name if filename is NULL */
+ /* ---------------------------------------------------------------------- */
+
+ if (user_filename == (char *) NULL)
+ {
+ filename = "numeric.umf" ;
+ }
+ else
+ {
+ filename = user_filename ;
+ }
+ f = fopen (filename, "rb") ;
+ if (!f)
+ {
+ return (UMFPACK_ERROR_file_IO) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* read the Numeric header from the file, in binary */
+ /* ---------------------------------------------------------------------- */
+
+ Numeric = (NumericType *) UMF_malloc (1, sizeof (NumericType)) ;
+ if (Numeric == (NumericType *) NULL)
+ {
+ fclose (f) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+ if (fread (Numeric, sizeof (NumericType), 1, f) != 1)
+ {
+ (void) UMF_free ((void *) Numeric) ;
+ fclose (f) ;
+ return (UMFPACK_ERROR_file_IO) ;
+ }
+ if (ferror (f))
+ {
+ (void) UMF_free ((void *) Numeric) ;
+ fclose (f) ;
+ return (UMFPACK_ERROR_file_IO) ;
+ }
+
+ if (Numeric->valid != NUMERIC_VALID || Numeric->n_row <= 0 ||
+ Numeric->n_col <= 0 || Numeric->npiv < 0 || Numeric->ulen < 0 ||
+ Numeric->size <= 0)
+ {
+ /* Numeric does not point to a NumericType object */
+ (void) UMF_free ((void *) Numeric) ;
+ fclose (f) ;
+ return (UMFPACK_ERROR_invalid_Numeric_object) ;
+ }
+
+ Numeric->D = (Entry *) NULL ;
+ Numeric->Rperm = (Int *) NULL ;
+ Numeric->Cperm = (Int *) NULL ;
+ Numeric->Lpos = (Int *) NULL ;
+ Numeric->Lilen = (Int *) NULL ;
+ Numeric->Lip = (Int *) NULL ;
+ Numeric->Upos = (Int *) NULL ;
+ Numeric->Uilen = (Int *) NULL ;
+ Numeric->Uip = (Int *) NULL ;
+ Numeric->Rs = (double *) NULL ;
+ Numeric->Memory = (Unit *) NULL ;
+ Numeric->Upattern = (Int *) NULL ;
+
+ /* umfpack_free_numeric can now be safely called if an error occurs */
+
+ /* ---------------------------------------------------------------------- */
+ /* read the rest of the Numeric object */
+ /* ---------------------------------------------------------------------- */
+
+ READ (Numeric->D, Entry, MIN (Numeric->n_row, Numeric->n_col)+1) ;
+ READ (Numeric->Rperm, Int, Numeric->n_row+1) ;
+ READ (Numeric->Cperm, Int, Numeric->n_col+1) ;
+ READ (Numeric->Lpos, Int, Numeric->npiv+1) ;
+ READ (Numeric->Lilen, Int, Numeric->npiv+1) ;
+ READ (Numeric->Lip, Int, Numeric->npiv+1) ;
+ READ (Numeric->Upos, Int, Numeric->npiv+1) ;
+ READ (Numeric->Uilen, Int, Numeric->npiv+1) ;
+ READ (Numeric->Uip, Int, Numeric->npiv+1) ;
+ if (Numeric->scale != UMFPACK_SCALE_NONE)
+ {
+ READ (Numeric->Rs, double, Numeric->n_row) ;
+ }
+ if (Numeric->ulen > 0)
+ {
+ READ (Numeric->Upattern, Int, Numeric->ulen+1) ;
+ }
+ READ (Numeric->Memory, Unit, Numeric->size) ;
+
+ /* close the file */
+ fclose (f) ;
+
+ /* make sure the Numeric object is valid */
+ if (!UMF_valid_numeric (Numeric))
+ {
+ UMFPACK_free_numeric ((void **) &Numeric) ;
+ return (UMFPACK_ERROR_invalid_Numeric_object) ;
+ }
+
+ *NumericHandle = (void *) Numeric ;
+ return (UMFPACK_OK) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_load_symbolic ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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. Loads a Symbolic object from a file created by
+ umfpack_*_save_symbolic.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_symbolic.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+#define READ(object,type,n) \
+{ \
+ object = (type *) UMF_malloc (n, sizeof (type)) ; \
+ if (object == (type *) NULL) \
+ { \
+ UMFPACK_free_symbolic ((void **) &Symbolic) ; \
+ fclose (f) ; \
+ return (UMFPACK_ERROR_out_of_memory) ; \
+ } \
+ if (fread (object, sizeof (type), n, f) != n) \
+ { \
+ UMFPACK_free_symbolic ((void **) &Symbolic) ; \
+ fclose (f) ; \
+ return (UMFPACK_ERROR_file_IO) ; \
+ } \
+ if (ferror (f)) \
+ { \
+ UMFPACK_free_symbolic ((void **) &Symbolic) ; \
+ fclose (f) ; \
+ return (UMFPACK_ERROR_file_IO) ; \
+ } \
+}
+
+/* ========================================================================== */
+/* === UMFPACK_load_symbolic ================================================ */
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_load_symbolic
+(
+ void **SymbolicHandle,
+ char *user_filename
+)
+{
+ SymbolicType *Symbolic ;
+ char *filename ;
+ FILE *f ;
+
+ *SymbolicHandle = (void *) NULL ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get the filename, or use the default name if filename is NULL */
+ /* ---------------------------------------------------------------------- */
+
+ if (user_filename == (char *) NULL)
+ {
+ filename = "symbolic.umf" ;
+ }
+ else
+ {
+ filename = user_filename ;
+ }
+ f = fopen (filename, "rb") ;
+ if (!f)
+ {
+ return (UMFPACK_ERROR_file_IO) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* read the Symbolic header from the file, in binary */
+ /* ---------------------------------------------------------------------- */
+
+ Symbolic = (SymbolicType *) UMF_malloc (1, sizeof (SymbolicType)) ;
+ if (Symbolic == (SymbolicType *) NULL)
+ {
+ fclose (f) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+ if (fread (Symbolic, sizeof (SymbolicType), 1, f) != 1)
+ {
+ (void) UMF_free ((void *) Symbolic) ;
+ fclose (f) ;
+ return (UMFPACK_ERROR_file_IO) ;
+ }
+ if (ferror (f))
+ {
+ (void) UMF_free ((void *) Symbolic) ;
+ fclose (f) ;
+ return (UMFPACK_ERROR_file_IO) ;
+ }
+
+ if (Symbolic->valid != SYMBOLIC_VALID || Symbolic->n_row <= 0 ||
+ Symbolic->n_col <= 0 || Symbolic->nfr < 0 || Symbolic->nchains < 0 ||
+ Symbolic->esize < 0)
+ {
+ /* Symbolic does not point to a Symbolic object */
+ (void) UMF_free ((void *) Symbolic) ;
+ fclose (f) ;
+ return (UMFPACK_ERROR_invalid_Symbolic_object) ;
+ }
+
+ Symbolic->Cperm_init = (Int *) NULL ;
+ Symbolic->Rperm_init = (Int *) NULL ;
+ Symbolic->Front_npivcol = (Int *) NULL ;
+ Symbolic->Front_parent = (Int *) NULL ;
+ Symbolic->Front_1strow = (Int *) NULL ;
+ Symbolic->Front_leftmostdesc = (Int *) NULL ;
+ Symbolic->Chain_start = (Int *) NULL ;
+ Symbolic->Chain_maxrows = (Int *) NULL ;
+ Symbolic->Chain_maxcols = (Int *) NULL ;
+ Symbolic->Cdeg = (Int *) NULL ;
+ Symbolic->Rdeg = (Int *) NULL ;
+ Symbolic->Esize = (Int *) NULL ;
+ Symbolic->Diagonal_map = (Int *) NULL ;
+
+ /* umfpack_free_symbolic can now be safely called if an error occurs */
+
+ /* ---------------------------------------------------------------------- */
+ /* read the rest of the Symbolic object */
+ /* ---------------------------------------------------------------------- */
+
+ READ (Symbolic->Cperm_init, Int, Symbolic->n_col+1) ;
+ READ (Symbolic->Rperm_init, Int, Symbolic->n_row+1) ;
+ READ (Symbolic->Front_npivcol, Int, Symbolic->nfr+1) ;
+ READ (Symbolic->Front_parent, Int, Symbolic->nfr+1) ;
+ READ (Symbolic->Front_1strow, Int, Symbolic->nfr+1) ;
+ READ (Symbolic->Front_leftmostdesc, Int, Symbolic->nfr+1) ;
+ READ (Symbolic->Chain_start, Int, Symbolic->nchains+1) ;
+ READ (Symbolic->Chain_maxrows, Int, Symbolic->nchains+1) ;
+ READ (Symbolic->Chain_maxcols, Int, Symbolic->nchains+1) ;
+ READ (Symbolic->Cdeg, Int, Symbolic->n_col+1) ;
+ READ (Symbolic->Rdeg, Int, Symbolic->n_row+1) ;
+ if (Symbolic->esize > 0)
+ {
+ /* only when dense rows are present */
+ READ (Symbolic->Esize, Int, Symbolic->esize) ;
+ }
+ if (Symbolic->prefer_diagonal)
+ {
+ /* only when diagonal pivoting is prefered */
+ READ (Symbolic->Diagonal_map, Int, Symbolic->n_col+1) ;
+ }
+
+ /* close the file */
+ fclose (f) ;
+
+ /* make sure the Symbolic object is valid */
+ if (!UMF_valid_symbolic (Symbolic))
+ {
+ UMFPACK_free_symbolic ((void **) &Symbolic) ;
+ return (UMFPACK_ERROR_invalid_Symbolic_object) ;
+ }
+
+ *SymbolicHandle = (void *) Symbolic ;
+ return (UMFPACK_OK) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_numeric ====================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 allocation: substantial. See comments (1) through (7),
+ below. If an error occurs, all allocated space is free'd by UMF_free.
+ If successful, the Numeric object contains 11 to 13 objects allocated by
+ UMF_malloc that hold the LU factors of the input matrix.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_symbolic.h"
+#include "umf_set_stats.h"
+#include "umf_kernel.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+#include "umf_realloc.h"
+
+#ifndef NDEBUG
+PRIVATE Int init_count ;
+#endif
+
+PRIVATE Int work_alloc
+(
+ WorkType *Work,
+ SymbolicType *Symbolic
+) ;
+
+PRIVATE void free_work
+(
+ WorkType *Work
+) ;
+
+PRIVATE Int numeric_alloc
+(
+ NumericType **NumericHandle,
+ SymbolicType *Symbolic,
+ double alloc_init,
+ Int scale
+) ;
+
+PRIVATE void error
+(
+ NumericType **Numeric,
+ WorkType *Work
+) ;
+
+
+/* ========================================================================== */
+/* === UMFPACK_numeric ====================================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_numeric
+(
+ const Int Ap [ ],
+ const Int Ai [ ],
+ const double Ax [ ],
+#ifdef COMPLEX
+ const double Az [ ],
+#endif
+ void *SymbolicHandle,
+ void **NumericHandle,
+ const double Control [UMFPACK_CONTROL],
+ double User_Info [UMFPACK_INFO]
+)
+{
+
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ NumericType *Numeric ;
+ SymbolicType *Symbolic ;
+ WorkType WorkSpace, *Work ;
+ Int n_row, n_col, n_inner, newsize, i, status, *inew, npiv, ulen, scale ;
+ Unit *mnew ;
+ double Info2 [UMFPACK_INFO], *Info, alloc_init, relpt, relpt2, droptol,
+ front_alloc_init, stats [2] ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get the amount of time used by the process so far */
+ /* ---------------------------------------------------------------------- */
+
+ umfpack_tic (stats) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* initialize and check inputs */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ UMF_dump_start ( ) ;
+ init_count = UMF_malloc_count ;
+ DEBUGm4 (("\nUMFPACK numeric: U transpose version\n")) ;
+#endif
+
+ /* If front_alloc_init negative then allocate that size of front in
+ * UMF_start_front. If alloc_init negative, then allocate that initial
+ * size of Numeric->Memory. */
+
+ relpt = GET_CONTROL (UMFPACK_PIVOT_TOLERANCE,
+ UMFPACK_DEFAULT_PIVOT_TOLERANCE) ;
+ relpt2 = GET_CONTROL (UMFPACK_SYM_PIVOT_TOLERANCE,
+ UMFPACK_DEFAULT_SYM_PIVOT_TOLERANCE) ;
+ alloc_init = GET_CONTROL (UMFPACK_ALLOC_INIT, UMFPACK_DEFAULT_ALLOC_INIT) ;
+ front_alloc_init = GET_CONTROL (UMFPACK_FRONT_ALLOC_INIT,
+ UMFPACK_DEFAULT_FRONT_ALLOC_INIT) ;
+ scale = GET_CONTROL (UMFPACK_SCALE, UMFPACK_DEFAULT_SCALE) ;
+ droptol = GET_CONTROL (UMFPACK_DROPTOL, UMFPACK_DEFAULT_DROPTOL) ;
+
+ relpt = MAX (0.0, MIN (relpt, 1.0)) ;
+ relpt2 = MAX (0.0, MIN (relpt2, 1.0)) ;
+ droptol = MAX (0.0, droptol) ;
+ front_alloc_init = MIN (1.0, front_alloc_init) ;
+
+ if (scale != UMFPACK_SCALE_NONE && scale != UMFPACK_SCALE_MAX)
+ {
+ scale = UMFPACK_DEFAULT_SCALE ;
+ }
+
+ if (User_Info != (double *) NULL)
+ {
+ /* return Info in user's array */
+ Info = User_Info ;
+ /* clear the parts of Info that are set by UMFPACK_numeric */
+ for (i = UMFPACK_NUMERIC_SIZE ; i <= UMFPACK_MAX_FRONT_NCOLS ; i++)
+ {
+ Info [i] = EMPTY ;
+ }
+ for (i = UMFPACK_NUMERIC_DEFRAG ; i < UMFPACK_IR_TAKEN ; i++)
+ {
+ Info [i] = EMPTY ;
+ }
+ }
+ else
+ {
+ /* no Info array passed - use local one instead */
+ Info = Info2 ;
+ for (i = 0 ; i < UMFPACK_INFO ; i++)
+ {
+ Info [i] = EMPTY ;
+ }
+ }
+
+ Symbolic = (SymbolicType *) SymbolicHandle ;
+ Numeric = (NumericType *) NULL ;
+ if (!UMF_valid_symbolic (Symbolic))
+ {
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_Symbolic_object ;
+ return (UMFPACK_ERROR_invalid_Symbolic_object) ;
+ }
+
+ /* compute alloc_init automatically for AMD ordering */
+ if (Symbolic->ordering == UMFPACK_ORDERING_AMD && alloc_init >= 0)
+ {
+ alloc_init = (Symbolic->nz + Symbolic->amd_lunz) / Symbolic->lunz_bound;
+ alloc_init = MIN (1.0, alloc_init) ;
+ alloc_init *= UMF_REALLOC_INCREASE ;
+ }
+
+ n_row = Symbolic->n_row ;
+ n_col = Symbolic->n_col ;
+ n_inner = MIN (n_row, n_col) ;
+
+ /* check for integer overflow in Numeric->Memory minimum size */
+ if (INT_OVERFLOW (Symbolic->dnum_mem_init_usage * sizeof (Unit)))
+ {
+ /* :: int overflow, initial Numeric->Memory size :: */
+ /* There's no hope to allocate a Numeric object big enough simply to
+ * hold the initial matrix, so return an out-of-memory condition */
+ DEBUGm4 (("out of memory: numeric int overflow\n")) ;
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+
+ Info [UMFPACK_STATUS] = UMFPACK_OK ;
+ Info [UMFPACK_NROW] = n_row ;
+ Info [UMFPACK_NCOL] = n_col ;
+ Info [UMFPACK_SIZE_OF_UNIT] = (double) (sizeof (Unit)) ;
+
+ if (!Ap || !Ai || !Ax || !NumericHandle
+#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 */
+ /* ---------------------------------------------------------------------- */
+
+ /* (1) calls UMF_malloc 15 or 17 times, to obtain temporary workspace of
+ * size c+1 Entry's and 2*(n_row+1) + 3*(n_col+1) + (n_col+n_inner+1) +
+ * (nn+1) + * 3*(c+1) + 2*(r+1) + max(r,c) + (nfr+1) integers plus 2*nn
+ * more integers if diagonal pivoting is to be done. r is the maximum
+ * number of rows in any frontal matrix, c is the maximum number of columns
+ * in any frontal matrix, n_inner is min (n_row,n_col), nn is
+ * max (n_row,n_col), and nfr is the number of frontal matrices. For a
+ * square matrix, this is c+1 Entry's and about 8n + 3c + 2r + max(r,c) +
+ * nfr integers, plus 2n more for diagonal pivoting.
+ */
+
+ Work = &WorkSpace ;
+ Work->n_row = n_row ;
+ Work->n_col = n_col ;
+ Work->nfr = Symbolic->nfr ;
+ Work->nb = Symbolic->nb ;
+ Work->n1 = Symbolic->n1 ;
+
+ if (!work_alloc (Work, Symbolic))
+ {
+ DEBUGm4 (("out of memory: numeric work\n")) ;
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+ error (&Numeric, Work) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+ ASSERT (UMF_malloc_count == init_count + 16 + 2*Symbolic->prefer_diagonal) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate Numeric object */
+ /* ---------------------------------------------------------------------- */
+
+ /* (2) calls UMF_malloc 10 or 11 times, for a total space of
+ * sizeof (NumericType) bytes, 4*(n_row+1) + 4*(n_row+1) integers, and
+ * (n_inner+1) Entry's, plus n_row Entry's if row scaling is to be done.
+ * sizeof (NumericType) is a small constant. Next, it calls UMF_malloc
+ * once, for the variable-sized part of the Numeric object
+ * (Numeric->Memory). The size of this object is the larger of
+ * (Control [UMFPACK_ALLOC_INIT]) * (the approximate upper bound computed
+ * by UMFPACK_symbolic), and the minimum required to start the numerical
+ * factorization. * This request is reduced if it fails.
+ */
+
+ if (!numeric_alloc (&Numeric, Symbolic, alloc_init, scale))
+ {
+ DEBUGm4 (("out of memory: initial numeric\n")) ;
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+ error (&Numeric, Work) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+ DEBUG0 (("malloc: init_count "ID" UMF_malloc_count "ID"\n",
+ init_count, UMF_malloc_count)) ;
+ ASSERT (UMF_malloc_count == init_count
+ + (16 + 2*Symbolic->prefer_diagonal)
+ + (11 + (scale != UMFPACK_SCALE_NONE))) ;
+
+ /* set control parameters */
+ Numeric->relpt = relpt ;
+ Numeric->relpt2 = relpt2 ;
+ Numeric->droptol = droptol ;
+ Numeric->alloc_init = alloc_init ;
+ Numeric->front_alloc_init = front_alloc_init ;
+ Numeric->scale = scale ;
+
+ DEBUG0 (("umf relpt %g %g init %g %g inc %g red %g\n",
+ relpt, relpt2, alloc_init, front_alloc_init,
+ UMF_REALLOC_INCREASE, UMF_REALLOC_REDUCTION)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* scale and factorize */
+ /* ---------------------------------------------------------------------- */
+
+ /* (3) During numerical factorization (inside UMF_kernel), the variable-size
+ * block of memory is increased in size via a call to UMF_realloc if it is
+ * found to be too small. During factorization, this block holds the
+ * pattern and values of L and U at the top end, and the elements
+ * (contibution blocks) and the current frontal matrix (Work->F*) at the
+ * bottom end. The peak size of the variable-sized object is estimated in
+ * UMFPACK_*symbolic (Info [UMFPACK_VARIABLE_PEAK_ESTIMATE]), although this
+ * upper bound can be very loose. The size of the Symbolic object
+ * (which is currently allocated) is in Info [UMFPACK_SYMBOLIC_SIZE], and
+ * is between 2*n and 13*n integers.
+ */
+
+ DEBUG0 (("Calling umf_kernel\n")) ;
+ status = UMF_kernel (Ap, Ai, Ax,
+#ifdef COMPLEX
+ Az,
+#endif
+ Numeric, Work, Symbolic) ;
+
+ Info [UMFPACK_STATUS] = status ;
+ if (status < UMFPACK_OK)
+ {
+ /* out of memory, or pattern has changed */
+ error (&Numeric, Work) ;
+ return (status) ;
+ }
+
+ Info [UMFPACK_FORCED_UPDATES] = Work->nforced ;
+ Info [UMFPACK_VARIABLE_INIT] = Numeric->init_usage ;
+ if (Symbolic->prefer_diagonal)
+ {
+ Info [UMFPACK_NOFF_DIAG] = Work->noff_diagonal ;
+ }
+
+ DEBUG0 (("malloc: init_count "ID" UMF_malloc_count "ID"\n",
+ init_count, UMF_malloc_count)) ;
+
+ npiv = Numeric->npiv ; /* = n_inner for nonsingular matrices */
+ ulen = Numeric->ulen ; /* = 0 for square nonsingular matrices */
+
+ /* ---------------------------------------------------------------------- */
+ /* free Work object */
+ /* ---------------------------------------------------------------------- */
+
+ /* (4) After numerical factorization all of the objects allocated in step
+ * (1) are freed via UMF_free, except that one object of size n_col+1 is
+ * kept if there are off-diagonal nonzeros in the last pivot row (can only
+ * occur for singular or rectangular matrices). This is Work->Upattern,
+ * which is transfered to Numeric->Upattern if ulen > 0.
+ */
+
+ DEBUG0 (("malloc: init_count "ID" UMF_malloc_count "ID"\n",
+ init_count, UMF_malloc_count)) ;
+
+ free_work (Work) ;
+
+ DEBUG0 (("malloc: init_count "ID" UMF_malloc_count "ID"\n",
+ init_count, UMF_malloc_count)) ;
+ DEBUG0 (("Numeric->ulen: "ID" scale: "ID"\n", ulen, scale)) ;
+ ASSERT (UMF_malloc_count == init_count + (ulen > 0) +
+ (11 + (scale != UMFPACK_SCALE_NONE))) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* reduce Lpos, Lilen, Lip, Upos, Uilen and Uip to size npiv+1 */
+ /* ---------------------------------------------------------------------- */
+
+ /* (5) Six components of the Numeric object are reduced in size if the
+ * matrix is singular or rectangular. The original size is 3*(n_row+1) +
+ * 3*(n_col+1) integers. The new size is 6*(npiv+1) integers. For
+ * square non-singular matrices, these two sizes are the same.
+ */
+
+ if (npiv < n_row)
+ {
+ /* reduce Lpos, Uilen, and Uip from size n_row+1 to size npiv */
+ inew = (Int *) UMF_realloc (Numeric->Lpos, npiv+1, sizeof (Int)) ;
+ if (inew)
+ {
+ Numeric->Lpos = inew ;
+ }
+ inew = (Int *) UMF_realloc (Numeric->Uilen, npiv+1, sizeof (Int)) ;
+ if (inew)
+ {
+ Numeric->Uilen = inew ;
+ }
+ inew = (Int *) UMF_realloc (Numeric->Uip, npiv+1, sizeof (Int)) ;
+ if (inew)
+ {
+ Numeric->Uip = inew ;
+ }
+ }
+
+ if (npiv < n_col)
+ {
+ /* reduce Upos, Lilen, and Lip from size n_col+1 to size npiv */
+ inew = (Int *) UMF_realloc (Numeric->Upos, npiv+1, sizeof (Int)) ;
+ if (inew)
+ {
+ Numeric->Upos = inew ;
+ }
+ inew = (Int *) UMF_realloc (Numeric->Lilen, npiv+1, sizeof (Int)) ;
+ if (inew)
+ {
+ Numeric->Lilen = inew ;
+ }
+ inew = (Int *) UMF_realloc (Numeric->Lip, npiv+1, sizeof (Int)) ;
+ if (inew)
+ {
+ Numeric->Lip = inew ;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* reduce Numeric->Upattern from size n_col+1 to size ulen+1 */
+ /* ---------------------------------------------------------------------- */
+
+ /* (6) The size of Numeric->Upattern (formerly Work->Upattern) is reduced
+ * from size n_col+1 to size ulen + 1. If ulen is zero, the object does
+ * not exist. */
+
+ DEBUG4 (("ulen: "ID" Upattern "ID"\n", ulen, (Int) Numeric->Upattern)) ;
+ ASSERT (IMPLIES (ulen == 0, Numeric->Upattern == (Int *) NULL)) ;
+ if (ulen > 0 && ulen < n_col)
+ {
+ inew = (Int *) UMF_realloc (Numeric->Upattern, ulen+1, sizeof (Int)) ;
+ if (inew)
+ {
+ Numeric->Upattern = inew ;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* reduce Numeric->Memory to hold just the LU factors at the head */
+ /* ---------------------------------------------------------------------- */
+
+ /* (7) The variable-sized block (Numeric->Memory) is reduced to hold just L
+ * and U, via a call to UMF_realloc, since the frontal matrices are no
+ * longer needed.
+ */
+
+ newsize = Numeric->ihead ;
+ if (newsize < Numeric->size)
+ {
+ mnew = (Unit *) UMF_realloc (Numeric->Memory, newsize, sizeof (Unit)) ;
+ if (mnew)
+ {
+ /* realloc succeeded (how can it fail since the size is reduced?) */
+ Numeric->Memory = mnew ;
+ Numeric->size = newsize ;
+ }
+ }
+ Numeric->ihead = Numeric->size ;
+ Numeric->itail = Numeric->ihead ;
+ Numeric->tail_usage = 0 ;
+ Numeric->ibig = EMPTY ;
+ /* UMF_mem_alloc_tail_block can no longer be called (no tail marker) */
+
+ /* ---------------------------------------------------------------------- */
+ /* report the results and return the Numeric object */
+ /* ---------------------------------------------------------------------- */
+
+ UMF_set_stats (
+ Info,
+ Symbolic,
+ (double) Numeric->max_usage, /* actual peak Numeric->Memory */
+ (double) Numeric->size, /* actual final Numeric->Memory */
+ Numeric->flops, /* actual "true flops" */
+ (double) Numeric->lnz + n_inner, /* actual nz in L */
+ (double) Numeric->unz + Numeric->nnzpiv, /* actual nz in U */
+ (double) Numeric->maxfrsize, /* actual largest front size */
+ (double) ulen, /* actual Numeric->Upattern size */
+ (double) npiv, /* actual # pivots found */
+ (double) Numeric->maxnrows, /* actual largest #rows in front */
+ (double) Numeric->maxncols, /* actual largest #cols in front */
+ scale != UMFPACK_SCALE_NONE,
+ Symbolic->prefer_diagonal,
+ ACTUAL) ;
+
+ Info [UMFPACK_ALLOC_INIT_USED] = Numeric->alloc_init ;
+ Info [UMFPACK_NUMERIC_DEFRAG] = Numeric->ngarbage ;
+ Info [UMFPACK_NUMERIC_REALLOC] = Numeric->nrealloc ;
+ Info [UMFPACK_NUMERIC_COSTLY_REALLOC] = Numeric->ncostly ;
+ Info [UMFPACK_COMPRESSED_PATTERN] = Numeric->isize ;
+ Info [UMFPACK_LU_ENTRIES] = Numeric->nLentries + Numeric->nUentries +
+ Numeric->npiv ;
+ Info [UMFPACK_UDIAG_NZ] = Numeric->nnzpiv ;
+ Info [UMFPACK_RSMIN] = Numeric->rsmin ;
+ Info [UMFPACK_RSMAX] = Numeric->rsmax ;
+ Info [UMFPACK_WAS_SCALED] = Numeric->scale ;
+
+ /* nz in L and U with no dropping of small entries */
+ Info [UMFPACK_ALL_LNZ] = Numeric->all_lnz + n_inner ;
+ Info [UMFPACK_ALL_UNZ] = Numeric->all_unz + Numeric->nnzpiv ;
+ Info [UMFPACK_NZDROPPED] =
+ (Numeric->all_lnz - Numeric->lnz)
+ + (Numeric->all_unz - Numeric->unz) ;
+
+ /* estimate of the reciprocal of the condition number. */
+ if (SCALAR_IS_ZERO (Numeric->min_udiag)
+ || SCALAR_IS_ZERO (Numeric->max_udiag)
+ || SCALAR_IS_NAN (Numeric->min_udiag)
+ || SCALAR_IS_NAN (Numeric->max_udiag))
+ {
+ /* rcond is zero if there is any zero or NaN on the diagonal */
+ Numeric->rcond = 0.0 ;
+ }
+ else
+ {
+ /* estimate of the recipricol of the condition number. */
+ /* This is NaN if diagonal is zero-free, but has one or more NaN's. */
+ Numeric->rcond = Numeric->min_udiag / Numeric->max_udiag ;
+ }
+ Info [UMFPACK_UMIN] = Numeric->min_udiag ;
+ Info [UMFPACK_UMAX] = Numeric->max_udiag ;
+ Info [UMFPACK_RCOND] = Numeric->rcond ;
+
+ if (Numeric->nnzpiv < n_inner
+ || SCALAR_IS_ZERO (Numeric->rcond) || SCALAR_IS_NAN (Numeric->rcond))
+ {
+ /* there are zeros and/or NaN's on the diagonal of U */
+ DEBUG0 (("Warning, matrix is singular in umfpack_numeric\n")) ;
+ DEBUG0 (("nnzpiv "ID" n_inner "ID" rcond %g\n", Numeric->nnzpiv,
+ n_inner, Numeric->rcond)) ;
+ status = UMFPACK_WARNING_singular_matrix ;
+ Info [UMFPACK_STATUS] = status ;
+ }
+
+ Numeric->valid = NUMERIC_VALID ;
+ *NumericHandle = (void *) Numeric ;
+
+ /* Numeric has 11 to 13 objects */
+ ASSERT (UMF_malloc_count == init_count + 11 +
+ + (ulen > 0) /* Numeric->Upattern */
+ + (scale != UMFPACK_SCALE_NONE)) ; /* Numeric->Rs */
+
+ /* ---------------------------------------------------------------------- */
+ /* get the time used by UMFPACK_numeric */
+ /* ---------------------------------------------------------------------- */
+
+ umfpack_toc (stats) ;
+ Info [UMFPACK_NUMERIC_WALLTIME] = stats [0] ;
+ Info [UMFPACK_NUMERIC_TIME] = stats [1] ;
+
+ /* return UMFPACK_OK or UMFPACK_WARNING_singular_matrix */
+ return (status) ;
+
+}
+
+
+/* ========================================================================== */
+/* === numeric_alloc ======================================================== */
+/* ========================================================================== */
+
+/* Allocate the Numeric object */
+
+PRIVATE Int numeric_alloc
+(
+ NumericType **NumericHandle,
+ SymbolicType *Symbolic,
+ double alloc_init,
+ Int scale
+)
+{
+ Int n_row, n_col, n_inner, min_usage, trying ;
+ NumericType *Numeric ;
+ double nsize, bsize ;
+
+ DEBUG0 (("numeric alloc:\n")) ;
+
+ n_row = Symbolic->n_row ;
+ n_col = Symbolic->n_col ;
+ n_inner = MIN (n_row, n_col) ;
+ *NumericHandle = (NumericType *) NULL ;
+
+ /* 1 allocation: accounted for in UMF_set_stats (num_On_size1),
+ * free'd in umfpack_free_numeric */
+ Numeric = (NumericType *) UMF_malloc (1, sizeof (NumericType)) ;
+
+ if (!Numeric)
+ {
+ return (FALSE) ; /* out of memory */
+ }
+ Numeric->valid = 0 ;
+ *NumericHandle = Numeric ;
+
+ /* 9 allocations: accounted for in UMF_set_stats (num_On_size1),
+ * free'd in umfpack_free_numeric */
+ Numeric->D = (Entry *) UMF_malloc (n_inner+1, sizeof (Entry)) ;
+ Numeric->Rperm = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+ Numeric->Cperm = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+ Numeric->Lpos = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+ Numeric->Lilen = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+ Numeric->Lip = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+ Numeric->Upos = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+ Numeric->Uilen = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+ Numeric->Uip = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+
+ /* 1 allocation if scaling: in UMF_set_stats (num_On_size1),
+ * free'd in umfpack_free_numeric */
+ if (scale != UMFPACK_SCALE_NONE)
+ {
+ DEBUG0 (("Allocating scale factors\n")) ;
+ Numeric->Rs = (double *) UMF_malloc (n_row, sizeof (double)) ;
+ }
+ else
+ {
+ DEBUG0 (("No scale factors allocated (R = I)\n")) ;
+ Numeric->Rs = (double *) NULL ;
+ }
+
+ Numeric->Memory = (Unit *) NULL ;
+
+ /* Upattern has already been allocated as part of the Work object. If
+ * the matrix is singular or rectangular, and there are off-diagonal
+ * nonzeros in the last pivot row, then Work->Upattern is not free'd.
+ * Instead it is transfered to Numeric->Upattern. If it exists,
+ * Numeric->Upattern is free'd in umfpack_free_numeric. */
+ Numeric->Upattern = (Int *) NULL ; /* used for singular matrices only */
+
+ if (!Numeric->D || !Numeric->Rperm || !Numeric->Cperm || !Numeric->Upos ||
+ !Numeric->Lpos || !Numeric->Lilen || !Numeric->Uilen || !Numeric->Lip ||
+ !Numeric->Uip || (scale != UMFPACK_SCALE_NONE && !Numeric->Rs))
+ {
+ return (FALSE) ; /* out of memory */
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate initial Numeric->Memory for LU factors and elements */
+ /* ---------------------------------------------------------------------- */
+
+ if (alloc_init < 0)
+ {
+ /* -alloc_init is the exact size to initially allocate */
+ nsize = -alloc_init ;
+ }
+ else
+ {
+ /* alloc_init is a ratio of the upper bound memory usage */
+ nsize = (alloc_init * Symbolic->num_mem_usage_est) + 1 ;
+ }
+ min_usage = Symbolic->num_mem_init_usage ;
+
+ /* Numeric->Memory must be large enough for UMF_kernel_init */
+ nsize = MAX (min_usage, nsize) ;
+
+ /* Numeric->Memory cannot be larger in size than Int_MAX / sizeof(Unit) */
+ /* For ILP32 mode: 2GB (nsize cannot be bigger than 256 Mwords) */
+ bsize = ((double) Int_MAX) / sizeof (Unit) - 1 ;
+ DEBUG0 (("bsize %g\n", bsize)) ;
+ nsize = MIN (nsize, bsize) ;
+
+ Numeric->size = (Int) nsize ;
+
+ DEBUG0 (("Num init %g usage_est %g numsize "ID" minusage "ID"\n",
+ alloc_init, Symbolic->num_mem_usage_est, Numeric->size, min_usage)) ;
+
+ /* allocates 1 object: */
+ /* keep trying until successful, or memory request is too small */
+ trying = TRUE ;
+ while (trying)
+ {
+ Numeric->Memory = (Unit *) UMF_malloc (Numeric->size, sizeof (Unit)) ;
+ if (Numeric->Memory)
+ {
+ DEBUG0 (("Successful Numeric->size: "ID"\n", Numeric->size)) ;
+ return (TRUE) ;
+ }
+ /* too much, reduce the request (but not below the minimum) */
+ /* and try again */
+ trying = Numeric->size > min_usage ;
+ Numeric->size = (Int)
+ (UMF_REALLOC_REDUCTION * ((double) Numeric->size)) ;
+ Numeric->size = MAX (min_usage, Numeric->size) ;
+ }
+
+ return (FALSE) ; /* we failed to allocate Numeric->Memory */
+}
+
+
+/* ========================================================================== */
+/* === work_alloc =========================================================== */
+/* ========================================================================== */
+
+/* Allocate the Work object. Return TRUE if successful. */
+
+PRIVATE Int work_alloc
+(
+ WorkType *Work,
+ SymbolicType *Symbolic
+)
+{
+ Int n_row, n_col, nn, maxnrows, maxncols, nfr, ok, maxnrc, n1 ;
+
+ n_row = Work->n_row ;
+ n_col = Work->n_col ;
+ nn = MAX (n_row, n_col) ;
+ nfr = Work->nfr ;
+ n1 = Symbolic->n1 ;
+ ASSERT (n1 <= n_row && n1 <= n_col) ;
+
+ maxnrows = Symbolic->maxnrows + Symbolic->nb ;
+ maxnrows = MIN (n_row, maxnrows) ;
+ maxncols = Symbolic->maxncols + Symbolic->nb ;
+ maxncols = MIN (n_col, maxncols) ;
+ maxnrc = MAX (maxnrows, maxncols) ;
+
+ DEBUG0 (("work alloc: maxnrows+nb "ID" maxncols+nb "ID"\n",
+ maxnrows, maxncols)) ;
+
+ /* 15 allocations, freed in free_work: */
+ /* accounted for in UMF_set_stats (work_usage) */
+ Work->Wx = (Entry *) UMF_malloc (maxnrows + 1, sizeof (Entry)) ;
+ Work->Wy = (Entry *) UMF_malloc (maxnrows + 1, sizeof (Entry)) ;
+ Work->Frpos = (Int *) UMF_malloc (n_row + 1, sizeof (Int)) ;
+ Work->Lpattern = (Int *) UMF_malloc (n_row + 1, sizeof (Int)) ;
+ Work->Fcpos = (Int *) UMF_malloc (n_col + 1, sizeof (Int)) ;
+ Work->Wp = (Int *) UMF_malloc (nn + 1, sizeof (Int)) ;
+ Work->Wrp = (Int *) UMF_malloc (MAX (n_col,maxnrows) + 1, sizeof (Int)) ;
+ Work->Frows = (Int *) UMF_malloc (maxnrows + 1, sizeof (Int)) ;
+ Work->Wm = (Int *) UMF_malloc (maxnrows + 1, sizeof (Int)) ;
+ Work->Fcols = (Int *) UMF_malloc (maxncols + 1, sizeof (Int)) ;
+ Work->Wio = (Int *) UMF_malloc (maxncols + 1, sizeof (Int)) ;
+ Work->Woi = (Int *) UMF_malloc (maxncols + 1, sizeof (Int)) ;
+ Work->Woo = (Int *) UMF_malloc (maxnrc + 1, sizeof (Int));
+ Work->elen = (n_col - n1) + (n_row - n1) + MIN (n_col-n1, n_row-n1) + 1 ;
+ Work->E = (Int *) UMF_malloc (Work->elen, sizeof (Int)) ;
+ Work->Front_new1strow = (Int *) UMF_malloc (nfr + 1, sizeof (Int)) ;
+
+ ok = (Work->Frpos && Work->Fcpos && Work->Lpattern
+ && Work->Wp && Work->Wrp && Work->Frows && Work->Fcols
+ && Work->Wio && Work->Woi && Work->Woo && Work->Wm
+ && Work->E && Work->Front_new1strow && Work->Wx && Work->Wy) ;
+
+ /* 2 allocations: accounted for in UMF_set_stats (work_usage) */
+ if (Symbolic->prefer_diagonal)
+ {
+ Work->Diagonal_map = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+ Work->Diagonal_imap = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+ ok = ok && Work->Diagonal_map && Work->Diagonal_imap ;
+ }
+ else
+ {
+ /* no diagonal map needed for rectangular matrices */
+ Work->Diagonal_map = (Int *) NULL ;
+ Work->Diagonal_imap = (Int *) NULL ;
+ }
+
+ /* 1 allocation, may become part of Numeric (if singular or rectangular): */
+ Work->Upattern = (Int *) UMF_malloc (n_col + 1, sizeof (Int)) ;
+ ok = ok && Work->Upattern ;
+
+ /* current frontal matrix does not yet exist */
+ Work->Flublock = (Entry *) NULL ;
+ Work->Flblock = (Entry *) NULL ;
+ Work->Fublock = (Entry *) NULL ;
+ Work->Fcblock = (Entry *) NULL ;
+
+ DEBUG0 (("work alloc done.\n")) ;
+ return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === free_work ============================================================ */
+/* ========================================================================== */
+
+PRIVATE void free_work
+(
+ WorkType *Work
+)
+{
+ DEBUG0 (("work free:\n")) ;
+ if (Work)
+ {
+ /* these 16 objects do exist */
+ Work->Wx = (Entry *) UMF_free ((void *) Work->Wx) ;
+ Work->Wy = (Entry *) UMF_free ((void *) Work->Wy) ;
+ Work->Frpos = (Int *) UMF_free ((void *) Work->Frpos) ;
+ Work->Fcpos = (Int *) UMF_free ((void *) Work->Fcpos) ;
+ Work->Lpattern = (Int *) UMF_free ((void *) Work->Lpattern) ;
+ Work->Upattern = (Int *) UMF_free ((void *) Work->Upattern) ;
+ Work->Wp = (Int *) UMF_free ((void *) Work->Wp) ;
+ Work->Wrp = (Int *) UMF_free ((void *) Work->Wrp) ;
+ Work->Frows = (Int *) UMF_free ((void *) Work->Frows) ;
+ Work->Fcols = (Int *) UMF_free ((void *) Work->Fcols) ;
+ Work->Wio = (Int *) UMF_free ((void *) Work->Wio) ;
+ Work->Woi = (Int *) UMF_free ((void *) Work->Woi) ;
+ Work->Woo = (Int *) UMF_free ((void *) Work->Woo) ;
+ Work->Wm = (Int *) UMF_free ((void *) Work->Wm) ;
+ Work->E = (Int *) UMF_free ((void *) Work->E) ;
+ Work->Front_new1strow =
+ (Int *) UMF_free ((void *) Work->Front_new1strow) ;
+
+ /* these objects might not exist */
+ Work->Diagonal_map = (Int *) UMF_free ((void *) Work->Diagonal_map) ;
+ Work->Diagonal_imap = (Int *) UMF_free ((void *) Work->Diagonal_imap) ;
+ }
+ DEBUG0 (("work free done.\n")) ;
+}
+
+
+/* ========================================================================== */
+/* === error ================================================================ */
+/* ========================================================================== */
+
+/* Error return from UMFPACK_numeric. Free all allocated memory. */
+
+PRIVATE void error
+(
+ NumericType **Numeric,
+ WorkType *Work
+)
+{
+ free_work (Work) ;
+ UMFPACK_free_numeric ((void **) Numeric) ;
+ ASSERT (UMF_malloc_count == init_count) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_qsymbolic ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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: about (3.4nz + 8n + n) integers and n double's as
+ workspace (via UMF_malloc, for a square matrix). All of it is free'd via
+ UMF_free if an error occurs. If successful, the Symbolic object contains
+ 12 to 14 objects allocated by UMF_malloc, with a total size of no more
+ than about 13*n integers.
+*/
+
+#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_malloc.h"
+#include "umf_free.h"
+#include "umf_2by2.h"
+#include "umf_singletons.h"
+
+typedef struct /* SWType */
+{
+ Int *Front_npivcol ; /* size n_col + 1 */
+ Int *Front_nrows ; /* size n_col */
+ Int *Front_ncols ; /* size n_col */
+ Int *Front_parent ; /* size n_col */
+ Int *Front_cols ; /* size n_col */
+ Int *InFront ; /* size n_row */
+ Int *Ci ; /* size Clen */
+ Int *Cperm1 ; /* size n_col */
+ Int *Rperm1 ; /* size n_row */
+ Int *InvRperm1 ; /* size n_row */
+ Int *Si ; /* size nz */
+ Int *Sp ; /* size n_col + 1 */
+ double *Rs ; /* size n_row */
+ Int *Rperm_2by2 ; /* size n_row */
+
+} SWType ;
+
+PRIVATE void free_work
+(
+ SWType *SW
+) ;
+
+PRIVATE void error
+(
+ SymbolicType **Symbolic,
+ SWType *SW
+) ;
+
+/* worst-case usage for SW object */
+#define SYM_WORK_USAGE(n_col,n_row,Clen) \
+ (DUNITS (Int, Clen) + \
+ DUNITS (Int, nz) + \
+ 4 * DUNITS (Int, n_row) + \
+ 4 * DUNITS (Int, n_col) + \
+ 2 * DUNITS (Int, n_col + 1) + \
+ DUNITS (double, n_row))
+
+/* 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),(n_col)) + 3*(nn)+1 + (n_col))
+
+/* size of an element (in Units), including tuples */
+#define ELEMENT_SIZE(r,c) \
+ (DGET_ELEMENT_SIZE (r, c) + 1 + (r + c) * UNITS (Tuple, 1))
+
+#ifndef NDEBUG
+PRIVATE Int init_count ;
+#endif
+
+/* ========================================================================== */
+/* === do_amd =============================================================== */
+/* ========================================================================== */
+
+PRIVATE void do_amd
+(
+ Int n,
+ const Int Ap [ ], /* size n+1 */
+ const Int Ai [ ], /* size nz = Ap [n] */
+ Int Q [ ], /* output permutation, j = Q [k] */
+ Int Qinv [ ], /* output inverse permutation, Qinv [j] = k */
+ Int Sdeg [ ], /* degree of A+A', from AMD_aat */
+ Int Clen, /* size of Ci */
+ Int Ci [ ], /* size Ci workspace */
+ double amd_Control [ ], /* AMD control parameters */
+ double amd_Info [ ], /* AMD info */
+ SymbolicType *Symbolic, /* Symbolic object */
+ double Info [ ] /* UMFPACK info */
+)
+{
+
+ if (n == 0)
+ {
+ Symbolic->amd_dmax = 0 ;
+ Symbolic->amd_lunz = 0 ;
+ Info [UMFPACK_SYMMETRIC_LUNZ] = 0 ;
+ Info [UMFPACK_SYMMETRIC_FLOPS] = 0 ;
+ Info [UMFPACK_SYMMETRIC_DMAX] = 0 ;
+ Info [UMFPACK_SYMMETRIC_NDENSE] = 0 ;
+ }
+ else
+ {
+ AMD_1 (n, Ap, Ai, Q, Qinv, Sdeg, Clen, Ci, amd_Control, amd_Info) ;
+
+ /* return estimates computed from AMD on PA+PA' */
+ Symbolic->amd_dmax = amd_Info [AMD_DMAX] ;
+ Symbolic->amd_lunz = 2 * amd_Info [AMD_LNZ] + n ;
+ Info [UMFPACK_SYMMETRIC_LUNZ] = Symbolic->amd_lunz ;
+ Info [UMFPACK_SYMMETRIC_FLOPS] = DIV_FLOPS * amd_Info [AMD_NDIV] +
+ MULTSUB_FLOPS * amd_Info [AMD_NMULTSUBS_LU] ;
+ Info [UMFPACK_SYMMETRIC_DMAX] = Symbolic->amd_dmax ;
+ Info [UMFPACK_SYMMETRIC_NDENSE] = amd_Info [AMD_NDENSE] ;
+ Info [UMFPACK_SYMBOLIC_DEFRAG] += amd_Info [AMD_NCMPA] ;
+ }
+}
+
+/* ========================================================================== */
+/* === prune_singletons ===================================================== */
+/* ========================================================================== */
+
+/* Create the submatrix after removing the n1 singletons. The matrix has
+ * row and column indices in the range 0 to n_row-n1 and 0 to n_col-n1,
+ * respectively. */
+
+PRIVATE Int prune_singletons
+(
+ Int n1,
+ Int n_col,
+ const Int Ap [ ],
+ const Int Ai [ ],
+ const double Ax [ ],
+#ifdef COMPLEX
+ const double Az [ ],
+#endif
+ Int Cperm1 [ ],
+ Int InvRperm1 [ ],
+ Int Si [ ],
+ Int Sp [ ]
+#ifndef NDEBUG
+ , Int Rperm1 [ ]
+ , Int n_row
+#endif
+)
+{
+ Int row, k, pp, p, oldcol, newcol, newrow, nzdiag, do_nzdiag ;
+
+ nzdiag = 0 ;
+ do_nzdiag = (Ax != (double *) NULL)
+#ifdef COMPLEX
+ && (Az != (double *) NULL)
+#endif
+ ;
+
+#ifndef NDEBUG
+ DEBUGm4 (("Prune : S = A (Cperm1 (n1+1:end), Rperm1 (n1+1:end))\n")) ;
+ for (k = 0 ; k < n_row ; k++)
+ {
+ ASSERT (Rperm1 [k] >= 0 && Rperm1 [k] < n_row) ;
+ ASSERT (InvRperm1 [Rperm1 [k]] == k) ;
+ }
+#endif
+
+ /* create the submatrix after removing singletons */
+
+ pp = 0 ;
+ for (k = n1 ; k < n_col ; k++)
+ {
+ oldcol = Cperm1 [k] ;
+ newcol = k - n1 ;
+ DEBUG5 (("Prune singletons k "ID" oldcol "ID" newcol "ID": "ID"\n",
+ k, oldcol, newcol, pp)) ;
+ Sp [newcol] = pp ; /* load column pointers */
+ for (p = Ap [oldcol] ; p < Ap [oldcol+1] ; p++)
+ {
+ row = Ai [p] ;
+ DEBUG5 ((" "ID": row "ID, pp, row)) ;
+ ASSERT (row >= 0 && row < n_row) ;
+ newrow = InvRperm1 [row] - n1 ;
+ ASSERT (newrow < n_row - n1) ;
+ if (newrow >= 0)
+ {
+ DEBUG5 ((" newrow "ID, newrow)) ;
+ Si [pp++] = newrow ;
+ if (do_nzdiag)
+ {
+ /* count the number of truly nonzero entries on the
+ * diagonal of S, excluding entries that are present,
+ * but numerically zero */
+ if (newrow == newcol)
+ {
+ /* this is the diagonal entry */
+ if (SCALAR_IS_NONZERO (Ax [p])
+#ifdef COMPLEX
+ || SCALAR_IS_NONZERO (Az [p])
+#endif
+ )
+ {
+ nzdiag++ ;
+ }
+ }
+ }
+ }
+ DEBUG5 (("\n")) ;
+ }
+ }
+ Sp [n_col - n1] = pp ;
+
+ ASSERT (AMD_valid (n_row - n1, n_col - n1, Sp, Si)) ;
+ return (nzdiag) ;
+}
+
+/* ========================================================================== */
+/* === combine_ordering ===================================================== */
+/* ========================================================================== */
+
+PRIVATE void combine_ordering
+(
+ Int n1,
+ Int nempty_col,
+ Int n_col,
+ Int Cperm_init [ ], /* output permutation */
+ Int Cperm1 [ ], /* singleton and empty column ordering */
+ Int Qinv [ ] /* Qinv from AMD or COLAMD */
+)
+{
+ Int k, oldcol, newcol, knew ;
+
+ /* combine the singleton ordering with Qinv */
+#ifndef NDEBUG
+ for (k = 0 ; k < n_col ; k++)
+ {
+ Cperm_init [k] = EMPTY ;
+ }
+#endif
+ for (k = 0 ; k < n1 ; k++)
+ {
+ DEBUG1 ((ID" Initial singleton: "ID"\n", k, Cperm1 [k])) ;
+ Cperm_init [k] = Cperm1 [k] ;
+ }
+ for (k = n1 ; k < n_col - nempty_col ; k++)
+ {
+ /* this is a non-singleton column */
+ oldcol = Cperm1 [k] ; /* user's name for this column */
+ newcol = k - n1 ; /* Qinv's name for this column */
+ knew = Qinv [newcol] ; /* Qinv's ordering for this column */
+ knew += n1 ; /* shift order, after singletons */
+ DEBUG1 ((" k "ID" oldcol "ID" newcol "ID" knew "ID"\n",
+ k, oldcol, newcol, knew)) ;
+ ASSERT (knew >= 0 && knew < n_col - nempty_col) ;
+ ASSERT (Cperm_init [knew] == EMPTY) ;
+ Cperm_init [knew] = oldcol ;
+ }
+ for (k = n_col - nempty_col ; k < n_col ; k++)
+ {
+ Cperm_init [k] = Cperm1 [k] ;
+ }
+#ifndef NDEBUG
+ {
+ Int *W = (Int *) malloc ((n_col + 1) * sizeof (Int)) ;
+ ASSERT (UMF_is_permutation (Cperm_init, W, n_col, n_col)) ;
+ free (W) ;
+ }
+#endif
+
+}
+
+/* ========================================================================== */
+/* === UMFPACK_qsymbolic ==================================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_qsymbolic
+(
+ Int n_row,
+ Int n_col,
+ const Int Ap [ ],
+ const Int Ai [ ],
+ const double Ax [ ],
+#ifdef COMPLEX
+ const double Az [ ],
+#endif
+ const Int Quser [ ],
+ void **SymbolicHandle,
+ const double Control [UMFPACK_CONTROL],
+ double User_Info [UMFPACK_INFO]
+)
+{
+
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int i, nz, j, newj, status, f1, f2, 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, n_inner, child, parent, *Link, row, *Front_parent,
+ analyze_compactions, k, chain, is_sym, *Si, *Sp, n2, do_UMF_analyze,
+ fpivcol, fallrows, fallcols, *InFront, *F1, snz, *Front_1strow, f1rows,
+ kk, *Cperm_init, *Rperm_init, newrow, *InvRperm1, *Front_leftmostdesc,
+ Clen_analyze, strategy, Clen_amd, fixQ, prefer_diagonal, nzdiag, nzaat,
+ *Wq, *Sdeg, *Fr_npivcol, nempty, *Fr_nrows, *Fr_ncols, *Fr_parent,
+ *Fr_cols, nempty_row, nempty_col, user_auto_strategy, fail, max_rdeg,
+ head_usage, tail_usage, lnz, unz, esize, *Esize, rdeg, *Cdeg, *Rdeg,
+ *Cperm1, *Rperm1, n1, oldcol, newcol, n1c, n1r, *Rperm_2by2, oldrow,
+ dense_row_threshold, tlen, aggressive ;
+ double knobs [COLAMD_KNOBS], flops, f, r, c, *Info, force_fixQ,
+ Info2 [UMFPACK_INFO], drow, dcol, dtail_usage, dlf, duf, dmax_usage,
+ dhead_usage, dlnz, dunz, dmaxfrsize, dClen, dClen_analyze, sym,
+ amd_Info [AMD_INFO], dClen_amd, dr, dc, cr, cc, cp,
+ amd_Control [AMD_CONTROL], stats [2], tol, scale ;
+ SymbolicType *Symbolic ;
+ SWType SWspace, *SW ;
+
+#ifndef NDEBUG
+ UMF_dump_start ( ) ;
+ init_count = UMF_malloc_count ;
+ PRINTF ((
+"**** Debugging enabled (UMFPACK will be exceedingly slow!) *****************\n"
+ )) ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* get the amount of time used by the process so far */
+ /* ---------------------------------------------------------------------- */
+
+ umfpack_tic (stats) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get control settings and check input parameters */
+ /* ---------------------------------------------------------------------- */
+
+ drow = GET_CONTROL (UMFPACK_DENSE_ROW, UMFPACK_DEFAULT_DENSE_ROW) ;
+ dcol = GET_CONTROL (UMFPACK_DENSE_COL, UMFPACK_DEFAULT_DENSE_COL) ;
+ nb = GET_CONTROL (UMFPACK_BLOCK_SIZE, UMFPACK_DEFAULT_BLOCK_SIZE) ;
+ strategy = GET_CONTROL (UMFPACK_STRATEGY, UMFPACK_DEFAULT_STRATEGY) ;
+ tol = GET_CONTROL (UMFPACK_2BY2_TOLERANCE, UMFPACK_DEFAULT_2BY2_TOLERANCE) ;
+ scale = GET_CONTROL (UMFPACK_SCALE, UMFPACK_DEFAULT_SCALE) ;
+ force_fixQ = GET_CONTROL (UMFPACK_FIXQ, UMFPACK_DEFAULT_FIXQ) ;
+ AMD_defaults (amd_Control) ;
+ amd_Control [AMD_DENSE] =
+ GET_CONTROL (UMFPACK_AMD_DENSE, UMFPACK_DEFAULT_AMD_DENSE) ;
+ aggressive =
+ (GET_CONTROL (UMFPACK_AGGRESSIVE, UMFPACK_DEFAULT_AGGRESSIVE) != 0) ;
+ amd_Control [AMD_AGGRESSIVE] = aggressive ;
+
+ nb = MAX (2, nb) ;
+ nb = MIN (nb, MAXNB) ;
+ ASSERT (nb >= 0) ;
+ if (nb % 2 == 1) nb++ ; /* make sure nb is even */
+ DEBUG0 (("UMFPACK_qsymbolic: nb = "ID" aggressive = "ID"\n", nb,
+ aggressive)) ;
+
+ tol = MAX (0.0, MIN (tol, 1.0)) ;
+ if (scale != UMFPACK_SCALE_NONE && scale != UMFPACK_SCALE_MAX)
+ {
+ scale = UMFPACK_DEFAULT_SCALE ;
+ }
+
+ if (User_Info != (double *) NULL)
+ {
+ /* return Info in user's array */
+ Info = User_Info ;
+ }
+ else
+ {
+ /* no Info array passed - use local one instead */
+ Info = Info2 ;
+ }
+ /* clear all of Info */
+ 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 (("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_invalid_matrix ;
+ return (UMFPACK_ERROR_invalid_matrix) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* get the requested strategy */
+ /* ---------------------------------------------------------------------- */
+
+ if (n_row != n_col)
+ {
+ /* if the matrix is rectangular, the only available strategy is
+ * unsymmetric */
+ strategy = UMFPACK_STRATEGY_UNSYMMETRIC ;
+ DEBUGm3 (("Rectangular: forcing unsymmetric strategy\n")) ;
+ }
+
+ if (strategy < UMFPACK_STRATEGY_AUTO
+ || strategy > UMFPACK_STRATEGY_SYMMETRIC)
+ {
+ /* unrecognized strategy */
+ strategy = UMFPACK_STRATEGY_AUTO ;
+ }
+
+ user_auto_strategy = (strategy == UMFPACK_STRATEGY_AUTO) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* 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. */
+
+ /* This is about 2.2*nz + 9*n_col + 6*n_row, or nz/5 + 13*n_col + 6*n_row,
+ * whichever is bigger. For square matrices, it works out to
+ * 2.2nz + 15n, or nz/5 + 19n, whichever is bigger (typically 2.2nz+15n). */
+ dClen = UMF_COLAMD_RECOMMENDED ((double) nz, (double) n_row,
+ (double) n_col) ;
+
+ /* This is defined above, as max (nz,n_col) + 3*nn+1 + 2*n_col, where
+ * nn = max (n_row,n_col). It is always smaller than the space required
+ * for colamd or amd. */
+ dClen_analyze = UMF_ANALYZE_CLEN ((double) nz, (double) n_row,
+ (double) n_col, (double) nn) ;
+ dClen = MAX (dClen, dClen_analyze) ;
+
+ /* The space for AMD can be larger than what's required for colamd: */
+ dClen_amd = 2.4 * (double) nz + 8 * (double) n_inner ;
+ /* additional space for the 2-by-2 strategy */
+ dClen_amd += (double) MAX (nn, nz) ;
+ dClen = MAX (dClen, dClen_amd) ;
+
+ /* worst case total memory usage for UMFPACK_symbolic (revised below) */
+ Info [UMFPACK_SYMBOLIC_PEAK_MEMORY] =
+ SYM_WORK_USAGE (n_col, n_row, dClen) +
+ UMF_symbolic_usage (n_row, n_col, n_col, n_col, n_col, TRUE) ;
+
+ if (INT_OVERFLOW (dClen * sizeof (Int)))
+ {
+ /* :: int overflow, Clen 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_*. */
+ DEBUGm4 (("out of memory: symbolic int overflow\n")) ;
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+
+ /* repeat the size calculations, in integers */
+ 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) ;
+ Clen_amd = 2.4 * nz + 8 * n_inner ;
+ Clen_amd += MAX (nn, nz) ; /* for Ri, in UMF_2by2 */
+ Clen = MAX (Clen, Clen_amd) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate the first part of the Symbolic object (header and Cperm_init) */
+ /* ---------------------------------------------------------------------- */
+
+ /* (1) Five calls to UMF_malloc are made, for a total space of
+ * 2 * (n_row + n_col) + 4 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. If A is square
+ * then this is about 4*n integers.
+ */
+
+ 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 ( ). */
+ DEBUGm4 (("out of memory: symbolic object\n")) ;
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+ error (&Symbolic, (SWType *) NULL) ;
+ 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->Esize = (Int *) NULL ;
+ Symbolic->esize = 0 ;
+
+ Symbolic->Cperm_init = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+ Symbolic->Rperm_init = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+ Symbolic->Cdeg = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+ Symbolic->Rdeg = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+ Symbolic->Diagonal_map = (Int *) NULL ;
+
+ Cperm_init = Symbolic->Cperm_init ;
+ Rperm_init = Symbolic->Rperm_init ;
+ Cdeg = Symbolic->Cdeg ;
+ Rdeg = Symbolic->Rdeg ;
+
+ if (!Cperm_init || !Rperm_init || !Cdeg || !Rdeg)
+ {
+ DEBUGm4 (("out of memory: symbolic perm\n")) ;
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+ error (&Symbolic, (SWType *) NULL) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+
+ Symbolic->n_row = n_row ;
+ Symbolic->n_col = n_col ;
+ Symbolic->nz = nz ;
+ Symbolic->nb = nb ;
+
+ /* ---------------------------------------------------------------------- */
+ /* check user's input permutation */
+ /* ---------------------------------------------------------------------- */
+
+ if (Quser != (Int *) NULL)
+ {
+ /* use Cperm_init as workspace to check input permutation */
+ if (!UMF_is_permutation (Quser, Cperm_init, n_col, n_col))
+ {
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_permutation ;
+ error (&Symbolic, (SWType *) NULL) ;
+ return (UMFPACK_ERROR_invalid_permutation) ;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate workspace */
+ /* ---------------------------------------------------------------------- */
+
+ /* (2) Eleven calls to UMF_malloc are made, for workspace of size
+ * Clen + nz + 7*n_col + 2*n_row + 2 integers. Clen is the larger of
+ * MAX (2*nz, 4*n_col) + 8*n_col + 6*n_row + n_col + nz/5 and
+ * 2.4*nz + 8 * MIN (n_row, n_col) + MAX (n_row, n_col, nz)
+ * If A is square and non-singular, then Clen is
+ * MAX (MAX (2*nz, 4*n) + 7*n + nz/5, 3.4*nz) + 8*n
+ * If A has at least 4*n nonzeros then Clen is
+ * MAX (2.2*nz + 7*n, 3.4*nz) + 8*n
+ * If A has at least (7/1.2)*n nonzeros, (about 5.8*n), then Clen is
+ * 3.4*nz + 8*n
+ * This space will be free'd when this routine finishes.
+ *
+ * Total space thus far is about 3.4nz + 12n integers.
+ * For the double precision, 32-bit integer version, the user's matrix
+ * requires an equivalent space of 3*nz + n integers. So this space is just
+ * slightly larger than the user's input matrix (including the numerical
+ * values themselves).
+ */
+
+ SW = &SWspace ; /* used for UMFPACK_symbolic only */
+
+ /* Note that SW->Front_* does not include the dummy placeholder front. */
+ /* This space is accounted for by the SYM_WORK_USAGE macro. */
+
+ /* this is free'd early */
+ SW->Si = (Int *) UMF_malloc (nz, sizeof (Int)) ;
+ SW->Sp = (Int *) UMF_malloc (n_col + 1, sizeof (Int)) ;
+ SW->InvRperm1 = (Int *) UMF_malloc (n_row, sizeof (Int)) ;
+ SW->Cperm1 = (Int *) UMF_malloc (n_col, sizeof (Int)) ;
+
+ /* this is free'd late */
+ SW->Ci = (Int *) UMF_malloc (Clen, sizeof (Int)) ;
+ SW->Front_npivcol = (Int *) UMF_malloc (n_col + 1, sizeof (Int)) ;
+ SW->Front_nrows = (Int *) UMF_malloc (n_col, sizeof (Int)) ;
+ SW->Front_ncols = (Int *) UMF_malloc (n_col, sizeof (Int)) ;
+ SW->Front_parent = (Int *) UMF_malloc (n_col, sizeof (Int)) ;
+ SW->Front_cols = (Int *) UMF_malloc (n_col, sizeof (Int)) ;
+ SW->Rperm1 = (Int *) UMF_malloc (n_row, sizeof (Int)) ;
+ SW->InFront = (Int *) UMF_malloc (n_row, sizeof (Int)) ;
+
+ /* this is allocated later, and free'd after Cperm1 but before Ci */
+ SW->Rperm_2by2 = (Int *) NULL ; /* will be nn Int's */
+
+ /* this is allocated last, and free'd first */
+ SW->Rs = (double *) NULL ; /* will be n_row double's */
+
+ Ci = SW->Ci ;
+ Fr_npivcol = SW->Front_npivcol ;
+ Fr_nrows = SW->Front_nrows ;
+ Fr_ncols = SW->Front_ncols ;
+ Fr_parent = SW->Front_parent ;
+ Fr_cols = SW->Front_cols ;
+ Cperm1 = SW->Cperm1 ;
+ Rperm1 = SW->Rperm1 ;
+ Si = SW->Si ;
+ Sp = SW->Sp ;
+ InvRperm1 = SW->InvRperm1 ;
+ Rperm_2by2 = (Int *) NULL ;
+ InFront = SW->InFront ;
+
+ if (!Ci || !Fr_npivcol || !Fr_nrows || !Fr_ncols || !Fr_parent || !Fr_cols
+ || !Cperm1 || !Rperm1 || !Si || !Sp || !InvRperm1 || !InFront)
+ {
+ DEBUGm4 (("out of memory: symbolic work\n")) ;
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+ error (&Symbolic, SW) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+
+ DEBUG0 (("Symbolic UMF_malloc_count - init_count = "ID"\n",
+ UMF_malloc_count - init_count)) ;
+ ASSERT (UMF_malloc_count == init_count + 17) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* find the row and column singletons */
+ /* ---------------------------------------------------------------------- */
+
+ /* [ use first nz + n_row + MAX (n_row, n_col) entries in Ci as workspace,
+ * and use Rperm_init as workspace */
+ ASSERT (Clen >= nz + n_row + MAX (n_row, n_col)) ;
+
+ status = UMF_singletons (n_row, n_col, Ap, Ai, Quser, Cdeg, Cperm1, Rdeg,
+ Rperm1, InvRperm1, &n1, &n1c, &n1r, &nempty_col, &nempty_row, &is_sym,
+ &max_rdeg, /* workspace: */ Rperm_init, Ci, Ci + nz, Ci + nz + n_row) ;
+
+ /* ] done using Rperm_init and Ci as workspace */
+
+ /* InvRperm1 is now the inverse of Rperm1 */
+
+ if (status != UMFPACK_OK)
+ {
+ DEBUGm4 (("matrix invalid: UMF_singletons\n")) ;
+ Info [UMFPACK_STATUS] = status ;
+ error (&Symbolic, SW) ;
+ return (status) ;
+ }
+ Info [UMFPACK_NEMPTY_COL] = nempty_col ;
+ Info [UMFPACK_NEMPTY_ROW] = nempty_row ;
+ Info [UMFPACK_NDENSE_COL] = 0 ; /* # dense rows/cols recomputed below */
+ Info [UMFPACK_NDENSE_ROW] = 0 ;
+ Info [UMFPACK_COL_SINGLETONS] = n1c ;
+ Info [UMFPACK_ROW_SINGLETONS] = n1r ;
+ Info [UMFPACK_S_SYMMETRIC] = is_sym ;
+
+ nempty = MIN (nempty_col, nempty_row) ;
+ Symbolic->nempty_row = nempty_row ;
+ Symbolic->nempty_col = nempty_col ;
+
+ /* UMF_singletons has verified that the user's input matrix is valid */
+ ASSERT (AMD_valid (n_row, n_col, Ap, Ai)) ;
+
+ Symbolic->n1 = n1 ;
+ Symbolic->nempty = nempty ;
+ ASSERT (n1 <= n_inner) ;
+ n2 = nn - n1 - nempty ;
+
+ dense_row_threshold =
+ UMFPACK_DENSE_DEGREE_THRESHOLD (drow, n_col - n1 - nempty_col) ;
+ Symbolic->dense_row_threshold = dense_row_threshold ;
+
+ if (!is_sym)
+ {
+ /* either the pruned submatrix rectangular, or it is square and
+ * Rperm [n1 .. n-nempty-1] is not the same as Cperm [n1 .. n-nempty-1].
+ * For the auto strategy, switch to the unsymmetric strategy.
+ * Otherwise, if the strategy selected by the user is symmetric or
+ * 2-by-2, then the singletons will be discarded. */
+ strategy = UMFPACK_STRATEGY_UNSYMMETRIC ;
+ DEBUGm4 (("Strategy: Unsymmetric singletons\n")) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* determine symmetry, nzdiag, and degrees of S+S' */
+ /* ---------------------------------------------------------------------- */
+
+ /* S is the matrix obtained after removing singletons
+ * = A (Cperm1 [n1..n_col-nempty_col-1], Rperm1 [n1..n_row-nempty_row-1])
+ */
+
+ Wq = Rperm_init ; /* use Rperm_init as workspace for Wq [ */
+ Sdeg = Cperm_init ; /* use Cperm_init as workspace for Sdeg [ */
+ sym = EMPTY ;
+ nzaat = EMPTY ;
+ nzdiag = EMPTY ;
+ for (i = 0 ; i < AMD_INFO ; i++)
+ {
+ amd_Info [i] = EMPTY ;
+ }
+
+ if (strategy != UMFPACK_STRATEGY_UNSYMMETRIC)
+ {
+ /* This also determines the degree of each node in S+S' (Sdeg), which
+ * is needed by the 2-by-2 strategy, the symmetry of S, and the number
+ * of nonzeros on the diagonal of S. */
+ ASSERT (n_row == n_col) ;
+ ASSERT (nempty_row == nempty_col) ;
+
+ /* get the count of nonzeros on the diagonal of S, excluding explicitly
+ * zero entries. nzdiag = amd_Info [AMD_NZDIAG] counts the zero entries
+ * in S. */
+
+ nzdiag = prune_singletons (n1, nn, Ap, Ai, Ax,
+#ifdef COMPLEX
+ Az,
+#endif
+ Cperm1, InvRperm1, Si, Sp
+#ifndef NDEBUG
+ , Rperm1, nn
+#endif
+ ) ;
+ nzaat = AMD_aat (n2, Sp, Si, Sdeg, Wq, amd_Info) ;
+ sym = amd_Info [AMD_SYMMETRY] ;
+ Info [UMFPACK_N2] = n2 ;
+ /* nzdiag = amd_Info [AMD_NZDIAG] counts the zero entries of S too */
+
+#ifndef NDEBUG
+ for (k = 0 ; k < n2 ; k++)
+ {
+ ASSERT (Sdeg [k] >= 0 && Sdeg [k] < n2) ;
+ }
+ ASSERT (Sp [n2] - n2 <= nzaat && nzaat <= 2 * Sp [n2]) ;
+ DEBUG0 (("Explicit zeros: "ID" %g\n", nzdiag, amd_Info [AMD_NZDIAG])) ;
+#endif
+ }
+
+ /* get statistics from amd_aat, if computed */
+ Symbolic->sym = sym ;
+ Symbolic->nzaat = nzaat ;
+ Symbolic->nzdiag = nzdiag ;
+ Symbolic->amd_dmax = EMPTY ;
+
+ Info [UMFPACK_PATTERN_SYMMETRY] = sym ;
+ Info [UMFPACK_NZ_A_PLUS_AT] = nzaat ;
+ Info [UMFPACK_NZDIAG] = nzdiag ;
+
+ /* ---------------------------------------------------------------------- */
+ /* determine the initial strategy based on symmetry and nnz (diag (S)) */
+ /* ---------------------------------------------------------------------- */
+
+ if (strategy == UMFPACK_STRATEGY_AUTO)
+ {
+ if (sym < 0.10)
+ {
+ /* highly unsymmetric: use the unsymmetric strategy */
+ strategy = UMFPACK_STRATEGY_UNSYMMETRIC ;
+ DEBUGm4 (("Strategy: select unsymmetric\n")) ;
+ }
+ else if (sym >= 0.7 && nzdiag == n2)
+ {
+ /* mostly symmetric, zero-free diagonal: use symmetric strategy */
+ strategy = UMFPACK_STRATEGY_SYMMETRIC ;
+ DEBUGm4 (("Strategy: select symmetric\n")) ;
+ }
+ else
+ {
+ /* Evaluate the symmetric 2-by-2 strategy, and select it, or
+ * the unsymmetric strategy if the 2-by-2 strategy doesn't look
+ * promising. */
+ strategy = UMFPACK_STRATEGY_2BY2 ;
+ DEBUGm4 (("Strategy: try 2-by-2\n")) ;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* try the 2-by-2 strategy */
+ /* ---------------------------------------------------------------------- */
+
+ /* (3) If the 2-by-2 strategy is attempted, additional workspace of size
+ * nn integers and nn double's is allocated, where nn = n_row = n_col.
+ * The real workspace is immediately free'd. The integer workspace of
+ * size nn remains until the end of umfpack_qsymbolic. */
+
+ /* If the resulting matrix S (Rperm_2by2, :) is too unsymmetric, then the
+ * unsymmetric strategy will be used instead. */
+
+ if (strategy == UMFPACK_STRATEGY_2BY2)
+ {
+ Int *Rp, *Ri, *Blen, *W, nz_papat, nzd2, nweak, unmatched,
+ Clen3 ;
+ double sym2 ;
+
+ /* ------------------------------------------------------------------ */
+ /* get workspace for UMF_2by2 */
+ /* ------------------------------------------------------------------ */
+
+ ASSERT (n_row == n_col && nn == n_row) ;
+
+#ifndef NDEBUG
+ for (k = 0 ; k < n2 ; k++)
+ {
+ ASSERT (Sdeg [k] >= 0 && Sdeg [k] < n2) ;
+ }
+#endif
+
+ /* allocate Rperm_2by2 */
+ SW->Rperm_2by2 = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+ Rperm_2by2 = SW->Rperm_2by2 ;
+ if (Rperm_2by2 == (Int *) NULL)
+ {
+ DEBUGm4 (("out of memory: Rperm_2by2\n")) ;
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+ error (&Symbolic, SW) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+
+ /* allocate Ri from the tail end of Ci [ */
+ Clen3 = Clen - (MAX (nn, nz) + 1) ;
+ Ri = Ci + Clen3 ;
+ ASSERT (Clen3 >= nz) ; /* space required for UMF_2by2 */
+
+ /* use Fr_* as workspace for Rp, Blen, and W [ */
+ Rp = Fr_npivcol ;
+ Blen = Fr_ncols ;
+ W = Fr_cols ;
+
+ if (scale != UMFPACK_SCALE_NONE)
+ {
+ SW->Rs = (double *) UMF_malloc (nn, sizeof (double)) ;
+ if (SW->Rs == (double *) NULL)
+ {
+ DEBUGm4 (("out of memory: scale factors for 2-by-2\n")) ;
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+ error (&Symbolic, SW) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* find the 2-by-2 row permutation */
+ /* ------------------------------------------------------------------ */
+
+ /* find a row permutation Rperm_2by2 such that S (Rperm_2by2, :)
+ * has a healthy diagonal */
+
+ UMF_2by2 (nn, Ap, Ai, Ax,
+#ifdef COMPLEX
+ Az,
+#endif
+ tol, scale, Cperm1,
+#ifndef NDEBUG
+ Rperm1,
+#endif
+ InvRperm1, n1, nempty, Sdeg, Rperm_2by2, &nweak, &unmatched,
+ Ri, Rp, SW->Rs, Blen, W, Ci, Wq) ;
+ DEBUGm3 (("2by2: nweak "ID" unmatched "ID"\n", nweak, unmatched)) ;
+ Info [UMFPACK_2BY2_NWEAK] = nweak ;
+ Info [UMFPACK_2BY2_UNMATCHED] = unmatched ;
+
+ SW->Rs = (double *) UMF_free ((void *) SW->Rs) ;
+
+ /* R = S (Rperm_2by2,:)' */
+ (void) UMF_transpose (n2, n2, Sp, Si, (double *) NULL, Rperm_2by2,
+ (Int *) NULL, 0, Rp, Ri, (double *) NULL, W, FALSE
+#ifdef COMPLEX
+ , (double *) NULL, (double *) NULL, FALSE
+#endif
+ ) ;
+ ASSERT (AMD_valid (n2, n2, Rp, Ri)) ;
+
+ /* contents of Si and Sp no longer needed, but the space is
+ * still needed */
+
+ /* ------------------------------------------------------------------ */
+ /* find symmetry of S (Rperm_2by2, :)', and prepare to order with AMD */
+ /* ------------------------------------------------------------------ */
+
+ for (i = 0 ; i < AMD_INFO ; i++)
+ {
+ amd_Info [i] = EMPTY ;
+ }
+ nz_papat = AMD_aat (n2, Rp, Ri, Sdeg, Wq, amd_Info) ;
+ sym2 = amd_Info [AMD_SYMMETRY] ;
+ nzd2 = amd_Info [AMD_NZDIAG] ;
+
+ Info [UMFPACK_2BY2_PATTERN_SYMMETRY] = sym2 ;
+ Info [UMFPACK_2BY2_NZ_PA_PLUS_PAT] = nz_papat ;
+ Info [UMFPACK_2BY2_NZDIAG] = nzd2 ;
+
+ DEBUG0 (("2by2: sym2 %g nzd2 "ID" n2 "ID"\n", sym2, nzd2, n2)) ;
+
+ /* ------------------------------------------------------------------ */
+ /* evaluate the 2-by-2 results */
+ /* ------------------------------------------------------------------ */
+
+ if (user_auto_strategy)
+ {
+ if ((sym2 > 1.1 * sym) && (nzd2 > 0.9 * n2))
+ {
+ /* 2-by-2 made it much more symmetric */
+ DEBUGm4 (("eval Strategy 2by2: much more symmetric: 2by2\n")) ;
+ strategy = UMFPACK_STRATEGY_2BY2 ;
+ }
+ else if (sym2 < 0.7 * sym)
+ {
+ /* 2-by-2 made it much more unsymmetric */
+ DEBUGm4 (("eval Strategy 2by2: much more UNsymmetric:unsym\n"));
+ strategy = UMFPACK_STRATEGY_UNSYMMETRIC ;
+ }
+ else if (sym2 < 0.25)
+ {
+ DEBUGm4 (("eval Strategy 2by2: is UNsymmetric: unsym\n"));
+ strategy = UMFPACK_STRATEGY_UNSYMMETRIC ;
+ }
+ else if (sym2 >= 0.51)
+ {
+ DEBUGm4 (("eval Strategy 2by2: sym2 >= 0.51: 2by2\n")) ;
+ strategy = UMFPACK_STRATEGY_2BY2 ;
+ }
+ else if (sym2 >= 0.999 * sym)
+ {
+ /* 2-by-2 improved symmetry, or made it only slightly worse */
+ DEBUGm4 (("eval Strategy 2by2: sym2 >= 0.999 sym: 2by2\n")) ;
+ strategy = UMFPACK_STRATEGY_2BY2 ;
+ }
+ else
+ {
+ /* can't decide what to do, so pick the unsymmetric strategy */
+ DEBUGm4 (("eval Strategy 2by2: punt: unsym\n"));
+ strategy = UMFPACK_STRATEGY_UNSYMMETRIC ;
+ }
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* if the 2-by-2 strategy is selected: */
+ /* ------------------------------------------------------------------ */
+
+ if (strategy == UMFPACK_STRATEGY_2BY2)
+ {
+ if (Quser == (Int *) NULL)
+ {
+ /* 2-by-2 strategy is successful */
+ /* compute amd (S) */
+ Int *Qinv = Fr_npivcol ;
+ ASSERT (Clen3 >= (nz_papat + nz_papat/5 + nn) + 7*nn) ;
+ do_amd (n2, Rp, Ri, Wq, Qinv, Sdeg, Clen3, Ci,
+ amd_Control, amd_Info, Symbolic, Info) ;
+ /* combine the singleton ordering and the AMD ordering */
+ combine_ordering (n1, nempty, nn, Cperm_init, Cperm1, Qinv) ;
+ }
+ /* fix Rperm_2by2 to reflect A, not S */
+ for (k = 0 ; k < n1 ; k++)
+ {
+ oldcol = Cperm1 [k] ;
+ i = k ;
+ oldrow = Rperm1 [k] ;
+ W [oldcol] = oldrow ;
+ }
+ for (k = n1 ; k < nn - nempty ; k++)
+ {
+ oldcol = Cperm1 [k] ;
+ i = Rperm_2by2 [k - n1] + n1 ;
+ oldrow = Rperm1 [i] ;
+ W [oldcol] = oldrow ;
+ }
+ for (k = nn - nempty ; k < nn ; k++)
+ {
+ oldcol = Cperm1 [k] ;
+ i = k ;
+ oldrow = Rperm1 [k] ;
+ W [oldcol] = oldrow ;
+ }
+ for (k = 0 ; k < nn ; k++)
+ {
+ Rperm_2by2 [k] = W [k] ;
+ }
+
+ /* Now, the "diagonal" entry in oldcol (where oldcol is the user's
+ * name for a column, is the entry in row oldrow (where oldrow is
+ * the user's name for a row, and oldrow = Rperm_2by2 [oldcol] */
+ }
+
+ /* Fr_* no longer needed for Rp, Blen, W ] */
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* finalize the strategy, including fixQ and prefer_diagonal */
+ /* ---------------------------------------------------------------------- */
+
+ if (strategy == UMFPACK_STRATEGY_SYMMETRIC)
+ {
+ /* use given Quser or AMD (A+A'), fix Q during factorization,
+ * prefer diagonal */
+ DEBUG0 (("\nStrategy: symmetric\n")) ;
+ ASSERT (n_row == n_col) ;
+ Symbolic->ordering = UMFPACK_ORDERING_AMD ;
+ fixQ = TRUE ;
+ prefer_diagonal = TRUE ;
+ }
+ else if (strategy == UMFPACK_STRATEGY_2BY2)
+ {
+ /* use Q = given Quser or Q = AMD (PA+PA'), fix Q during factorization,
+ * prefer diagonal, and factorize PAQ, where P is found by UMF_2by2. */
+ DEBUG0 (("\nStrategy: symmetric 2-by-2\n")) ;
+ ASSERT (n_row == n_col) ;
+ Symbolic->ordering = UMFPACK_ORDERING_AMD ;
+ fixQ = TRUE ;
+ prefer_diagonal = TRUE ;
+ }
+ else
+ {
+ /* use given Quser or COLAMD (A), refine Q during factorization,
+ * no diagonal preference */
+ ASSERT (strategy == UMFPACK_STRATEGY_UNSYMMETRIC) ;
+ DEBUG0 (("\nStrategy: unsymmetric\n")) ;
+ Symbolic->ordering = UMFPACK_ORDERING_COLAMD ;
+ fixQ = FALSE ;
+ prefer_diagonal = FALSE ;
+ }
+
+ if (Quser != (Int *) NULL)
+ {
+ Symbolic->ordering = UMFPACK_ORDERING_GIVEN ;
+ }
+
+ if (force_fixQ > 0)
+ {
+ fixQ = TRUE ;
+ DEBUG0 (("Force fixQ true\n")) ;
+ }
+ else if (force_fixQ < 0)
+ {
+ fixQ = FALSE ;
+ DEBUG0 (("Force fixQ false\n")) ;
+ }
+
+ DEBUG0 (("Strategy: ordering: "ID"\n", Symbolic->ordering)) ;
+ DEBUG0 (("Strategy: fixQ: "ID"\n", fixQ)) ;
+ DEBUG0 (("Strategy: prefer diag "ID"\n", prefer_diagonal)) ;
+
+ /* get statistics from amd_aat, if computed */
+ Symbolic->strategy = strategy ;
+ Symbolic->fixQ = fixQ ;
+ Symbolic->prefer_diagonal = prefer_diagonal ;
+
+ Info [UMFPACK_STRATEGY_USED] = strategy ;
+ Info [UMFPACK_ORDERING_USED] = Symbolic->ordering ;
+ Info [UMFPACK_QFIXED] = fixQ ;
+ Info [UMFPACK_DIAG_PREFERRED] = prefer_diagonal ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get the AMD ordering for the symmetric strategy */
+ /* ---------------------------------------------------------------------- */
+
+ if (strategy == UMFPACK_STRATEGY_SYMMETRIC && Quser == (Int *) NULL)
+ {
+ /* symmetric strategy for a matrix with mostly symmetric pattern */
+ Int *Qinv = Fr_npivcol ;
+ ASSERT (n_row == n_col && nn == n_row) ;
+ ASSERT (Clen >= (nzaat + nzaat/5 + nn) + 7*nn) ;
+ do_amd (n2, Sp, Si, Wq, Qinv, Sdeg, Clen, Ci,
+ amd_Control, amd_Info, Symbolic, Info) ;
+ /* combine the singleton ordering and the AMD ordering */
+ combine_ordering (n1, nempty, nn, Cperm_init, Cperm1, Qinv) ;
+ }
+ /* Sdeg no longer needed ] */
+ /* done using Rperm_init as workspace for Wq ] */
+
+ /* Contents of Si and Sp no longer needed, but the space is still needed */
+
+ /* ---------------------------------------------------------------------- */
+ /* use the user's input column ordering (already in Cperm1) */
+ /* ---------------------------------------------------------------------- */
+
+ if (Quser != (Int *) NULL)
+ {
+ for (k = 0 ; k < n_col ; k++)
+ {
+ Cperm_init [k] = Cperm1 [k] ;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* use COLAMD to order the matrix */
+ /* ---------------------------------------------------------------------- */
+
+ if (strategy == UMFPACK_STRATEGY_UNSYMMETRIC && Quser == (Int *) NULL)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* copy the matrix into colamd workspace (colamd destroys its input) */
+ /* ------------------------------------------------------------------ */
+
+ /* C = A (Cperm1 (n1+1:end), Rperm1 (n1+1:end)), where Ci is used as
+ * the row indices and Cperm_init (on input) is used as the column
+ * pointers. */
+
+ (void) prune_singletons (n1, n_col, Ap, Ai,
+ (double *) NULL,
+#ifdef COMPLEX
+ (double *) NULL,
+#endif
+ Cperm1, InvRperm1, Ci, Cperm_init
+#ifndef NDEBUG
+ , Rperm1, n_row
+#endif
+ ) ;
+
+ /* ------------------------------------------------------------------ */
+ /* set UMF_colamd defaults */
+ /* ------------------------------------------------------------------ */
+
+ UMF_colamd_set_defaults (knobs) ;
+ knobs [COLAMD_DENSE_ROW] = drow ;
+ knobs [COLAMD_DENSE_COL] = dcol ;
+ knobs [COLAMD_AGGRESSIVE] = aggressive ;
+
+ /* ------------------------------------------------------------------ */
+ /* check input matrix and find the initial column pre-ordering */
+ /* ------------------------------------------------------------------ */
+
+ /* NOTE: umf_colamd is not given any original empty rows or columns.
+ * Those have already been removed via prune_singletons, above. The
+ * umf_colamd routine has been modified to assume that all rows and
+ * columns have at least one entry in them. It will break if it is
+ * given empty rows or columns (an assertion is triggered when running
+ * in debug mode. */
+
+ (void) UMF_colamd (
+ n_row - n1 - nempty_row,
+ n_col - n1 - nempty_col,
+ Clen, Ci, Cperm_init, knobs, colamd_stats,
+ Fr_npivcol, Fr_nrows, Fr_ncols, Fr_parent, Fr_cols, &nfr,
+ InFront) ;
+ ASSERT (colamd_stats [COLAMD_EMPTY_ROW] == 0) ;
+ ASSERT (colamd_stats [COLAMD_EMPTY_COL] == 0) ;
+
+ /* # of dense rows will be recomputed below */
+ Info [UMFPACK_NDENSE_ROW] = colamd_stats [COLAMD_DENSE_ROW] ;
+ Info [UMFPACK_NDENSE_COL] = colamd_stats [COLAMD_DENSE_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 ;
+
+ /* Combine the singleton and colamd ordering into Cperm_init */
+ /* Note that colamd returns its inverse permutation in Ci */
+ combine_ordering (n1, nempty_col, n_col, Cperm_init, Cperm1, Ci) ;
+
+ /* contents of Ci no longer needed */
+
+#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 != (Int *) NULL) ;
+ ASSERT (UMF_is_permutation (Cperm_init, Ci, n_col, n_col)) ;
+#endif
+
+ }
+ else
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* do not call colamd - use input Quser or AMD instead */
+ /* ------------------------------------------------------------------ */
+
+ /* The ordering (Quser or Qamd) is already in Cperm_init */
+ do_UMF_analyze = TRUE ;
+
+ }
+
+ Cperm_init [n_col] = EMPTY ; /* unused in Cperm_init */
+
+ /* ---------------------------------------------------------------------- */
+ /* AMD ordering, if it exists, has been copied into Cperm_init */
+ /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+ DEBUG3 (("Cperm_init column permutation:\n")) ;
+ ASSERT (UMF_is_permutation (Cperm_init, 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, Cdeg [j] == 0)) ;
+ ASSERT (IMPLIES (newj < n_col-nempty_col, Cdeg [j] > 0)) ;
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* symbolic factorization (unless colamd has already done it) */
+ /* ---------------------------------------------------------------------- */
+
+ if (do_UMF_analyze)
+ {
+
+ Int *W, *Bp, *Bi, *Cperm2, ok, *P, Clen2, bsize, Clen0 ;
+
+ /* ------------------------------------------------------------------ */
+ /* construct column pre-ordered, pruned submatrix */
+ /* ------------------------------------------------------------------ */
+
+ /* S = column form submatrix after removing singletons and applying
+ * initial column ordering (includes singleton ordering) */
+ (void) prune_singletons (n1, n_col, Ap, Ai,
+ (double *) NULL,
+#ifdef COMPLEX
+ (double *) NULL,
+#endif
+ Cperm_init, InvRperm1, Si, Sp
+#ifndef NDEBUG
+ , Rperm1, n_row
+#endif
+ ) ;
+
+ /* ------------------------------------------------------------------ */
+ /* 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]
+
+ We have Clen >= n_col + MAX (nz,n_col) + 3*nn+1 + n_col,
+ So Clen0 >= 2*n_col as required for AMD_postorder
+ and Clen0 >= n_col + nz as required
+ */
+
+ 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) ;
+ ASSERT (Clen0 >= 2*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 - n1 ; row++)
+ {
+ W [row] = FALSE ;
+ }
+ P = Link ;
+
+ k = 0 ;
+
+ for (col = 0 ; col < n_col - n1 ; col++)
+ {
+ /* empty columns are last in S */
+ for (p = Sp [col] ; p < Sp [col+1] ; p++)
+ {
+ row = Si [p] ;
+ if (!W [row])
+ {
+ /* this row has just been seen for the first time */
+ W [row] = TRUE ;
+ P [k++] = row ;
+ }
+ }
+ }
+
+ /* If the matrix has truly empty rows, then P will not be */
+ /* complete, and visa versa. The matrix is structurally singular. */
+ nempty_row = n_row - n1 - k ;
+ if (k < n_row - n1)
+ {
+ /* 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 - n1 ; 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 - n1) ;
+ ASSERT (UMF_is_permutation (P, W, n_row - n1, n_row - n1)) ;
+ for (k = 0 ; k < n_row - n1 ; k++)
+ {
+ DEBUG3 ((ID"\n", P [k])) ;
+ }
+#endif
+
+ /* ------------------------------------------------------------------ */
+ /* B = row-form of the pattern of S (excluding empty columns) */
+ /* ------------------------------------------------------------------ */
+
+ /* 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 ;
+ snz = Sp [n_col - n1] ;
+ bsize = MAX (snz, 1) ;
+ Clen2 -= bsize ;
+ Bi = Ci + Clen2 ;
+ ASSERT (Clen2 >= n_col) ;
+
+ (void) UMF_transpose (n_row - n1, n_col - n1 - nempty_col,
+ Sp, Si, (double *) NULL,
+ P, (Int *) NULL, 0, Bp, Bi, (double *) NULL, W, FALSE
+#ifdef COMPLEX
+ , (double *) NULL, (double *) NULL, FALSE
+#endif
+ ) ;
+
+ /* contents of Si and Sp no longer needed */
+
+ /* 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 - n1] == snz) ;
+
+ /* increment Bp to point into Ci, not Bi */
+ for (i = 0 ; i <= n_row - n1 ; i++)
+ {
+ Bp [i] += Clen2 ;
+ }
+ ASSERT (Bp [0] == Clen0 - bsize) ;
+ ASSERT (Bp [n_row - n1] <= 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 (snz,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, non-singleton part of the matrix */
+ ok = UMF_analyze (
+ n_row - n1 - nempty_row,
+ n_col - n1 - nempty_col,
+ Ci, Bp, Cperm2, fixQ, W, Link,
+ Fr_ncols, Fr_nrows, Fr_npivcol,
+ Fr_parent, &nfr, &analyze_compactions) ;
+ if (!ok)
+ {
+ /* :: internal error in umf_analyze :: */
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_internal_error ;
+ error (&Symbolic, SW) ;
+ return (UMFPACK_ERROR_internal_error) ;
+ }
+ Info [UMFPACK_SYMBOLIC_DEFRAG] += analyze_compactions ;
+
+ /* ------------------------------------------------------------------ */
+ /* combine the input permutation and UMF_analyze's permutation */
+ /* ------------------------------------------------------------------ */
+
+ if (!fixQ)
+ {
+ /* Cperm2 is the column etree post-ordering */
+ ASSERT (UMF_is_permutation (Cperm2, W,
+ n_col-n1-nempty_col, n_col-n1-nempty_col)) ;
+
+ /* Note that the empty columns remain at the end of Cperm_init */
+ for (k = 0 ; k < n_col - n1 - nempty_col ; k++)
+ {
+ W [k] = Cperm_init [n1 + Cperm2 [k]] ;
+ }
+
+ for (k = 0 ; k < n_col - n1 - nempty_col ; k++)
+ {
+ Cperm_init [n1 + k] = W [k] ;
+ }
+ }
+
+ ASSERT (UMF_is_permutation (Cperm_init, W, n_col, n_col)) ;
+
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* free some of the workspace */
+ /* ---------------------------------------------------------------------- */
+
+ /* (4) The real workspace, Rs, of size n_row doubles has already been
+ * free'd. An additional workspace of size nz + n_col+1 + n_col integers
+ * is now free'd as well. */
+
+ SW->Si = (Int *) UMF_free ((void *) SW->Si) ;
+ SW->Sp = (Int *) UMF_free ((void *) SW->Sp) ;
+ SW->Cperm1 = (Int *) UMF_free ((void *) SW->Cperm1) ;
+ ASSERT (SW->Rs == (double *) NULL) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* determine the size of the Symbolic object */
+ /* ---------------------------------------------------------------------- */
+
+ /* ---------------------------------------------------------------------- */
+ /* determine the size of the Symbolic object */
+ /* ---------------------------------------------------------------------- */
+
+ nchains = 0 ;
+ for (i = 0 ; i < nfr ; i++)
+ {
+ if (Fr_parent [i] != i+1)
+ {
+ nchains++ ;
+ }
+ }
+
+ Symbolic->nchains = nchains ;
+ Symbolic->nfr = nfr ;
+ Symbolic->esize
+ = (max_rdeg > dense_row_threshold) ? (n_col - n1 - nempty_col) : 0 ;
+
+ /* true size of Symbolic object */
+ Info [UMFPACK_SYMBOLIC_SIZE] = UMF_symbolic_usage (n_row, n_col, nchains,
+ nfr, Symbolic->esize, prefer_diagonal) ;
+
+ /* actual peak memory usage for UMFPACK_symbolic (actual nfr, nchains) */
+ Info [UMFPACK_SYMBOLIC_PEAK_MEMORY] =
+ SYM_WORK_USAGE (n_col, n_row, 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_*) */
+ /* ---------------------------------------------------------------------- */
+
+ /* (5) UMF_malloc is called 7 or 8 times, for a total space of
+ * (4*(nfr+1) + 3*(nchains+1) + esize) 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. esize is zero if there
+ * are no dense rows, or n_col-n1-nempty_col otherwise (n1 is the number of
+ * singletons and nempty_col is the number of empty columns). This space is
+ * part of the Symbolic object and is not free'd unless an error occurs.
+ * This is between 7 and about 8n integers when A is square.
+ */
+
+ /* 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)) ;
+
+ fail = (!Symbolic->Front_npivcol || !Symbolic->Front_parent ||
+ !Symbolic->Front_1strow || !Symbolic->Front_leftmostdesc ||
+ !Symbolic->Chain_start || !Symbolic->Chain_maxrows ||
+ !Symbolic->Chain_maxcols) ;
+
+ if (Symbolic->esize > 0)
+ {
+ Symbolic->Esize = (Int *) UMF_malloc (Symbolic->esize, sizeof (Int)) ;
+ fail = fail || !Symbolic->Esize ;
+ }
+
+ if (fail)
+ {
+ DEBUGm4 (("out of memory: rest of symbolic object\n")) ;
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+ error (&Symbolic, SW) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+ DEBUG0 (("Symbolic UMF_malloc_count - init_count = "ID"\n",
+ UMF_malloc_count - init_count)) ;
+ ASSERT (UMF_malloc_count == init_count + 21
+ + (SW->Rperm_2by2 != (Int *) NULL)
+ + (Symbolic->Esize != (Int *) NULL)) ;
+
+ 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 ;
+
+ Esize = Symbolic->Esize ;
+
+ /* ---------------------------------------------------------------------- */
+ /* assign rows to fronts */
+ /* ---------------------------------------------------------------------- */
+
+ /* find InFront, unless colamd has already computed it */
+ if (do_UMF_analyze)
+ {
+
+ DEBUGm4 ((">>>>>>>>>Computing Front_1strow from scratch\n")) ;
+ /* empty rows go to dummy front nfr */
+ for (row = 0 ; row < n_row ; row++)
+ {
+ InFront [row] = nfr ;
+ }
+ /* assign the singleton pivot rows to the "empty" front */
+ for (k = 0 ; k < n1 ; k++)
+ {
+ row = Rperm1 [k] ;
+ InFront [row] = EMPTY ;
+ }
+ DEBUG1 (("Front (EMPTY), singleton nrows "ID" ncols "ID"\n", k, k)) ;
+ newj = n1 ;
+ for (i = 0 ; i < nfr ; i++)
+ {
+ fpivcol = Fr_npivcol [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 (InFront [row] == nfr)
+ {
+ /* this row belongs to front i */
+ DEBUG1 ((" Row "ID" in Front "ID"\n", row, i)) ;
+ InFront [row] = i ;
+ f1rows++ ;
+ }
+ }
+ }
+ Front_1strow [i] = f1rows ;
+ DEBUG1 ((" Front "ID" has 1strows: "ID" pivcols "ID"\n",
+ i, f1rows, fpivcol)) ;
+ }
+
+ }
+ else
+ {
+
+ /* COLAMD has already computed InFront, but it is not yet
+ * InFront [row] = front i, where row is an original row. It is
+ * InFront [k-n1] = i for k in the range n1 to n_row-nempty_row,
+ * and where row = Rperm1 [k]. Need to permute InFront. Also compute
+ * # of original rows assembled into each front.
+ * [ use Ci as workspace */
+ DEBUGm4 ((">>>>>>>>>Computing Front_1strow from colamd's InFront\n")) ;
+ for (i = 0 ; i <= nfr ; i++)
+ {
+ Front_1strow [i] = 0 ;
+ }
+ /* assign the singleton pivot rows to "empty" front */
+ for (k = 0 ; k < n1 ; k++)
+ {
+ row = Rperm1 [k] ;
+ Ci [row] = EMPTY ;
+ }
+ /* assign the non-empty rows to the front that assembled them */
+ for ( ; k < n_row - nempty_row ; k++)
+ {
+ row = Rperm1 [k] ;
+ i = InFront [k - n1] ;
+ ASSERT (i >= EMPTY && i < nfr) ;
+ if (i != EMPTY)
+ {
+ Front_1strow [i]++ ;
+ }
+ /* use Ci as permuted version of InFront */
+ Ci [row] = i ;
+ }
+ /* empty rows go to the "dummy" front */
+ for ( ; k < n_row ; k++)
+ {
+ row = Rperm1 [k] ;
+ Ci [row] = nfr ;
+ }
+ /* permute InFront so that InFront [row] = i if the original row is
+ * in front i */
+ for (row = 0 ; row < n_row ; row++)
+ {
+ InFront [row] = Ci [row] ;
+ }
+ /* ] no longer need Ci as workspace */
+ }
+
+#ifndef NDEBUG
+ for (row = 0 ; row < n_row ; row++)
+ {
+ if (InFront [row] == nfr)
+ {
+ DEBUG1 ((" Row "ID" in Dummy Front "ID"\n", row, nfr)) ;
+ }
+ else if (InFront [row] == EMPTY)
+ {
+ DEBUG1 ((" singleton Row "ID"\n", row)) ;
+ }
+ else
+ {
+ DEBUG1 ((" Row "ID" in Front "ID"\n", row, nfr)) ;
+ }
+ }
+ for (i = 0 ; i <= nfr ; i++)
+ {
+ DEBUG1 (("Front "ID" has 1strows: "ID" pivcols "ID"\n",
+ i, f1rows, fpivcol)) ;
+ }
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* copy front information into Symbolic object */
+ /* ---------------------------------------------------------------------- */
+
+ k = n1 ;
+ for (i = 0 ; i < nfr ; i++)
+ {
+ fpivcol = Fr_npivcol [i] ;
+ DEBUG1 (("Front "ID" k "ID" npivcol "ID" nrows "ID" ncols "ID"\n",
+ i, k, fpivcol, Fr_nrows [i], Fr_ncols [i])) ;
+ k += fpivcol ;
+ /* copy Front info into Symbolic object from SW */
+ Front_npivcol [i] = fpivcol ;
+ Front_parent [i] = Fr_parent [i] ;
+ }
+
+ /* 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 */
+ /* ---------------------------------------------------------------------- */
+
+ /* order the singleton pivot rows */
+ for (k = 0 ; k < n1 ; k++)
+ {
+ Rperm_init [k] = Rperm1 [k] ;
+ }
+
+ /* determine the first row in each front (in the new row ordering) */
+ 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)) ;
+
+ /* Use Ci as temporary workspace for F1 */
+ F1 = Ci ; /* [ of size nfr+1 */
+ ASSERT (Clen >= 2*n_row + nfr+1) ;
+
+ for (i = 0 ; i <= nfr ; i++)
+ {
+ F1 [i] = Front_1strow [i] ;
+ }
+
+ for (row = 0 ; row < n_row ; row++)
+ {
+ i = InFront [row] ;
+ if (i != EMPTY)
+ {
+ newrow = F1 [i]++ ;
+ ASSERT (newrow >= n1) ;
+ 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 */
+
+ /* ---------------------------------------------------------------------- */
+ /* find the diagonal map */
+ /* ---------------------------------------------------------------------- */
+
+ /* Rperm_init [newrow] = row gives the row permutation that is implied
+ * by the column permutation, where "row" is a row index of the original
+ * matrix A. It is not dependent on the Rperm_2by2 permutation, which
+ * only redefines the "diagonal". Both are used to construct the
+ * Diagonal_map. Diagonal_map only needs to be defined for
+ * k = n1 to nn - nempty, but go ahead and define it for all of
+ * k = 0 to nn */
+
+ if (prefer_diagonal)
+ {
+ Int *Diagonal_map ;
+ ASSERT (n_row == n_col && nn == n_row) ;
+ ASSERT (nempty_row == nempty_col && nempty == nempty_row) ;
+
+ /* allocate the Diagonal_map */
+ Symbolic->Diagonal_map = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ;
+ Diagonal_map = Symbolic->Diagonal_map ;
+ if (Diagonal_map == (Int *) NULL)
+ {
+ /* :: out of memory (diagonal map) :: */
+ DEBUGm4 (("out of memory: Diagonal map\n")) ;
+ Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ;
+ error (&Symbolic, SW) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+
+ /* use Ci as workspace to compute the inverse of Rperm_init [ */
+ for (newrow = 0 ; newrow < nn ; newrow++)
+ {
+ oldrow = Rperm_init [newrow] ;
+ ASSERT (oldrow >= 0 && oldrow < nn) ;
+ Ci [oldrow] = newrow ;
+ }
+ if (strategy == UMFPACK_STRATEGY_2BY2)
+ {
+ ASSERT (Rperm_2by2 != (Int *) NULL) ;
+ for (newcol = 0 ; newcol < nn ; newcol++)
+ {
+ oldcol = Cperm_init [newcol] ;
+ /* 2-by-2 pivoting done in S */
+ oldrow = Rperm_2by2 [oldcol] ;
+ newrow = Ci [oldrow] ;
+ Diagonal_map [newcol] = newrow ;
+ }
+ }
+ else
+ {
+ for (newcol = 0 ; newcol < nn ; newcol++)
+ {
+ oldcol = Cperm_init [newcol] ;
+ /* no 2-by-2 pivoting in S */
+ oldrow = oldcol ;
+ newrow = Ci [oldrow] ;
+ Diagonal_map [newcol] = newrow ;
+ }
+ }
+
+#ifndef NDEBUG
+ DEBUG1 (("\nDiagonal map:\n")) ;
+ for (newcol = 0 ; newcol < nn ; newcol++)
+ {
+ oldcol = Cperm_init [newcol] ;
+ DEBUG3 (("oldcol "ID" newcol "ID":\n", oldcol, newcol)) ;
+ for (p = Ap [oldcol] ; p < Ap [oldcol+1] ; p++)
+ {
+ Entry aij ;
+ oldrow = Ai [p] ;
+ newrow = Ci [oldrow] ;
+ if (Ax != (double *) NULL
+#ifdef COMPLEX
+ && Az != (double *) NULL
+#endif
+ )
+ {
+ ASSIGN (aij, Ax [p], Az [p]) ;
+ }
+ if (oldrow == oldcol)
+ {
+ DEBUG2 ((" old diagonal : oldcol "ID" oldrow "ID" ",
+ oldcol, oldrow)) ;
+ EDEBUG2 (aij) ;
+ DEBUG2 (("\n")) ;
+ }
+ if (newrow == Diagonal_map [newcol])
+ {
+ DEBUG2 ((" MAP diagonal : newcol "ID" MAProw "ID" ",
+ newcol, Diagonal_map [newrow])) ;
+ EDEBUG2 (aij) ;
+ DEBUG2 (("\n")) ;
+ }
+ }
+ }
+#endif
+ /* done using Ci as workspace ] */
+
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* 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)) ;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* find the frontal matrix chains and max frontal matrix sizes */
+ /* ---------------------------------------------------------------------- */
+
+ maxnrows = 1 ; /* max # rows in any front */
+ maxncols = 1 ; /* max # cols in any front */
+ dmaxfrsize = 1 ; /* max frontal matrix size */
+
+ /* start the first chain */
+ nchains = 0 ; /* number of chains */
+ Chain_start [0] = 0 ; /* front 0 starts a new chain */
+ maxrows = 1 ; /* max # rows for any front in current chain */
+ maxcols = 1 ; /* max # cols for any front in current chain */
+ DEBUG1 (("Constructing chains:\n")) ;
+
+ for (i = 0 ; i < nfr ; i++)
+ {
+ /* get frontal matrix info */
+ fpivcol = Front_npivcol [i] ; /* # candidate pivot columns */
+ fallrows = Fr_nrows [i] ; /* all rows (not just Schur comp) */
+ fallcols = Fr_ncols [i] ; /* all cols (not just Schur comp) */
+ parent = Front_parent [i] ; /* parent in column etree */
+ fpiv = MIN (fpivcol, fallrows) ; /* # pivot rows and cols */
+ maxrows = MAX (maxrows, fallrows) ;
+ maxcols = MAX (maxcols, fallcols) ;
+
+ DEBUG1 (("Front: "ID", pivcol "ID", "ID"-by-"ID" parent "ID
+ ", npiv "ID" Chain: maxrows "ID" maxcols "ID"\n", i, fpivcol,
+ fallrows, fallcols, parent, fpiv, maxrows, maxcols)) ;
+
+ if (parent != i+1)
+ {
+ /* this is the end of a chain */
+ double s ;
+ DEBUG1 (("\nEnd of chain "ID"\n", nchains)) ;
+
+ /* make sure maxrows is an odd number */
+ ASSERT (maxrows >= 0) ;
+ if (maxrows % 2 == 0) maxrows++ ;
+
+ DEBUG1 (("Chain maxrows "ID" maxcols "ID"\n", maxrows, maxcols)) ;
+
+ Chain_maxrows [nchains] = maxrows ;
+ Chain_maxcols [nchains] = maxcols ;
+
+ /* keep track of the maximum front size for all chains */
+
+ /* for Info only: */
+ s = (double) maxrows * (double) maxcols ;
+ dmaxfrsize = MAX (dmaxfrsize, s) ;
+
+ /* for the subsequent numerical factorization */
+ maxnrows = MAX (maxnrows, maxrows) ;
+ maxncols = MAX (maxncols, maxcols) ;
+
+ DEBUG1 (("Chain dmaxfrsize %g\n\n", dmaxfrsize)) ;
+
+ /* start the next chain */
+ nchains++ ;
+ Chain_start [nchains] = i+1 ;
+ maxrows = 1 ;
+ maxcols = 1 ;
+ }
+ }
+
+ /* for Info only: */
+ dmaxfrsize = ceil (dmaxfrsize) ;
+ DEBUGm1 (("dmaxfrsize %30.20g Int_MAX "ID"\n", dmaxfrsize, Int_MAX)) ;
+ ASSERT (Symbolic->nchains == nchains) ;
+
+ /* For allocating objects in umfpack_numeric (does not include all possible
+ * pivots, particularly pivots from prior fronts in the chain. Need to add
+ * nb to these to get the # of columns in the L block, for example. This
+ * is the largest row dimension and largest column dimension of any frontal
+ * matrix. maxnrows is always odd. */
+ Symbolic->maxnrows = maxnrows ;
+ Symbolic->maxncols = maxncols ;
+ DEBUGm3 (("maxnrows "ID" maxncols "ID"\n", maxnrows, maxncols)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* find the initial element sizes */
+ /* ---------------------------------------------------------------------- */
+
+ if (max_rdeg > dense_row_threshold)
+ {
+ /* there are one or more dense rows in the input matrix */
+ /* count the number of dense rows in each column */
+ /* use Ci as workspace for inverse of Rperm_init [ */
+ ASSERT (Esize != (Int *) NULL) ;
+ for (newrow = 0 ; newrow < n_row ; newrow++)
+ {
+ oldrow = Rperm_init [newrow] ;
+ ASSERT (oldrow >= 0 && oldrow < nn) ;
+ Ci [oldrow] = newrow ;
+ }
+ for (col = n1 ; col < n_col - nempty_col ; col++)
+ {
+ oldcol = Cperm_init [col] ;
+ esize = Cdeg [oldcol] ;
+ ASSERT (esize > 0) ;
+ for (p = Ap [oldcol] ; p < Ap [oldcol+1] ; p++)
+ {
+ oldrow = Ai [p] ;
+ newrow = Ci [oldrow] ;
+ if (newrow >= n1 && Rdeg [oldrow] > dense_row_threshold)
+ {
+ esize-- ;
+ }
+ }
+ ASSERT (esize >= 0) ;
+ Esize [col - n1] = esize ;
+ }
+ /* done using Ci as workspace ] */
+ }
+
+ /* If there are no dense rows, then Esize [col-n1] is identical to
+ * Cdeg [col], once Cdeg is permuted below */
+
+ /* ---------------------------------------------------------------------- */
+ /* permute Cdeg and Rdeg according to initial column and row permutation */
+ /* ---------------------------------------------------------------------- */
+
+ /* use Ci as workspace [ */
+ for (k = 0 ; k < n_col ; k++)
+ {
+ Ci [k] = Cdeg [Cperm_init [k]] ;
+ }
+ for (k = 0 ; k < n_col ; k++)
+ {
+ Cdeg [k] = Ci [k] ;
+ }
+ for (k = 0 ; k < n_row ; k++)
+ {
+ Ci [k] = Rdeg [Rperm_init [k]] ;
+ }
+ for (k = 0 ; k < n_row ; k++)
+ {
+ Rdeg [k] = Ci [k] ;
+ }
+ /* done using Ci as workspace ] */
+
+ /* ---------------------------------------------------------------------- */
+ /* simulate UMF_kernel_init */
+ /* ---------------------------------------------------------------------- */
+
+ /* count elements and tuples at tail, LU factors of singletons, and
+ * head and tail markers */
+
+ dlnz = n_inner ; /* upper limit of nz in L (incl diag) */
+ dunz = dlnz ; /* upper limit of nz in U (incl diag) */
+
+ /* head marker */
+ head_usage = 1 ;
+ dhead_usage = 1 ;
+
+ /* tail markers: */
+ tail_usage = 2 ;
+ dtail_usage = 2 ;
+
+ /* allocate the Rpi and Rpx workspace for UMF_kernel_init (incl. headers) */
+ tail_usage += UNITS (Int *, n_row+1) + UNITS (Entry *, n_row+1) + 2 ;
+ dtail_usage += DUNITS (Int *, n_row+1) + DUNITS (Entry *, n_row+1) + 2 ;
+ DEBUG1 (("Symbolic usage after Rpi/Rpx allocation: head "ID" tail "ID"\n",
+ head_usage, tail_usage)) ;
+
+ /* LU factors for singletons, at the head of memory */
+ for (k = 0 ; k < n1 ; k++)
+ {
+ lnz = Cdeg [k] - 1 ;
+ unz = Rdeg [k] - 1 ;
+ dlnz += lnz ;
+ dunz += unz ;
+ DEBUG1 (("singleton k "ID" pivrow "ID" pivcol "ID" lnz "ID" unz "ID"\n",
+ k, Rperm_init [k], Cperm_init [k], lnz, unz)) ;
+ head_usage += UNITS (Int, lnz) + UNITS (Entry, lnz)
+ + UNITS (Int, unz) + UNITS (Entry, unz) ;
+ dhead_usage += DUNITS (Int, lnz) + DUNITS (Entry, lnz)
+ + DUNITS (Int, unz) + DUNITS (Entry, unz) ;
+ }
+ DEBUG1 (("Symbolic init head usage: "ID" for LU singletons\n",head_usage)) ;
+
+ /* column elements: */
+ for (k = n1 ; k < n_col - nempty_col; k++)
+ {
+ esize = Esize ? Esize [k-n1] : Cdeg [k] ;
+ DEBUG2 ((" esize: "ID"\n", esize)) ;
+ ASSERT (esize >= 0) ;
+ if (esize > 0)
+ {
+ tail_usage += GET_ELEMENT_SIZE (esize, 1) + 1 ;
+ dtail_usage += DGET_ELEMENT_SIZE (esize, 1) + 1 ;
+ }
+ }
+
+ /* dense row elements */
+ if (Esize)
+ {
+ Int nrow_elements = 0 ;
+ for (k = n1 ; k < n_row - nempty_row ; k++)
+ {
+ rdeg = Rdeg [k] ;
+ if (rdeg > dense_row_threshold)
+ {
+ tail_usage += GET_ELEMENT_SIZE (1, rdeg) + 1 ;
+ dtail_usage += GET_ELEMENT_SIZE (1, rdeg) + 1 ;
+ nrow_elements++ ;
+ }
+ }
+ Info [UMFPACK_NDENSE_ROW] = nrow_elements ;
+ }
+
+ DEBUG1 (("Symbolic usage: "ID" = head "ID" + tail "ID" after els\n",
+ head_usage + tail_usage, head_usage, tail_usage)) ;
+
+ /* compute the tuple lengths */
+ if (Esize)
+ {
+ /* row tuples */
+ for (row = n1 ; row < n_row ; row++)
+ {
+ rdeg = Rdeg [row] ;
+ tlen = (rdeg > dense_row_threshold) ? 1 : rdeg ;
+ tail_usage += 1 + UNITS (Tuple, TUPLES (tlen)) ;
+ dtail_usage += 1 + DUNITS (Tuple, TUPLES (tlen)) ;
+ }
+ /* column tuples */
+ for (col = n1 ; col < n_col - nempty_col ; col++)
+ {
+ /* tlen is 1 plus the number of dense rows in this column */
+ esize = Esize [col - n1] ;
+ tlen = (esize > 0) + (Cdeg [col] - esize) ;
+ tail_usage += 1 + UNITS (Tuple, TUPLES (tlen)) ;
+ dtail_usage += 1 + DUNITS (Tuple, TUPLES (tlen)) ;
+ }
+ for ( ; col < n_col ; col++)
+ {
+ tail_usage += 1 + UNITS (Tuple, TUPLES (0)) ;
+ dtail_usage += 1 + DUNITS (Tuple, TUPLES (0)) ;
+ }
+ }
+ else
+ {
+ /* row tuples */
+ for (row = n1 ; row < n_row ; row++)
+ {
+ tlen = Rdeg [row] ;
+ tail_usage += 1 + UNITS (Tuple, TUPLES (tlen)) ;
+ dtail_usage += 1 + DUNITS (Tuple, TUPLES (tlen)) ;
+ }
+ /* column tuples */
+ for (col = n1 ; col < n_col ; col++)
+ {
+ tail_usage += 1 + UNITS (Tuple, TUPLES (1)) ;
+ dtail_usage += 1 + DUNITS (Tuple, TUPLES (1)) ;
+ }
+ }
+
+ Symbolic->num_mem_init_usage = head_usage + tail_usage ;
+ DEBUG1 (("Symbolic usage: "ID" = head "ID" + tail "ID" final\n",
+ Symbolic->num_mem_init_usage, head_usage, tail_usage)) ;
+
+ ASSERT (UMF_is_permutation (Rperm_init, Ci, n_row, n_row)) ;
+
+ /* initial head and tail usage in Numeric->Memory */
+ dmax_usage = dhead_usage + dtail_usage ;
+ dmax_usage = MAX (Symbolic->num_mem_init_usage, ceil (dmax_usage)) ;
+ Info [UMFPACK_VARIABLE_INIT_ESTIMATE] = dmax_usage ;
+
+ /* In case Symbolic->num_mem_init_usage overflows, keep as a double, too */
+ Symbolic->dnum_mem_init_usage = dmax_usage ;
+
+ /* free the Rpi and Rpx workspace */
+ tail_usage -= UNITS (Int *, n_row+1) + UNITS (Entry *, n_row+1) ;
+ dtail_usage -= DUNITS (Int *, n_row+1) + DUNITS (Entry *, n_row+1) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* simulate UMF_kernel, assuming unsymmetric pivoting */
+ /* ---------------------------------------------------------------------- */
+
+ /* Use Ci as temporary workspace for link lists [ */
+ Link = Ci ;
+ for (i = 0 ; i < nfr ; i++)
+ {
+ Link [i] = EMPTY ;
+ }
+
+ flops = 0 ; /* flop count upper bound */
+
+ for (chain = 0 ; chain < nchains ; chain++)
+ {
+ double fsize ;
+ f1 = Chain_start [chain] ;
+ f2 = Chain_start [chain+1] - 1 ;
+
+ /* allocate frontal matrix working array (C, L, and U) */
+ dr = Chain_maxrows [chain] ;
+ dc = Chain_maxcols [chain] ;
+ fsize =
+ nb*nb /* LU is nb-by-nb */
+ + dr*nb /* L is dr-by-nb */
+ + nb*dc /* U is nb-by-dc, stored by rows */
+ + dr*dc ; /* C is dr by dc */
+ dtail_usage += DUNITS (Entry, fsize) ;
+ dmax_usage = MAX (dmax_usage, dhead_usage + dtail_usage) ;
+
+ for (i = f1 ; i <= f2 ; i++)
+ {
+
+ /* get frontal matrix info */
+ fpivcol = Front_npivcol [i] ; /* # candidate pivot columns */
+ fallrows = Fr_nrows [i] ; /* all rows (not just Schur comp*/
+ fallcols = Fr_ncols [i] ; /* all cols (not just Schur comp*/
+ parent = Front_parent [i] ; /* parent in column etree */
+ fpiv = MIN (fpivcol, fallrows) ; /* # pivot rows and cols */
+ f = (double) fpiv ;
+ r = fallrows - fpiv ; /* # rows in Schur comp. */
+ c = fallcols - fpiv ; /* # cols in Schur comp. */
+
+ /* 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 and remove it from tuple lists */
+ cp = MIN (Front_npivcol [child], Fr_nrows [child]) ;
+ cr = Fr_nrows [child] - cp ;
+ cc = Fr_ncols [child] - cp ;
+ ASSERT (cp >= 0 && cr >= 0 && cc >= 0) ;
+ dtail_usage -= ELEMENT_SIZE (cr, cc) ;
+
+ }
+
+ /* The flop count computed here is "canonical". */
+
+ /* factorize the frontal matrix */
+ 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 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 ;
+
+ /* store f columns of L and f rows of U */
+ dhead_usage +=
+ DUNITS (Entry, dlf + duf) /* numerical values (excl diag) */
+ + DUNITS (Int, r + c + f) ; /* indices (compressed) */
+
+ if (parent != EMPTY)
+ {
+ /* create new element and place in tuple lists */
+ dtail_usage += ELEMENT_SIZE (r, c) ;
+
+ /* place in link list of parent */
+ Link [i] = Link [parent] ;
+ Link [parent] = i ;
+ }
+
+ /* keep track of peak Numeric->Memory usage */
+ dmax_usage = MAX (dmax_usage, dhead_usage + dtail_usage) ;
+
+ }
+
+ /* free the current frontal matrix */
+ dtail_usage -= DUNITS (Entry, fsize) ;
+ }
+
+ dhead_usage = ceil (dhead_usage) ;
+ dmax_usage = ceil (dmax_usage) ;
+ Symbolic->num_mem_size_est = dhead_usage ;
+ Symbolic->num_mem_usage_est = dmax_usage ;
+ Symbolic->lunz_bound = dlnz + dunz - n_inner ;
+
+ /* ] done using Ci as workspace for Link array */
+
+ /* ---------------------------------------------------------------------- */
+ /* 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 */
+ (double) maxnrows, /* estimated largest #rows in front */
+ (double) maxncols, /* estimated largest #cols in front */
+ TRUE, /* assume scaling is to be performed */
+ prefer_diagonal,
+ 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], Fr_parent, Fr_npivcol, Fr_nrows,
+ Fr_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" dmaxfrsize %g\n",
+ maxnrows, maxncols, dmaxfrsize)) ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* UMFPACK_symbolic was successful, return the object handle */
+ /* ---------------------------------------------------------------------- */
+
+ Symbolic->valid = SYMBOLIC_VALID ;
+ *SymbolicHandle = (void *) Symbolic ;
+
+ /* ---------------------------------------------------------------------- */
+ /* free workspace */
+ /* ---------------------------------------------------------------------- */
+
+ /* (6) The last of the workspace is free'd. The final Symbolic object
+ * consists of 12 to 14 allocated objects. Its final total size is lies
+ * roughly between 4*n and 13*n for a square matrix, which is all that is
+ * left of the memory allocated by this routine. If an error occurs, the
+ * entire Symbolic object is free'd when this routine returns (the error
+ * return routine, below).
+ */
+
+ free_work (SW) ;
+
+ DEBUG0 (("(3)Symbolic UMF_malloc_count - init_count = "ID"\n",
+ UMF_malloc_count - init_count)) ;
+ ASSERT (UMF_malloc_count == init_count + 12
+ + (Symbolic->Esize != (Int *) NULL)
+ + (Symbolic->Diagonal_map != (Int *) NULL)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get the time used by UMFPACK_*symbolic */
+ /* ---------------------------------------------------------------------- */
+
+ umfpack_toc (stats) ;
+ Info [UMFPACK_SYMBOLIC_WALLTIME] = stats [0] ;
+ Info [UMFPACK_SYMBOLIC_TIME] = stats [1] ;
+
+ return (UMFPACK_OK) ;
+}
+
+
+/* ========================================================================== */
+/* === free_work ============================================================ */
+/* ========================================================================== */
+
+PRIVATE void free_work
+(
+ SWType *SW
+)
+{
+ if (SW)
+ {
+ SW->Rperm_2by2 = (Int *) UMF_free ((void *) SW->Rperm_2by2) ;
+ SW->InvRperm1 = (Int *) UMF_free ((void *) SW->InvRperm1) ;
+ SW->Rs = (double *) UMF_free ((void *) SW->Rs) ;
+ SW->Si = (Int *) UMF_free ((void *) SW->Si) ;
+ SW->Sp = (Int *) UMF_free ((void *) SW->Sp) ;
+ SW->Ci = (Int *) UMF_free ((void *) SW->Ci) ;
+ SW->Front_npivcol = (Int *) UMF_free ((void *) SW->Front_npivcol);
+ SW->Front_nrows = (Int *) UMF_free ((void *) SW->Front_nrows) ;
+ SW->Front_ncols = (Int *) UMF_free ((void *) SW->Front_ncols) ;
+ SW->Front_parent = (Int *) UMF_free ((void *) SW->Front_parent) ;
+ SW->Front_cols = (Int *) UMF_free ((void *) SW->Front_cols) ;
+ SW->Cperm1 = (Int *) UMF_free ((void *) SW->Cperm1) ;
+ SW->Rperm1 = (Int *) UMF_free ((void *) SW->Rperm1) ;
+ SW->InFront = (Int *) UMF_free ((void *) SW->InFront) ;
+ }
+}
+
+
+/* ========================================================================== */
+/* === error ================================================================ */
+/* ========================================================================== */
+
+/* Error return from UMFPACK_symbolic. Free all allocated memory. */
+
+PRIVATE void error
+(
+ SymbolicType **Symbolic,
+ SWType *SW
+)
+{
+
+ free_work (SW) ;
+ UMFPACK_free_symbolic ((void **) Symbolic) ;
+ ASSERT (UMF_malloc_count == init_count) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_report_control =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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. Prints the control settings. See umfpack_report_control.h
+ for details.
+*/
+
+#include "umf_internal.h"
+
+GLOBAL void UMFPACK_report_control
+(
+ const double Control [UMFPACK_CONTROL]
+)
+{
+ Int prl, nb, irstep, strategy, scale, s ;
+ double drow, dcol, relpt, relpt2, alloc_init, front_alloc_init, amd_alpha,
+ tol, force_fixQ, droptol, aggr ;
+
+ prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+ if (prl < 2)
+ {
+ /* default is to print nothing */
+ return ;
+ }
+
+ PRINTF (("\n%s, Control:\n\n", UMFPACK_VERSION)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* run-time options */
+ /* ---------------------------------------------------------------------- */
+
+ /* This is a "run-time" option because all four umfpack_* versions */
+ /* compiled into the UMFPACK library. */
+
+#ifdef DINT
+ PRINTF ((" Matrix entry defined as: double\n")) ;
+ PRINTF ((" Int (generic integer) defined as: int\n")) ;
+#endif
+#ifdef DLONG
+ PRINTF ((" Matrix entry defined as: double\n")) ;
+ PRINTF ((" Int (generic integer) defined as: long\n")) ;
+#endif
+#ifdef ZINT
+ PRINTF ((" Matrix entry defined as: double complex\n")) ;
+ PRINTF ((" Int (generic integer) defined as: int\n")) ;
+#endif
+#ifdef ZLONG
+ PRINTF ((" Matrix entry defined as: double complex\n")) ;
+ PRINTF ((" Int (generic integer) defined as: long\n")) ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* printing level */
+ /* ---------------------------------------------------------------------- */
+
+ PRINTF (("\n "ID": print level: "ID"\n",
+ (Int) INDEX (UMFPACK_PRL), prl)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* dense row/col parameters */
+ /* ---------------------------------------------------------------------- */
+
+ drow = GET_CONTROL (UMFPACK_DENSE_ROW, UMFPACK_DEFAULT_DENSE_ROW) ;
+ dcol = GET_CONTROL (UMFPACK_DENSE_COL, UMFPACK_DEFAULT_DENSE_COL) ;
+
+ PRINTF ((" "ID": dense row parameter: %g\n",
+ (Int) INDEX (UMFPACK_DENSE_ROW), drow)) ;
+ PRINTF ((" \"dense\" rows have > max (16, (%g)*16*sqrt(n_col)"
+ " entries)\n", drow)) ;
+ PRINTF ((" "ID": dense column parameter: %g\n",
+ (Int) INDEX (UMFPACK_DENSE_COL), dcol)) ;
+ PRINTF ((" \"dense\" columns have > max (16, (%g)*16*sqrt(n_row)"
+ " entries)\n", dcol)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* pivot tolerance */
+ /* ---------------------------------------------------------------------- */
+
+ relpt = GET_CONTROL (UMFPACK_PIVOT_TOLERANCE,
+ UMFPACK_DEFAULT_PIVOT_TOLERANCE) ;
+ relpt = MAX (0.0, MIN (relpt, 1.0)) ;
+ PRINTF ((" "ID": pivot tolerance: %g\n",
+ (Int) INDEX (UMFPACK_PIVOT_TOLERANCE), relpt)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* block size */
+ /* ---------------------------------------------------------------------- */
+
+ nb = GET_CONTROL (UMFPACK_BLOCK_SIZE, UMFPACK_DEFAULT_BLOCK_SIZE) ;
+ nb = MAX (1, nb) ;
+ PRINTF ((" "ID": block size for dense matrix kernels: "ID"\n",
+ (Int) INDEX (UMFPACK_BLOCK_SIZE), nb)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* strategy */
+ /* ---------------------------------------------------------------------- */
+
+ strategy = GET_CONTROL (UMFPACK_STRATEGY, UMFPACK_DEFAULT_STRATEGY) ;
+ if (strategy < UMFPACK_STRATEGY_AUTO
+ || strategy > UMFPACK_STRATEGY_SYMMETRIC)
+ {
+ strategy = UMFPACK_STRATEGY_AUTO ;
+ }
+
+ PRINTF ((" "ID": strategy: "ID,
+ (Int) INDEX (UMFPACK_STRATEGY), strategy)) ;
+
+ if (strategy == UMFPACK_STRATEGY_SYMMETRIC)
+ {
+ PRINTF ((" (symmetric)\n"
+ " Q = AMD (A+A'), Q not refined during numerical\n"
+ " factorization, and diagonal pivoting (P=Q') attempted.\n")) ;
+ }
+ else if (strategy == UMFPACK_STRATEGY_UNSYMMETRIC)
+ {
+ PRINTF ((" (unsymmetric)\n"
+ " Q = COLAMD (A), Q refined during numerical\n"
+ " factorization, and no attempt at diagonal pivoting.\n")) ;
+ }
+ else if (strategy == UMFPACK_STRATEGY_2BY2)
+ {
+ PRINTF ((" (symmetric, with 2-by-2 block pivoting)\n"
+ " P2 = row permutation that tries to place large entries on\n"
+ " the diagonal. Q = AMD (P2*A+(P2*A)'), Q not refined during\n"
+ " numerical factorization, attempt to select pivots from the\n"
+ " diagonal of P2*A.\n")) ;
+ }
+ else /* auto strategy */
+ {
+ strategy = UMFPACK_STRATEGY_AUTO ;
+ PRINTF ((" (auto)\n")) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* initial allocation parameter */
+ /* ---------------------------------------------------------------------- */
+
+ alloc_init = GET_CONTROL (UMFPACK_ALLOC_INIT, UMFPACK_DEFAULT_ALLOC_INIT) ;
+ if (alloc_init >= 0)
+ {
+ PRINTF ((" "ID": initial allocation ratio: %g\n",
+ (Int) INDEX (UMFPACK_ALLOC_INIT), alloc_init)) ;
+ }
+ else
+ {
+ s = -alloc_init ;
+ s = MAX (1, s) ;
+ PRINTF ((" "ID": initial allocation (in Units): "ID"\n",
+ (Int) INDEX (UMFPACK_ALLOC_INIT), s)) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* maximum iterative refinement steps */
+ /* ---------------------------------------------------------------------- */
+
+ irstep = GET_CONTROL (UMFPACK_IRSTEP, UMFPACK_DEFAULT_IRSTEP) ;
+ irstep = MAX (0, irstep) ;
+ PRINTF ((" "ID": max iterative refinement steps: "ID"\n",
+ (Int) INDEX (UMFPACK_IRSTEP), irstep)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* 2-by-2 pivot tolerance */
+ /* ---------------------------------------------------------------------- */
+
+ tol = GET_CONTROL (UMFPACK_2BY2_TOLERANCE, UMFPACK_DEFAULT_2BY2_TOLERANCE) ;
+ tol = MAX (0.0, MIN (tol, 1.0)) ;
+ PRINTF ((" "ID": 2-by-2 pivot tolerance: %g\n",
+ (Int) INDEX (UMFPACK_2BY2_TOLERANCE), tol)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* force fixQ */
+ /* ---------------------------------------------------------------------- */
+
+ force_fixQ = GET_CONTROL (UMFPACK_FIXQ, UMFPACK_DEFAULT_FIXQ) ;
+ PRINTF ((" "ID": Q fixed during numerical factorization: %g ",
+ (Int) INDEX (UMFPACK_FIXQ), force_fixQ)) ;
+ if (force_fixQ > 0)
+ {
+ PRINTF (("(yes)\n")) ;
+ }
+ else if (force_fixQ < 0)
+ {
+ PRINTF (("(no)\n")) ;
+ }
+ else
+ {
+ PRINTF (("(auto)\n")) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* AMD parameters */
+ /* ---------------------------------------------------------------------- */
+
+ amd_alpha = GET_CONTROL (UMFPACK_AMD_DENSE, UMFPACK_DEFAULT_AMD_DENSE) ;
+ PRINTF ((" "ID": AMD dense row/col parameter: %g\n",
+ (Int) INDEX (UMFPACK_AMD_DENSE), amd_alpha)) ;
+ if (amd_alpha < 0)
+ {
+ PRINTF ((" no \"dense\" rows/columns\n")) ;
+ }
+ else
+ {
+ PRINTF ((" \"dense\" rows/columns have > max (16, (%g)*sqrt(n))"
+ " entries\n", amd_alpha)) ;
+ }
+ PRINTF ((" Only used if the AMD ordering is used.\n")) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* pivot tolerance for symmetric pivoting */
+ /* ---------------------------------------------------------------------- */
+
+ relpt2 = GET_CONTROL (UMFPACK_SYM_PIVOT_TOLERANCE,
+ UMFPACK_DEFAULT_SYM_PIVOT_TOLERANCE) ;
+ relpt2 = MAX (0.0, MIN (relpt2, 1.0)) ;
+ PRINTF ((" "ID": diagonal pivot tolerance: %g\n"
+ " Only used if diagonal pivoting is attempted.\n",
+ (Int) INDEX (UMFPACK_SYM_PIVOT_TOLERANCE), relpt2)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* scaling */
+ /* ---------------------------------------------------------------------- */
+
+ scale = GET_CONTROL (UMFPACK_SCALE, UMFPACK_DEFAULT_SCALE) ;
+ if (scale != UMFPACK_SCALE_NONE && scale != UMFPACK_SCALE_MAX)
+ {
+ scale = UMFPACK_DEFAULT_SCALE ;
+ }
+ PRINTF ((" "ID": scaling: "ID, (Int) INDEX (UMFPACK_SCALE), scale)) ;
+ if (scale == UMFPACK_SCALE_NONE)
+ {
+ PRINTF ((" (no)")) ;
+ }
+ else if (scale == UMFPACK_SCALE_SUM)
+ {
+ PRINTF ((" (divide each row by sum of abs. values in each row)")) ;
+ }
+ else if (scale == UMFPACK_SCALE_MAX)
+ {
+ PRINTF ((" (divide each row by max. abs. value in each row)")) ;
+ }
+ PRINTF (("\n")) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* frontal matrix allocation parameter */
+ /* ---------------------------------------------------------------------- */
+
+ front_alloc_init = GET_CONTROL (UMFPACK_FRONT_ALLOC_INIT,
+ UMFPACK_DEFAULT_FRONT_ALLOC_INIT) ;
+ front_alloc_init = MIN (1.0, front_alloc_init) ;
+ if (front_alloc_init >= 0)
+ {
+ PRINTF ((" "ID": frontal matrix allocation ratio: %g\n",
+ (Int) INDEX (UMFPACK_FRONT_ALLOC_INIT), front_alloc_init)) ;
+ }
+ else
+ {
+ s = -front_alloc_init ;
+ s = MAX (1, s) ;
+ PRINTF ((" "ID": initial frontal matrix size (# of Entry's): "ID"\n",
+ (Int) INDEX (UMFPACK_FRONT_ALLOC_INIT), s)) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* drop tolerance */
+ /* ---------------------------------------------------------------------- */
+
+ droptol = GET_CONTROL (UMFPACK_DROPTOL, UMFPACK_DEFAULT_DROPTOL) ;
+ PRINTF ((" "ID": drop tolerance: %g\n",
+ (Int) INDEX (UMFPACK_DROPTOL), droptol)) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* aggressive absorption */
+ /* ---------------------------------------------------------------------- */
+
+ aggr = GET_CONTROL (UMFPACK_AGGRESSIVE, UMFPACK_DEFAULT_AGGRESSIVE) ;
+ PRINTF ((" "ID": AMD and COLAMD aggressive absorption: %g",
+ (Int) INDEX (UMFPACK_AGGRESSIVE), aggr)) ;
+ if (aggr != 0.0)
+ {
+ PRINTF ((" (yes)\n")) ;
+ }
+ else
+ {
+ PRINTF ((" (no)\n")) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* compile-time options */
+ /* ---------------------------------------------------------------------- */
+
+ PRINTF ((
+ "\n The following options can only be changed at compile-time:\n")) ;
+
+ PRINTF ((" "ID": BLAS library used: ",
+ (Int) INDEX (UMFPACK_COMPILED_WITH_BLAS))) ;
+
+#if defined (USE_NO_BLAS)
+ PRINTF (("none. UMFPACK will be slow.\n")) ;
+#elif defined (USE_C_BLAS)
+ PRINTF (("C-BLAS.\n")) ;
+#elif defined (USE_MATLAB_BLAS)
+ PRINTF (("built-in MATLAB BLAS (ATLAS).\n")) ;
+#elif defined (USE_SUNPERF_BLAS)
+ PRINTF (("Sun Performance Library BLAS.\n")) ;
+#elif defined (USE_SCSL_BLAS)
+ PRINTF (("SGI SCSL BLAS.\n")) ;
+#elif defined (USE_FORTRAN_BLAS)
+ PRINTF (("Fortran BLAS.\n")) ;
+#endif
+
+#ifdef MATLAB_MEX_FILE
+#ifdef NUTIL
+ PRINTF ((" "ID": compiled for MATLAB"
+ " (uses mxMalloc, mxFree, mxRealloc, and mexPrintf)\n",
+ (Int) INDEX (UMFPACK_COMPILED_FOR_MATLAB))) ;
+#else
+ PRINTF ((" "ID": compiled for MATLAB"
+ " (uses utMalloc, utFree, utRealloc, and mexPrintf)\n",
+ (Int) INDEX (UMFPACK_COMPILED_FOR_MATLAB))) ;
+#endif
+#else
+#ifdef MATHWORKS
+ PRINTF ((" "ID": compiled for MATLAB, using internal utility routines\n"
+ " (uses utMalloc, utFree, utRealloc, and utPrintf)\n",
+ (Int) INDEX (UMFPACK_COMPILED_FOR_MATLAB))) ;
+ PRINTF ((" (complex version uses utDivideComplex, utFdlibm_hypot)\n")) ;
+#else
+ PRINTF ((" "ID": compiled for ANSI C"
+ " (uses malloc, free, realloc, and printf)\n",
+ (Int) INDEX (UMFPACK_COMPILED_FOR_MATLAB))) ;
+#endif
+#endif
+
+#ifdef NO_TIMER
+ PRINTF ((" "ID": no CPU timer \n",
+ (Int) INDEX (UMFPACK_COMPILED_WITH_GETRUSAGE))) ;
+#else
+#ifndef NPOSIX
+ PRINTF ((" "ID": CPU timer is POSIX times ( ) routine.\n",
+ (Int) INDEX (UMFPACK_COMPILED_WITH_GETRUSAGE))) ;
+#else
+#ifdef GETRUSAGE
+ PRINTF ((" "ID": CPU timer is getrusage.\n",
+ (Int) INDEX (UMFPACK_COMPILED_WITH_GETRUSAGE))) ;
+#else
+ PRINTF ((" "ID": CPU timer is ANSI C clock (may wrap around).\n",
+ (Int) INDEX (UMFPACK_COMPILED_WITH_GETRUSAGE))) ;
+#endif
+#endif
+#endif
+
+#ifndef NDEBUG
+ PRINTF ((
+"**** Debugging enabled (UMFPACK will be exceedingly slow!) *****************\n"
+" "ID": compiled with debugging enabled. ",
+ (Int) INDEX (UMFPACK_COMPILED_IN_DEBUG_MODE))) ;
+#ifdef MATLAB_MEX_FILE
+ PRINTF (("Uses mxAssert.\n")) ;
+#else
+#ifdef MATHWORKS
+ PRINTF (("Uses utAssert.\n")) ;
+#else
+ PRINTF (("Uses ANSI C assert.\n")) ;
+#endif
+#endif
+#else
+ PRINTF ((" "ID": compiled for normal operation (debugging disabled)\n",
+ (Int) INDEX (UMFPACK_COMPILED_IN_DEBUG_MODE))) ;
+#endif
+
+ PRINTF ((" computer/operating system: %s\n", UMFPACK_ARCHITECTURE)) ;
+ PRINTF ((" size of int: %g long: %g Int: %g pointer: %g"
+ " double: %g Entry: %g (in bytes)\n\n", (double) sizeof (int),
+ (double) sizeof (long), (double) sizeof (Int),
+ (double) sizeof (void *), (double) sizeof (double),
+ (double) sizeof (Entry))) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_report_info ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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. Prints the Info array. See umfpack_report_info.h for
+ details.
+*/
+
+#include "umf_internal.h"
+
+#define PRINT_INFO(format,x) \
+{ \
+ if (SCALAR_IS_NAN (x) || (!SCALAR_IS_LTZERO (x))) \
+ { \
+ PRINTF ((format, x)) ; \
+ } \
+}
+
+/* RATIO macro uses a double relop, but ignore NaN case: */
+#define RATIO(a,b,c) (((b) == 0) ? (c) : (((double) a)/((double) b)))
+
+/* ========================================================================== */
+/* === print_ratio ========================================================== */
+/* ========================================================================== */
+
+PRIVATE void print_ratio
+(
+ char *what,
+ char *format,
+ double estimate,
+ double actual
+)
+{
+ if (estimate < 0 && actual < 0) /* double relop, but ignore Nan case */
+ {
+ return ;
+ }
+ PRINTF ((" %-27s", what)) ;
+ if (estimate >= 0) /* double relop, but ignore Nan case */
+ {
+ PRINTF ((format, estimate)) ;
+ }
+ else
+ {
+ PRINTF ((" -")) ;
+ }
+ if (actual >= 0) /* double relop, but ignore Nan case */
+ {
+ PRINTF ((format, actual)) ;
+ }
+ else
+ {
+ PRINTF ((" -")) ;
+ }
+ if (estimate >= 0 && actual >= 0) /* double relop, but ignore Nan case */
+ {
+ PRINTF ((" %5.0f%%\n", 100 * RATIO (actual, estimate, 1))) ;
+ }
+ else
+ {
+ PRINTF ((" -\n")) ;
+ }
+}
+
+/* ========================================================================== */
+/* === UMFPACK_report_info ================================================== */
+/* ========================================================================== */
+
+GLOBAL void UMFPACK_report_info
+(
+ const double Control [UMFPACK_CONTROL],
+ const double Info [UMFPACK_INFO]
+)
+{
+
+ double lnz_est, unz_est, lunz_est, lnz, unz, lunz, tsym, tnum, fnum, tsolve,
+ fsolve, ttot, ftot, twsym, twnum, twsolve, twtot, n2 ;
+ Int n_row, n_col, n_inner, prl, is_sym ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get control settings and status to determine what to print */
+ /* ---------------------------------------------------------------------- */
+
+ prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+ if (!Info || prl < 2)
+ {
+ /* no output generated if Info is (double *) NULL */
+ /* or if prl is less than 2 */
+ return ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* print umfpack version */
+ /* ---------------------------------------------------------------------- */
+
+ PRINTF (("\n%s, Info:\n", UMFPACK_VERSION)) ;
+
+#ifndef NDEBUG
+ PRINTF ((
+"**** Debugging enabled (UMFPACK will be exceedingly slow!) *****************\n"
+ )) ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* print run-time options */
+ /* ---------------------------------------------------------------------- */
+
+#ifdef DINT
+ PRINTF ((" matrix entry defined as: double\n")) ;
+ PRINTF ((" Int (generic integer) defined as: int\n")) ;
+#endif
+#ifdef DLONG
+ PRINTF ((" matrix entry defined as: double\n")) ;
+ PRINTF ((" Int (generic integer) defined as: long\n")) ;
+#endif
+#ifdef ZINT
+ PRINTF ((" matrix entry defined as: double complex\n")) ;
+ PRINTF ((" Int (generic integer) defined as: int\n")) ;
+#endif
+#ifdef ZLONG
+ PRINTF ((" matrix entry defined as: double complex\n")) ;
+ PRINTF ((" Int (generic integer) defined as: long\n")) ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* print compile-time options */
+ /* ---------------------------------------------------------------------- */
+
+ PRINTF ((" BLAS library used: ")) ;
+
+#if defined (USE_NO_BLAS)
+ PRINTF (("none. UMFPACK will be slow.\n")) ;
+#elif defined (USE_C_BLAS)
+ PRINTF (("C-BLAS.\n")) ;
+#elif defined (USE_MATLAB_BLAS)
+ PRINTF (("built-in MATLAB BLAS.\n")) ;
+#elif defined (USE_SUNPERF_BLAS)
+ PRINTF (("Sun Performance Library BLAS.\n")) ;
+#elif defined (USE_SCSL_BLAS)
+ PRINTF (("SGI SCSL BLAS.\n")) ;
+#elif defined (USE_FORTRAN_BLAS)
+ PRINTF (("Fortran BLAS.\n")) ;
+#endif
+
+ PRINTF ((" MATLAB: ")) ;
+#ifdef MATLAB_MEX_FILE
+ PRINTF (("yes.\n")) ;
+#else
+#ifdef MATHWORKS
+ PRINTF (("yes (using internal ut* routines).\n")) ;
+#else
+ PRINTF (("no.\n")) ;
+#endif
+#endif
+
+ PRINTF ((" CPU timer: ")) ;
+#ifdef NO_TIMER
+ PRINTF (("none.\n")) ;
+#else
+#ifndef NPOSIX
+ PRINTF (("POSIX times ( ) routine.\n")) ;
+#else
+#ifdef GETRUSAGE
+ PRINTF (("getrusage ( ) routine.\n")) ;
+#else
+ PRINTF (("ANSI clock ( ) routine.\n")) ;
+#endif
+#endif
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* print n and nz */
+ /* ---------------------------------------------------------------------- */
+
+ n_row = (Int) Info [UMFPACK_NROW] ;
+ n_col = (Int) Info [UMFPACK_NCOL] ;
+ n_inner = MIN (n_row, n_col) ;
+
+ PRINT_INFO (" number of rows in matrix A: "ID"\n", n_row) ;
+ PRINT_INFO (" number of columns in matrix A: "ID"\n", n_col) ;
+ PRINT_INFO (" entries in matrix A: "ID"\n",
+ (Int) Info [UMFPACK_NZ]) ;
+ PRINT_INFO (" memory usage reported in: "ID"-byte Units\n",
+ (Int) Info [UMFPACK_SIZE_OF_UNIT]) ;
+
+ PRINT_INFO (" size of int: "ID" bytes\n",
+ (Int) Info [UMFPACK_SIZE_OF_INT]) ;
+ PRINT_INFO (" size of long: "ID" bytes\n",
+ (Int) Info [UMFPACK_SIZE_OF_LONG]) ;
+ PRINT_INFO (" size of pointer: "ID" bytes\n",
+ (Int) Info [UMFPACK_SIZE_OF_POINTER]) ;
+ PRINT_INFO (" size of numerical entry: "ID" bytes\n",
+ (Int) Info [UMFPACK_SIZE_OF_ENTRY]) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* symbolic parameters */
+ /* ---------------------------------------------------------------------- */
+
+ if (Info [UMFPACK_STRATEGY_USED] == UMFPACK_STRATEGY_SYMMETRIC)
+ {
+ PRINTF (("\n strategy used: symmetric\n")) ;
+ }
+ else if (Info [UMFPACK_STRATEGY_USED] == UMFPACK_STRATEGY_UNSYMMETRIC)
+ {
+ PRINTF (("\n strategy used: unsymmetric\n")) ;
+ }
+ else if (Info [UMFPACK_STRATEGY_USED] == UMFPACK_STRATEGY_2BY2)
+ {
+ PRINTF (("\n strategy used: symmetric 2-by-2\n"));
+ }
+
+ if (Info [UMFPACK_ORDERING_USED] == UMFPACK_ORDERING_AMD)
+ {
+ PRINTF ((" ordering used: amd on A+A'\n")) ;
+ }
+ else if (Info [UMFPACK_ORDERING_USED] == UMFPACK_ORDERING_COLAMD)
+ {
+ PRINTF ((" ordering used: colamd on A\n")) ;
+ }
+ else if (Info [UMFPACK_ORDERING_USED] == UMFPACK_ORDERING_GIVEN)
+ {
+ PRINTF ((" ordering used: provided by user\n")) ;
+ }
+
+ if (Info [UMFPACK_QFIXED] == 1)
+ {
+ PRINTF ((" modify Q during factorization: no\n")) ;
+ }
+ else if (Info [UMFPACK_QFIXED] == 0)
+ {
+ PRINTF ((" modify Q during factorization: yes\n")) ;
+ }
+
+ if (Info [UMFPACK_DIAG_PREFERRED] == 0)
+ {
+ PRINTF ((" prefer diagonal pivoting: no\n")) ;
+ }
+ else if (Info [UMFPACK_DIAG_PREFERRED] == 1)
+ {
+ PRINTF ((" prefer diagonal pivoting: yes\n")) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* singleton statistics */
+ /* ---------------------------------------------------------------------- */
+
+ PRINT_INFO (" pivots with zero Markowitz cost: %0.f\n",
+ Info [UMFPACK_COL_SINGLETONS] + Info [UMFPACK_ROW_SINGLETONS]) ;
+ PRINT_INFO (" submatrix S after removing zero-cost pivots:\n"
+ " number of \"dense\" rows: %.0f\n",
+ Info [UMFPACK_NDENSE_ROW]) ;
+ PRINT_INFO (" number of \"dense\" columns: %.0f\n",
+ Info [UMFPACK_NDENSE_COL]) ;
+ PRINT_INFO (" number of empty rows: %.0f\n",
+ Info [UMFPACK_NEMPTY_ROW]) ;
+ PRINT_INFO (" number of empty columns %.0f\n",
+ Info [UMFPACK_NEMPTY_COL]) ;
+ is_sym = Info [UMFPACK_S_SYMMETRIC] ;
+ if (is_sym > 0)
+ {
+ PRINTF ((" submatrix S square and diagonal preserved\n")) ;
+ }
+ else if (is_sym == 0)
+ {
+ PRINTF ((" submatrix S not square or diagonal not preserved\n"));
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* statistics from amd_aat */
+ /* ---------------------------------------------------------------------- */
+
+ n2 = Info [UMFPACK_N2] ;
+ if (n2 >= 0)
+ {
+ PRINTF ((" pattern of square submatrix S:\n")) ;
+ }
+ PRINT_INFO (" number rows and columns %.0f\n",
+ n2) ;
+ PRINT_INFO (" symmetry of nonzero pattern: %.6f\n",
+ Info [UMFPACK_PATTERN_SYMMETRY]) ;
+ PRINT_INFO (" nz in S+S' (excl. diagonal): %.0f\n",
+ Info [UMFPACK_NZ_A_PLUS_AT]) ;
+ PRINT_INFO (" nz on diagonal of matrix S: %.0f\n",
+ Info [UMFPACK_NZDIAG]) ;
+ if (Info [UMFPACK_NZDIAG] >= 0 && n2 > 0)
+ {
+ PRINTF ((" fraction of nz on diagonal: %.6f\n",
+ Info [UMFPACK_NZDIAG] / n2)) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* statistics from 2-by-2 permutation */
+ /* ---------------------------------------------------------------------- */
+
+ PRINT_INFO (" 2-by-2 pivoting to place large entries on diagonal:\n"
+ " # of small diagonal entries of S: %.0f\n",
+ Info [UMFPACK_2BY2_NWEAK]) ;
+ PRINT_INFO (" # unmatched: %.0f\n",
+ Info [UMFPACK_2BY2_UNMATCHED]) ;
+ PRINT_INFO (" symmetry of P2*S: %.6f\n",
+ Info [UMFPACK_2BY2_PATTERN_SYMMETRY]) ;
+ PRINT_INFO (" nz in P2*S+(P2*S)' (excl. diag.): %.0f\n",
+ Info [UMFPACK_2BY2_NZ_PA_PLUS_PAT]) ;
+ PRINT_INFO (" nz on diagonal of P2*S: %.0f\n",
+ Info [UMFPACK_2BY2_NZDIAG]) ;
+ if (Info [UMFPACK_2BY2_NZDIAG] >= 0 && n2 > 0)
+ {
+ PRINTF ((" fraction of nz on diag of P2*S: %.6f\n",
+ Info [UMFPACK_2BY2_NZDIAG] / n2)) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* statistics from AMD */
+ /* ---------------------------------------------------------------------- */
+
+ if (Info [UMFPACK_ORDERING_USED] == UMFPACK_ORDERING_AMD)
+ {
+ double dmax = Info [UMFPACK_SYMMETRIC_DMAX] ;
+ PRINTF ((" AMD statistics, for strict diagonal pivoting:\n")) ;
+ PRINT_INFO (" est. flops for LU factorization: %.5e\n",
+ Info [UMFPACK_SYMMETRIC_FLOPS]) ;
+ PRINT_INFO (" est. nz in L+U (incl. diagonal): %.0f\n",
+ Info [UMFPACK_SYMMETRIC_LUNZ]) ;
+ PRINT_INFO (" est. largest front (# entries): %.0f\n",
+ dmax*dmax) ;
+ PRINT_INFO (" est. max nz in any column of L: %.0f\n",
+ dmax) ;
+ PRINT_INFO (
+ " number of \"dense\" rows/columns in S+S': %.0f\n",
+ Info [UMFPACK_SYMMETRIC_NDENSE]) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* symbolic factorization */
+ /* ---------------------------------------------------------------------- */
+
+ tsym = Info [UMFPACK_SYMBOLIC_TIME] ;
+ twsym = Info [UMFPACK_SYMBOLIC_WALLTIME] ;
+
+ PRINT_INFO (" symbolic factorization defragmentations: %.0f\n",
+ Info [UMFPACK_SYMBOLIC_DEFRAG]) ;
+ PRINT_INFO (" symbolic memory usage (Units): %.0f\n",
+ Info [UMFPACK_SYMBOLIC_PEAK_MEMORY]) ;
+ PRINT_INFO (" symbolic memory usage (MBytes): %.1f\n",
+ MBYTES (Info [UMFPACK_SYMBOLIC_PEAK_MEMORY])) ;
+ PRINT_INFO (" Symbolic size (Units): %.0f\n",
+ Info [UMFPACK_SYMBOLIC_SIZE]) ;
+ PRINT_INFO (" Symbolic size (MBytes): %.0f\n",
+ MBYTES (Info [UMFPACK_SYMBOLIC_SIZE])) ;
+ PRINT_INFO (" symbolic factorization CPU time (sec): %.2f\n",
+ tsym) ;
+ PRINT_INFO (" symbolic factorization wallclock time(sec): %.2f\n",
+ twsym) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* scaling, from numerical factorization */
+ /* ---------------------------------------------------------------------- */
+
+ if (Info [UMFPACK_WAS_SCALED] == UMFPACK_SCALE_NONE)
+ {
+ PRINTF (("\n matrix scaled: no\n")) ;
+ }
+ else if (Info [UMFPACK_WAS_SCALED] == UMFPACK_SCALE_SUM)
+ {
+ PRINTF (("\n matrix scaled: yes ")) ;
+ PRINTF (("(divided each row by sum of abs values in each row)\n")) ;
+ PRINTF ((" minimum sum (abs (rows of A)): %.5e\n",
+ Info [UMFPACK_RSMIN])) ;
+ PRINTF ((" maximum sum (abs (rows of A)): %.5e\n",
+ Info [UMFPACK_RSMAX])) ;
+ }
+ else if (Info [UMFPACK_WAS_SCALED] == UMFPACK_SCALE_MAX)
+ {
+ PRINTF (("\n matrix scaled: yes ")) ;
+ PRINTF (("(divided each row by max abs value in each row)\n")) ;
+ PRINTF ((" minimum max (abs (rows of A)): %.5e\n",
+ Info [UMFPACK_RSMIN])) ;
+ PRINTF ((" maximum max (abs (rows of A)): %.5e\n",
+ Info [UMFPACK_RSMAX])) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* estimate/actual in symbolic/numeric factorization */
+ /* ---------------------------------------------------------------------- */
+
+ /* double relop, but ignore NaN case: */
+ if (Info [UMFPACK_SYMBOLIC_DEFRAG] >= 0 /* UMFPACK_*symbolic called */
+ || Info [UMFPACK_NUMERIC_DEFRAG] >= 0) /* UMFPACK_numeric called */
+ {
+ PRINTF (("\n symbolic/numeric factorization: upper bound")) ;
+ PRINTF ((" actual %%\n")) ;
+ PRINTF ((" variable-sized part of Numeric object:\n")) ;
+ }
+ print_ratio (" initial size (Units)", " %20.0f",
+ Info [UMFPACK_VARIABLE_INIT_ESTIMATE], Info [UMFPACK_VARIABLE_INIT]) ;
+ print_ratio (" peak size (Units)", " %20.0f",
+ Info [UMFPACK_VARIABLE_PEAK_ESTIMATE], Info [UMFPACK_VARIABLE_PEAK]) ;
+ print_ratio (" final size (Units)", " %20.0f",
+ Info [UMFPACK_VARIABLE_FINAL_ESTIMATE], Info [UMFPACK_VARIABLE_FINAL]) ;
+ print_ratio ("Numeric final size (Units)", " %20.0f",
+ Info [UMFPACK_NUMERIC_SIZE_ESTIMATE], Info [UMFPACK_NUMERIC_SIZE]) ;
+ print_ratio ("Numeric final size (MBytes)", " %20.1f",
+ MBYTES (Info [UMFPACK_NUMERIC_SIZE_ESTIMATE]),
+ MBYTES (Info [UMFPACK_NUMERIC_SIZE])) ;
+ print_ratio ("peak memory usage (Units)", " %20.0f",
+ Info [UMFPACK_PEAK_MEMORY_ESTIMATE], Info [UMFPACK_PEAK_MEMORY]) ;
+ print_ratio ("peak memory usage (MBytes)", " %20.1f",
+ MBYTES (Info [UMFPACK_PEAK_MEMORY_ESTIMATE]),
+ MBYTES (Info [UMFPACK_PEAK_MEMORY])) ;
+ print_ratio ("numeric factorization flops", " %20.5e",
+ Info [UMFPACK_FLOPS_ESTIMATE], Info [UMFPACK_FLOPS]) ;
+
+ lnz_est = Info [UMFPACK_LNZ_ESTIMATE] ;
+ unz_est = Info [UMFPACK_UNZ_ESTIMATE] ;
+ if (lnz_est >= 0 && unz_est >= 0) /* double relop, but ignore NaN case */
+ {
+ lunz_est = lnz_est + unz_est - n_inner ;
+ }
+ else
+ {
+ lunz_est = EMPTY ;
+ }
+ lnz = Info [UMFPACK_LNZ] ;
+ unz = Info [UMFPACK_UNZ] ;
+ if (lnz >= 0 && unz >= 0) /* double relop, but ignore NaN case */
+ {
+ lunz = lnz + unz - n_inner ;
+ }
+ else
+ {
+ lunz = EMPTY ;
+ }
+ print_ratio ("nz in L (incl diagonal)", " %20.0f", lnz_est, lnz) ;
+ print_ratio ("nz in U (incl diagonal)", " %20.0f", unz_est, unz) ;
+ print_ratio ("nz in L+U (incl diagonal)", " %20.0f", lunz_est, lunz) ;
+
+ print_ratio ("largest front (# entries)", " %20.0f",
+ Info [UMFPACK_MAX_FRONT_SIZE_ESTIMATE], Info [UMFPACK_MAX_FRONT_SIZE]) ;
+ print_ratio ("largest # rows in front", " %20.0f",
+ Info [UMFPACK_MAX_FRONT_NROWS_ESTIMATE],
+ Info [UMFPACK_MAX_FRONT_NROWS]) ;
+ print_ratio ("largest # columns in front", " %20.0f",
+ Info [UMFPACK_MAX_FRONT_NCOLS_ESTIMATE],
+ Info [UMFPACK_MAX_FRONT_NCOLS]) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* numeric factorization */
+ /* ---------------------------------------------------------------------- */
+
+ tnum = Info [UMFPACK_NUMERIC_TIME] ;
+ twnum = Info [UMFPACK_NUMERIC_WALLTIME] ;
+ fnum = Info [UMFPACK_FLOPS] ;
+
+ PRINT_INFO ("\n initial allocation ratio used: %0.3g\n",
+ Info [UMFPACK_ALLOC_INIT_USED]) ;
+ PRINT_INFO (" # of forced updates due to frontal growth: %.0f\n",
+ Info [UMFPACK_FORCED_UPDATES]) ;
+ PRINT_INFO (" number of off-diagonal pivots: %.0f\n",
+ Info [UMFPACK_NOFF_DIAG]) ;
+ PRINT_INFO (" nz in L (incl diagonal), if none dropped %.0f\n",
+ Info [UMFPACK_ALL_LNZ]) ;
+ PRINT_INFO (" nz in U (incl diagonal), if none dropped %.0f\n",
+ Info [UMFPACK_ALL_UNZ]) ;
+ PRINT_INFO (" number of small entries dropped %.0f\n",
+ Info [UMFPACK_NZDROPPED]) ;
+ PRINT_INFO (" nonzeros on diagonal of U: %.0f\n",
+ Info [UMFPACK_UDIAG_NZ]) ;
+ PRINT_INFO (" min abs. value on diagonal of U: %.2e\n",
+ Info [UMFPACK_UMIN]) ;
+ PRINT_INFO (" max abs. value on diagonal of U: %.2e\n",
+ Info [UMFPACK_UMAX]) ;
+ PRINT_INFO (" estimate of reciprocal of condition number: %.2e\n",
+ Info [UMFPACK_RCOND]) ;
+ PRINT_INFO (" indices in compressed pattern: %.0f\n",
+ Info [UMFPACK_COMPRESSED_PATTERN]) ;
+ PRINT_INFO (" numerical values stored in Numeric object: %.0f\n",
+ Info [UMFPACK_LU_ENTRIES]) ;
+ PRINT_INFO (" numeric factorization defragmentations: %.0f\n",
+ Info [UMFPACK_NUMERIC_DEFRAG]) ;
+ PRINT_INFO (" numeric factorization reallocations: %.0f\n",
+ Info [UMFPACK_NUMERIC_REALLOC]) ;
+ PRINT_INFO (" costly numeric factorization reallocations: %.0f\n",
+ Info [UMFPACK_NUMERIC_COSTLY_REALLOC]) ;
+ PRINT_INFO (" numeric factorization CPU time (sec): %.2f\n",
+ tnum) ;
+ PRINT_INFO (" numeric factorization wallclock time (sec): %.2f\n",
+ twnum) ;
+
+ if (tnum > 0 && fnum > 0)
+ {
+ PRINT_INFO (
+ " numeric factorization mflops (CPU time): %.2f\n",
+ 1e-6 * fnum / tnum) ;
+ }
+ if (twnum > 0 && fnum > 0)
+ {
+ PRINT_INFO (
+ " numeric factorization mflops (wallclock): %.2f\n",
+ 1e-6 * fnum / twnum) ;
+ }
+
+ ttot = EMPTY ;
+ ftot = fnum ;
+ if (tsym >= 0 && tnum >= 0)
+ {
+ ttot = tsym + tnum ;
+ PRINT_INFO (" symbolic + numeric CPU time (sec): %.2f\n",
+ ttot) ;
+ if (ftot > 0 && ttot > 0)
+ {
+ PRINT_INFO (
+ " symbolic + numeric mflops (CPU time): %.2f\n",
+ 1e-6 * ftot / ttot) ;
+ }
+ }
+
+ twtot = EMPTY ;
+ if (twsym >= 0 && twnum >= 0)
+ {
+ twtot = twsym + twnum ;
+ PRINT_INFO (" symbolic + numeric wall clock time (sec): %.2f\n",
+ twtot) ;
+ if (ftot > 0 && twtot > 0)
+ {
+ PRINT_INFO (
+ " symbolic + numeric mflops (wall clock): %.2f\n",
+ 1e-6 * ftot / twtot) ;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* solve */
+ /* ---------------------------------------------------------------------- */
+
+ tsolve = Info [UMFPACK_SOLVE_TIME] ;
+ twsolve = Info [UMFPACK_SOLVE_WALLTIME] ;
+ fsolve = Info [UMFPACK_SOLVE_FLOPS] ;
+
+ PRINT_INFO ("\n solve flops: %.5e\n",
+ fsolve) ;
+ PRINT_INFO (" iterative refinement steps taken: %.0f\n",
+ Info [UMFPACK_IR_TAKEN]) ;
+ PRINT_INFO (" iterative refinement steps attempted: %.0f\n",
+ Info [UMFPACK_IR_ATTEMPTED]) ;
+ PRINT_INFO (" sparse backward error omega1: %.2e\n",
+ Info [UMFPACK_OMEGA1]) ;
+ PRINT_INFO (" sparse backward error omega2: %.2e\n",
+ Info [UMFPACK_OMEGA2]) ;
+ PRINT_INFO (" solve CPU time (sec): %.2f\n",
+ tsolve) ;
+ PRINT_INFO (" solve wall clock time (sec): %.2f\n",
+ twsolve) ;
+ if (fsolve > 0 && tsolve > 0)
+ {
+ PRINT_INFO (
+ " solve mflops (CPU time): %.2f\n",
+ 1e-6 * fsolve / tsolve) ;
+ }
+ if (fsolve > 0 && twsolve > 0)
+ {
+ PRINT_INFO (
+ " solve mflops (wall clock time): %.2f\n",
+ 1e-6 * fsolve / twsolve) ;
+ }
+
+ if (ftot >= 0 && fsolve >= 0)
+ {
+ ftot += fsolve ;
+ PRINT_INFO (
+ "\n total symbolic + numeric + solve flops: %.5e\n", ftot) ;
+ }
+
+ if (tsolve >= 0)
+ {
+ if (ttot >= 0 && ftot >= 0)
+ {
+ ttot += tsolve ;
+ PRINT_INFO (
+ " total symbolic + numeric + solve CPU time: %.2f\n",
+ ttot) ;
+ if (ftot > 0 && ttot > 0)
+ {
+ PRINT_INFO (
+ " total symbolic + numeric + solve mflops (CPU): %.2f\n",
+ 1e-6 * ftot / ttot) ;
+ }
+ }
+ }
+
+ if (twsolve >= 0)
+ {
+ if (twtot >= 0 && ftot >= 0)
+ {
+ twtot += tsolve ;
+ PRINT_INFO (
+ " total symbolic+numeric+solve wall clock time: %.2f\n",
+ twtot) ;
+ if (ftot > 0 && twtot > 0)
+ {
+ PRINT_INFO (
+ " total symbolic+numeric+solve mflops(wallclock) %.2f\n",
+ 1e-6 * ftot / twtot) ;
+ }
+ }
+ }
+ PRINTF (("\n")) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_report_matrix ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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. Prints a column or row-oriented matrix. See
+ umfpack_report_matrix.h for details.
+*/
+
+#include "umf_internal.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+GLOBAL Int UMFPACK_report_matrix
+(
+ Int n_row,
+ Int n_col,
+ const Int Ap [ ],
+ const Int Ai [ ],
+ const double Ax [ ],
+#ifdef COMPLEX
+ const double Az [ ],
+#endif
+ Int col_form, /* 1: column form, 0: row form */
+ const double Control [UMFPACK_CONTROL]
+)
+{
+ Int prl, i, k, length, ilast, p, nz, prl1, p1, p2, n, n_i, do_values ;
+ char *vector, *index ;
+ Entry a ;
+
+ /* ---------------------------------------------------------------------- */
+ /* determine the form, and check if inputs exist */
+ /* ---------------------------------------------------------------------- */
+
+ prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+ if (prl <= 2)
+ {
+ return (UMFPACK_OK) ;
+ }
+
+ if (col_form)
+ {
+ vector = "column" ; /* column vectors */
+ index = "row" ; /* with row indices */
+ n = n_col ;
+ n_i = n_row ;
+ }
+ else
+ {
+ vector = "row" ; /* row vectors */
+ index = "column" ; /* with column indices */
+ n = n_row ;
+ n_i = n_col ;
+ }
+
+ PRINTF (("%s-form matrix, n_row "ID" n_col "ID", ", vector, n_row, n_col)) ;
+
+ if (n_row <= 0 || n_col <= 0)
+ {
+ PRINTF (("ERROR: n_row <= 0 or n_col <= 0\n\n")) ;
+ return (UMFPACK_ERROR_n_nonpositive) ;
+ }
+
+ if (!Ap)
+ {
+ PRINTF (("ERROR: Ap missing\n\n")) ;
+ return (UMFPACK_ERROR_argument_missing) ;
+ }
+
+ nz = Ap [n] ;
+ PRINTF (("nz = "ID". ", nz)) ;
+ if (nz < 0)
+ {
+ PRINTF (("ERROR: number of entries < 0\n\n")) ;
+ return (UMFPACK_ERROR_invalid_matrix) ;
+ }
+
+ if (Ap [0] != 0)
+ {
+ PRINTF (("ERROR: Ap ["ID"] = "ID" must be "ID"\n\n",
+ (Int) INDEX (0), INDEX (Ap [0]), (Int) INDEX (0))) ;
+ return (UMFPACK_ERROR_invalid_matrix) ;
+ }
+
+ if (!Ai)
+ {
+ PRINTF (("ERROR: Ai missing\n\n")) ;
+ return (UMFPACK_ERROR_argument_missing) ;
+ }
+
+#ifdef COMPLEX
+ do_values = Ax && Az ;
+#else
+ do_values = Ax != (double *) NULL ;
+#endif
+
+ PRINTF4 (("\n")) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* check the row/column pointers, Ap */
+ /* ---------------------------------------------------------------------- */
+
+ for (k = 0 ; k < n ; k++)
+ {
+ if (Ap [k] < 0)
+ {
+ PRINTF (("ERROR: Ap ["ID"] < 0\n\n", INDEX (k))) ;
+ return (UMFPACK_ERROR_invalid_matrix) ;
+ }
+ if (Ap [k] > nz)
+ {
+ PRINTF (("ERROR: Ap ["ID"] > size of Ai\n\n", INDEX (k))) ;
+ return (UMFPACK_ERROR_invalid_matrix) ;
+ }
+ }
+
+ for (k = 0 ; k < n ; k++)
+ {
+ length = Ap [k+1] - Ap [k] ;
+ if (length < 0)
+ {
+ PRINTF (("ERROR: # entries in %s "ID" is < 0\n\n",
+ vector, INDEX (k))) ;
+ return (UMFPACK_ERROR_invalid_matrix) ;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* print each vector */
+ /* ---------------------------------------------------------------------- */
+
+ prl1 = prl ;
+
+ for (k = 0 ; k < n ; k++)
+ {
+ /* if prl is 4, print the first 10 entries of the first 10 vectors */
+ if (k < 10)
+ {
+ prl = prl1 ;
+ }
+ /* get the vector pointers */
+ p1 = Ap [k] ;
+ p2 = Ap [k+1] ;
+ length = p2 - p1 ;
+ PRINTF4 (("\n %s "ID": start: "ID" end: "ID" entries: "ID"\n",
+ vector, INDEX (k), p1, p2-1, length)) ;
+ ilast = EMPTY ;
+ for (p = p1 ; p < p2 ; p++)
+ {
+ i = Ai [p] ;
+ PRINTF4 (("\t%s "ID" ", index, INDEX (i))) ;
+ if (do_values && prl >= 4)
+ {
+ PRINTF ((":")) ;
+ ASSIGN (a, Ax [p], Az [p]) ;
+ PRINT_ENTRY (a) ;
+ }
+ if (i < 0 || i >= n_i)
+ {
+ PRINTF ((" ERROR: %s index "ID" out of range in %s "ID"\n\n",
+ index, INDEX (i), vector, INDEX (k))) ;
+ return (UMFPACK_ERROR_invalid_matrix) ;
+ }
+ if (i <= ilast)
+ {
+ PRINTF ((" ERROR: %s index "ID" out of order (or duplicate) in "
+ "%s "ID"\n\n", index, INDEX (i), vector, INDEX (k))) ;
+ return (UMFPACK_ERROR_invalid_matrix) ;
+ }
+ PRINTF4 (("\n")) ;
+ /* truncate printout, but continue to check matrix */
+ if (prl == 4 && (p - p1) == 9 && length > 10)
+ {
+ PRINTF4 (("\t...\n")) ;
+ prl-- ;
+ }
+ ilast = i ;
+ }
+ /* truncate printout, but continue to check matrix */
+ if (prl == 4 && k == 9 && n > 10)
+ {
+ PRINTF4 (("\n ...\n")) ;
+ prl-- ;
+ }
+ }
+ prl = prl1 ;
+
+ /* ---------------------------------------------------------------------- */
+ /* return the status of the matrix */
+ /* ---------------------------------------------------------------------- */
+
+ PRINTF4 ((" %s-form matrix ", vector)) ;
+ PRINTF (("OK\n\n")) ;
+
+ return (UMFPACK_OK) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_report_numeric =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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. Prints the Numeric object.
+ See umfpack_report_numeric.h for details.
+
+ Dynamic memory usage: Allocates a size n*sizeof(Int) workspace via a single
+ call to UMF_malloc and then frees all of it via UMF_free on return. The
+ workspace is not allocated if an early error return occurs before the
+ workspace is needed.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+#include "umf_report_perm.h"
+#include "umf_report_vector.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+
+PRIVATE Int report_L
+(
+ NumericType *Numeric,
+ Int Pattern [ ],
+ Int prl
+) ;
+
+
+PRIVATE Int report_U
+(
+ NumericType *Numeric,
+ Int Pattern [ ],
+ Int prl
+) ;
+
+/* ========================================================================== */
+/* === UMFPACK_report_numeric =============================================== */
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_report_numeric
+(
+ void *NumericHandle,
+ const double Control [UMFPACK_CONTROL]
+)
+{
+ Int prl, *W, nn, n_row, n_col, n_inner, num_fixed_size, numeric_size,
+ npiv ;
+ NumericType *Numeric ;
+
+ prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+ if (prl <= 2)
+ {
+ return (UMFPACK_OK) ;
+ }
+
+ PRINTF (("Numeric object: ")) ;
+
+ Numeric = (NumericType *) NumericHandle ;
+ if (!UMF_valid_numeric (Numeric))
+ {
+ PRINTF (("ERROR: LU factors invalid\n\n")) ;
+ 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) ;
+ npiv = Numeric->npiv ;
+
+ DEBUG1 (("n_row "ID" n_col "ID" nn "ID" n_inner "ID" npiv "ID"\n",
+ n_row, n_col, nn, n_inner, npiv)) ;
+
+ /* size of Numeric object, except Numeric->Memory and Numeric->Upattern */
+ /* see also UMF_set_stats */
+ num_fixed_size =
+ UNITS (NumericType, 1) /* Numeric structure */
+ + UNITS (Entry, n_inner+1) /* D */
+ + UNITS (Int, n_row+1) /* Rperm */
+ + UNITS (Int, n_col+1) /* Cperm */
+ + 6 * UNITS (Int, npiv+1) /* Lpos, Uilen, Uip, Upos, Lilen, Lip */
+ + ((Numeric->scale != UMFPACK_SCALE_NONE) ?
+ UNITS (Entry, n_row) : 0) ; /* Rs */
+
+ DEBUG1 (("num fixed size: "ID"\n", num_fixed_size)) ;
+ DEBUG1 (("Numeric->size "ID"\n", Numeric->size)) ;
+ DEBUG1 (("ulen units "ID"\n", UNITS (Int, Numeric->ulen))) ;
+
+ /* size of Numeric->Memory is Numeric->size */
+ /* size of Numeric->Upattern is Numeric->ulen */
+ numeric_size = num_fixed_size + Numeric->size
+ + UNITS (Int, Numeric->ulen) ;
+
+ DEBUG1 (("numeric total size "ID"\n", numeric_size)) ;
+
+ if (prl >= 4)
+ {
+ PRINTF (("\n n_row: "ID" n_col: "ID"\n", n_row, n_col)) ;
+
+ PRINTF ((" relative pivot tolerance used: %g\n",
+ Numeric->relpt)) ;
+ PRINTF ((" relative symmetric pivot tolerance used: %g\n",
+ Numeric->relpt2)) ;
+
+ PRINTF ((" matrix scaled: ")) ;
+ if (Numeric->scale == UMFPACK_SCALE_NONE)
+ {
+ PRINTF (("no")) ;
+ }
+ else if (Numeric->scale == UMFPACK_SCALE_SUM)
+ {
+ PRINTF (("yes (divided each row by sum abs value in each row)\n")) ;
+ PRINTF ((" minimum sum (abs (rows of A)): %.5e\n",
+ Numeric->rsmin)) ;
+ PRINTF ((" maximum sum (abs (rows of A)): %.5e",
+ Numeric->rsmax)) ;
+ }
+ else if (Numeric->scale == UMFPACK_SCALE_MAX)
+ {
+ PRINTF (("yes (divided each row by max abs value in each row)\n")) ;
+ PRINTF ((" minimum max (abs (rows of A)): %.5e\n",
+ Numeric->rsmin)) ;
+ PRINTF ((" maximum max (abs (rows of A)): %.5e",
+ Numeric->rsmax)) ;
+ }
+ PRINTF (("\n")) ;
+
+ PRINTF ((" initial allocation parameter used: %g\n",
+ Numeric->alloc_init)) ;
+ PRINTF ((" frontal matrix allocation parameter used: %g\n",
+ Numeric->front_alloc_init)) ;
+ PRINTF ((" final total size of Numeric object (Units): "ID"\n",
+ numeric_size)) ;
+ PRINTF ((" final total size of Numeric object (MBytes): %.1f\n",
+ MBYTES (numeric_size))) ;
+ PRINTF ((" peak size of variable-size part (Units): "ID"\n",
+ Numeric->max_usage)) ;
+ PRINTF ((" peak size of variable-size part (MBytes): %.1f\n",
+ MBYTES (Numeric->max_usage))) ;
+ PRINTF ((" largest actual frontal matrix size: "ID"\n",
+ Numeric->maxfrsize)) ;
+ PRINTF ((" memory defragmentations: "ID"\n",
+ Numeric->ngarbage)) ;
+ PRINTF ((" memory reallocations: "ID"\n",
+ Numeric->nrealloc)) ;
+ PRINTF ((" costly memory reallocations: "ID"\n",
+ Numeric->ncostly)) ;
+ PRINTF ((" entries in compressed pattern (L and U): "ID"\n",
+ Numeric->isize)) ;
+ PRINTF ((" number of nonzeros in L (excl diag): "ID"\n",
+ Numeric->lnz)) ;
+ PRINTF ((" number of entries stored in L (excl diag): "ID"\n",
+ Numeric->nLentries)) ;
+ PRINTF ((" number of nonzeros in U (excl diag): "ID"\n",
+ Numeric->unz)) ;
+ PRINTF ((" number of entries stored in U (excl diag): "ID"\n",
+ Numeric->nUentries)) ;
+ PRINTF ((" factorization floating-point operations: %g\n",
+ Numeric->flops)) ;
+ PRINTF ((" number of nonzeros on diagonal of U: "ID"\n",
+ Numeric->nnzpiv)) ;
+ PRINTF ((" min abs. value on diagonal of U: %.5e\n",
+ Numeric->min_udiag)) ;
+ PRINTF ((" max abs. value on diagonal of U: %.5e\n",
+ Numeric->max_udiag)) ;
+ PRINTF ((" reciprocal condition number estimate: %.2e\n",
+ Numeric->rcond)) ;
+ }
+
+ W = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+ if (!W)
+ {
+ PRINTF ((" ERROR: out of memory to check Numeric object\n\n")) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+
+ if (Numeric->Rs)
+ {
+#ifndef NRECIPROCAL
+ if (Numeric->do_recip)
+ {
+ PRINTF4 (("\nScale factors applied via multiplication\n")) ;
+ }
+ else
+#endif
+ {
+ PRINTF4 (("\nScale factors applied via division\n")) ;
+ }
+ PRINTF4 (("Scale factors, Rs: ")) ;
+ (void) UMF_report_vector (n_row, Numeric->Rs, (double *) NULL,
+ prl, FALSE, TRUE) ;
+ }
+ else
+ {
+ PRINTF4 (("Scale factors, Rs: (not present)\n")) ;
+ }
+
+ PRINTF4 (("\nP: row ")) ;
+ if (UMF_report_perm (n_row, Numeric->Rperm, W, prl, 0) != UMFPACK_OK)
+ {
+ (void) UMF_free ((void *) W) ;
+ return (UMFPACK_ERROR_invalid_Numeric_object) ;
+ }
+
+ PRINTF4 (("\nQ: column ")) ;
+ if (UMF_report_perm (n_col, Numeric->Cperm, W, prl, 0) != UMFPACK_OK)
+ {
+ (void) UMF_free ((void *) W) ;
+ return (UMFPACK_ERROR_invalid_Numeric_object) ;
+ }
+
+ if (!report_L (Numeric, W, prl))
+ {
+ (void) UMF_free ((void *) W) ;
+ PRINTF ((" ERROR: L factor invalid\n\n")) ;
+ return (UMFPACK_ERROR_invalid_Numeric_object) ;
+ }
+
+ if (!report_U (Numeric, W, prl))
+ {
+ (void) UMF_free ((void *) W) ;
+ PRINTF ((" ERROR: U factor invalid\n\n")) ;
+ return (UMFPACK_ERROR_invalid_Numeric_object) ;
+ }
+
+ /* The diagonal of U is in "merged" (Entry) form, not "split" form. */
+ PRINTF4 (("\ndiagonal of U: ")) ;
+ (void) UMF_report_vector (n_inner, (double *) Numeric->D, (double *) NULL,
+ prl, FALSE, FALSE) ;
+
+ (void) UMF_free ((void *) W) ;
+
+ PRINTF4 ((" Numeric object: ")) ;
+ PRINTF (("OK\n\n")) ;
+ return (UMFPACK_OK) ;
+}
+
+
+/* ========================================================================== */
+/* === report_L ============================================================= */
+/* ========================================================================== */
+
+PRIVATE Int report_L
+(
+ NumericType *Numeric,
+ Int Pattern [ ],
+ Int prl
+)
+{
+ Int k, deg, *ip, j, row, n_row, *Lpos, *Lilen, valid, k1,
+ *Lip, newLchain, llen, prl1, pos, lp, p, npiv, n1, *Li ;
+ Entry *xp, *Lval ;
+
+ /* ---------------------------------------------------------------------- */
+
+ ASSERT (prl >= 3) ;
+
+ n_row = Numeric->n_row ;
+ npiv = Numeric->npiv ;
+ n1 = Numeric->n1 ;
+ Lpos = Numeric->Lpos ;
+ Lilen = Numeric->Lilen ;
+ Lip = Numeric->Lip ;
+ prl1 = prl ;
+ deg = 0 ;
+
+ PRINTF4 ((
+ "\nL in Numeric object, in column-oriented compressed-pattern form:\n"
+ " Diagonal entries are all equal to 1.0 (not stored)\n")) ;
+
+ ASSERT (Pattern != (Int *) NULL) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* print L */
+ /* ---------------------------------------------------------------------- */
+
+ k1 = 12 ;
+
+ /* ---------------------------------------------------------------------- */
+ /* print the singleton columns of L */
+ /* ---------------------------------------------------------------------- */
+
+ for (k = 0 ; k < n1 ; k++)
+ {
+ if (k1 > 0)
+ {
+ prl = prl1 ;
+ }
+ lp = Lip [k] ;
+ deg = Lilen [k] ;
+ Li = (Int *) (Numeric->Memory + lp) ;
+ lp += UNITS (Int, deg) ;
+ Lval = (Entry *) (Numeric->Memory + lp) ;
+ if (k1-- > 0)
+ {
+ prl = prl1 ;
+ }
+ else if (prl == 4)
+ {
+ PRINTF ((" ...\n")) ;
+ prl-- ;
+ }
+ PRINTF4 (("\n column "ID":", INDEX (k))) ;
+ PRINTF4 ((" length "ID".\n", deg)) ;
+ for (j = 0 ; j < deg ; j++)
+ {
+ row = Li [j] ;
+ PRINTF4 (("\trow "ID" : ", INDEX (row))) ;
+ if (prl >= 4) PRINT_ENTRY (Lval [j]) ;
+ if (row <= k || row >= n_row)
+ {
+ return (FALSE) ;
+ }
+ PRINTF4 (("\n")) ;
+ /* truncate printout, but continue to check L */
+ if (prl == 4 && j == 9 && deg > 10)
+ {
+ PRINTF (("\t...\n")) ;
+ prl-- ;
+ }
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* print the regular columns of L */
+ /* ---------------------------------------------------------------------- */
+
+ for (k = n1 ; k < npiv ; k++)
+ {
+ /* if prl is 4, print the first 10 entries of the first 10 columns */
+ if (k1 > 0)
+ {
+ prl = prl1 ;
+ }
+
+ lp = Lip [k] ;
+ newLchain = (lp < 0) ;
+ if (newLchain)
+ {
+ lp = -lp ;
+ deg = 0 ;
+ }
+
+ if (k1-- > 0)
+ {
+ prl = prl1 ;
+ }
+ else if (prl == 4)
+ {
+ PRINTF ((" ...\n")) ;
+ prl-- ;
+ }
+
+ PRINTF4 (("\n column "ID":", INDEX (k))) ;
+
+ /* ------------------------------------------------------------------ */
+ /* make column of L in Pattern [0..deg-1] */
+ /* ------------------------------------------------------------------ */
+
+ /* remove pivot row */
+ pos = Lpos [k] ;
+ if (pos != EMPTY)
+ {
+ PRINTF4 ((" remove row "ID" at position "ID".",
+ INDEX (Pattern [pos]), INDEX (pos))) ;
+ valid = (!newLchain) && (deg > 0) && (pos < deg) && (pos >= 0)
+ && (Pattern [pos] == k) ;
+ if (!valid)
+ {
+ return (FALSE) ;
+ }
+ Pattern [pos] = Pattern [--deg] ;
+ }
+
+ /* concatenate the pattern */
+ llen = Lilen [k] ;
+ if (llen < 0)
+ {
+ return (FALSE) ;
+ }
+ p = lp + UNITS (Int, llen) ;
+ xp = (Entry *) (Numeric->Memory + p) ;
+ if ((llen > 0 || deg > 0)
+ && (p + (Int) UNITS (Entry, deg) > Numeric->size))
+ {
+ return (FALSE) ;
+ }
+ if (llen > 0)
+ {
+ PRINTF4 ((" add "ID" entries.", llen)) ;
+ ip = (Int *) (Numeric->Memory + lp) ;
+ for (j = 0 ; j < llen ; j++)
+ {
+ Pattern [deg++] = *ip++ ;
+ }
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* print column k of L */
+ /* ------------------------------------------------------------------ */
+
+ PRINTF4 ((" length "ID".", deg)) ;
+ if (newLchain)
+ {
+ PRINTF4 ((" Start of Lchain.")) ;
+ }
+ PRINTF4 (("\n")) ;
+
+ for (j = 0 ; j < deg ; j++)
+ {
+ row = Pattern [j] ;
+ PRINTF4 (("\trow "ID" : ", INDEX (row))) ;
+ if (prl >= 4) PRINT_ENTRY (*xp) ;
+ if (row <= k || row >= n_row)
+ {
+ return (FALSE) ;
+ }
+ PRINTF4 (("\n")) ;
+ xp++ ;
+ /* truncate printout, but continue to check L */
+ if (prl == 4 && j == 9 && deg > 10)
+ {
+ PRINTF (("\t...\n")) ;
+ prl-- ;
+ }
+ }
+ }
+
+ PRINTF4 (("\n")) ;
+ return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === report_U ============================================================= */
+/* ========================================================================== */
+
+PRIVATE Int report_U
+(
+ NumericType *Numeric,
+ Int Pattern [ ],
+ Int prl
+)
+{
+ /* ---------------------------------------------------------------------- */
+
+ Int k, deg, j, *ip, col, *Upos, *Uilen, k1, prl1, pos,
+ *Uip, n_col, ulen, p, newUchain, up, npiv, n1, *Ui ;
+ Entry *xp, *Uval ;
+
+ /* ---------------------------------------------------------------------- */
+
+ ASSERT (prl >= 3) ;
+
+ n_col = Numeric->n_col ;
+ npiv = Numeric->npiv ;
+ n1 = Numeric->n1 ;
+ Upos = Numeric->Upos ;
+ Uilen = Numeric->Uilen ;
+ Uip = Numeric->Uip ;
+ prl1 = prl ;
+
+ PRINTF4 ((
+ "\nU in Numeric object, in row-oriented compressed-pattern form:\n"
+ " Diagonal is stored separately.\n")) ;
+
+ ASSERT (Pattern != (Int *) NULL) ;
+
+ k1 = 12 ;
+
+ /* ---------------------------------------------------------------------- */
+ /* print the sparse part 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] ;
+ }
+ }
+
+ PRINTF4 (("\n row "ID": length "ID". End of Uchain.\n", INDEX (npiv-1),
+ deg)) ;
+
+ for (k = npiv-1 ; k >= n1 ; k--)
+ {
+
+ /* ------------------------------------------------------------------ */
+ /* print row k of U */
+ /* ------------------------------------------------------------------ */
+
+ /* if prl is 3, print the first 10 entries of the first 10 columns */
+ if (k1 > 0)
+ {
+ prl = prl1 ;
+ }
+
+ up = Uip [k] ;
+ ulen = Uilen [k] ;
+ if (ulen < 0)
+ {
+ return (FALSE) ;
+ }
+ newUchain = (up < 0) ;
+ if (newUchain)
+ {
+ up = -up ;
+ p = up + UNITS (Int, ulen) ;
+ }
+ else
+ {
+ p = up ;
+ }
+ xp = (Entry *) (Numeric->Memory + p) ;
+ if (deg > 0 && (p + (Int) UNITS (Entry, deg) > Numeric->size))
+ {
+ return (FALSE) ;
+ }
+ for (j = 0 ; j < deg ; j++)
+ {
+ col = Pattern [j] ;
+ PRINTF4 (("\tcol "ID" :", INDEX (col))) ;
+ if (prl >= 4) PRINT_ENTRY (*xp) ;
+ if (col <= k || col >= n_col)
+ {
+ return (FALSE) ;
+ }
+ PRINTF4 (("\n")) ;
+ xp++ ;
+ /* truncate printout, but continue to check U */
+ if (prl == 4 && j == 9 && deg > 10)
+ {
+ PRINTF (("\t...\n")) ;
+ prl-- ;
+ }
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* make row k-1 of U in Pattern [0..deg-1] */
+ /* ------------------------------------------------------------------ */
+
+ if (k1-- > 0)
+ {
+ prl = prl1 ;
+ }
+ else if (prl == 4)
+ {
+ PRINTF ((" ...\n")) ;
+ prl-- ;
+ }
+
+ if (k > 0)
+ {
+ PRINTF4 (("\n row "ID": ", INDEX (k-1))) ;
+ }
+
+ if (newUchain)
+ {
+ /* next row is a new Uchain */
+ if (k > 0)
+ {
+ deg = ulen ;
+ PRINTF4 (("length "ID". End of Uchain.\n", deg)) ;
+ if (up + (Int) UNITS (Int, ulen) > Numeric->size)
+ {
+ return (FALSE) ;
+ }
+ ip = (Int *) (Numeric->Memory + up) ;
+ for (j = 0 ; j < deg ; j++)
+ {
+ Pattern [j] = *ip++ ;
+ }
+ }
+ }
+ else
+ {
+ if (ulen > 0)
+ {
+ PRINTF4 (("remove "ID" entries. ", ulen)) ;
+ }
+ deg -= ulen ;
+ if (deg < 0)
+ {
+ return (FALSE) ;
+ }
+ pos = Upos [k] ;
+ if (pos != EMPTY)
+ {
+ /* add the pivot column */
+ PRINTF4 (("add column "ID" at position "ID". ",
+ INDEX (k), INDEX (pos))) ;
+ if (pos < 0 || pos > deg)
+ {
+ return (FALSE) ;
+ }
+ Pattern [deg++] = Pattern [pos] ;
+ Pattern [pos] = k ;
+ }
+ PRINTF4 (("length "ID".\n", deg)) ;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* print the singleton rows of U */
+ /* ---------------------------------------------------------------------- */
+
+ for (k = n1 - 1 ; k >= 0 ; k--)
+ {
+ if (k1 > 0)
+ {
+ prl = prl1 ;
+ }
+ up = Uip [k] ;
+ deg = Uilen [k] ;
+ Ui = (Int *) (Numeric->Memory + up) ;
+ up += UNITS (Int, deg) ;
+ Uval = (Entry *) (Numeric->Memory + up) ;
+ if (k1-- > 0)
+ {
+ prl = prl1 ;
+ }
+ else if (prl == 4)
+ {
+ PRINTF ((" ...\n")) ;
+ prl-- ;
+ }
+ PRINTF4 (("\n row "ID":", INDEX (k))) ;
+ PRINTF4 ((" length "ID".\n", deg)) ;
+ for (j = 0 ; j < deg ; j++)
+ {
+ col = Ui [j] ;
+ PRINTF4 (("\tcol "ID" : ", INDEX (col))) ;
+ if (prl >= 4) PRINT_ENTRY (Uval [j]) ;
+ if (col <= k || col >= n_col)
+ {
+ return (FALSE) ;
+ }
+ PRINTF4 (("\n")) ;
+ /* truncate printout, but continue to check U */
+ if (prl == 4 && j == 9 && deg > 10)
+ {
+ PRINTF (("\t...\n")) ;
+ prl-- ;
+ }
+ }
+ }
+
+ prl = prl1 ;
+ PRINTF4 (("\n")) ;
+ return (TRUE) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_report_perm ================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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. Prints a permutation vector. See umfpack_report_perm.h
+ for details.
+
+ Dynamic memory usage: Allocates a size max(np,1)*sizeof(Int) workspace via
+ a single call to UMF_malloc and then frees all of it via UMF_free on return.
+*/
+
+#include "umf_internal.h"
+#include "umf_report_perm.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+GLOBAL Int UMFPACK_report_perm
+(
+ Int np,
+ const Int Perm [ ],
+ const double Control [UMFPACK_CONTROL]
+)
+{
+ Int prl, *W, status ;
+
+ prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+ if (prl <= 2)
+ {
+ return (UMFPACK_OK) ;
+ }
+
+ W = (Int *) UMF_malloc (MAX (np,1), sizeof (Int)) ;
+ status = UMF_report_perm (np, Perm, W, prl, 1) ;
+ (void) UMF_free ((void *) W) ;
+ return (status) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_report_status ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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. Prints the return value from other UMFPACK_* routines.
+ See umfpack_report_status.h for details.
+*/
+
+#include "umf_internal.h"
+
+GLOBAL void UMFPACK_report_status
+(
+ const double Control [UMFPACK_CONTROL],
+ Int status
+)
+{
+ Int prl ;
+
+ /* ---------------------------------------------------------------------- */
+ /* get control settings and status to determine what to print */
+ /* ---------------------------------------------------------------------- */
+
+ prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+ if (prl < 1)
+ {
+ /* no output generated if prl is less than 1 */
+ return ;
+ }
+
+ if (status == UMFPACK_OK && prl <= 1)
+ {
+ /* no output generated if prl is 1 or less and no error occured. */
+ /* note that the default printing level is 1. */
+ return ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* print umfpack license, copyright, version, and status condition */
+ /* ---------------------------------------------------------------------- */
+
+ PRINTF (("\n")) ;
+ PRINTF4 (("%s\n", UMFPACK_COPYRIGHT)) ;
+ PRINTF6 (("%s", UMFPACK_LICENSE_PART1)) ;
+ PRINTF6 (("%s", UMFPACK_LICENSE_PART2)) ;
+ PRINTF6 (("%s", UMFPACK_LICENSE_PART3)) ;
+ PRINTF (("%s: ", UMFPACK_VERSION)) ;
+
+ switch (status)
+ {
+ case UMFPACK_OK:
+ PRINTF (("OK\n")) ;
+ break ;
+
+ case UMFPACK_WARNING_singular_matrix:
+ PRINTF (("WARNING: matrix is singular\n")) ;
+ break ;
+
+ case UMFPACK_ERROR_out_of_memory:
+ PRINTF (("ERROR: out of memory\n")) ;
+ break ;
+
+ case UMFPACK_ERROR_invalid_Numeric_object:
+ PRINTF (("ERROR: Numeric object is invalid\n")) ;
+ break ;
+
+ case UMFPACK_ERROR_invalid_Symbolic_object:
+ PRINTF (("ERROR: Symbolic object is invalid\n")) ;
+ break ;
+
+ case UMFPACK_ERROR_argument_missing:
+ PRINTF (("ERROR: required argument(s) missing\n")) ;
+ break ;
+
+ case UMFPACK_ERROR_n_nonpositive:
+ PRINTF (("ERROR: dimension (n_row or n_col) must be > 0\n")) ;
+ break ;
+
+ case UMFPACK_ERROR_invalid_matrix:
+ PRINTF (("ERROR: input matrix is invalid\n")) ;
+ break ;
+
+ case UMFPACK_ERROR_invalid_system:
+ PRINTF (("ERROR: system argument invalid\n")) ;
+ break ;
+
+ case UMFPACK_ERROR_invalid_permutation:
+ PRINTF (("ERROR: invalid permutation\n")) ;
+ break ;
+
+ case UMFPACK_ERROR_different_pattern:
+ PRINTF (("ERROR: pattern of matrix (Ap and/or Ai) has changed\n")) ;
+ break ;
+
+ case UMFPACK_ERROR_internal_error:
+ PRINTF (("INTERNAL ERROR!\n"
+ "Input arguments might be corrupted or aliased, or an internal\n"
+ "error has occurred. Check your input arguments with the\n"
+ "umfpack_*_report_* routines before calling the umfpack_*\n"
+ "computational routines. Recompile UMFPACK with debugging\n"
+ "enabled, and look for failed assertions. If all else fails\n"
+ "please report this error to Tim Davis (davis@cise.ufl.edu).\n"
+ )) ;
+ break ;
+
+ default:
+ PRINTF (("ERROR: Unrecognized error code: "ID"\n", status)) ;
+
+ }
+ PRINTF (("\n")) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_report_symbolic ============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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. Prints the Symbolic object. See umfpack_report_symbolic.h
+ for details. Does not print new Cdeg, Rdeg, Esize, and the Diagonal_map.
+
+ Dynamic memory usage: Allocates a size MAX (n_row,n_col)*sizeof(Int)
+ workspace via a single call to UMF_malloc and then frees all of it via
+ UMF_free on return. The workspace is not allocated if an early error
+ return occurs before the workspace is needed.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_symbolic.h"
+#include "umf_report_perm.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+
+GLOBAL Int UMFPACK_report_symbolic
+(
+ void *SymbolicHandle,
+ const double Control [UMFPACK_CONTROL]
+)
+{
+ Int n_row, n_col, nz, nchains, nfr, maxnrows, maxncols, prl,
+ k, chain, frontid, frontid1, frontid2, kk, *Chain_start, *W,
+ *Chain_maxrows, *Chain_maxcols, *Front_npivcol, *Front_1strow,
+ *Front_leftmostdesc, *Front_parent, done, status1, status2 ;
+ SymbolicType *Symbolic ;
+
+ prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+ if (prl <= 2)
+ {
+ return (UMFPACK_OK) ;
+ }
+
+ PRINTF (("Symbolic object: ")) ;
+
+ Symbolic = (SymbolicType *) SymbolicHandle ;
+ if (!UMF_valid_symbolic (Symbolic))
+ {
+ PRINTF (("ERROR: invalid\n")) ;
+ return (UMFPACK_ERROR_invalid_Symbolic_object) ;
+ }
+
+ n_row = Symbolic->n_row ;
+ n_col = Symbolic->n_col ;
+
+ nz = Symbolic->nz ;
+
+ nchains = Symbolic->nchains ;
+ nfr = Symbolic->nfr ;
+ maxnrows = Symbolic->maxnrows ;
+ maxncols = Symbolic->maxncols ;
+
+ Chain_start = Symbolic->Chain_start ;
+ Chain_maxrows = Symbolic->Chain_maxrows ;
+ Chain_maxcols = Symbolic->Chain_maxcols ;
+ Front_npivcol = Symbolic->Front_npivcol ;
+ Front_1strow = Symbolic->Front_1strow ;
+ Front_leftmostdesc = Symbolic->Front_leftmostdesc ;
+ Front_parent = Symbolic->Front_parent ;
+
+ if (prl >= 4)
+ {
+
+ PRINTF (("\n matrix to be factorized:\n")) ;
+ PRINTF (("\tn_row: "ID" n_col: "ID"\n", n_row, n_col)) ;
+ PRINTF (("\tnumber of entries: "ID"\n", nz)) ;
+ PRINTF ((" block size used for dense matrix kernels: "ID"\n",
+ Symbolic->nb)) ;
+
+ PRINTF ((" strategy used: ")) ;
+ /* strategy cannot be auto */
+ if (Symbolic->strategy == UMFPACK_STRATEGY_SYMMETRIC)
+ {
+ PRINTF (("symmetric")) ;
+ }
+ else if (Symbolic->strategy == UMFPACK_STRATEGY_UNSYMMETRIC)
+ {
+ PRINTF (("unsymmetric")) ;
+ }
+ else if (Symbolic->strategy == UMFPACK_STRATEGY_2BY2)
+ {
+ PRINTF (("symmetric 2-by-2")) ;
+ }
+ PRINTF (("\n")) ;
+
+ PRINTF ((" ordering used: ")) ;
+ if (Symbolic->ordering == UMFPACK_ORDERING_COLAMD)
+ {
+ PRINTF (("colamd on A\n")) ;
+ }
+ else if (Symbolic->ordering == UMFPACK_ORDERING_AMD)
+ {
+ PRINTF (("amd on A+A'\n")) ;
+ }
+ else if (Symbolic->ordering == UMFPACK_ORDERING_GIVEN)
+ {
+ PRINTF (("provided by user")) ;
+ }
+ PRINTF (("\n")) ;
+
+ PRINTF ((" performn column etree postorder: ")) ;
+ if (Symbolic->fixQ)
+ {
+ PRINTF (("no\n")) ;
+ }
+ else
+ {
+ PRINTF (("yes\n")) ;
+ }
+
+ PRINTF ((" prefer diagonal pivoting (attempt P=Q): ")) ;
+ if (Symbolic->prefer_diagonal)
+ {
+ PRINTF (("yes\n")) ;
+ }
+ else
+ {
+ PRINTF (("no\n")) ;
+ }
+
+ PRINTF ((" variable-size part of Numeric object:\n")) ;
+ PRINTF (("\tminimum initial size (Units): %.20g (MBytes): %.1f\n",
+ Symbolic->dnum_mem_init_usage,
+ MBYTES (Symbolic->dnum_mem_init_usage))) ;
+ PRINTF (("\testimated peak size (Units): %.20g (MBytes): %.1f\n",
+ Symbolic->num_mem_usage_est,
+ MBYTES (Symbolic->num_mem_usage_est))) ;
+ PRINTF (("\testimated final size (Units): %.20g (MBytes): %.1f\n",
+ Symbolic->num_mem_size_est,
+ MBYTES (Symbolic->num_mem_size_est))) ;
+ PRINTF ((" symbolic factorization memory usage (Units):"
+ " %.20g (MBytes): %.1f\n",
+ Symbolic->peak_sym_usage,
+ MBYTES (Symbolic->peak_sym_usage))) ;
+ PRINTF ((" frontal matrices / supercolumns:\n")) ;
+ PRINTF (("\tnumber of frontal chains: "ID"\n", nchains)) ;
+ PRINTF (("\tnumber of frontal matrices: "ID"\n", nfr)) ;
+ PRINTF (("\tlargest frontal matrix row dimension: "ID"\n", maxnrows)) ;
+ PRINTF (("\tlargest frontal matrix column dimension: "ID"\n",maxncols));
+ }
+
+ k = 0 ;
+ done = FALSE ;
+
+ for (chain = 0 ; chain < nchains ; chain++)
+ {
+ frontid1 = Chain_start [chain] ;
+ frontid2 = Chain_start [chain+1] - 1 ;
+ PRINTF4 (("\n Frontal chain: "ID". Frontal matrices "ID" to "ID"\n",
+ INDEX (chain), INDEX (frontid1), INDEX (frontid2))) ;
+ PRINTF4 (("\tLargest frontal matrix in Frontal chain: "ID"-by-"ID"\n",
+ Chain_maxrows [chain], Chain_maxcols [chain])) ;
+ for (frontid = frontid1 ; frontid <= frontid2 ; frontid++)
+ {
+ kk = Front_npivcol [frontid] ;
+ PRINTF4 (("\tFront: "ID" pivot cols: "ID" (pivot columns "ID" to "
+ ID")\n", INDEX (frontid), kk, INDEX (k), INDEX (k+kk-1))) ;
+ PRINTF4 (("\t pivot row candidates: "ID" to "ID"\n",
+ INDEX (Front_1strow [Front_leftmostdesc [frontid]]),
+ INDEX (Front_1strow [frontid+1]-1))) ;
+ PRINTF4 (("\t leftmost descendant: "ID"\n",
+ INDEX (Front_leftmostdesc [frontid]))) ;
+ PRINTF4 (("\t 1st new candidate row : "ID"\n",
+ INDEX (Front_1strow [frontid]))) ;
+ PRINTF4 (("\t parent:")) ;
+ if (Front_parent [frontid] == EMPTY)
+ {
+ PRINTF4 ((" (none)\n")) ;
+ }
+ else
+ {
+ PRINTF4 ((" "ID"\n", INDEX (Front_parent [frontid]))) ;
+ }
+ done = (frontid == 20 && frontid < nfr-1 && prl == 4) ;
+ if (done)
+ {
+ PRINTF4 (("\t...\n")) ;
+ break ;
+ }
+ k += kk ;
+ }
+ if (Front_npivcol [nfr] != 0)
+ {
+ PRINTF4 (("\tFront: "ID" placeholder for "ID" empty columns\n",
+ INDEX (nfr), Front_npivcol [nfr])) ;
+ }
+ if (done)
+ {
+ break ;
+ }
+ }
+
+ W = (Int *) UMF_malloc (MAX (n_row, n_col), sizeof (Int)) ;
+ if (!W)
+ {
+ PRINTF (("ERROR: out of memory to check Symbolic object\n\n")) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+
+ PRINTF4 (("\nInitial column permutation, Q1: ")) ;
+ status1 = UMF_report_perm (n_col, Symbolic->Cperm_init, W, prl, 0) ;
+
+ PRINTF4 (("\nInitial row permutation, P1: ")) ;
+ status2 = UMF_report_perm (n_row, Symbolic->Rperm_init, W, prl, 0) ;
+
+ (void) UMF_free ((void *) W) ;
+
+ if (status1 != UMFPACK_OK || status2 != UMFPACK_OK)
+ {
+ return (UMFPACK_ERROR_invalid_Symbolic_object) ;
+ }
+
+ PRINTF4 ((" Symbolic object: ")) ;
+ PRINTF (("OK\n\n")) ;
+ return (UMFPACK_OK) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_report_triplet =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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. Prints a matrix in triplet form. See
+ umfpack_report_triplet.h for details.
+*/
+
+#include "umf_internal.h"
+
+GLOBAL Int UMFPACK_report_triplet
+(
+ Int n_row,
+ Int n_col,
+ Int nz,
+ const Int Ti [ ],
+ const Int Tj [ ],
+ const double Tx [ ],
+#ifdef COMPLEX
+ const double Tz [ ],
+#endif
+ const double Control [UMFPACK_CONTROL]
+)
+{
+ Int prl, prl1, k, i, j, do_values ;
+ Entry t ;
+
+ prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+ if (prl <= 2)
+ {
+ return (UMFPACK_OK) ;
+ }
+
+ PRINTF (("triplet-form matrix, n_row = "ID", n_col = "ID" nz = "ID". ",
+ n_row, n_col, nz)) ;
+
+ if (!Ti || !Tj)
+ {
+ PRINTF (("ERROR: indices not present\n\n")) ;
+ return (UMFPACK_ERROR_argument_missing) ;
+ }
+
+ if (n_row <= 0 || n_col <= 0)
+ {
+ PRINTF (("ERROR: n_row or n_col is <= 0\n\n")) ;
+ return (UMFPACK_ERROR_n_nonpositive) ;
+ }
+
+ if (nz < 0)
+ {
+ PRINTF (("ERROR: nz is < 0\n\n")) ;
+ return (UMFPACK_ERROR_invalid_matrix) ;
+ }
+
+ PRINTF4 (("\n")) ;
+
+#ifdef COMPLEX
+ do_values = Tx && Tz ;
+#else
+ do_values = Tx != (double *) NULL ;
+#endif
+
+ prl1 = prl ;
+ for (k = 0 ; k < nz ; k++)
+ {
+ i = Ti [k] ;
+ j = Tj [k] ;
+ PRINTF4 ((" "ID" : "ID" "ID" ", INDEX (k), INDEX (i), INDEX (j))) ;
+ if (do_values && prl >= 4)
+ {
+ ASSIGN (t, Tx [k], Tz [k]) ;
+ PRINT_ENTRY (t) ;
+ }
+ PRINTF4 (("\n")) ;
+ if (i < 0 || i >= n_row || j < 0 || j >= n_col)
+ {
+ /* invalid triplet */
+ PRINTF (("ERROR: invalid triplet\n\n")) ;
+ return (UMFPACK_ERROR_invalid_matrix) ;
+ }
+ if (prl == 4 && k == 9 && nz > 10)
+ {
+ PRINTF ((" ...\n")) ;
+ prl-- ;
+ }
+ }
+ prl = prl1 ;
+
+ PRINTF4 ((" triplet-form matrix ")) ;
+ PRINTF (("OK\n\n")) ;
+ return (UMFPACK_OK) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_report_vector ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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. Prints a real or complex vector.
+ See umfpack_report_vector.h for details.
+*/
+
+#include "umf_internal.h"
+#include "umf_report_vector.h"
+
+GLOBAL Int UMFPACK_report_vector
+(
+ Int n,
+ const double Xx [ ],
+#ifdef COMPLEX
+ const double Xz [ ],
+#endif
+ const double Control [UMFPACK_CONTROL]
+)
+{
+ Int prl ;
+
+#ifndef COMPLEX
+ double *Xz = (double *) NULL ;
+#endif
+
+ prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
+
+ if (prl <= 2)
+ {
+ return (UMFPACK_OK) ;
+ }
+
+ return (UMF_report_vector (n, Xx, Xz, prl, TRUE, FALSE)) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_save_numeric ================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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. Saves a Numeric object to a file. It can later be read back
+ in via a call to umfpack_*_load_numeric.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+
+#define WRITE(object,type,n) \
+{ \
+ ASSERT (object != (type *) NULL) ; \
+ if (fwrite (object, sizeof (type), n, f) != n) \
+ { \
+ fclose (f) ; \
+ return (UMFPACK_ERROR_file_IO) ; \
+ } \
+}
+
+/* ========================================================================== */
+/* === UMFPACK_save_numeric ================================================= */
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_save_numeric
+(
+ void *NumericHandle,
+ char *user_filename
+)
+{
+ NumericType *Numeric ;
+ char *filename ;
+ FILE *f ;
+
+ /* get the Numeric object */
+ Numeric = (NumericType *) NumericHandle ;
+
+ /* make sure the Numeric object is valid */
+ if (!UMF_valid_numeric (Numeric))
+ {
+ return (UMFPACK_ERROR_invalid_Numeric_object) ;
+ }
+
+ /* get the filename, or use the default name if filename is NULL */
+ if (user_filename == (char *) NULL)
+ {
+ filename = "numeric.umf" ;
+ }
+ else
+ {
+ filename = user_filename ;
+ }
+ f = fopen (filename, "wb") ;
+ if (!f)
+ {
+ return (UMFPACK_ERROR_file_IO) ;
+ }
+
+ /* write the Numeric object to the file, in binary */
+ WRITE (Numeric, NumericType, 1) ;
+ WRITE (Numeric->D, Entry, MIN (Numeric->n_row, Numeric->n_col)+1) ;
+ WRITE (Numeric->Rperm, Int, Numeric->n_row+1) ;
+ WRITE (Numeric->Cperm, Int, Numeric->n_col+1) ;
+ WRITE (Numeric->Lpos, Int, Numeric->npiv+1) ;
+ WRITE (Numeric->Lilen, Int, Numeric->npiv+1) ;
+ WRITE (Numeric->Lip, Int, Numeric->npiv+1) ;
+ WRITE (Numeric->Upos, Int, Numeric->npiv+1) ;
+ WRITE (Numeric->Uilen, Int, Numeric->npiv+1) ;
+ WRITE (Numeric->Uip, Int, Numeric->npiv+1) ;
+ if (Numeric->scale != UMFPACK_SCALE_NONE)
+ {
+ WRITE (Numeric->Rs, double, Numeric->n_row) ;
+ }
+ if (Numeric->ulen > 0)
+ {
+ WRITE (Numeric->Upattern, Int, Numeric->ulen+1) ;
+ }
+ WRITE (Numeric->Memory, Unit, Numeric->size) ;
+
+ /* close the file */
+ fclose (f) ;
+
+ return (UMFPACK_OK) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_save_symbolic ================================================ */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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. Saves a Symbolic object to a file. It can later be read
+ back in via a call to umfpack_*_load_symbolic.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_symbolic.h"
+
+#define WRITE(object,type,n) \
+{ \
+ ASSERT (object != (type *) NULL) ; \
+ if (fwrite (object, sizeof (type), n, f) != n) \
+ { \
+ fclose (f) ; \
+ return (UMFPACK_ERROR_file_IO) ; \
+ } \
+}
+
+/* ========================================================================== */
+/* === UMFPACK_save_symbolic ================================================ */
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_save_symbolic
+(
+ void *SymbolicHandle,
+ char *user_filename
+)
+{
+ SymbolicType *Symbolic ;
+ char *filename ;
+ FILE *f ;
+
+ /* get the Symbolic object */
+ Symbolic = (SymbolicType *) SymbolicHandle ;
+
+ /* make sure the Symbolic object is valid */
+ if (!UMF_valid_symbolic (Symbolic))
+ {
+ return (UMFPACK_ERROR_invalid_Symbolic_object) ;
+ }
+
+ /* get the filename, or use the default name if filename is NULL */
+ if (user_filename == (char *) NULL)
+ {
+ filename = "symbolic.umf" ;
+ }
+ else
+ {
+ filename = user_filename ;
+ }
+ f = fopen (filename, "wb") ;
+ if (!f)
+ {
+ return (UMFPACK_ERROR_file_IO) ;
+ }
+
+ /* write the Symbolic object to the file, in binary */
+ WRITE (Symbolic, SymbolicType, 1) ;
+ WRITE (Symbolic->Cperm_init, Int, Symbolic->n_col+1) ;
+ WRITE (Symbolic->Rperm_init, Int, Symbolic->n_row+1) ;
+ WRITE (Symbolic->Front_npivcol, Int, Symbolic->nfr+1) ;
+ WRITE (Symbolic->Front_parent, Int, Symbolic->nfr+1) ;
+ WRITE (Symbolic->Front_1strow, Int, Symbolic->nfr+1) ;
+ WRITE (Symbolic->Front_leftmostdesc, Int, Symbolic->nfr+1) ;
+ WRITE (Symbolic->Chain_start, Int, Symbolic->nchains+1) ;
+ WRITE (Symbolic->Chain_maxrows, Int, Symbolic->nchains+1) ;
+ WRITE (Symbolic->Chain_maxcols, Int, Symbolic->nchains+1) ;
+ WRITE (Symbolic->Cdeg, Int, Symbolic->n_col+1) ;
+ WRITE (Symbolic->Rdeg, Int, Symbolic->n_row+1) ;
+ if (Symbolic->esize > 0)
+ {
+ /* only when dense rows are present */
+ WRITE (Symbolic->Esize, Int, Symbolic->esize) ;
+ }
+ if (Symbolic->prefer_diagonal)
+ {
+ /* only when diagonal pivoting is prefered */
+ WRITE (Symbolic->Diagonal_map, Int, Symbolic->n_col+1) ;
+ }
+
+ /* close the file */
+ fclose (f) ;
+
+ return (UMFPACK_OK) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_scale ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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. Applies the scale factors computed during numerical
+ factorization to a vector. See umfpack_scale.h for more details.
+
+ The LU factorization is L*U = P*R*A*Q, where P and Q are permutation
+ matrices, and R is diagonal. This routine computes X = R * B using the
+ matrix R stored in the Numeric object.
+
+ Returns FALSE if any argument is invalid, TRUE otherwise.
+
+ If R not present in the Numeric object, then R = I and no floating-point
+ work is done. B is simply copied into X.
+*/
+
+#include "umf_internal.h"
+#include "umf_valid_numeric.h"
+
+GLOBAL Int UMFPACK_scale
+(
+ double Xx [ ],
+#ifdef COMPLEX
+ double Xz [ ],
+#endif
+ const double Bx [ ],
+#ifdef COMPLEX
+ const double Bz [ ],
+#endif
+ void *NumericHandle
+)
+{
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ NumericType *Numeric ;
+ Int n, i ;
+ double *Rs ;
+
+ Numeric = (NumericType *) NumericHandle ;
+ if (!UMF_valid_numeric (Numeric))
+ {
+ return (UMFPACK_ERROR_invalid_Numeric_object) ;
+ }
+
+ n = Numeric->n_row ;
+ Rs = Numeric->Rs ;
+
+ if (!Xx || !Bx
+#ifdef COMPLEX
+ || !Xz || !Bz
+#endif
+ )
+ {
+ return (UMFPACK_ERROR_argument_missing) ;
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* X = R*B or R\B */
+ /* ---------------------------------------------------------------------- */
+
+ if (Rs != (double *) NULL)
+ {
+#ifndef NRECIPROCAL
+ if (Numeric->do_recip)
+ {
+ /* multiply by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ Xx [i] = Bx [i] * Rs [i] ;
+#ifdef COMPLEX
+ Xz [i] = Bz [i] * Rs [i] ;
+#endif
+ }
+ }
+ else
+#endif
+ {
+ /* divide by the scale factors */
+ for (i = 0 ; i < n ; i++)
+ {
+ Xx [i] = Bx [i] / Rs [i] ;
+#ifdef COMPLEX
+ Xz [i] = Bz [i] / Rs [i] ;
+#endif
+ }
+ }
+ }
+ else
+ {
+ /* no scale factors, just copy B into X */
+ for (i = 0 ; i < n ; i++)
+ {
+ Xx [i] = Bx [i] ;
+#ifdef COMPLEX
+ Xz [i] = Bz [i] ;
+#endif
+ }
+ }
+
+ return (UMFPACK_OK) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_solve ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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:
+ No dynamic memory usage. Input arrays are used for workspace instead.
+ 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 */ stats [2] ;
+#ifndef WSOLVE
+ Int *Pattern, wsize ;
+ double *W ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* get the amount of time used by the process so far */
+ /* ---------------------------------------------------------------------- */
+
+ umfpack_tic (stats) ;
+
+#ifndef WSOLVE
+#ifndef NDEBUG
+ init_count = UMF_malloc_count ;
+#endif
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* get parameters */
+ /* ---------------------------------------------------------------------- */
+
+ irstep = GET_CONTROL (UMFPACK_IRSTEP, UMFPACK_DEFAULT_IRSTEP) ;
+
+ if (User_Info != (double *) NULL)
+ {
+ /* return Info in user's array */
+ Info = User_Info ;
+ /* clear the parts of Info that are set by UMFPACK_solve */
+ 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)
+ {
+ DEBUGm4 (("out of memory: solve work\n")) ;
+ 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)
+ {
+ umfpack_toc (stats) ;
+ Info [UMFPACK_SOLVE_WALLTIME] = stats [0] ;
+ Info [UMFPACK_SOLVE_TIME] = stats [1] ;
+ }
+
+ return (status) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_symbolic ===================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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 [ ],
+ const double Ax [ ],
+#ifdef COMPLEX
+ const double Az [ ],
+#endif
+ void **SymbolicHandle,
+ const double Control [UMFPACK_CONTROL],
+ double Info [UMFPACK_INFO]
+)
+{
+ Int *Qinit = (Int *) NULL ;
+ return (UMFPACK_qsymbolic (n_row, n_col, Ap, Ai, Ax,
+#ifdef COMPLEX
+ Az,
+#endif
+ Qinit, SymbolicHandle, Control, Info)) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_tictoc ======================================================= */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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, and
+ the current wall clock time. BE CAREFUL: if you compare the run time of
+ UMFPACK with other sparse matrix packages, be sure to use the same timer.
+ See umfpack_tictoc.h for details.
+
+ These routines conform to the POSIX standard. See umf_config.h for
+ more details.
+*/
+
+#include "umf_internal.h"
+
+#ifdef NO_TIMER
+
+/* -------------------------------------------------------------------------- */
+/* no timer used if -DNO_TIMER is defined at compile time */
+/* -------------------------------------------------------------------------- */
+
+void umfpack_tic (double stats [2])
+{
+ stats [0] = 0 ;
+ stats [1] = 0 ;
+}
+
+void umfpack_toc (double stats [2])
+{
+ stats [0] = 0 ;
+ stats [1] = 0 ;
+}
+
+#else
+
+/* -------------------------------------------------------------------------- */
+/* timer routines, using either times() or clock() */
+/* -------------------------------------------------------------------------- */
+
+#define TINY_TIME 1e-4
+
+#ifndef NPOSIX
+
+#include <unistd.h>
+#include <sys/times.h>
+
+void umfpack_tic (double stats [2])
+{
+ /* Return the current time */
+ /* stats [0]: current wallclock time, in seconds */
+ /* stats [1]: user + system time for the process, in seconds */
+
+ struct tms t ;
+ double ticks ;
+
+ ticks = (double) sysconf (_SC_CLK_TCK) ;
+ stats [0] = (double) times (&t) / ticks ;
+ stats [1] = (double) (t.tms_utime + t.tms_stime) / ticks ;
+
+ /* if time is tiny, just return zero */
+ if (stats [0] < TINY_TIME) stats [0] = 0 ;
+ if (stats [1] < TINY_TIME) stats [1] = 0 ;
+}
+
+#else
+
+/* Generic ANSI C: use the ANSI clock function. No wallclock time. */
+
+#include <time.h>
+
+void umfpack_tic (double stats [2])
+{
+ stats [0] = 0 ;
+ stats [1] = ((double) (clock ( ))) / ((double) (CLOCKS_PER_SEC)) ;
+ if (stats [1] < TINY_TIME) stats [1] = 0 ;
+}
+
+#endif
+
+/* -------------------------------------------------------------------------- */
+
+void umfpack_toc (double stats [2])
+{
+ /* Return the current time since the last call to umfpack_tic. */
+ /* On input, stats holds the values returned by umfpack_tic. */
+ /* On ouput, stats holds the time since the last umfpack_tic. */
+
+ double done [2] ;
+ umfpack_tic (done) ;
+
+ stats [0] = done [0] - stats [0] ;
+ stats [1] = done [1] - stats [1] ;
+
+ if (stats [0] < 0) stats [0] = 0 ;
+ if (stats [1] < 0) stats [1] = 0 ;
+
+}
+
+#endif
--- /dev/null
+/* ========================================================================== */
+/* === umfpack_timer ======================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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.
+ This was the timer used internally by UMFPACK Version 4.0. See
+ umfpack_tictoc.h, which is the timer now used internally by UMFPACK V4.1.
+*/
+
+#ifdef NO_TIMER
+
+/* -------------------------------------------------------------------------- */
+/* no timer used if -DNO_TIMER is defined at compile time */
+/* -------------------------------------------------------------------------- */
+
+double umfpack_timer ( void )
+{
+ return (0) ;
+}
+
+#else
+
+#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
+#endif
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_transpose ==================================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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)
+ {
+ DEBUGm4 (("out of memory: transpose work\n")) ;
+ 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) ;
+}
--- /dev/null
+/* ========================================================================== */
+/* === UMFPACK_triplet_to_col =============================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* UMFPACK Version 4.3 (Jan. 16, 2004), Copyright (c) 2004 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. Converts triplet input to column-oriented form. Duplicate
+ entries may exist (they are summed in the output). The columns of the
+ column-oriented form are in sorted order. The input is not modified.
+ Returns 1 if OK, 0 if an error occured. See umfpack_triplet_to_col.h for
+ details.
+
+ If Map is present (a non-NULL pointer to an Int array of size nz), then on
+ output it holds the position of the triplets in the column-form matrix.
+ That is, suppose p = Map [k], and the k-th triplet is i=Ti[k], j=Tj[k], and
+ aij=Tx[k]. Then i=Ai[p], and aij will have been summed into Ax[p]. Also,
+ Ap[j] <= p < Ap[j+1]. The Map array is not computed if it is (Int *) NULL.
+
+ Dynamic memory usage:
+
+ If numerical values are present, then one (two for complex version)
+ workspace of size (nz+1)*sizeof(double) is allocated via UMF_malloc.
+ Next, 4 calls to UMF_malloc are made to obtain workspace of size
+ ((nz+1) + (n_row+1) + n_row + MAX (n_row,n_col)) * sizeof(Int). All of
+ this workspace (4 to 6 objects) are free'd via UMF_free on return.
+
+ For the complex version, additional space is allocated.
+
+ An extra array of size nz*sizeof(Int) is allocated if Map is present.
+*/
+
+#include "umf_internal.h"
+#include "umf_malloc.h"
+#include "umf_free.h"
+#include "umf_triplet.h"
+
+#ifndef NDEBUG
+PRIVATE Int init_count ;
+#endif
+
+/* ========================================================================== */
+
+GLOBAL Int UMFPACK_triplet_to_col
+(
+ Int n_row,
+ Int n_col,
+ Int nz,
+ const Int Ti [ ], /* size nz */
+ const Int Tj [ ], /* size nz */
+ const double Tx [ ], /* size nz */
+#ifdef COMPLEX
+ const double Tz [ ], /* size nz */
+#endif
+ Int Ap [ ], /* size n_col + 1 */
+ Int Ai [ ], /* size nz */
+ double Ax [ ] /* size nz */
+#ifdef COMPLEX
+ , double Az [ ] /* size nz */
+#endif
+ , Int Map [ ] /* size nz */
+)
+{
+
+ /* ---------------------------------------------------------------------- */
+ /* local variables */
+ /* ---------------------------------------------------------------------- */
+
+ Int *RowCount, *Rp, *Rj, *W, nn, do_values, do_map, *Map2, status ;
+ double *Rx, *Rz ;
+
+#ifndef NDEBUG
+ UMF_dump_start ( ) ;
+ init_count = UMF_malloc_count ;
+#endif
+
+ /* ---------------------------------------------------------------------- */
+ /* check inputs */
+ /* ---------------------------------------------------------------------- */
+
+ if (!Ai || !Ap || !Ti || !Tj)
+ {
+ return (UMFPACK_ERROR_argument_missing) ;
+ }
+
+ if (n_row <= 0 || n_col <= 0) /* must be > 0 */
+ {
+ return (UMFPACK_ERROR_n_nonpositive) ;
+ }
+
+ if (nz < 0) /* nz must be >= 0 (singular matrices are OK) */
+ {
+ return (UMFPACK_ERROR_invalid_matrix) ;
+ }
+
+ nn = MAX (n_row, n_col) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* allocate workspace */
+ /* ---------------------------------------------------------------------- */
+
+ Rx = (double *) NULL ;
+ Rz = (double *) NULL ;
+
+#ifdef COMPLEX
+ do_values = Ax && Tx && Az && Tz ;
+ if (do_values)
+ {
+ Rx = (double *) UMF_malloc (nz+1, sizeof (double)) ;
+ Rz = (double *) UMF_malloc (nz+1, sizeof (double)) ;
+ if (!Rx || !Rz)
+ {
+ DEBUGm4 (("out of memory: triplet work (complex)\n")) ;
+ (void) UMF_free ((void *) Rx) ;
+ (void) UMF_free ((void *) Rz) ;
+ ASSERT (UMF_malloc_count == init_count) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+ }
+#else
+ do_values = Ax && Tx ;
+ if (do_values)
+ {
+ Rx = (double *) UMF_malloc (nz+1, sizeof (double)) ;
+ if (!Rx)
+ {
+ DEBUGm4 (("out of memory: triplet work (real)\n")) ;
+ ASSERT (UMF_malloc_count == init_count) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+ }
+#endif
+
+ do_map = (Map != (Int *) NULL) ;
+ Map2 = (Int *) NULL ;
+ if (do_map)
+ {
+ DEBUG0 (("Do map:\n")) ;
+ Map2 = (Int *) UMF_malloc (nz+1, sizeof (Int)) ;
+ if (!Map2)
+ {
+ DEBUGm4 (("out of memory: triplet map\n")) ;
+ (void) UMF_free ((void *) Rx) ;
+ (void) UMF_free ((void *) Rz) ;
+ ASSERT (UMF_malloc_count == init_count) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+ }
+
+ Rj = (Int *) UMF_malloc (nz+1, sizeof (Int)) ;
+ Rp = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ;
+ RowCount = (Int *) UMF_malloc (n_row, sizeof (Int)) ;
+ W = (Int *) UMF_malloc (nn, sizeof (Int)) ;
+ if (!Rj || !Rp || !RowCount || !W)
+ {
+ DEBUGm4 (("out of memory: triplet work (int)\n")) ;
+ (void) UMF_free ((void *) Rx) ;
+ (void) UMF_free ((void *) Rz) ;
+ (void) UMF_free ((void *) Map2) ;
+ (void) UMF_free ((void *) Rp) ;
+ (void) UMF_free ((void *) Rj) ;
+ (void) UMF_free ((void *) RowCount) ;
+ (void) UMF_free ((void *) W) ;
+ ASSERT (UMF_malloc_count == init_count) ;
+ return (UMFPACK_ERROR_out_of_memory) ;
+ }
+
+ ASSERT (UMF_malloc_count == init_count + 4 +
+ (Rx != (double *) NULL) + (Rz != (double *) NULL) + do_map) ;
+
+ /* ---------------------------------------------------------------------- */
+ /* convert from triplet to column form */
+ /* ---------------------------------------------------------------------- */
+
+ if (do_map)
+ {
+ if (do_values)
+ {
+ status = UMF_triplet_map_x (n_row, n_col, nz, Ti, Tj, Ap, Ai, Rp,
+ Rj, W, RowCount, Tx, Ax, Rx
+#ifdef COMPLEX
+ , Tz, Az, Rz
+#endif
+ , Map, Map2) ;
+ }
+ else
+ {
+ status = UMF_triplet_map_nox (n_row, n_col, nz, Ti, Tj, Ap, Ai, Rp,
+ Rj, W, RowCount, Map, Map2) ;
+ }
+ }
+ else
+ {
+ if (do_values)
+ {
+ status = UMF_triplet_nomap_x (n_row, n_col, nz, Ti, Tj, Ap, Ai, Rp,
+ Rj, W, RowCount , Tx, Ax, Rx
+#ifdef COMPLEX
+ , Tz, Az, Rz
+#endif
+ ) ;
+ }
+ else
+ {
+ status = UMF_triplet_nomap_nox (n_row, n_col, nz, Ti, Tj, Ap, Ai,
+ Rp, Rj, W, RowCount) ;
+ }
+ }
+
+ /* ---------------------------------------------------------------------- */
+ /* free the workspace */
+ /* ---------------------------------------------------------------------- */
+
+ (void) UMF_free ((void *) Rx) ;
+ (void) UMF_free ((void *) Rz) ;
+ (void) UMF_free ((void *) Map2) ;
+ (void) UMF_free ((void *) Rp) ;
+ (void) UMF_free ((void *) Rj) ;
+ (void) UMF_free ((void *) RowCount) ;
+ (void) UMF_free ((void *) W) ;
+ ASSERT (UMF_malloc_count == init_count) ;
+
+ return (status) ;
+}