From: wolf Date: Fri, 20 Aug 2004 16:31:03 +0000 (+0000) Subject: Import UMFPACK 4.3 X-Git-Url: https://gitweb.dealii.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=14831d98b0e3280696af1e864bc63a6141db60a4;p=dealii-svn.git Import UMFPACK 4.3 git-svn-id: https://svn.dealii.org/trunk@9557 0785d39b-7218-0410-832d-ea1e28bc413d --- diff --git a/deal.II/contrib/umfpack/AMD/Demo/Makefile b/deal.II/contrib/umfpack/AMD/Demo/Makefile new file mode 100644 index 0000000000..395cc73375 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Demo/Makefile @@ -0,0 +1,79 @@ +#------------------------------------------------------------------------------ +# 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 diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_demo.c b/deal.II/contrib/umfpack/AMD/Demo/amd_demo.c new file mode 100644 index 0000000000..009dc3d583 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Demo/amd_demo.c @@ -0,0 +1,169 @@ +/* ========================================================================= */ +/* === 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 +#include + +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) ; +} diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_demo.out b/deal.II/contrib/umfpack/AMD/Demo/amd_demo.out new file mode 100644 index 0000000000..eb8d845bc1 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Demo/amd_demo.out @@ -0,0 +1,177 @@ +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 diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_demo2.c b/deal.II/contrib/umfpack/AMD/Demo/amd_demo2.c new file mode 100644 index 0000000000..450d7c55ba --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Demo/amd_demo2.c @@ -0,0 +1,261 @@ +/* ========================================================================= */ +/* === 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 +#include + +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) ; +} diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_demo2.out b/deal.II/contrib/umfpack/AMD/Demo/amd_demo2.out new file mode 100644 index 0000000000..c03e8d5690 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Demo/amd_demo2.out @@ -0,0 +1,310 @@ +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 diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_f77cross.f b/deal.II/contrib/umfpack/AMD/Demo/amd_f77cross.f new file mode 100644 index 0000000000..ddbfd00268 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Demo/amd_f77cross.f @@ -0,0 +1,51 @@ +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 + diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_f77cross.out b/deal.II/contrib/umfpack/AMD/Demo/amd_f77cross.out new file mode 100644 index 0000000000..6d8a670da5 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Demo/amd_f77cross.out @@ -0,0 +1,51 @@ +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 diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_f77demo.f b/deal.II/contrib/umfpack/AMD/Demo/amd_f77demo.f new file mode 100644 index 0000000000..3ed47ab206 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Demo/amd_f77demo.f @@ -0,0 +1,161 @@ +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 diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_f77demo.out b/deal.II/contrib/umfpack/AMD/Demo/amd_f77demo.out new file mode 100644 index 0000000000..10758dd511 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Demo/amd_f77demo.out @@ -0,0 +1,318 @@ +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 diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_f77simple.f b/deal.II/contrib/umfpack/AMD/Demo/amd_f77simple.f new file mode 100644 index 0000000000..ef189fb416 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Demo/amd_f77simple.f @@ -0,0 +1,38 @@ +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 diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_f77simple.out b/deal.II/contrib/umfpack/AMD/Demo/amd_f77simple.out new file mode 100644 index 0000000000..c7f902e0a4 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Demo/amd_f77simple.out @@ -0,0 +1,5 @@ +P ( 1) = 4 +P ( 2) = 1 +P ( 3) = 3 +P ( 4) = 5 +P ( 5) = 2 diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_f77wrapper.c b/deal.II/contrib/umfpack/AMD/Demo/amd_f77wrapper.c new file mode 100644 index 0000000000..01802b8fa7 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Demo/amd_f77wrapper.c @@ -0,0 +1,108 @@ +/* ========================================================================= */ +/* === 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 + +/* ------------------------------------------------------------------------- */ +/* 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 ; +} diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_simple.c b/deal.II/contrib/umfpack/AMD/Demo/amd_simple.c new file mode 100644 index 0000000000..2399526f22 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Demo/amd_simple.c @@ -0,0 +1,23 @@ +/* ------------------------------------------------------------------------- */ +/* 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 +#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) ; +} + diff --git a/deal.II/contrib/umfpack/AMD/Demo/amd_simple.out b/deal.II/contrib/umfpack/AMD/Demo/amd_simple.out new file mode 100644 index 0000000000..08a04e0b9f --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Demo/amd_simple.out @@ -0,0 +1,5 @@ +P [0] = 0 +P [1] = 3 +P [2] = 2 +P [3] = 4 +P [4] = 1 diff --git a/deal.II/contrib/umfpack/AMD/Doc/AMD_UserGuide.bib b/deal.II/contrib/umfpack/AMD/Doc/AMD_UserGuide.bib new file mode 100644 index 0000000000..9584598a94 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Doc/AMD_UserGuide.bib @@ -0,0 +1,86 @@ +@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)} + } + diff --git a/deal.II/contrib/umfpack/AMD/Doc/AMD_UserGuide.pdf b/deal.II/contrib/umfpack/AMD/Doc/AMD_UserGuide.pdf new file mode 100644 index 0000000000..39ca0b2abf Binary files /dev/null and b/deal.II/contrib/umfpack/AMD/Doc/AMD_UserGuide.pdf differ diff --git a/deal.II/contrib/umfpack/AMD/Doc/AMD_UserGuide.tex b/deal.II/contrib/umfpack/AMD/Doc/AMD_UserGuide.tex new file mode 100644 index 0000000000..8e4d67b3b7 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Doc/AMD_UserGuide.tex @@ -0,0 +1,1138 @@ +\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 +#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} diff --git a/deal.II/contrib/umfpack/AMD/Doc/ChangeLog b/deal.II/contrib/umfpack/AMD/Doc/ChangeLog new file mode 100644 index 0000000000..69c1806d0d --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Doc/ChangeLog @@ -0,0 +1,37 @@ +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) diff --git a/deal.II/contrib/umfpack/AMD/Doc/License b/deal.II/contrib/umfpack/AMD/Doc/License new file mode 100644 index 0000000000..ed8f2ab901 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Doc/License @@ -0,0 +1,25 @@ +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 diff --git a/deal.II/contrib/umfpack/AMD/Doc/Makefile b/deal.II/contrib/umfpack/AMD/Doc/Makefile new file mode 100644 index 0000000000..c0cf976c74 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Doc/Makefile @@ -0,0 +1,28 @@ +#------------------------------------------------------------------------------ +# 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 + diff --git a/deal.II/contrib/umfpack/AMD/Include/amd.h b/deal.II/contrib/umfpack/AMD/Include/amd.h new file mode 100644 index 0000000000..d23c0bbe36 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Include/amd.h @@ -0,0 +1,359 @@ +/* ========================================================================= */ +/* === 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 diff --git a/deal.II/contrib/umfpack/AMD/MATLAB/Contents.m b/deal.II/contrib/umfpack/AMD/MATLAB/Contents.m new file mode 100644 index 0000000000..8200578956 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/MATLAB/Contents.m @@ -0,0 +1,13 @@ +%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 diff --git a/deal.II/contrib/umfpack/AMD/MATLAB/GNUmakefile b/deal.II/contrib/umfpack/AMD/MATLAB/GNUmakefile new file mode 100644 index 0000000000..ad97a781f5 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/MATLAB/GNUmakefile @@ -0,0 +1,30 @@ +#------------------------------------------------------------------------------ +# 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 diff --git a/deal.II/contrib/umfpack/AMD/MATLAB/Makefile b/deal.II/contrib/umfpack/AMD/MATLAB/Makefile new file mode 100644 index 0000000000..d3c4f8cc2f --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/MATLAB/Makefile @@ -0,0 +1,50 @@ +#------------------------------------------------------------------------------ +# 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 diff --git a/deal.II/contrib/umfpack/AMD/MATLAB/amd.m b/deal.II/contrib/umfpack/AMD/MATLAB/amd.m new file mode 100644 index 0000000000..610ce0207d --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/MATLAB/amd.m @@ -0,0 +1,74 @@ +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'); diff --git a/deal.II/contrib/umfpack/AMD/MATLAB/amd_demo.m b/deal.II/contrib/umfpack/AMD/MATLAB/amd_demo.m new file mode 100644 index 0000000000..a2d6c7226b --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/MATLAB/amd_demo.m @@ -0,0 +1,96 @@ +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) ; diff --git a/deal.II/contrib/umfpack/AMD/MATLAB/amd_demo.m.out b/deal.II/contrib/umfpack/AMD/MATLAB/amd_demo.m.out new file mode 100644 index 0000000000..b77732f00c --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/MATLAB/amd_demo.m.out @@ -0,0 +1,136 @@ +>> 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 diff --git a/deal.II/contrib/umfpack/AMD/MATLAB/amd_make.m b/deal.II/contrib/umfpack/AMD/MATLAB/amd_make.m new file mode 100644 index 0000000000..4668c55fce --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/MATLAB/amd_make.m @@ -0,0 +1,32 @@ +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 diff --git a/deal.II/contrib/umfpack/AMD/MATLAB/amd_mex.c b/deal.II/contrib/umfpack/AMD/MATLAB/amd_mex.c new file mode 100644 index 0000000000..0b36690292 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/MATLAB/amd_mex.c @@ -0,0 +1,189 @@ +/* ========================================================================= */ +/* === 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] ; + } + } +} diff --git a/deal.II/contrib/umfpack/AMD/MATLAB/can_24.mat b/deal.II/contrib/umfpack/AMD/MATLAB/can_24.mat new file mode 100644 index 0000000000..a346d0d3fb Binary files /dev/null and b/deal.II/contrib/umfpack/AMD/MATLAB/can_24.mat differ diff --git a/deal.II/contrib/umfpack/AMD/README b/deal.II/contrib/umfpack/AMD/README new file mode 100644 index 0000000000..e47f18e60a --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/README @@ -0,0 +1,202 @@ +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 diff --git a/deal.II/contrib/umfpack/AMD/Source/Makefile b/deal.II/contrib/umfpack/AMD/Source/Makefile new file mode 100644 index 0000000000..a285ac591b --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Source/Makefile @@ -0,0 +1,35 @@ +#------------------------------------------------------------------------------- +# 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)== $( 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) ; +} diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_2.c b/deal.II/contrib/umfpack/AMD/Source/amd_2.c new file mode 100644 index 0000000000..ca1141e265 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Source/amd_2.c @@ -0,0 +1,1823 @@ +/* ========================================================================= */ +/* === 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)) ; + } +} diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_aat.c b/deal.II/contrib/umfpack/AMD/Source/amd_aat.c new file mode 100644 index 0000000000..3de1e2446a --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Source/amd_aat.c @@ -0,0 +1,180 @@ +/* ========================================================================= */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_control.c b/deal.II/contrib/umfpack/AMD/Source/amd_control.c new file mode 100644 index 0000000000..6fc8f9f475 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Source/amd_control.c @@ -0,0 +1,61 @@ +/* ========================================================================= */ +/* === 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")) ; + } +} diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_defaults.c b/deal.II/contrib/umfpack/AMD/Source/amd_defaults.c new file mode 100644 index 0000000000..d0737f4fab --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Source/amd_defaults.c @@ -0,0 +1,33 @@ +/* ========================================================================= */ +/* === 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 ; + } +} diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_dump.c b/deal.II/contrib/umfpack/AMD/Source/amd_dump.c new file mode 100644 index 0000000000..c526007fe7 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Source/amd_dump.c @@ -0,0 +1,176 @@ +/* ========================================================================= */ +/* === 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 diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_info.c b/deal.II/contrib/umfpack/AMD/Source/amd_info.c new file mode 100644 index 0000000000..1cc8968f98 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Source/amd_info.c @@ -0,0 +1,115 @@ +/* ========================================================================= */ +/* === 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)) ; + } +} diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_internal.h b/deal.II/contrib/umfpack/AMD/Source/amd_internal.h new file mode 100644 index 0000000000..e1ec500bd3 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Source/amd_internal.h @@ -0,0 +1,426 @@ +/* ========================================================================= */ +/* === 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 + +/* from stdio.h: printf. When in debug mode: fopen, fscanf */ +#include + +/* from limits.h: INT_MAX and LONG_MAX */ +#include + +/* from math.h: sqrt */ +#include + +/* ------------------------------------------------------------------------- */ +/* 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 . */ +/* 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 +#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 diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_order.c b/deal.II/contrib/umfpack/AMD/Source/amd_order.c new file mode 100644 index 0000000000..eac5471a0b --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Source/amd_order.c @@ -0,0 +1,139 @@ +/* ========================================================================= */ +/* === 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 */ +} diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_post_tree.c b/deal.II/contrib/umfpack/AMD/Source/amd_post_tree.c new file mode 100644 index 0000000000..3928925457 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Source/amd_post_tree.c @@ -0,0 +1,121 @@ +/* ========================================================================= */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_postorder.c b/deal.II/contrib/umfpack/AMD/Source/amd_postorder.c new file mode 100644 index 0000000000..2b1bcd6893 --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Source/amd_postorder.c @@ -0,0 +1,207 @@ +/* ========================================================================= */ +/* === 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 + ) ; + } + } +} diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_preprocess.c b/deal.II/contrib/umfpack/AMD/Source/amd_preprocess.c new file mode 100644 index 0000000000..db635e2d0d --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Source/amd_preprocess.c @@ -0,0 +1,225 @@ +/* ========================================================================= */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/AMD/Source/amd_valid.c b/deal.II/contrib/umfpack/AMD/Source/amd_valid.c new file mode 100644 index 0000000000..77e3dea68c --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Source/amd_valid.c @@ -0,0 +1,78 @@ +/* ========================================================================= */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/AMD/Source/amdbar.f b/deal.II/contrib/umfpack/AMD/Source/amdbar.f new file mode 100644 index 0000000000..13843928ba --- /dev/null +++ b/deal.II/contrib/umfpack/AMD/Source/amdbar.f @@ -0,0 +1,1206 @@ +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 + diff --git a/deal.II/contrib/umfpack/Makefile b/deal.II/contrib/umfpack/Makefile new file mode 100644 index 0000000000..1da96a2a71 --- /dev/null +++ b/deal.II/contrib/umfpack/Makefile @@ -0,0 +1,32 @@ +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 diff --git a/deal.II/contrib/umfpack/README b/deal.II/contrib/umfpack/README new file mode 100644 index 0000000000..adf016bb70 --- /dev/null +++ b/deal.II/contrib/umfpack/README @@ -0,0 +1,5 @@ +UMFPACK v4.3 and AMD v1.1. + +See UMFPACK/README and AMD/README for details. Documention is in +UMFPACK/Doc and AMD/Doc. + diff --git a/deal.II/contrib/umfpack/README.deal.II b/deal.II/contrib/umfpack/README.deal.II new file mode 100644 index 0000000000..56c3c4133e --- /dev/null +++ b/deal.II/contrib/umfpack/README.deal.II @@ -0,0 +1,14 @@ +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 diff --git a/deal.II/contrib/umfpack/UMFPACK/Doc/ChangeLog b/deal.II/contrib/umfpack/UMFPACK/Doc/ChangeLog new file mode 100644 index 0000000000..165d5efa72 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Doc/ChangeLog @@ -0,0 +1,334 @@ +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. + + * 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. + diff --git a/deal.II/contrib/umfpack/UMFPACK/Doc/License b/deal.II/contrib/umfpack/UMFPACK/Doc/License new file mode 100644 index 0000000000..20fdc97a62 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Doc/License @@ -0,0 +1,53 @@ +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 diff --git a/deal.II/contrib/umfpack/UMFPACK/Doc/Makefile b/deal.II/contrib/umfpack/UMFPACK/Doc/Makefile new file mode 100644 index 0000000000..a7458bbcf6 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Doc/Makefile @@ -0,0 +1,52 @@ +#------------------------------------------------------------------------------- +# 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 diff --git a/deal.II/contrib/umfpack/UMFPACK/Doc/QuickStart.pdf b/deal.II/contrib/umfpack/UMFPACK/Doc/QuickStart.pdf new file mode 100644 index 0000000000..43c785cfdc Binary files /dev/null and b/deal.II/contrib/umfpack/UMFPACK/Doc/QuickStart.pdf differ diff --git a/deal.II/contrib/umfpack/UMFPACK/Doc/QuickStart.tex b/deal.II/contrib/umfpack/UMFPACK/Doc/QuickStart.tex new file mode 100644 index 0000000000..eba0ee3b77 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Doc/QuickStart.tex @@ -0,0 +1,1020 @@ +%------------------------------------------------------------------------------- +% 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 + #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} diff --git a/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.bib b/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.bib new file mode 100644 index 0000000000..691ba73e45 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.bib @@ -0,0 +1,324 @@ +@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}} + diff --git a/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.pdf b/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.pdf new file mode 100644 index 0000000000..3aab8d8566 Binary files /dev/null and b/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.pdf differ diff --git a/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.sed1 b/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.sed1 new file mode 100644 index 0000000000..c44a6408b1 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.sed1 @@ -0,0 +1,32 @@ +/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 diff --git a/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.sed2 b/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.sed2 new file mode 100644 index 0000000000..0df47d9fcb --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.sed2 @@ -0,0 +1,3 @@ +/[/][*]/d +/[*][/]/d +/INCLUDE umfpack/d diff --git a/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.stex b/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.stex new file mode 100644 index 0000000000..99dc586642 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Doc/UserGuide.stex @@ -0,0 +1,2554 @@ +%------------------------------------------------------------------------------- +% 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.} +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.} 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 /bin/mexopts.sh} by adding your BLAS library +to the {\tt CLIBS} string, +where {\tt } 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 }$\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} diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack.h new file mode 100644 index 0000000000..c1918f6e51 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack.h @@ -0,0 +1,405 @@ +/* ========================================================================== */ +/* === 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 */ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_col_to_triplet.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_col_to_triplet.h new file mode 100644 index 0000000000..54cb72237f --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_col_to_triplet.h @@ -0,0 +1,111 @@ +/* ========================================================================== */ +/* === 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. +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_defaults.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_defaults.h new file mode 100644 index 0000000000..ee6106914a --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_defaults.h @@ -0,0 +1,75 @@ +/* ========================================================================== */ +/* === 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). +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_free_numeric.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_free_numeric.h new file mode 100644 index 0000000000..e0b4ea7d41 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_free_numeric.h @@ -0,0 +1,68 @@ +/* ========================================================================== */ +/* === 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. +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_free_symbolic.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_free_symbolic.h new file mode 100644 index 0000000000..103988a7f6 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_free_symbolic.h @@ -0,0 +1,68 @@ +/* ========================================================================== */ +/* === 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. +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_get_lunz.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_get_lunz.h new file mode 100644 index 0000000000..8f9d4b0fab --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_get_lunz.h @@ -0,0 +1,134 @@ +/* ========================================================================== */ +/* === 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. +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_get_numeric.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_get_numeric.h new file mode 100644 index 0000000000..42001c4b83 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_get_numeric.h @@ -0,0 +1,253 @@ +/* ========================================================================== */ +/* === 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. +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_get_symbolic.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_get_symbolic.h new file mode 100644 index 0000000000..5c48418a6c --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_get_symbolic.h @@ -0,0 +1,342 @@ +/* ========================================================================== */ +/* === 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. +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_load_numeric.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_load_numeric.h new file mode 100644 index 0000000000..7d1f3b33dc --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_load_numeric.h @@ -0,0 +1,96 @@ +/* ========================================================================== */ +/* === 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. +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_load_symbolic.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_load_symbolic.h new file mode 100644 index 0000000000..69ece02688 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_load_symbolic.h @@ -0,0 +1,96 @@ +/* ========================================================================== */ +/* === 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. +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_numeric.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_numeric.h new file mode 100644 index 0000000000..a57fd0d012 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_numeric.h @@ -0,0 +1,552 @@ +/* ========================================================================== */ +/* === 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. +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_qsymbolic.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_qsymbolic.h new file mode 100644 index 0000000000..23088a12de --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_qsymbolic.h @@ -0,0 +1,140 @@ +/* ========================================================================== */ +/* === 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. + +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_control.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_control.h new file mode 100644 index 0000000000..6aebfdf5b5 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_control.h @@ -0,0 +1,77 @@ +/* ========================================================================== */ +/* === 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 +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_info.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_info.h new file mode 100644 index 0000000000..ccba175018 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_info.h @@ -0,0 +1,87 @@ +/* ========================================================================== */ +/* === 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. +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_matrix.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_matrix.h new file mode 100644 index 0000000000..b0225dae30 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_matrix.h @@ -0,0 +1,198 @@ +/* ========================================================================== */ +/* === 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 +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_numeric.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_numeric.h new file mode 100644 index 0000000000..54fd8f7ffe --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_numeric.h @@ -0,0 +1,113 @@ +/* ========================================================================== */ +/* === 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 +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_perm.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_perm.h new file mode 100644 index 0000000000..17969dd6e1 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_perm.h @@ -0,0 +1,113 @@ +/* ========================================================================== */ +/* === 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 +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_status.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_status.h new file mode 100644 index 0000000000..7d826de56f --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_status.h @@ -0,0 +1,91 @@ +/* ========================================================================== */ +/* === 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. +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_symbolic.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_symbolic.h new file mode 100644 index 0000000000..f9d9f12c03 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_symbolic.h @@ -0,0 +1,112 @@ +/* ========================================================================== */ +/* === 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 +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_triplet.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_triplet.h new file mode 100644 index 0000000000..928675400d --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_triplet.h @@ -0,0 +1,149 @@ +/* ========================================================================== */ +/* === 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 +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_vector.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_vector.h new file mode 100644 index 0000000000..66db99d1f8 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_report_vector.h @@ -0,0 +1,134 @@ +/* ========================================================================== */ +/* === 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 +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_save_numeric.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_save_numeric.h new file mode 100644 index 0000000000..0e3f57be87 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_save_numeric.h @@ -0,0 +1,93 @@ +/* ========================================================================== */ +/* === 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. +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_save_symbolic.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_save_symbolic.h new file mode 100644 index 0000000000..a183ede9b2 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_save_symbolic.h @@ -0,0 +1,93 @@ +/* ========================================================================== */ +/* === 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. +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_scale.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_scale.h new file mode 100644 index 0000000000..8e254f8f2e --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_scale.h @@ -0,0 +1,105 @@ +/* ========================================================================== */ +/* === 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. + +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_solve.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_solve.h new file mode 100644 index 0000000000..d6a0a96106 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_solve.h @@ -0,0 +1,302 @@ +/* ========================================================================== */ +/* === 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. +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_symbolic.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_symbolic.h new file mode 100644 index 0000000000..ed09ca5d1d --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_symbolic.h @@ -0,0 +1,542 @@ +/* ========================================================================== */ +/* === 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. +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_tictoc.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_tictoc.h new file mode 100644 index 0000000000..550d7d5d5d --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_tictoc.h @@ -0,0 +1,61 @@ +/* ========================================================================== */ +/* === 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 +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_timer.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_timer.h new file mode 100644 index 0000000000..a29c2f4dac --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_timer.h @@ -0,0 +1,41 @@ +/* ========================================================================== */ +/* === 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. +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_transpose.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_transpose.h new file mode 100644 index 0000000000..f9d34cbb29 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_transpose.h @@ -0,0 +1,217 @@ +/* ========================================================================== */ +/* === 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. +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_triplet_to_col.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_triplet_to_col.h new file mode 100644 index 0000000000..ea55157117 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_triplet_to_col.h @@ -0,0 +1,261 @@ +/* ========================================================================== */ +/* === 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. +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_wsolve.h b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_wsolve.h new file mode 100644 index 0000000000..7eda906edc --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Include/umfpack_wsolve.h @@ -0,0 +1,166 @@ +/* ========================================================================== */ +/* === 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 +*/ diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/Contents.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/Contents.m new file mode 100644 index 0000000000..c6657b2375 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/MATLAB/Contents.m @@ -0,0 +1,22 @@ +%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 diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/GNUmakefile b/deal.II/contrib/umfpack/UMFPACK/MATLAB/GNUmakefile new file mode 100644 index 0000000000..90edfec8dd --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/MATLAB/GNUmakefile @@ -0,0 +1,232 @@ +#------------------------------------------------------------------------------- +# 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 diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/Makefile b/deal.II/contrib/umfpack/UMFPACK/MATLAB/Makefile new file mode 100644 index 0000000000..4501ba33a5 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/MATLAB/Makefile @@ -0,0 +1,436 @@ +#------------------------------------------------------------------------------- +# 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 diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/lu_normest.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/lu_normest.m new file mode 100644 index 0000000000..ea3490cfca --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/MATLAB/lu_normest.m @@ -0,0 +1,106 @@ +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 % } diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/luflop.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/luflop.m new file mode 100644 index 0000000000..dcc080b55e --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/MATLAB/luflop.m @@ -0,0 +1,24 @@ +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.') ; diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/luflopmex.c b/deal.II/contrib/umfpack/UMFPACK/MATLAB/luflopmex.c new file mode 100644 index 0000000000..5342856ae8 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/MATLAB/luflopmex.c @@ -0,0 +1,121 @@ +/* ========================================================================== */ +/* === 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 ; +} + diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack.m new file mode 100644 index 0000000000..3285bb6935 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack.m @@ -0,0 +1,44 @@ +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.') ; + diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_btf.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_btf.m new file mode 100644 index 0000000000..a9da270f6b --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_btf.m @@ -0,0 +1,129 @@ +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 diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_demo.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_demo.m new file mode 100644 index 0000000000..422a32ffa1 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_demo.m @@ -0,0 +1,195 @@ +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)) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_demo.m.out b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_demo.m.out new file mode 100644 index 0000000000..10adebe433 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_demo.m.out @@ -0,0 +1,72 @@ +>> 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 diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_details.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_details.m new file mode 100644 index 0000000000..315de174cc --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_details.m @@ -0,0 +1,155 @@ +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 + diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_make.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_make.m new file mode 100644 index 0000000000..ca239a9fe3 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_make.m @@ -0,0 +1,356 @@ +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', ... + '\\extern\\lib\\win32\\lcc\\ directory, where 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', ... + '\\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 ; + diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_report.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_report.m new file mode 100644 index 0000000000..10d661a1dc --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_report.m @@ -0,0 +1,346 @@ +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 diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_simple.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_simple.m new file mode 100644 index 0000000000..829b6718a4 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_simple.m @@ -0,0 +1,61 @@ +% 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') ; diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_simple.m.out b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_simple.m.out new file mode 100644 index 0000000000..6c019147ad --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_simple.m.out @@ -0,0 +1,74 @@ +>> 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 diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_solve.m b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_solve.m new file mode 100644 index 0000000000..1a988c5833 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpack_solve.m @@ -0,0 +1,96 @@ +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 diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpackmex.c b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpackmex.c new file mode 100644 index 0000000000..8e64a7e422 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/MATLAB/umfpackmex.c @@ -0,0 +1,1284 @@ +/* ========================================================================== */ +/* === 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 +#include +#include + +#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] ; + } + } +} diff --git a/deal.II/contrib/umfpack/UMFPACK/MATLAB/west0067.mat b/deal.II/contrib/umfpack/UMFPACK/MATLAB/west0067.mat new file mode 100644 index 0000000000..6cd8c88e60 Binary files /dev/null and b/deal.II/contrib/umfpack/UMFPACK/MATLAB/west0067.mat differ diff --git a/deal.II/contrib/umfpack/UMFPACK/README b/deal.II/contrib/umfpack/UMFPACK/README new file mode 100644 index 0000000000..ff39cb6f17 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/README @@ -0,0 +1,376 @@ +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 diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/Makefile b/deal.II/contrib/umfpack/UMFPACK/Source/Makefile new file mode 100644 index 0000000000..a2801eaf20 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/Makefile @@ -0,0 +1,193 @@ +#------------------------------------------------------------------------------- +# 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)== $(= 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 +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_2by2.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_2by2.h new file mode 100644 index 0000000000..a7bb479af5 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_2by2.h @@ -0,0 +1,37 @@ +/* -------------------------------------------------------------------------- */ +/* 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 [ ] +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_analyze.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_analyze.c new file mode 100644 index 0000000000..b4da7e291b --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_analyze.c @@ -0,0 +1,707 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_analyze.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_analyze.h new file mode 100644 index 0000000000..cb3af8a9fb --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_analyze.h @@ -0,0 +1,24 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_apply_order.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_apply_order.c new file mode 100644 index 0000000000..88e9b62d68 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_apply_order.c @@ -0,0 +1,44 @@ +/* ========================================================================== */ +/* === 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] ; + } +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_apply_order.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_apply_order.h new file mode 100644 index 0000000000..73b63a6945 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_apply_order.h @@ -0,0 +1,15 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_assemble.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_assemble.c new file mode 100644 index 0000000000..1e1b0f224e --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_assemble.c @@ -0,0 +1,1216 @@ +/* ========================================================================== */ +/* === 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 */ +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_assemble.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_assemble.h new file mode 100644 index 0000000000..4cbfc57556 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_assemble.h @@ -0,0 +1,18 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_blas3_update.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_blas3_update.c new file mode 100644 index 0000000000..acceb5f775 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_blas3_update.c @@ -0,0 +1,165 @@ +/* ========================================================================== */ +/* === 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)) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_blas3_update.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_blas3_update.h new file mode 100644 index 0000000000..2285d97fdc --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_blas3_update.h @@ -0,0 +1,11 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_build_tuples.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_build_tuples.c new file mode 100644 index 0000000000..cabb7e0239 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_build_tuples.c @@ -0,0 +1,160 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_build_tuples.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_build_tuples.h new file mode 100644 index 0000000000..a4b5ed1e6f --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_build_tuples.h @@ -0,0 +1,12 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_colamd.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_colamd.c new file mode 100644 index 0000000000..8a574dd183 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_colamd.c @@ -0,0 +1,3140 @@ +/* ========================================================================== */ +/* === 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 */ diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_colamd.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_colamd.h new file mode 100644 index 0000000000..b33ebe197d --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_colamd.h @@ -0,0 +1,256 @@ +/* ========================================================================== */ +/* === 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 + +/* ========================================================================== */ +/* === 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 */ diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_config.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_config.h new file mode 100644 index 0000000000..ea4b641418 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_config.h @@ -0,0 +1,920 @@ +/* ========================================================================== */ +/* === 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 + \extern\lib\win32\lcc\ directory, where 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 +/* 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 +#else +#include +#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 + 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 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) } */ diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_create_element.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_create_element.c new file mode 100644 index 0000000000..48b1d5907c --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_create_element.c @@ -0,0 +1,605 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_create_element.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_create_element.h new file mode 100644 index 0000000000..81df97f4d3 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_create_element.h @@ -0,0 +1,13 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_dump.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_dump.c new file mode 100644 index 0000000000..9990c2c49b --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_dump.c @@ -0,0 +1,1220 @@ +/* ========================================================================== */ +/* === 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 */ diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_dump.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_dump.h new file mode 100644 index 0000000000..de220f37a1 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_dump.h @@ -0,0 +1,187 @@ +/* -------------------------------------------------------------------------- */ +/* 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 */ diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_extend_front.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_extend_front.c new file mode 100644 index 0000000000..241ed8aa58 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_extend_front.c @@ -0,0 +1,393 @@ +/* ========================================================================== */ +/* === 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) ; + +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_extend_front.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_extend_front.h new file mode 100644 index 0000000000..45e3d47500 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_extend_front.h @@ -0,0 +1,12 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_free.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_free.c new file mode 100644 index 0000000000..5f74ae97ba --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_free.c @@ -0,0 +1,46 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_free.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_free.h new file mode 100644 index 0000000000..b2bf660d2c --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_free.h @@ -0,0 +1,11 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_fsize.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_fsize.c new file mode 100644 index 0000000000..ceaf648b2b --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_fsize.c @@ -0,0 +1,70 @@ +/* ========================================================================== */ +/* === 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])); + } + } + } +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_fsize.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_fsize.h new file mode 100644 index 0000000000..cef2ad9878 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_fsize.h @@ -0,0 +1,16 @@ +/* -------------------------------------------------------------------------- */ +/* 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 [ ] +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_garbage_collection.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_garbage_collection.c new file mode 100644 index 0000000000..abaf180f5d --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_garbage_collection.c @@ -0,0 +1,696 @@ +/* ========================================================================== */ +/* === 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")) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_garbage_collection.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_garbage_collection.h new file mode 100644 index 0000000000..29d9186cf7 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_garbage_collection.h @@ -0,0 +1,15 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_get_memory.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_get_memory.c new file mode 100644 index 0000000000..480288b2df --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_get_memory.c @@ -0,0 +1,223 @@ +/* ========================================================================== */ +/* === 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)) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_get_memory.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_get_memory.h new file mode 100644 index 0000000000..754f1faced --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_get_memory.h @@ -0,0 +1,16 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_grow_front.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_grow_front.c new file mode 100644 index 0000000000..9ecf67388a --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_grow_front.c @@ -0,0 +1,295 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_grow_front.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_grow_front.h new file mode 100644 index 0000000000..2f27fe52d3 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_grow_front.h @@ -0,0 +1,15 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_init_front.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_init_front.c new file mode 100644 index 0000000000..cce2dd1979 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_init_front.c @@ -0,0 +1,268 @@ +/* ========================================================================== */ +/* === 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) ; + +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_init_front.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_init_front.h new file mode 100644 index 0000000000..96a77ab66d --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_init_front.h @@ -0,0 +1,12 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_internal.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_internal.h new file mode 100644 index 0000000000..f4e26c2f80 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_internal.h @@ -0,0 +1,756 @@ +/* ========================================================================== */ +/* === 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 + +/* from string.h: strcmp */ +#include + +/* 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 diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_is_permutation.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_is_permutation.c new file mode 100644 index 0000000000..845ece2ac0 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_is_permutation.c @@ -0,0 +1,56 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_is_permutation.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_is_permutation.h new file mode 100644 index 0000000000..386604b2f5 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_is_permutation.h @@ -0,0 +1,14 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel.c new file mode 100644 index 0000000000..7e433f1653 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel.c @@ -0,0 +1,300 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel.h new file mode 100644 index 0000000000..3f64436204 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel.h @@ -0,0 +1,19 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_init.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_init.c new file mode 100644 index 0000000000..a1f0b97068 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_init.c @@ -0,0 +1,1053 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_init.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_init.h new file mode 100644 index 0000000000..67deb41e69 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_init.h @@ -0,0 +1,19 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_wrapup.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_wrapup.c new file mode 100644 index 0000000000..6b32a1bce0 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_wrapup.c @@ -0,0 +1,466 @@ +/* ========================================================================== */ +/* === 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). */ +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_wrapup.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_wrapup.h new file mode 100644 index 0000000000..4550821eba --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_kernel_wrapup.h @@ -0,0 +1,13 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_local_search.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_local_search.c new file mode 100644 index 0000000000..7c54cd2aa8 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_local_search.c @@ -0,0 +1,1949 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_local_search.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_local_search.h new file mode 100644 index 0000000000..51ca38bdaa --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_local_search.h @@ -0,0 +1,13 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_lsolve.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_lsolve.c new file mode 100644 index 0000000000..03a84a31e0 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_lsolve.c @@ -0,0 +1,151 @@ +/* ========================================================================== */ +/* === 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)) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_lsolve.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_lsolve.h new file mode 100644 index 0000000000..75d6467823 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_lsolve.h @@ -0,0 +1,13 @@ +/* -------------------------------------------------------------------------- */ +/* 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 [ ] +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_ltsolve.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_ltsolve.c new file mode 100644 index 0000000000..6011f0c24b --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_ltsolve.c @@ -0,0 +1,225 @@ +/* ========================================================================== */ +/* === 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)) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_ltsolve.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_ltsolve.h new file mode 100644 index 0000000000..3b4ad1f53b --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_ltsolve.h @@ -0,0 +1,20 @@ +/* -------------------------------------------------------------------------- */ +/* 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 [ ] +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_malloc.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_malloc.c new file mode 100644 index 0000000000..9416435e5e --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_malloc.c @@ -0,0 +1,92 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_malloc.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_malloc.h new file mode 100644 index 0000000000..44529b57c9 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_malloc.h @@ -0,0 +1,16 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_element.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_element.c new file mode 100644 index 0000000000..6eefa35504 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_element.c @@ -0,0 +1,83 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_element.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_element.h new file mode 100644 index 0000000000..b3886cf396 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_element.h @@ -0,0 +1,18 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_head_block.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_head_block.c new file mode 100644 index 0000000000..9f94c2c775 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_head_block.c @@ -0,0 +1,55 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_head_block.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_head_block.h new file mode 100644 index 0000000000..7217e51049 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_head_block.h @@ -0,0 +1,12 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_tail_block.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_tail_block.c new file mode 100644 index 0000000000..a6ca5cf7c5 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_tail_block.c @@ -0,0 +1,134 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_tail_block.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_tail_block.h new file mode 100644 index 0000000000..b0502e0727 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_alloc_tail_block.h @@ -0,0 +1,12 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_free_tail_block.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_free_tail_block.c new file mode 100644 index 0000000000..842d4bca6c --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_free_tail_block.c @@ -0,0 +1,143 @@ +/* ========================================================================== */ +/* === 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))) ; + +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_free_tail_block.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_free_tail_block.h new file mode 100644 index 0000000000..87b232bae1 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_free_tail_block.h @@ -0,0 +1,12 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_init_memoryspace.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_init_memoryspace.c new file mode 100644 index 0000000000..5a2310d5d2 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_init_memoryspace.c @@ -0,0 +1,65 @@ +/* ========================================================================== */ +/* === 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 + +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_init_memoryspace.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_init_memoryspace.h new file mode 100644 index 0000000000..8626eeb9ac --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_mem_init_memoryspace.h @@ -0,0 +1,11 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_realloc.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_realloc.c new file mode 100644 index 0000000000..339705bd61 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_realloc.c @@ -0,0 +1,76 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_realloc.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_realloc.h new file mode 100644 index 0000000000..376de63a3a --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_realloc.h @@ -0,0 +1,13 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_report_perm.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_report_perm.c new file mode 100644 index 0000000000..0f67f3cf4d --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_report_perm.c @@ -0,0 +1,86 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_report_perm.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_report_perm.h new file mode 100644 index 0000000000..5fd7a7ab07 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_report_perm.h @@ -0,0 +1,15 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_report_vector.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_report_vector.c new file mode 100644 index 0000000000..d811d57421 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_report_vector.c @@ -0,0 +1,119 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_report_vector.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_report_vector.h new file mode 100644 index 0000000000..9ca5ae8197 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_report_vector.h @@ -0,0 +1,16 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_row_search.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_row_search.c new file mode 100644 index 0000000000..3a73a7252c --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_row_search.c @@ -0,0 +1,838 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_row_search.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_row_search.h new file mode 100644 index 0000000000..9490c87532 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_row_search.h @@ -0,0 +1,33 @@ +/* -------------------------------------------------------------------------- */ +/* 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 diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_scale.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_scale.c new file mode 100644 index 0000000000..b07654f9db --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_scale.c @@ -0,0 +1,128 @@ +/* ========================================================================== */ +/* === 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 + + } +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_scale.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_scale.h new file mode 100644 index 0000000000..74967a064e --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_scale.h @@ -0,0 +1,13 @@ +/* -------------------------------------------------------------------------- */ +/* 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 [ ] +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_scale_column.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_scale_column.c new file mode 100644 index 0000000000..2c47898280 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_scale_column.c @@ -0,0 +1,434 @@ +/* ========================================================================== */ +/* === 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 + +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_scale_column.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_scale_column.h new file mode 100644 index 0000000000..fe383635ed --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_scale_column.h @@ -0,0 +1,12 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_set_stats.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_set_stats.c new file mode 100644 index 0000000000..63e51a7bb9 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_set_stats.c @@ -0,0 +1,134 @@ +/* ========================================================================== */ +/* === 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 ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_set_stats.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_set_stats.h new file mode 100644 index 0000000000..5b0a6c4cd2 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_set_stats.h @@ -0,0 +1,25 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_singletons.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_singletons.c new file mode 100644 index 0000000000..841edeed03 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_singletons.c @@ -0,0 +1,891 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_singletons.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_singletons.h new file mode 100644 index 0000000000..460defa95c --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_singletons.h @@ -0,0 +1,31 @@ +/* -------------------------------------------------------------------------- */ +/* 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 [ ] +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_solve.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_solve.c new file mode 100644 index 0000000000..8450c40ee8 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_solve.c @@ -0,0 +1,1372 @@ +/* ========================================================================== */ +/* === 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 */ + /* 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_solve.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_solve.h new file mode 100644 index 0000000000..35a4867594 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_solve.h @@ -0,0 +1,26 @@ +/* -------------------------------------------------------------------------- */ +/* 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 [ ] +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_start_front.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_start_front.c new file mode 100644 index 0000000000..bb34a9385c --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_start_front.c @@ -0,0 +1,284 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_start_front.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_start_front.h new file mode 100644 index 0000000000..5992e73351 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_start_front.h @@ -0,0 +1,14 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_store_lu.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_store_lu.c new file mode 100644 index 0000000000..df0c63e094 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_store_lu.c @@ -0,0 +1,1035 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_store_lu.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_store_lu.h new file mode 100644 index 0000000000..142ee5b71d --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_store_lu.h @@ -0,0 +1,18 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_symbolic_usage.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_symbolic_usage.c new file mode 100644 index 0000000000..cc8b94a298 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_symbolic_usage.c @@ -0,0 +1,46 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_symbolic_usage.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_symbolic_usage.h new file mode 100644 index 0000000000..1767c2ce06 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_symbolic_usage.h @@ -0,0 +1,16 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_transpose.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_transpose.c new file mode 100644 index 0000000000..074911939d --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_transpose.c @@ -0,0 +1,332 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_transpose.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_transpose.h new file mode 100644 index 0000000000..0e1aac9c22 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_transpose.h @@ -0,0 +1,28 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_triplet.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_triplet.c new file mode 100644 index 0000000000..8192af7f2c --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_triplet.c @@ -0,0 +1,386 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_triplet.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_triplet.h new file mode 100644 index 0000000000..73704e6593 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_triplet.h @@ -0,0 +1,86 @@ +/* -------------------------------------------------------------------------- */ +/* 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 [ ] +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_tuple_lengths.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_tuple_lengths.c new file mode 100644 index 0000000000..6843428d1d --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_tuple_lengths.c @@ -0,0 +1,136 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_tuple_lengths.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_tuple_lengths.h new file mode 100644 index 0000000000..6d1560b9b2 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_tuple_lengths.h @@ -0,0 +1,13 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_usolve.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_usolve.c new file mode 100644 index 0000000000..c292eb4d25 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_usolve.c @@ -0,0 +1,226 @@ +/* ========================================================================== */ +/* === 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)); +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_usolve.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_usolve.h new file mode 100644 index 0000000000..c546111380 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_usolve.h @@ -0,0 +1,13 @@ +/* -------------------------------------------------------------------------- */ +/* 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 [ ] +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_utsolve.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_utsolve.c new file mode 100644 index 0000000000..bd7d08e57d --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_utsolve.c @@ -0,0 +1,331 @@ +/* ========================================================================== */ +/* === 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)); +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_utsolve.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_utsolve.h new file mode 100644 index 0000000000..86ccb40140 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_utsolve.h @@ -0,0 +1,21 @@ +/* -------------------------------------------------------------------------- */ +/* 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 [ ] +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_numeric.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_numeric.c new file mode 100644 index 0000000000..58da8ac94b --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_numeric.c @@ -0,0 +1,47 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_numeric.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_numeric.h new file mode 100644 index 0000000000..11895fd12e --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_numeric.h @@ -0,0 +1,11 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_symbolic.c b/deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_symbolic.c new file mode 100644 index 0000000000..1acc6ac5f1 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_symbolic.c @@ -0,0 +1,48 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_symbolic.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_symbolic.h new file mode 100644 index 0000000000..5cada3c146 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_valid_symbolic.h @@ -0,0 +1,11 @@ +/* -------------------------------------------------------------------------- */ +/* 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 +) ; diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umf_version.h b/deal.II/contrib/umfpack/UMFPACK/Source/umf_version.h new file mode 100644 index 0000000000..b3c4df09ec --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umf_version.h @@ -0,0 +1,989 @@ +/* ========================================================================== */ +/* === 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 , 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 diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_col_to_triplet.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_col_to_triplet.c new file mode 100644 index 0000000000..ef27bc2e8d --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_col_to_triplet.c @@ -0,0 +1,73 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_defaults.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_defaults.c new file mode 100644 index 0000000000..8de4c1b0d0 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_defaults.c @@ -0,0 +1,119 @@ +/* ========================================================================== */ +/* === 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 +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_free_numeric.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_free_numeric.c new file mode 100644 index 0000000000..ec19adfa9d --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_free_numeric.c @@ -0,0 +1,58 @@ +/* ========================================================================== */ +/* === 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 ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_free_symbolic.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_free_symbolic.c new file mode 100644 index 0000000000..347727f85f --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_free_symbolic.c @@ -0,0 +1,57 @@ +/* ========================================================================== */ +/* === 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 ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_get_lunz.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_get_lunz.c new file mode 100644 index 0000000000..37ac8bffe6 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_get_lunz.c @@ -0,0 +1,56 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_get_numeric.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_get_numeric.c new file mode 100644 index 0000000000..e270b1e3a4 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_get_numeric.c @@ -0,0 +1,980 @@ +/* ========================================================================== */ +/* === 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 + +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_get_symbolic.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_get_symbolic.c new file mode 100644 index 0000000000..6a88f37b7e --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_get_symbolic.c @@ -0,0 +1,192 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_load_numeric.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_load_numeric.c new file mode 100644 index 0000000000..db98757cb7 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_load_numeric.c @@ -0,0 +1,162 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_load_symbolic.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_load_symbolic.c new file mode 100644 index 0000000000..dceea052f7 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_load_symbolic.c @@ -0,0 +1,166 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_numeric.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_numeric.c new file mode 100644 index 0000000000..9456d911ed --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_numeric.c @@ -0,0 +1,796 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_qsymbolic.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_qsymbolic.c new file mode 100644 index 0000000000..910a50c117 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_qsymbolic.c @@ -0,0 +1,2366 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_control.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_control.c new file mode 100644 index 0000000000..fdc614f279 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_control.c @@ -0,0 +1,387 @@ +/* ========================================================================== */ +/* === 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))) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_info.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_info.c new file mode 100644 index 0000000000..4c806d2f90 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_info.c @@ -0,0 +1,616 @@ +/* ========================================================================== */ +/* === 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")) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_matrix.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_matrix.c new file mode 100644 index 0000000000..d5066a4a91 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_matrix.c @@ -0,0 +1,205 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_numeric.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_numeric.c new file mode 100644 index 0000000000..c66a2c6c89 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_numeric.c @@ -0,0 +1,664 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_perm.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_perm.c new file mode 100644 index 0000000000..2dc4c13779 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_perm.c @@ -0,0 +1,45 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_status.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_status.c new file mode 100644 index 0000000000..06bc9244c9 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_status.c @@ -0,0 +1,119 @@ +/* ========================================================================== */ +/* === 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")) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_symbolic.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_symbolic.c new file mode 100644 index 0000000000..14503d9280 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_symbolic.c @@ -0,0 +1,229 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_triplet.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_triplet.c new file mode 100644 index 0000000000..d044dad377 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_triplet.c @@ -0,0 +1,101 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_vector.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_vector.c new file mode 100644 index 0000000000..d5e18a1353 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_report_vector.c @@ -0,0 +1,44 @@ +/* ========================================================================== */ +/* === 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)) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_save_numeric.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_save_numeric.c new file mode 100644 index 0000000000..b7803b7c17 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_save_numeric.c @@ -0,0 +1,93 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_save_symbolic.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_save_symbolic.c new file mode 100644 index 0000000000..7908b83f23 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_save_symbolic.c @@ -0,0 +1,96 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_scale.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_scale.c new file mode 100644 index 0000000000..90d0221ff1 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_scale.c @@ -0,0 +1,112 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_solve.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_solve.c new file mode 100644 index 0000000000..30bf8121a4 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_solve.c @@ -0,0 +1,249 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_symbolic.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_symbolic.c new file mode 100644 index 0000000000..2125695978 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_symbolic.c @@ -0,0 +1,40 @@ +/* ========================================================================== */ +/* === 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)) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_tictoc.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_tictoc.c new file mode 100644 index 0000000000..706f3acb85 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_tictoc.c @@ -0,0 +1,107 @@ +/* ========================================================================== */ +/* === 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 +#include + +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 + +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 diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_timer.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_timer.c new file mode 100644 index 0000000000..be0e7fc647 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_timer.c @@ -0,0 +1,85 @@ +/* ========================================================================== */ +/* === 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 +#include + +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 + +double umfpack_timer ( void ) +{ + return (((double) (clock ( ))) / ((double) (CLOCKS_PER_SEC))) ; +} + +#endif +#endif diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_transpose.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_transpose.c new file mode 100644 index 0000000000..7dedecb6be --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_transpose.c @@ -0,0 +1,109 @@ +/* ========================================================================== */ +/* === 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) ; +} diff --git a/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_triplet_to_col.c b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_triplet_to_col.c new file mode 100644 index 0000000000..a868231a81 --- /dev/null +++ b/deal.II/contrib/umfpack/UMFPACK/Source/umfpack_triplet_to_col.c @@ -0,0 +1,229 @@ +/* ========================================================================== */ +/* === 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) ; +}