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