Amesos Package Browser (Single Doxygen Collection)  Development
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
amesos_klu_analyze.c
Go to the documentation of this file.
1 /* ========================================================================== */
2 /* === klu_analyze ========================================================== */
3 /* ========================================================================== */
4 
5 /* Order the matrix using BTF (or not), and then AMD, COLAMD, the natural
6  * ordering, or the user-provided-function on the blocks. Does not support
7  * using a given ordering (use klu_analyze_given for that case). */
8 
9 #include "amesos_klu_internal.h"
10 
11 /* ========================================================================== */
12 /* === analyze_worker ======================================================= */
13 /* ========================================================================== */
14 
15 static Int analyze_worker /* returns KLU_OK or < 0 if error */
16 (
17  /* inputs, not modified */
18  Int n, /* A is n-by-n */
19  Int Ap [ ], /* size n+1, column pointers */
20  Int Ai [ ], /* size nz, row indices */
21  Int nblocks, /* # of blocks */
22  Int Pbtf [ ], /* BTF row permutation */
23  Int Qbtf [ ], /* BTF col permutation */
24  Int R [ ], /* size n+1, but only Rbtf [0..nblocks] is used */
25  Int ordering, /* what ordering to use (0, 1, or 3 for this routine) */
26 
27  /* output only, not defined on input */
28  Int P [ ], /* size n */
29  Int Q [ ], /* size n */
30  double Lnz [ ], /* size n, but only Lnz [0..nblocks-1] is used */
31 
32  /* workspace, not defined on input or output */
33  Int Pblk [ ], /* size maxblock */
34  Int Cp [ ], /* size maxblock+1 */
35  Int Ci [ ], /* size MAX (nz+1, Cilen) */
36  Int Cilen, /* nz+1, or COLAMD_recommend(nz,n,n) for COLAMD */
37  Int Pinv [ ], /* size maxblock */
38 
39  /* input/output */
40  KLU_symbolic *Symbolic,
41  KLU_common *Common
42 )
43 {
44  double amd_Info [AMD_INFO], lnz, lnz1, flops, flops1 ;
45  Int k1, k2, nk, k, block, oldcol, pend, newcol, result, pc, p, newrow,
46  maxnz, nzoff, cstats [COLAMD_STATS], ok, err = KLU_INVALID ;
47 
48  /* ---------------------------------------------------------------------- */
49  /* initializations */
50  /* ---------------------------------------------------------------------- */
51 
52  /* compute the inverse of Pbtf */
53 #ifndef NDEBUG
54  for (k = 0 ; k < n ; k++)
55  {
56  P [k] = EMPTY ;
57  Q [k] = EMPTY ;
58  Pinv [k] = EMPTY ;
59  }
60 #endif
61  for (k = 0 ; k < n ; k++)
62  {
63  ASSERT (Pbtf [k] >= 0 && Pbtf [k] < n) ;
64  Pinv [Pbtf [k]] = k ;
65  }
66 #ifndef NDEBUG
67  for (k = 0 ; k < n ; k++) ASSERT (Pinv [k] != EMPTY) ;
68 #endif
69  nzoff = 0 ;
70  lnz = 0 ;
71  maxnz = 0 ;
72  flops = 0 ;
73  Symbolic->symmetry = EMPTY ; /* only computed by AMD */
74 
75  /* ---------------------------------------------------------------------- */
76  /* order each block */
77  /* ---------------------------------------------------------------------- */
78 
79  for (block = 0 ; block < nblocks ; block++)
80  {
81 
82  /* ------------------------------------------------------------------ */
83  /* the block is from rows/columns k1 to k2-1 */
84  /* ------------------------------------------------------------------ */
85 
86  k1 = R [block] ;
87  k2 = R [block+1] ;
88  nk = k2 - k1 ;
89  PRINTF (("BLOCK %d, k1 %d k2-1 %d nk %d\n", block, k1, k2-1, nk)) ;
90 
91  /* ------------------------------------------------------------------ */
92  /* construct the kth block, C */
93  /* ------------------------------------------------------------------ */
94 
95  Lnz [block] = EMPTY ;
96  pc = 0 ;
97  for (k = k1 ; k < k2 ; k++)
98  {
99  newcol = k-k1 ;
100  Cp [newcol] = pc ;
101  oldcol = Qbtf [k] ;
102  pend = Ap [oldcol+1] ;
103  for (p = Ap [oldcol] ; p < pend ; p++)
104  {
105  newrow = Pinv [Ai [p]] ;
106  if (newrow < k1)
107  {
108  nzoff++ ;
109  }
110  else
111  {
112  /* (newrow,newcol) is an entry in the block */
113  ASSERT (newrow < k2) ;
114  newrow -= k1 ;
115  Ci [pc++] = newrow ;
116  }
117  }
118  }
119  Cp [nk] = pc ;
120  maxnz = MAX (maxnz, pc) ;
121  ASSERT (KLU_valid (nk, Cp, Ci, NULL)) ;
122 
123  /* ------------------------------------------------------------------ */
124  /* order the block C */
125  /* ------------------------------------------------------------------ */
126 
127  if (nk <= 3)
128  {
129 
130  /* -------------------------------------------------------------- */
131  /* use natural ordering for tiny blocks (3-by-3 or less) */
132  /* -------------------------------------------------------------- */
133 
134  for (k = 0 ; k < nk ; k++)
135  {
136  Pblk [k] = k ;
137  }
138  lnz1 = nk * (nk + 1) / 2 ;
139  flops1 = nk * (nk - 1) / 2 + (nk-1)*nk*(2*nk-1) / 6 ;
140  ok = TRUE ;
141 
142  }
143  else if (ordering == 0)
144  {
145 
146  /* -------------------------------------------------------------- */
147  /* order the block with AMD (C+C') */
148  /* -------------------------------------------------------------- */
149 
150  result = AMD_order (nk, Cp, Ci, Pblk, NULL, amd_Info) ;
151  ok = (result >= AMD_OK) ;
152  if (result == AMD_OUT_OF_MEMORY)
153  {
154  err = KLU_OUT_OF_MEMORY ;
155  }
156 
157  /* account for memory usage in AMD */
158  Common->mempeak = ( size_t) ( MAX (Common->mempeak,
159  Common->memusage + amd_Info [AMD_MEMORY]) ) ;
160 
161  /* get the ordering statistics from AMD */
162  lnz1 = (Int) (amd_Info [AMD_LNZ]) + nk ;
163  flops1 = 2 * amd_Info [AMD_NMULTSUBS_LU] + amd_Info [AMD_NDIV] ;
164  if (pc == maxnz)
165  {
166  /* get the symmetry of the biggest block */
167  Symbolic->symmetry = amd_Info [AMD_SYMMETRY] ;
168  }
169 
170  }
171  else if (ordering == 1)
172  {
173 
174  /* -------------------------------------------------------------- */
175  /* order the block with COLAMD (C) */
176  /* -------------------------------------------------------------- */
177 
178  /* order (and destroy) Ci, returning column permutation in Cp.
179  * COLAMD "cannot" fail since the matrix has already been checked,
180  * and Ci allocated. */
181 
182  ok = COLAMD (nk, nk, Cilen, Ci, Cp, NULL, cstats) ;
183  lnz1 = EMPTY ;
184  flops1 = EMPTY ;
185 
186  /* copy the permutation from Cp to Pblk */
187  for (k = 0 ; k < nk ; k++)
188  {
189  Pblk [k] = Cp [k] ;
190  }
191 
192  }
193  else
194  {
195 
196  /* -------------------------------------------------------------- */
197  /* pass the block to the user-provided ordering function */
198  /* -------------------------------------------------------------- */
199 
200  lnz1 = (Common->user_order) (nk, Cp, Ci, Pblk, Common) ;
201  flops1 = EMPTY ;
202  ok = (lnz1 != 0) ;
203  }
204 
205  if (!ok)
206  {
207  return (err) ; /* ordering method failed */
208  }
209 
210  /* ------------------------------------------------------------------ */
211  /* keep track of nnz(L) and flops statistics */
212  /* ------------------------------------------------------------------ */
213 
214  Lnz [block] = lnz1 ;
215  lnz = (lnz == EMPTY || lnz1 == EMPTY) ? EMPTY : (lnz + lnz1) ;
216  flops = (flops == EMPTY || flops1 == EMPTY) ? EMPTY : (flops + flops1) ;
217 
218  /* ------------------------------------------------------------------ */
219  /* combine the preordering with the BTF ordering */
220  /* ------------------------------------------------------------------ */
221 
222  PRINTF (("Pblk, 1-based:\n")) ;
223  for (k = 0 ; k < nk ; k++)
224  {
225  ASSERT (k + k1 < n) ;
226  ASSERT (Pblk [k] + k1 < n) ;
227  Q [k + k1] = Qbtf [Pblk [k] + k1] ;
228  }
229  for (k = 0 ; k < nk ; k++)
230  {
231  ASSERT (k + k1 < n) ;
232  ASSERT (Pblk [k] + k1 < n) ;
233  P [k + k1] = Pbtf [Pblk [k] + k1] ;
234  }
235  }
236 
237  PRINTF (("nzoff %d Ap[n] %d\n", nzoff, Ap [n])) ;
238  ASSERT (nzoff >= 0 && nzoff <= Ap [n]) ;
239 
240  /* return estimates of # of nonzeros in L including diagonal */
241  Symbolic->lnz = lnz ; /* EMPTY if COLAMD used */
242  Symbolic->unz = lnz ;
243  Symbolic->nzoff = nzoff ;
244  Symbolic->est_flops = flops ; /* EMPTY if COLAMD or user-ordering used */
245  return (KLU_OK) ;
246 }
247 
248 
249 /* ========================================================================== */
250 /* === order_and_analyze ==================================================== */
251 /* ========================================================================== */
252 
253 /* Orders the matrix with or with BTF, then orders each block with AMD, COLAMD,
254  * or the user ordering function. Does not handle the natural or given
255  * ordering cases. */
256 
257 static KLU_symbolic *order_and_analyze /* returns NULL if error, or a valid
258  KLU_symbolic object if successful */
259 (
260  /* inputs, not modified */
261  Int n, /* A is n-by-n */
262  Int Ap [ ], /* size n+1, column pointers */
263  Int Ai [ ], /* size nz, row indices */
264  /* --------------------- */
265  KLU_common *Common
266 )
267 {
268  double work ;
269  KLU_symbolic *Symbolic ;
270  double *Lnz ;
271  Int *Qbtf, *Cp, *Ci, *Pinv, *Pblk, *Pbtf, *P, *Q, *R ;
272  Int nblocks, nz, block, maxblock, k1, k2, nk, do_btf, ordering, k, Cilen,
273  *Work ;
274 
275  /* ---------------------------------------------------------------------- */
276  /* allocate the Symbolic object, and check input matrix */
277  /* ---------------------------------------------------------------------- */
278 
279  Symbolic = KLU_alloc_symbolic (n, Ap, Ai, Common) ;
280  if (Symbolic == NULL)
281  {
282  return (NULL) ;
283  }
284  P = Symbolic->P ;
285  Q = Symbolic->Q ;
286  R = Symbolic->R ;
287  Lnz = Symbolic->Lnz ;
288  nz = Symbolic->nz ;
289 
290  ordering = Common->ordering ;
291  if (ordering == 1)
292  {
293  /* COLAMD */
294  Cilen = COLAMD_recommended (nz, n, n) ;
295  }
296  else if (ordering == 0 || (ordering == 3 && Common->user_order != NULL))
297  {
298  /* AMD or user ordering function */
299  Cilen = nz+1 ;
300  }
301  else
302  {
303  /* invalid ordering */
304  Common->status = KLU_INVALID ;
305  KLU_free_symbolic (&Symbolic, Common) ;
306  return (NULL) ;
307  }
308 
309  /* AMD memory management routines */
310  amesos_amd_malloc = Common->malloc_memory ;
311  amesos_amd_free = Common->free_memory ;
312  amesos_amd_calloc = Common->calloc_memory ;
313  amesos_amd_realloc = Common->realloc_memory ;
314 
315  /* ---------------------------------------------------------------------- */
316  /* allocate workspace for BTF permutation */
317  /* ---------------------------------------------------------------------- */
318 
319  Pbtf = KLU_malloc (n, sizeof (Int), Common) ;
320  Qbtf = KLU_malloc (n, sizeof (Int), Common) ;
321  if (Common->status < KLU_OK)
322  {
323  KLU_free (Pbtf, n, sizeof (Int), Common) ;
324  KLU_free (Qbtf, n, sizeof (Int), Common) ;
325  KLU_free_symbolic (&Symbolic, Common) ;
326  return (NULL) ;
327  }
328 
329  /* ---------------------------------------------------------------------- */
330  /* get the common parameters for BTF and ordering method */
331  /* ---------------------------------------------------------------------- */
332 
333  do_btf = Common->btf ;
334  do_btf = (do_btf) ? TRUE : FALSE ;
335  Symbolic->ordering = ordering ;
336  Symbolic->do_btf = do_btf ;
337  Symbolic->structural_rank = EMPTY ;
338 
339  /* ---------------------------------------------------------------------- */
340  /* find the block triangular form (if requested) */
341  /* ---------------------------------------------------------------------- */
342 
343  Common->work = 0 ;
344 
345  if (do_btf)
346  {
347  Work = KLU_malloc (5*n, sizeof (Int), Common) ;
348  if (Common->status < KLU_OK)
349  {
350  /* out of memory */
351  KLU_free (Pbtf, n, sizeof (Int), Common) ;
352  KLU_free (Qbtf, n, sizeof (Int), Common) ;
353  KLU_free_symbolic (&Symbolic, Common) ;
354  return (NULL) ;
355  }
356 
357  nblocks = BTF_order (n, Ap, Ai, Common->maxwork, &work, Pbtf, Qbtf, R,
358  &(Symbolic->structural_rank), Work) ;
359  Common->structural_rank = Symbolic->structural_rank ;
360  Common->work += work ;
361 
362  KLU_free (Work, 5*n, sizeof (Int), Common) ;
363 
364  /* unflip Qbtf if the matrix does not have full structural rank */
365  if (Symbolic->structural_rank < n)
366  {
367  for (k = 0 ; k < n ; k++)
368  {
369  Qbtf [k] = BTF_UNFLIP (Qbtf [k]) ;
370  }
371  }
372 
373  /* find the size of the largest block */
374  maxblock = 1 ;
375  for (block = 0 ; block < nblocks ; block++)
376  {
377  k1 = R [block] ;
378  k2 = R [block+1] ;
379  nk = k2 - k1 ;
380  PRINTF (("block %d size %d\n", block, nk)) ;
381  maxblock = MAX (maxblock, nk) ;
382  }
383  }
384  else
385  {
386  /* BTF not requested */
387  nblocks = 1 ;
388  maxblock = n ;
389  R [0] = 0 ;
390  R [1] = n ;
391  for (k = 0 ; k < n ; k++)
392  {
393  Pbtf [k] = k ;
394  Qbtf [k] = k ;
395  }
396  }
397 
398  Symbolic->nblocks = nblocks ;
399 
400  PRINTF (("maxblock size %d\n", maxblock)) ;
401  Symbolic->maxblock = maxblock ;
402 
403  /* ---------------------------------------------------------------------- */
404  /* allocate more workspace, for analyze_worker */
405  /* ---------------------------------------------------------------------- */
406 
407  Pblk = KLU_malloc (maxblock, sizeof (Int), Common) ;
408  Cp = KLU_malloc (maxblock + 1, sizeof (Int), Common) ;
409  Ci = KLU_malloc (MAX (Cilen, nz+1), sizeof (Int), Common) ;
410  Pinv = KLU_malloc (n, sizeof (Int), Common) ;
411 
412  /* ---------------------------------------------------------------------- */
413  /* order each block of the BTF ordering, and a fill-reducing ordering */
414  /* ---------------------------------------------------------------------- */
415 
416  if (Common->status == KLU_OK)
417  {
418  PRINTF (("calling analyze_worker\n")) ;
419  Common->status = analyze_worker (n, Ap, Ai, nblocks, Pbtf, Qbtf, R,
420  ordering, P, Q, Lnz, Pblk, Cp, Ci, Cilen, Pinv, Symbolic, Common) ;
421  PRINTF (("analyze_worker done\n")) ;
422  }
423 
424  /* ---------------------------------------------------------------------- */
425  /* free all workspace */
426  /* ---------------------------------------------------------------------- */
427 
428  KLU_free (Pblk, maxblock, sizeof (Int), Common) ;
429  KLU_free (Cp, maxblock+1, sizeof (Int), Common) ;
430  KLU_free (Ci, MAX (Cilen, nz+1), sizeof (Int), Common) ;
431  KLU_free (Pinv, n, sizeof (Int), Common) ;
432  KLU_free (Pbtf, n, sizeof (Int), Common) ;
433  KLU_free (Qbtf, n, sizeof (Int), Common) ;
434 
435  /* ---------------------------------------------------------------------- */
436  /* return the symbolic object */
437  /* ---------------------------------------------------------------------- */
438 
439  if (Common->status < KLU_OK)
440  {
441  KLU_free_symbolic (&Symbolic, Common) ;
442  }
443  return (Symbolic) ;
444 }
445 
446 
447 /* ========================================================================== */
448 /* === KLU_analyze ========================================================== */
449 /* ========================================================================== */
450 
451 KLU_symbolic *KLU_analyze /* returns NULL if error, or a valid
452  KLU_symbolic object if successful */
453 (
454  /* inputs, not modified */
455  Int n, /* A is n-by-n */
456  Int Ap [ ], /* size n+1, column pointers */
457  Int Ai [ ], /* size nz, row indices */
458  /* -------------------- */
459  KLU_common *Common
460 )
461 {
462 
463  /* ---------------------------------------------------------------------- */
464  /* get the control parameters for BTF and ordering method */
465  /* ---------------------------------------------------------------------- */
466 
467  if (Common == NULL)
468  {
469  return (NULL) ;
470  }
471  Common->status = KLU_OK ;
472  Common->structural_rank = EMPTY ;
473 
474  /* ---------------------------------------------------------------------- */
475  /* order and analyze */
476  /* ---------------------------------------------------------------------- */
477 
478  if (Common->ordering == 2)
479  {
480  /* natural ordering */
481  return (KLU_analyze_given (n, Ap, Ai, NULL, NULL, Common)) ;
482  }
483  else
484  {
485  /* order with P and Q */
486  return (order_and_analyze (n, Ap, Ai, Common)) ;
487  }
488 }
EXTERN void *(* amesos_amd_realloc)(void *, size_t)
Definition: amesos_amd.h:320
#define KLU_INVALID
#define EMPTY
#define KLU_symbolic
#define Int
static Int analyze_worker(Int n, Int Ap[], Int Ai[], Int nblocks, Int Pbtf[], Int Qbtf[], Int R[], Int ordering, Int P[], Int Q[], double Lnz[], Int Pblk[], Int Cp[], Int Ci[], Int Cilen, Int Pinv[], KLU_symbolic *Symbolic, KLU_common *Common)
#define FALSE
#define P(k)
EXTERN void(* amesos_amd_free)(void *)
Definition: amesos_amd.h:319
#define AMD_order
#define MAX(a, b)
#define COLAMD_recommended
#define KLU_OUT_OF_MEMORY
#define BTF_UNFLIP(j)
#define NULL
#define ASSERT(expression)
#define AMD_MEMORY
Definition: amesos_amd.h:359
#define COLAMD
EXTERN void *(* amesos_amd_calloc)(size_t, size_t)
Definition: amesos_amd.h:321
#define KLU_alloc_symbolic
#define KLU_malloc
#define COLAMD_STATS
#define AMD_NMULTSUBS_LU
Definition: amesos_amd.h:364
#define KLU_free_symbolic
#define AMD_OK
Definition: amesos_amd.h:371
#define AMD_NDIV
Definition: amesos_amd.h:362
#define KLU_analyze_given
#define KLU_valid
static KLU_symbolic * order_and_analyze(Int n, Int Ap[], Int Ai[], KLU_common *Common)
#define KLU_common
#define AMD_SYMMETRY
Definition: amesos_amd.h:355
#define AMD_OUT_OF_MEMORY
Definition: amesos_amd.h:372
#define PRINTF(params)
#define BTF_order
int n
#define TRUE
#define AMD_INFO
Definition: amesos_amd.h:341
#define KLU_free
#define KLU_OK
EXTERN void *(* amesos_amd_malloc)(size_t)
Definition: amesos_amd.h:318
KLU_symbolic * KLU_analyze(Int n, Int Ap[], Int Ai[], KLU_common *Common)
#define AMD_LNZ
Definition: amesos_amd.h:361