1 /* ========================================================================== */
2 /* === UMFPACK_report_numeric =============================================== */
3 /* ========================================================================== */
4
5 /* -------------------------------------------------------------------------- */
6 /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */
7 /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */
8 /* web: http://www.cise.ufl.edu/research/sparse/umfpack */
9 /* -------------------------------------------------------------------------- */
10
11 /*
12 User-callable. Prints the Numeric object.
13 See umfpack_report_numeric.h for details.
14
15 Dynamic memory usage: Allocates a size n*sizeof(Int) workspace via a single
16 call to UMF_malloc and then frees all of it via UMF_free on return. The
17 workspace is not allocated if an early error return occurs before the
18 workspace is needed.
19 */
20
21 #include "umf_internal.h"
22 #include "umf_valid_numeric.h"
23 #include "umf_report_perm.h"
24 #include "umf_report_vector.h"
25 #include "umf_malloc.h"
26 #include "umf_free.h"
27
28
29 PRIVATE Int report_L
30 (
31 NumericType *Numeric,
32 Int Pattern [ ],
33 Int prl
34 ) ;
35
36
37 PRIVATE Int report_U
38 (
39 NumericType *Numeric,
40 Int Pattern [ ],
41 Int prl
42 ) ;
43
44 /* ========================================================================== */
45 /* === UMFPACK_report_numeric =============================================== */
46 /* ========================================================================== */
47
UMFPACK_report_numeric(void * NumericHandle,const double Control[UMFPACK_CONTROL])48 GLOBAL Int UMFPACK_report_numeric
49 (
50 void *NumericHandle,
51 const double Control [UMFPACK_CONTROL]
52 )
53 {
54 Int prl, *W, nn, n_row, n_col, n_inner, num_fixed_size, numeric_size,
55 npiv ;
56 NumericType *Numeric ;
57
58 prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ;
59
60 if (prl <= 2)
61 {
62 return (UMFPACK_OK) ;
63 }
64
65 PRINTF (("Numeric object: ")) ;
66
67 Numeric = (NumericType *) NumericHandle ;
68 if (!UMF_valid_numeric (Numeric))
69 {
70 PRINTF (("ERROR: LU factors invalid\n\n")) ;
71 return (UMFPACK_ERROR_invalid_Numeric_object) ;
72 }
73
74 n_row = Numeric->n_row ;
75 n_col = Numeric->n_col ;
76 nn = MAX (n_row, n_col) ;
77 n_inner = MIN (n_row, n_col) ;
78 npiv = Numeric->npiv ;
79
80 DEBUG1 (("n_row "ID" n_col "ID" nn "ID" n_inner "ID" npiv "ID"\n",
81 n_row, n_col, nn, n_inner, npiv)) ;
82
83 /* size of Numeric object, except Numeric->Memory and Numeric->Upattern */
84 /* see also UMF_set_stats */
85 num_fixed_size =
86 UNITS (NumericType, 1) /* Numeric structure */
87 + UNITS (Entry, n_inner+1) /* D */
88 + UNITS (Int, n_row+1) /* Rperm */
89 + UNITS (Int, n_col+1) /* Cperm */
90 + 6 * UNITS (Int, npiv+1) /* Lpos, Uilen, Uip, Upos, Lilen, Lip */
91 + ((Numeric->scale != UMFPACK_SCALE_NONE) ?
92 UNITS (Entry, n_row) : 0) ; /* Rs */
93
94 DEBUG1 (("num fixed size: "ID"\n", num_fixed_size)) ;
95 DEBUG1 (("Numeric->size "ID"\n", Numeric->size)) ;
96 DEBUG1 (("ulen units "ID"\n", UNITS (Int, Numeric->ulen))) ;
97
98 /* size of Numeric->Memory is Numeric->size */
99 /* size of Numeric->Upattern is Numeric->ulen */
100 numeric_size = num_fixed_size + Numeric->size
101 + UNITS (Int, Numeric->ulen) ;
102
103 DEBUG1 (("numeric total size "ID"\n", numeric_size)) ;
104
105 if (prl >= 4)
106 {
107 PRINTF (("\n n_row: "ID" n_col: "ID"\n", n_row, n_col)) ;
108
109 PRINTF ((" relative pivot tolerance used: %g\n",
110 Numeric->relpt)) ;
111 PRINTF ((" relative symmetric pivot tolerance used: %g\n",
112 Numeric->relpt2)) ;
113
114 PRINTF ((" matrix scaled: ")) ;
115 if (Numeric->scale == UMFPACK_SCALE_NONE)
116 {
117 PRINTF (("no")) ;
118 }
119 else if (Numeric->scale == UMFPACK_SCALE_SUM)
120 {
121 PRINTF (("yes (divided each row by sum abs value in each row)\n")) ;
122 PRINTF ((" minimum sum (abs (rows of A)): %.5e\n",
123 Numeric->rsmin)) ;
124 PRINTF ((" maximum sum (abs (rows of A)): %.5e",
125 Numeric->rsmax)) ;
126 }
127 else if (Numeric->scale == UMFPACK_SCALE_MAX)
128 {
129 PRINTF (("yes (divided each row by max abs value in each row)\n")) ;
130 PRINTF ((" minimum max (abs (rows of A)): %.5e\n",
131 Numeric->rsmin)) ;
132 PRINTF ((" maximum max (abs (rows of A)): %.5e",
133 Numeric->rsmax)) ;
134 }
135 PRINTF (("\n")) ;
136
137 PRINTF ((" initial allocation parameter used: %g\n",
138 Numeric->alloc_init)) ;
139 PRINTF ((" frontal matrix allocation parameter used: %g\n",
140 Numeric->front_alloc_init)) ;
141 PRINTF ((" final total size of Numeric object (Units): "ID"\n",
142 numeric_size)) ;
143 PRINTF ((" final total size of Numeric object (MBytes): %.1f\n",
144 MBYTES (numeric_size))) ;
145 PRINTF ((" peak size of variable-size part (Units): "ID"\n",
146 Numeric->max_usage)) ;
147 PRINTF ((" peak size of variable-size part (MBytes): %.1f\n",
148 MBYTES (Numeric->max_usage))) ;
149 PRINTF ((" largest actual frontal matrix size: "ID"\n",
150 Numeric->maxfrsize)) ;
151 PRINTF ((" memory defragmentations: "ID"\n",
152 Numeric->ngarbage)) ;
153 PRINTF ((" memory reallocations: "ID"\n",
154 Numeric->nrealloc)) ;
155 PRINTF ((" costly memory reallocations: "ID"\n",
156 Numeric->ncostly)) ;
157 PRINTF ((" entries in compressed pattern (L and U): "ID"\n",
158 Numeric->isize)) ;
159 PRINTF ((" number of nonzeros in L (excl diag): "ID"\n",
160 Numeric->lnz)) ;
161 PRINTF ((" number of entries stored in L (excl diag): "ID"\n",
162 Numeric->nLentries)) ;
163 PRINTF ((" number of nonzeros in U (excl diag): "ID"\n",
164 Numeric->unz)) ;
165 PRINTF ((" number of entries stored in U (excl diag): "ID"\n",
166 Numeric->nUentries)) ;
167 PRINTF ((" factorization floating-point operations: %g\n",
168 Numeric->flops)) ;
169 PRINTF ((" number of nonzeros on diagonal of U: "ID"\n",
170 Numeric->nnzpiv)) ;
171 PRINTF ((" min abs. value on diagonal of U: %.5e\n",
172 Numeric->min_udiag)) ;
173 PRINTF ((" max abs. value on diagonal of U: %.5e\n",
174 Numeric->max_udiag)) ;
175 PRINTF ((" reciprocal condition number estimate: %.2e\n",
176 Numeric->rcond)) ;
177 }
178
179 W = (Int *) UMF_malloc (nn, sizeof (Int)) ;
180 if (!W)
181 {
182 PRINTF ((" ERROR: out of memory to check Numeric object\n\n")) ;
183 return (UMFPACK_ERROR_out_of_memory) ;
184 }
185
186 if (Numeric->Rs)
187 {
188 #ifndef NRECIPROCAL
189 if (Numeric->do_recip)
190 {
191 PRINTF4 (("\nScale factors applied via multiplication\n")) ;
192 }
193 else
194 #endif
195 {
196 PRINTF4 (("\nScale factors applied via division\n")) ;
197 }
198 PRINTF4 (("Scale factors, Rs: ")) ;
199 (void) UMF_report_vector (n_row, Numeric->Rs, (double *) NULL,
200 prl, FALSE, TRUE) ;
201 }
202 else
203 {
204 PRINTF4 (("Scale factors, Rs: (not present)\n")) ;
205 }
206
207 PRINTF4 (("\nP: row ")) ;
208 if (UMF_report_perm (n_row, Numeric->Rperm, W, prl, 0) != UMFPACK_OK)
209 {
210 (void) UMF_free ((void *) W) ;
211 return (UMFPACK_ERROR_invalid_Numeric_object) ;
212 }
213
214 PRINTF4 (("\nQ: column ")) ;
215 if (UMF_report_perm (n_col, Numeric->Cperm, W, prl, 0) != UMFPACK_OK)
216 {
217 (void) UMF_free ((void *) W) ;
218 return (UMFPACK_ERROR_invalid_Numeric_object) ;
219 }
220
221 if (!report_L (Numeric, W, prl))
222 {
223 (void) UMF_free ((void *) W) ;
224 PRINTF ((" ERROR: L factor invalid\n\n")) ;
225 return (UMFPACK_ERROR_invalid_Numeric_object) ;
226 }
227
228 if (!report_U (Numeric, W, prl))
229 {
230 (void) UMF_free ((void *) W) ;
231 PRINTF ((" ERROR: U factor invalid\n\n")) ;
232 return (UMFPACK_ERROR_invalid_Numeric_object) ;
233 }
234
235 /* The diagonal of U is in "merged" (Entry) form, not "split" form. */
236 PRINTF4 (("\ndiagonal of U: ")) ;
237 (void) UMF_report_vector (n_inner, (double *) Numeric->D, (double *) NULL,
238 prl, FALSE, FALSE) ;
239
240 (void) UMF_free ((void *) W) ;
241
242 PRINTF4 ((" Numeric object: ")) ;
243 PRINTF (("OK\n\n")) ;
244 return (UMFPACK_OK) ;
245 }
246
247
248 /* ========================================================================== */
249 /* === report_L ============================================================= */
250 /* ========================================================================== */
251
report_L(NumericType * Numeric,Int Pattern[],Int prl)252 PRIVATE Int report_L
253 (
254 NumericType *Numeric,
255 Int Pattern [ ],
256 Int prl
257 )
258 {
259 Int k, deg, *ip, j, row, n_row, *Lpos, *Lilen, valid, k1,
260 *Lip, newLchain, llen, prl1, pos, lp, p, npiv, n1, *Li ;
261 Entry *xp, *Lval ;
262
263 /* ---------------------------------------------------------------------- */
264
265 ASSERT (prl >= 3) ;
266
267 n_row = Numeric->n_row ;
268 npiv = Numeric->npiv ;
269 n1 = Numeric->n1 ;
270 Lpos = Numeric->Lpos ;
271 Lilen = Numeric->Lilen ;
272 Lip = Numeric->Lip ;
273 prl1 = prl ;
274 deg = 0 ;
275
276 PRINTF4 ((
277 "\nL in Numeric object, in column-oriented compressed-pattern form:\n"
278 " Diagonal entries are all equal to 1.0 (not stored)\n")) ;
279
280 ASSERT (Pattern != (Int *) NULL) ;
281
282 /* ---------------------------------------------------------------------- */
283 /* print L */
284 /* ---------------------------------------------------------------------- */
285
286 k1 = 12 ;
287
288 /* ---------------------------------------------------------------------- */
289 /* print the singleton columns of L */
290 /* ---------------------------------------------------------------------- */
291
292 for (k = 0 ; k < n1 ; k++)
293 {
294 if (k1 > 0)
295 {
296 prl = prl1 ;
297 }
298 lp = Lip [k] ;
299 deg = Lilen [k] ;
300 Li = (Int *) (Numeric->Memory + lp) ;
301 lp += UNITS (Int, deg) ;
302 Lval = (Entry *) (Numeric->Memory + lp) ;
303 if (k1-- > 0)
304 {
305 prl = prl1 ;
306 }
307 else if (prl == 4)
308 {
309 PRINTF ((" ...\n")) ;
310 prl-- ;
311 }
312 PRINTF4 (("\n column "ID":", INDEX (k))) ;
313 PRINTF4 ((" length "ID".\n", deg)) ;
314 for (j = 0 ; j < deg ; j++)
315 {
316 row = Li [j] ;
317 PRINTF4 (("\trow "ID" : ", INDEX (row))) ;
318 if (prl >= 4) PRINT_ENTRY (Lval [j]) ;
319 if (row <= k || row >= n_row)
320 {
321 return (FALSE) ;
322 }
323 PRINTF4 (("\n")) ;
324 /* truncate printout, but continue to check L */
325 if (prl == 4 && j == 9 && deg > 10)
326 {
327 PRINTF (("\t...\n")) ;
328 prl-- ;
329 }
330 }
331 }
332
333 /* ---------------------------------------------------------------------- */
334 /* print the regular columns of L */
335 /* ---------------------------------------------------------------------- */
336
337 for (k = n1 ; k < npiv ; k++)
338 {
339 /* if prl is 4, print the first 10 entries of the first 10 columns */
340 if (k1 > 0)
341 {
342 prl = prl1 ;
343 }
344
345 lp = Lip [k] ;
346 newLchain = (lp < 0) ;
347 if (newLchain)
348 {
349 lp = -lp ;
350 deg = 0 ;
351 }
352
353 if (k1-- > 0)
354 {
355 prl = prl1 ;
356 }
357 else if (prl == 4)
358 {
359 PRINTF ((" ...\n")) ;
360 prl-- ;
361 }
362
363 PRINTF4 (("\n column "ID":", INDEX (k))) ;
364
365 /* ------------------------------------------------------------------ */
366 /* make column of L in Pattern [0..deg-1] */
367 /* ------------------------------------------------------------------ */
368
369 /* remove pivot row */
370 pos = Lpos [k] ;
371 if (pos != EMPTY)
372 {
373 PRINTF4 ((" remove row "ID" at position "ID".",
374 INDEX (Pattern [pos]), INDEX (pos))) ;
375 valid = (!newLchain) && (deg > 0) && (pos < deg) && (pos >= 0)
376 && (Pattern [pos] == k) ;
377 if (!valid)
378 {
379 return (FALSE) ;
380 }
381 Pattern [pos] = Pattern [--deg] ;
382 }
383
384 /* concatenate the pattern */
385 llen = Lilen [k] ;
386 if (llen < 0)
387 {
388 return (FALSE) ;
389 }
390 p = lp + UNITS (Int, llen) ;
391 xp = (Entry *) (Numeric->Memory + p) ;
392 if ((llen > 0 || deg > 0)
393 && (p + (Int) UNITS (Entry, deg) > Numeric->size))
394 {
395 return (FALSE) ;
396 }
397 if (llen > 0)
398 {
399 PRINTF4 ((" add "ID" entries.", llen)) ;
400 ip = (Int *) (Numeric->Memory + lp) ;
401 for (j = 0 ; j < llen ; j++)
402 {
403 Pattern [deg++] = *ip++ ;
404 }
405 }
406
407 /* ------------------------------------------------------------------ */
408 /* print column k of L */
409 /* ------------------------------------------------------------------ */
410
411 PRINTF4 ((" length "ID".", deg)) ;
412 if (newLchain)
413 {
414 PRINTF4 ((" Start of Lchain.")) ;
415 }
416 PRINTF4 (("\n")) ;
417
418 for (j = 0 ; j < deg ; j++)
419 {
420 row = Pattern [j] ;
421 PRINTF4 (("\trow "ID" : ", INDEX (row))) ;
422 if (prl >= 4) PRINT_ENTRY (*xp) ;
423 if (row <= k || row >= n_row)
424 {
425 return (FALSE) ;
426 }
427 PRINTF4 (("\n")) ;
428 xp++ ;
429 /* truncate printout, but continue to check L */
430 if (prl == 4 && j == 9 && deg > 10)
431 {
432 PRINTF (("\t...\n")) ;
433 prl-- ;
434 }
435 }
436 }
437
438 PRINTF4 (("\n")) ;
439 return (TRUE) ;
440 }
441
442
443 /* ========================================================================== */
444 /* === report_U ============================================================= */
445 /* ========================================================================== */
446
report_U(NumericType * Numeric,Int Pattern[],Int prl)447 PRIVATE Int report_U
448 (
449 NumericType *Numeric,
450 Int Pattern [ ],
451 Int prl
452 )
453 {
454 /* ---------------------------------------------------------------------- */
455
456 Int k, deg, j, *ip, col, *Upos, *Uilen, k1, prl1, pos,
457 *Uip, n_col, ulen, p, newUchain, up, npiv, n1, *Ui ;
458 Entry *xp, *Uval ;
459
460 /* ---------------------------------------------------------------------- */
461
462 ASSERT (prl >= 3) ;
463
464 n_col = Numeric->n_col ;
465 npiv = Numeric->npiv ;
466 n1 = Numeric->n1 ;
467 Upos = Numeric->Upos ;
468 Uilen = Numeric->Uilen ;
469 Uip = Numeric->Uip ;
470 prl1 = prl ;
471
472 PRINTF4 ((
473 "\nU in Numeric object, in row-oriented compressed-pattern form:\n"
474 " Diagonal is stored separately.\n")) ;
475
476 ASSERT (Pattern != (Int *) NULL) ;
477
478 k1 = 12 ;
479
480 /* ---------------------------------------------------------------------- */
481 /* print the sparse part of U */
482 /* ---------------------------------------------------------------------- */
483
484 deg = Numeric->ulen ;
485 if (deg > 0)
486 {
487 /* make last pivot row of U (singular matrices only) */
488 for (j = 0 ; j < deg ; j++)
489 {
490 Pattern [j] = Numeric->Upattern [j] ;
491 }
492 }
493
494 PRINTF4 (("\n row "ID": length "ID". End of Uchain.\n", INDEX (npiv-1),
495 deg)) ;
496
497 for (k = npiv-1 ; k >= n1 ; k--)
498 {
499
500 /* ------------------------------------------------------------------ */
501 /* print row k of U */
502 /* ------------------------------------------------------------------ */
503
504 /* if prl is 3, print the first 10 entries of the first 10 columns */
505 if (k1 > 0)
506 {
507 prl = prl1 ;
508 }
509
510 up = Uip [k] ;
511 ulen = Uilen [k] ;
512 if (ulen < 0)
513 {
514 return (FALSE) ;
515 }
516 newUchain = (up < 0) ;
517 if (newUchain)
518 {
519 up = -up ;
520 p = up + UNITS (Int, ulen) ;
521 }
522 else
523 {
524 p = up ;
525 }
526 xp = (Entry *) (Numeric->Memory + p) ;
527 if (deg > 0 && (p + (Int) UNITS (Entry, deg) > Numeric->size))
528 {
529 return (FALSE) ;
530 }
531 for (j = 0 ; j < deg ; j++)
532 {
533 col = Pattern [j] ;
534 PRINTF4 (("\tcol "ID" :", INDEX (col))) ;
535 if (prl >= 4) PRINT_ENTRY (*xp) ;
536 if (col <= k || col >= n_col)
537 {
538 return (FALSE) ;
539 }
540 PRINTF4 (("\n")) ;
541 xp++ ;
542 /* truncate printout, but continue to check U */
543 if (prl == 4 && j == 9 && deg > 10)
544 {
545 PRINTF (("\t...\n")) ;
546 prl-- ;
547 }
548 }
549
550 /* ------------------------------------------------------------------ */
551 /* make row k-1 of U in Pattern [0..deg-1] */
552 /* ------------------------------------------------------------------ */
553
554 if (k1-- > 0)
555 {
556 prl = prl1 ;
557 }
558 else if (prl == 4)
559 {
560 PRINTF ((" ...\n")) ;
561 prl-- ;
562 }
563
564 if (k > 0)
565 {
566 PRINTF4 (("\n row "ID": ", INDEX (k-1))) ;
567 }
568
569 if (newUchain)
570 {
571 /* next row is a new Uchain */
572 if (k > 0)
573 {
574 deg = ulen ;
575 PRINTF4 (("length "ID". End of Uchain.\n", deg)) ;
576 if (up + (Int) UNITS (Int, ulen) > Numeric->size)
577 {
578 return (FALSE) ;
579 }
580 ip = (Int *) (Numeric->Memory + up) ;
581 for (j = 0 ; j < deg ; j++)
582 {
583 Pattern [j] = *ip++ ;
584 }
585 }
586 }
587 else
588 {
589 if (ulen > 0)
590 {
591 PRINTF4 (("remove "ID" entries. ", ulen)) ;
592 }
593 deg -= ulen ;
594 if (deg < 0)
595 {
596 return (FALSE) ;
597 }
598 pos = Upos [k] ;
599 if (pos != EMPTY)
600 {
601 /* add the pivot column */
602 PRINTF4 (("add column "ID" at position "ID". ",
603 INDEX (k), INDEX (pos))) ;
604 if (pos < 0 || pos > deg)
605 {
606 return (FALSE) ;
607 }
608 Pattern [deg++] = Pattern [pos] ;
609 Pattern [pos] = k ;
610 }
611 PRINTF4 (("length "ID".\n", deg)) ;
612 }
613 }
614
615 /* ---------------------------------------------------------------------- */
616 /* print the singleton rows of U */
617 /* ---------------------------------------------------------------------- */
618
619 for (k = n1 - 1 ; k >= 0 ; k--)
620 {
621 if (k1 > 0)
622 {
623 prl = prl1 ;
624 }
625 up = Uip [k] ;
626 deg = Uilen [k] ;
627 Ui = (Int *) (Numeric->Memory + up) ;
628 up += UNITS (Int, deg) ;
629 Uval = (Entry *) (Numeric->Memory + up) ;
630 if (k1-- > 0)
631 {
632 prl = prl1 ;
633 }
634 else if (prl == 4)
635 {
636 PRINTF ((" ...\n")) ;
637 prl-- ;
638 }
639 PRINTF4 (("\n row "ID":", INDEX (k))) ;
640 PRINTF4 ((" length "ID".\n", deg)) ;
641 for (j = 0 ; j < deg ; j++)
642 {
643 col = Ui [j] ;
644 PRINTF4 (("\tcol "ID" : ", INDEX (col))) ;
645 if (prl >= 4) PRINT_ENTRY (Uval [j]) ;
646 if (col <= k || col >= n_col)
647 {
648 return (FALSE) ;
649 }
650 PRINTF4 (("\n")) ;
651 /* truncate printout, but continue to check U */
652 if (prl == 4 && j == 9 && deg > 10)
653 {
654 PRINTF (("\t...\n")) ;
655 prl-- ;
656 }
657 }
658 }
659
660 prl = prl1 ;
661 PRINTF4 (("\n")) ;
662 return (TRUE) ;
663 }
664