1 /* ========================================================================= */
2 /* === AMD:  approximate minimum degree ordering =========================== */
3 /* ========================================================================= */
4 
5 /* ------------------------------------------------------------------------- */
6 /* AMD Version 2.4, Copyright (c) 1996-2013 by Timothy A. Davis,             */
7 /* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
8 /* email: DrTimothyAldenDavis@gmail.com                                      */
9 /* ------------------------------------------------------------------------- */
10 
11 /* AMD finds a symmetric ordering P of a matrix A so that the Cholesky
12  * factorization of P*A*P' has fewer nonzeros and takes less work than the
13  * Cholesky factorization of A.  If A is not symmetric, then it performs its
14  * ordering on the matrix A+A'.  Two sets of user-callable routines are
15  * provided, one for int integers and the other for SuiteSparse_long integers.
16  *
17  * The method is based on the approximate minimum degree algorithm, discussed
18  * in Amestoy, Davis, and Duff, "An approximate degree ordering algorithm",
19  * SIAM Journal of Matrix Analysis and Applications, vol. 17, no. 4, pp.
20  * 886-905, 1996.  This package can perform both the AMD ordering (with
21  * aggressive absorption), and the AMDBAR ordering (without aggressive
22  * absorption) discussed in the above paper.  This package differs from the
23  * Fortran codes discussed in the paper:
24  *
25  *       (1) it can ignore "dense" rows and columns, leading to faster run times
26  *       (2) it computes the ordering of A+A' if A is not symmetric
27  *       (3) it is followed by a depth-first post-ordering of the assembly tree
28  *           (or supernodal elimination tree)
29  *
30  * For historical reasons, the Fortran versions, amd.f and amdbar.f, have
31  * been left (nearly) unchanged.  They compute the identical ordering as
32  * described in the above paper.
33  */
34 
35 module amd;
36 
37 nothrow @nogc extern(C):
38 
39 import glob_opts;
40 
41 import SuiteSparse_config;
42 
43 /* get the definition of size_t: */
44 import core.stdc.stddef;
45 
46 enum c_int AMD_CONTROL = 5;        /* size of Control array */
47 enum c_int AMD_INFO = 20;          /* size of Info array */
48 
49 /* contents of Control */
50 enum c_int AMD_DENSE = 0;       /* "dense" if degree > Control [0] * sqrt (n) */
51 enum c_int AMD_AGGRESSIVE = 1;  /* do aggressive absorption if Control [1] != 0 */
52 
53 /* default Control settings */
54 enum c_float AMD_DEFAULT_DENSE = 10.0 ;   /* default "dense" degree 10*sqrt(n) */     
55 enum c_int AMD_DEFAULT_AGGRESSIVE = 1;        /* do aggressive absorption by default */
56 
57 /* contents of Info */
58 enum c_int AMD_STATUS = 0;           /* return value of amd_order and amd_l_order */
59 enum c_int AMD_N = 1;               /* A is n-by-n */
60 enum c_int AMD_NZ = 2;     /* number of nonzeros in A */
61 enum c_int AMD_SYMMETRY = 3;        /* symmetry of pattern (1 is sym., 0 is unsym.) */
62 enum c_int AMD_NZDIAG = 4;           /* # of entries on diagonal */
63 enum c_int AMD_NZ_A_PLUS_AT = 5;  /* nz in A+A' */
64 enum c_int AMD_NDENSE = 6;           /* number of "dense" rows/columns in A */
65 enum c_int AMD_MEMORY = 7;           /* amount of memory used by AMD */
66 enum c_int AMD_NCMPA = 8;            /* number of garbage collections in AMD */
67 enum c_int AMD_LNZ = 9;     /* approx. nz in L, excluding the diagonal */
68 enum c_int AMD_NDIV = 10;            /* number of fl. point divides for LU and LDL' */
69 enum c_int AMD_NMULTSUBS_LDL = 11; /* number of fl. point (*,-) pairs for LDL' */
70 enum c_int AMD_NMULTSUBS_LU = 12;  /* number of fl. point (*,-) pairs for LU */
71 enum c_int AMD_DMAX = 13;            /* max nz. in any column of L, incl. diagonal */
72 
73 /* ------------------------------------------------------------------------- */
74 /* return values of AMD */
75 /* ------------------------------------------------------------------------- */
76 
77 enum c_int AMD_OK = 0;           /* success */
78 enum c_int AMD_OUT_OF_MEMORY = -1;        /* malloc failed, or problem too large */
79 enum c_int AMD_INVALID = -2;              /* input arguments are not valid */
80 enum c_int AMD_OK_BUT_JUMBLED = 1;        /* input matrix is OK for amd_order, but
81     * columns were not sorted, and/or duplicate entries were present.  AMD had
82     * to do extra work before ordering the matrix.  This is a warning, not an
83     * error.  */
84 
85 /* ========================================================================== */
86 /* === AMD version ========================================================== */
87 /* ========================================================================== */
88 
89 /* AMD Version 1.2 and later include the following definitions.
90  * As an example, to test if the version you are using is 1.2 or later:
91  *
92  * #ifdef AMD_VERSION
93  *       if (AMD_VERSION >= AMD_VERSION_CODE (1,2)) ...
94  * #endif
95  *
96  * This also works during compile-time:
97  *
98  *       #if defined(AMD_VERSION) && (AMD_VERSION >= AMD_VERSION_CODE (1,2))
99  *           printf ("This is version 1.2 or later\n") ;
100  *       #else
101  *           printf ("This is an early version\n") ;
102  *       #endif
103  *
104  * Versions 1.1 and earlier of AMD do not include a #define'd version number.
105  */
106 
107 enum string AMD_DATE = "May 4, 2016";
108 //#define AMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub))
109 c_int AMD_VERSION_CODE(c_int main, c_int sub) { return (main) * 1000 + (sub); }
110 enum c_int AMD_MAIN_VERSION = 2;
111 enum c_int AMD_SUB_VERSION = 4;
112 enum c_int AMD_SUBSUB_VERSION = 6;
113 //#define AMD_VERSION AMD_VERSION_CODE(AMD_MAIN_VERSION,AMD_SUB_VERSION)
114 enum c_int AMD_VERSION = AMD_VERSION_CODE(AMD_MAIN_VERSION,AMD_SUB_VERSION); // todo : check it
115 
116 
117 
118 /* Input arguments (not modified):
119  *
120  *       n: the matrix A is n-by-n.
121  *       Ap: an int/SuiteSparse_long array of size n+1, containing column
122  *              pointers of A.
123  *       Ai: an int/SuiteSparse_long array of size nz, containing the row
124  *              indices of A, where nz = Ap [n].
125  *       Control:  a c_float array of size AMD_CONTROL, containing control
126  *           parameters.  Defaults are used if Control is NULL.
127  *
128  * Output arguments (not defined on input):
129  *
130  *       P: an int/SuiteSparse_long array of size n, containing the output
131  *           permutation. If row i is the kth pivot row, then P [k] = i.  In
132  *           MATLAB notation, the reordered matrix is A (P,P).
133  *       Info: a c_float array of size AMD_INFO, containing statistical
134  *           information.  Ignored if Info is NULL.
135  *
136  * On input, the matrix A is stored in column-oriented form.  The row indices
137  * of nonzero entries in column j are stored in Ai [Ap [j] ... Ap [j+1]-1].
138  *
139  * If the row indices appear in ascending order in each column, and there
140  * are no duplicate entries, then amd_order is slightly more efficient in
141  * terms of time and memory usage.  If this condition does not hold, a copy
142  * of the matrix is created (where these conditions do hold), and the copy is
143  * ordered.  This feature is new to v2.0 (v1.2 and earlier required this
144  * condition to hold for the input matrix).
145  *
146  * Row indices must be in the range 0 to
147  * n-1.  Ap [0] must be zero, and thus nz = Ap [n] is the number of nonzeros
148  * in A.  The array Ap is of size n+1, and the array Ai is of size nz = Ap [n].
149  * The matrix does not need to be symmetric, and the diagonal does not need to
150  * be present (if diagonal entries are present, they are ignored except for
151  * the output statistic Info [AMD_NZDIAG]).  The arrays Ai and Ap are not
152  * modified.  This form of the Ap and Ai arrays to represent the nonzero
153  * pattern of the matrix A is the same as that used internally by MATLAB.
154  * If you wish to use a more flexible input structure, please see the
155  * umfpack_*_triplet_to_col routines in the UMFPACK package, at
156  * http://www.suitesparse.com.
157  *
158  * Restrictions:  n >= 0.  Ap [0] = 0.  Ap [j] <= Ap [j+1] for all j in the
159  *       range 0 to n-1.  nz = Ap [n] >= 0.  Ai [0..nz-1] must be in the range 0
160  *       to n-1.  Finally, Ai, Ap, and P must not be NULL.  If any of these
161  *       restrictions are not met, AMD returns AMD_INVALID.
162  *
163  * AMD returns:
164  *
165  *       AMD_OK if the matrix is valid and sufficient memory can be allocated to
166  *           perform the ordering.
167  *
168  *       AMD_OUT_OF_MEMORY if not enough memory can be allocated.
169  *
170  *       AMD_INVALID if the input arguments n, Ap, Ai are invalid, or if P is
171  *           NULL.
172  *
173  *       AMD_OK_BUT_JUMBLED if the matrix had unsorted columns, and/or duplicate
174  *           entries, but was otherwise valid.
175  *
176  * The AMD routine first forms the pattern of the matrix A+A', and then
177  * computes a fill-reducing ordering, P.  If P [k] = i, then row/column i of
178  * the original is the kth pivotal row.  In MATLAB notation, the permuted
179  * matrix is A (P,P), except that 0-based indexing is used instead of the
180  * 1-based indexing in MATLAB.
181  *
182  * The Control array is used to set various parameters for AMD.  If a NULL
183  * pointer is passed, default values are used.  The Control array is not
184  * modified.
185  *
186  *       Control [AMD_DENSE]:  controls the threshold for "dense" rows/columns.
187  *           A dense row/column in A+A' can cause AMD to spend a lot of time in
188  *           ordering the matrix.  If Control [AMD_DENSE] >= 0, rows/columns
189  *           with more than Control [AMD_DENSE] * sqrt (n) entries are ignored
190  *           during the ordering, and placed last in the output order.  The
191  *           default value of Control [AMD_DENSE] is 10.  If negative, no
192  *           rows/columns are treated as "dense".  Rows/columns with 16 or
193  *           fewer off-diagonal entries are never considered "dense".
194  *
195  *       Control [AMD_AGGRESSIVE]: controls whether or not to use aggressive
196  *           absorption, in which a prior element is absorbed into the current
197  *           element if is a subset of the current element, even if it is not
198  *           adjacent to the current pivot element (refer to Amestoy, Davis,
199  *           & Duff, 1996, for more details).  The default value is nonzero,
200  *           which means to perform aggressive absorption.  This nearly always
201  *           leads to a better ordering (because the approximate degrees are
202  *           more accurate) and a lower execution time.  There are cases where
203  *           it can lead to a slightly worse ordering, however.  To turn it off,
204  *           set Control [AMD_AGGRESSIVE] to 0.
205  *
206  *       Control [2..4] are not used in the current version, but may be used in
207  *           future versions.
208  *
209  * The Info array provides statistics about the ordering on output.  If it is
210  * not present, the statistics are not returned.  This is not an error
211  * condition.
212  *
213  *       Info [AMD_STATUS]:  the return value of AMD, either AMD_OK,
214  *           AMD_OK_BUT_JUMBLED, AMD_OUT_OF_MEMORY, or AMD_INVALID.
215  *
216  *       Info [AMD_N]: n, the size of the input matrix
217  *
218  *       Info [AMD_NZ]: the number of nonzeros in A, nz = Ap [n]
219  *
220  *       Info [AMD_SYMMETRY]:  the symmetry of the matrix A.  It is the number
221  *           of "matched" off-diagonal entries divided by the total number of
222  *           off-diagonal entries.  An entry A(i,j) is matched if A(j,i) is also
223  *           an entry, for any pair (i,j) for which i != j.  In MATLAB notation,
224  *                S = spones (A) ;
225  *                B = tril (S, -1) + triu (S, 1) ;
226  *                symmetry = nnz (B & B') / nnz (B) ;
227  *
228  *       Info [AMD_NZDIAG]: the number of entries on the diagonal of A.
229  *
230  *       Info [AMD_NZ_A_PLUS_AT]:  the number of nonzeros in A+A', excluding the
231  *           diagonal.  If A is perfectly symmetric (Info [AMD_SYMMETRY] = 1)
232  *           with a fully nonzero diagonal, then Info [AMD_NZ_A_PLUS_AT] = nz-n
233  *           (the smallest possible value).  If A is perfectly unsymmetric
234  *           (Info [AMD_SYMMETRY] = 0, for an upper triangular matrix, for
235  *           example) with no diagonal, then Info [AMD_NZ_A_PLUS_AT] = 2*nz
236  *           (the largest possible value).
237  *
238  *       Info [AMD_NDENSE]: the number of "dense" rows/columns of A+A' that were
239  *           removed from A prior to ordering.  These are placed last in the
240  *           output order P.
241  *
242  *       Info [AMD_MEMORY]: the amount of memory used by AMD, in bytes.  In the
243  *           current version, this is 1.2 * Info  [AMD_NZ_A_PLUS_AT] + 9*n
244  *           times the size of an integer.  This is at most 2.4nz + 9n.  This
245  *           excludes the size of the input arguments Ai, Ap, and P, which have
246  *           a total size of nz + 2*n + 1 integers.
247  *
248  *       Info [AMD_NCMPA]: the number of garbage collections performed.
249  *
250  *       Info [AMD_LNZ]: the number of nonzeros in L (excluding the diagonal).
251  *           This is a slight upper bound because mass elimination is combined
252  *           with the approximate degree update.  It is a rough upper bound if
253  *           there are many "dense" rows/columns.  The rest of the statistics,
254  *           below, are also slight or rough upper bounds, for the same reasons.
255  *           The post-ordering of the assembly tree might also not exactly
256  *           correspond to a true elimination tree postordering.
257  *
258  *       Info [AMD_NDIV]: the number of divide operations for a subsequent LDL'
259  *           or LU factorization of the permuted matrix A (P,P).
260  *
261  *       Info [AMD_NMULTSUBS_LDL]:  the number of multiply-subtract pairs for a
262  *           subsequent LDL' factorization of A (P,P).
263  *
264  *       Info [AMD_NMULTSUBS_LU]:  the number of multiply-subtract pairs for a
265  *           subsequent LU factorization of A (P,P), assuming that no numerical
266  *           pivoting is required.
267  *
268  *       Info [AMD_DMAX]:  the maximum number of nonzeros in any column of L,
269  *           including the diagonal.
270  *
271  *       Info [14..19] are not used in the current version, but may be used in
272  *           future versions.
273  */
274 
275 /* ------------------------------------------------------------------------- */
276 /* direct interface to AMD */
277 /* ------------------------------------------------------------------------- */
278 
279 version (DLONG){
280     SuiteSparse_long AMD_order
281     (
282         SuiteSparse_long n,
283         const SuiteSparse_long * Ap,
284         const SuiteSparse_long * Ai,
285         SuiteSparse_long * P,
286         c_float * Control,
287         c_float * Info
288     );
289 }
290 else {
291     int AMD_order                  /* returns AMD_OK, AMD_OK_BUT_JUMBLED,
292                                 * AMD_INVALID, or AMD_OUT_OF_MEMORY */
293     (
294         int n,                     /* A is n-by-n.  n must be >= 0. */
295         const int * Ap,          /* column pointers for A, of size n+1 */
296         const int * Ai,          /* row indices of A, of size nz = Ap [n] */
297         int * P,                 /* output permutation, of size n */
298         c_float * Control,        /* input Control settings, of size AMD_CONTROL */
299         c_float * Info            /* output Info statistics, of size AMD_INFO */
300     );
301 }
302 
303 /* ------------------------------------------------------------------------- */
304 /* AMD Control and Info arrays */
305 /* ------------------------------------------------------------------------- */
306 
307 /* amd_defaults:  sets the default control settings */
308 void amd_defaults   (c_float * Control) ;
309 void amd_l_defaults (c_float * Control) ;
310 
311 /* amd_control: prints the control settings */
312 void amd_control    (c_float * Control) ;
313 void amd_l_control  (c_float * Control) ;
314 
315 /* amd_info: prints the statistics */
316 void amd_info       (c_float * Info) ;
317 void amd_l_info     (c_float * Info) ;