1 /* ========================================================================== */
2 /* === Core/cholmod_common ================================================== */
3 /* ========================================================================== */
4 
5 /* -----------------------------------------------------------------------------
6  * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
7  * Univ. of Florida.  Author: Timothy A. Davis
8  * -------------------------------------------------------------------------- */
9 
10 /* Core utility routines for the cholmod_common object:
11  *
12  * Primary routines:
13  * -----------------
14  * cholmod_start		the first call to CHOLMOD
15  * cholmod_finish		the last call to CHOLMOD
16  *
17  * Secondary routines:
18  * -------------------
19  * cholmod_defaults		restore (most) default control parameters
20  * cholmod_allocate_work	allocate (or reallocate) workspace in Common
21  * cholmod_free_work		free workspace in Common
22  * cholmod_clear_flag		clear Common->Flag in workspace
23  * cholmod_maxrank		column dimension of Common->Xwork workspace
24  *
25  * The Common object is unique.  It cannot be allocated or deallocated by
26  * CHOLMOD, since it contains the definition of the memory management routines
27  * used (pointers to malloc, free, realloc, and calloc, or their equivalent).
28  * The Common object contains workspace that is used between calls to
29  * CHOLMOD routines.  This workspace allocated by CHOLMOD as needed, by
30  * cholmod_allocate_work and cholmod_free_work.
31  */
32 
33 #include "cholmod_internal.h"
34 #include "cholmod_core.h"
35 
36 #ifdef GPU_BLAS
37 #include "cholmod_gpu.h"
38 #endif
39 
40 /* ========================================================================== */
41 /* === cholmod_start ======================================================== */
42 /* ========================================================================== */
43 
44 /* Initialize Common default parameters and statistics.  Sets workspace
45  * pointers to NULL.
46  *
47  * This routine must be called just once, prior to calling any other CHOLMOD
48  * routine.  Do not call this routine after any other CHOLMOD routine (except
49  * cholmod_finish, to start a new CHOLMOD session), or a memory leak will
50  * occur.
51  *
52  * workspace: none
53  */
54 
CHOLMOD(start)55 int CHOLMOD(start)
56 (
57     cholmod_common *Common
58 )
59 {
60     int k ;
61 
62     if (Common == NULL)
63     {
64 	return (FALSE) ;
65     }
66 
67     /* ---------------------------------------------------------------------- */
68     /* user error handling routine */
69     /* ---------------------------------------------------------------------- */
70 
71     Common->error_handler = NULL ;
72 
73     /* ---------------------------------------------------------------------- */
74     /* integer and numerical types */
75     /* ---------------------------------------------------------------------- */
76 
77     Common->itype = ITYPE ;
78     Common->dtype = DTYPE ;
79 
80     /* ---------------------------------------------------------------------- */
81     /* default control parameters */
82     /* ---------------------------------------------------------------------- */
83 
84     CHOLMOD(defaults) (Common) ;
85     Common->try_catch = FALSE ;
86 
87     /* ---------------------------------------------------------------------- */
88     /* memory management routines */
89     /* ---------------------------------------------------------------------- */
90 
91         /* moved to SuiteSparse_config */
92 
93     /* ---------------------------------------------------------------------- */
94     /* complex arithmetic routines */
95     /* ---------------------------------------------------------------------- */
96 
97         /* moved to SuiteSparse_config */
98 
99     /* ---------------------------------------------------------------------- */
100     /* print routine */
101     /* ---------------------------------------------------------------------- */
102 
103         /* moved to SuiteSparse_config */
104 
105     /* ---------------------------------------------------------------------- */
106     /* workspace */
107     /* ---------------------------------------------------------------------- */
108 
109     /* This code assumes the workspace held in Common is not initialized.  If
110      * it is, then a memory leak will occur because the pointers are
111      * overwritten with NULL. */
112 
113     Common->nrow = 0 ;
114     Common->mark = EMPTY ;
115     Common->xworksize = 0 ;
116     Common->iworksize = 0 ;
117     Common->Flag = NULL ;
118     Common->Head = NULL ;
119     Common->Iwork = NULL ;
120     Common->Xwork = NULL ;
121     Common->no_workspace_reallocate = FALSE ;
122 
123     /* ---------------------------------------------------------------------- */
124     /* statistics */
125     /* ---------------------------------------------------------------------- */
126 
127     /* fl and lnz are computed in cholmod_analyze and cholmod_rowcolcounts */
128     Common->fl = EMPTY ;
129     Common->lnz = EMPTY ;
130 
131     /* modfl is computed in cholmod_updown, cholmod_rowadd, and cholmod_rowdel*/
132     Common->modfl = EMPTY ;
133 
134     /* all routines use status as their error-report code */
135     Common->status = CHOLMOD_OK ;
136 
137     Common->malloc_count = 0 ;	/* # calls to malloc minus # calls to free */
138     Common->memory_usage = 0 ;	/* peak memory usage (in bytes) */
139     Common->memory_inuse = 0 ;	/* current memory in use (in bytes) */
140 
141     Common->nrealloc_col = 0 ;
142     Common->nrealloc_factor = 0 ;
143     Common->ndbounds_hit = 0 ;
144     Common->rowfacfl = 0 ;
145     Common->aatfl = EMPTY ;
146 
147     /* Common->called_nd is TRUE if cholmod_analyze called or NESDIS */
148     Common->called_nd = FALSE ;
149 
150     Common->blas_ok = TRUE ;    /* false if BLAS int overflow occurs */
151 
152     /* ---------------------------------------------------------------------- */
153     /* default SuiteSparseQR knobs and statististics */
154     /* ---------------------------------------------------------------------- */
155 
156     for (k = 0 ; k < 10 ; k++) Common->SPQR_istat [k] = 0 ;
157 
158     Common->SPQR_flopcount_bound = 0 ;   /* upper bound on flop count */
159     Common->SPQR_tol_used = 0 ;          /* tolerance used */
160     Common->SPQR_norm_E_fro = 0 ;        /* Frobenius norm of dropped entries */
161 
162     Common->SPQR_grain = 1 ;    /* no Intel TBB multitasking, by default */
163     Common->SPQR_small = 1e6 ;  /* target min task size for TBB */
164     Common->SPQR_shrink = 1 ;   /* controls SPQR shrink realloc */
165     Common->SPQR_nthreads = 0 ; /* 0: let TBB decide how many threads to use */
166 
167     Common->SPQR_flopcount = 0 ;         /* flop count for SPQR */
168     Common->SPQR_analyze_time = 0 ;      /* analysis time for SPQR */
169     Common->SPQR_factorize_time = 0 ;    /* factorize time for SPQR */
170     Common->SPQR_solve_time = 0 ;        /* backsolve time for SPQR */
171 
172     /* ---------------------------------------------------------------------- */
173     /* GPU initializations */
174     /* ---------------------------------------------------------------------- */
175 
176     /* these are destroyed by cholmod_gpu_deallocate and cholmod_gpu_end */
177     Common->cublasHandle = NULL ;
178     Common->cublasEventPotrf [0] = NULL ;
179     Common->cublasEventPotrf [1] = NULL ;
180     Common->cublasEventPotrf [2] = NULL ;
181     for (k = 0 ; k < CHOLMOD_HOST_SUPERNODE_BUFFERS ; k++)
182     {
183         Common->gpuStream [k] = NULL ;
184         Common->updateCBuffersFree [k] = NULL ;
185     }
186     Common->updateCKernelsComplete = NULL;
187 
188     /* these are destroyed by cholmod_gpu_deallocate */
189     Common->dev_mempool = NULL;
190     Common->dev_mempool_size = 0;
191     Common->host_pinned_mempool = NULL;
192     Common->host_pinned_mempool_size = 0;
193 
194     Common->syrkStart = 0 ;
195 
196     Common->cholmod_cpu_gemm_time = 0 ;
197     Common->cholmod_cpu_syrk_time = 0 ;
198     Common->cholmod_cpu_trsm_time = 0 ;
199     Common->cholmod_cpu_potrf_time = 0 ;
200     Common->cholmod_gpu_gemm_time = 0 ;
201     Common->cholmod_gpu_syrk_time = 0 ;
202     Common->cholmod_gpu_trsm_time = 0 ;
203     Common->cholmod_gpu_potrf_time = 0 ;
204     Common->cholmod_assemble_time = 0 ;
205     Common->cholmod_assemble_time2 = 0 ;
206 
207     Common->cholmod_cpu_gemm_calls = 0 ;
208     Common->cholmod_cpu_syrk_calls = 0 ;
209     Common->cholmod_cpu_trsm_calls = 0 ;
210     Common->cholmod_cpu_potrf_calls = 0 ;
211 
212     Common->cholmod_gpu_gemm_calls = 0 ;
213     Common->cholmod_gpu_syrk_calls = 0 ;
214     Common->cholmod_gpu_trsm_calls = 0 ;
215     Common->cholmod_gpu_potrf_calls = 0 ;
216 
217     Common->maxGpuMemBytes = 0;
218     Common->maxGpuMemFraction = 0.0;
219 
220     /* SPQR statistics and settings */
221     Common->gpuMemorySize = 1 ;         /* default: no GPU memory available */
222     Common->gpuKernelTime = 0.0 ;
223     Common->gpuFlops = 0 ;
224     Common->gpuNumKernelLaunches = 0 ;
225 
226     DEBUG_INIT ("cholmod start", Common) ;
227 
228     return (TRUE) ;
229 }
230 
231 
232 /* ========================================================================== */
233 /* === cholmod_defaults ===================================================== */
234 /* ========================================================================== */
235 
236 /* Set Common default parameters, except for the function pointers.
237  *
238  * workspace: none
239  */
240 
CHOLMOD(defaults)241 int CHOLMOD(defaults)
242 (
243     cholmod_common *Common
244 )
245 {
246     Int i ;
247 
248     RETURN_IF_NULL_COMMON (FALSE) ;
249 
250     /* ---------------------------------------------------------------------- */
251     /* default control parameters */
252     /* ---------------------------------------------------------------------- */
253 
254     Common->dbound = 0.0 ;
255     Common->grow0 = 1.2 ;
256     Common->grow1 = 1.2 ;
257     Common->grow2 = 5 ;
258     Common->maxrank = 8 ;
259 
260     Common->final_asis = TRUE ;
261     Common->final_super = TRUE ;
262     Common->final_ll = FALSE ;
263     Common->final_pack = TRUE ;
264     Common->final_monotonic = TRUE ;
265     Common->final_resymbol = FALSE ;
266 
267     /* use simplicial factorization if flop/nnz(L) < 40, supernodal otherwise */
268     Common->supernodal = CHOLMOD_AUTO ;
269     Common->supernodal_switch = 40 ;
270 
271     Common->nrelax [0] = 4 ;
272     Common->nrelax [1] = 16 ;
273     Common->nrelax [2] = 48 ;
274     Common->zrelax [0] = 0.8 ;
275     Common->zrelax [1] = 0.1 ;
276     Common->zrelax [2] = 0.05 ;
277 
278     Common->prefer_zomplex = FALSE ;
279     Common->prefer_upper = TRUE ;
280     Common->prefer_binary = FALSE ;
281     Common->quick_return_if_not_posdef = FALSE ;
282 
283     /* METIS workarounds */
284     Common->metis_memory = 0.0 ;    /* > 0 for memory guard (2 is reasonable) */
285     Common->metis_nswitch = 3000 ;
286     Common->metis_dswitch = 0.66 ;
287 
288     Common->print = 3 ;
289     Common->precise = FALSE ;
290 
291     /* ---------------------------------------------------------------------- */
292     /* default ordering methods */
293     /* ---------------------------------------------------------------------- */
294 
295     /* Note that if the Partition module is not installed, the CHOLMOD_METIS
296      * and CHOLMOD_NESDIS methods will not be available.  cholmod_analyze will
297      * report the CHOLMOD_NOT_INSTALLED error, and safely skip over them.
298      */
299 
300 #if (CHOLMOD_MAXMETHODS < 9)
301 #error "CHOLMOD_MAXMETHODS must be 9 or more (defined in cholmod_core.h)."
302 #endif
303 
304     /* default strategy: try given, AMD, and then METIS if AMD reports high
305      * fill-in.  NESDIS can be used instead, if Common->default_nesdis is TRUE.
306      */
307     Common->nmethods = 0 ;		/* use default strategy */
308     Common->default_nesdis = FALSE ;	/* use METIS in default strategy */
309 
310     Common->current = 0 ;	/* current method being tried */
311     Common->selected = 0 ;	/* the best method selected */
312 
313     /* first, fill each method with default parameters */
314     for (i = 0 ; i <= CHOLMOD_MAXMETHODS ; i++)
315     {
316 	/* CHOLMOD's default method is AMD for A or AA' */
317 	Common->method [i].ordering = CHOLMOD_AMD ;
318 
319 	/* CHOLMOD nested dissection and minimum degree parameter */
320 	Common->method [i].prune_dense = 10.0 ;	/* dense row/col control */
321 
322 	/* min degree parameters (AMD, COLAMD, SYMAMD, CAMD, CCOLAMD, CSYMAMD)*/
323 	Common->method [i].prune_dense2 = -1 ;	/* COLAMD dense row control */
324 	Common->method [i].aggressive = TRUE ;	/* aggressive absorption */
325 	Common->method [i].order_for_lu = FALSE ;/* order for Cholesky not LU */
326 
327 	/* CHOLMOD's nested dissection (METIS + constrained AMD) */
328 	Common->method [i].nd_small = 200 ;	/* small graphs aren't cut */
329 	Common->method [i].nd_compress = TRUE ;	/* compress graph & subgraphs */
330 	Common->method [i].nd_camd = 1 ;	/* use CAMD */
331 	Common->method [i].nd_components = FALSE ;  /* lump connected comp. */
332 	Common->method [i].nd_oksep = 1.0 ;	/* sep ok if < oksep*n */
333 
334 	/* statistics for each method are not yet computed */
335 	Common->method [i].fl = EMPTY ;
336 	Common->method [i].lnz = EMPTY ;
337     }
338 
339     Common->postorder = TRUE ;	/* follow ordering with weighted postorder */
340 
341     /* Next, define some methods.  The first five use default parameters. */
342     Common->method [0].ordering = CHOLMOD_GIVEN ;   /* skip if UserPerm NULL */
343     Common->method [1].ordering = CHOLMOD_AMD ;
344     Common->method [2].ordering = CHOLMOD_METIS ;
345     Common->method [3].ordering = CHOLMOD_NESDIS ;
346     Common->method [4].ordering = CHOLMOD_NATURAL ;
347 
348     /* CHOLMOD's nested dissection with large leaves of separator tree */
349     Common->method [5].ordering = CHOLMOD_NESDIS ;
350     Common->method [5].nd_small = 20000 ;
351 
352     /* CHOLMOD's nested dissection with tiny leaves, and no AMD ordering */
353     Common->method [6].ordering = CHOLMOD_NESDIS ;
354     Common->method [6].nd_small = 4 ;
355     Common->method [6].nd_camd = 0 ;		/* no CSYMAMD or CAMD */
356 
357     /* CHOLMOD's nested dissection with no dense node removal */
358     Common->method [7].ordering = CHOLMOD_NESDIS ;
359     Common->method [7].prune_dense = -1. ;
360 
361     /* COLAMD for A*A', AMD for A */
362     Common->method [8].ordering = CHOLMOD_COLAMD ;
363 
364     /* ---------------------------------------------------------------------- */
365     /* GPU configuration and statistics */
366     /* ---------------------------------------------------------------------- */
367 
368 #ifdef DLONG
369     Common->useGPU = EMPTY ;
370 #else
371     /* GPU acceleration is not supported for int version of CHOLMOD */
372     Common->useGPU = 0 ;
373 #endif
374 
375     return (TRUE) ;
376 }
377 
378 
379 /* ========================================================================== */
380 /* === cholmod_finish ======================================================= */
381 /* ========================================================================== */
382 
383 /* The last call to CHOLMOD must be cholmod_finish.  You may call this routine
384  * more than once, and can safely call any other CHOLMOD routine after calling
385  * it (including cholmod_start).
386  *
387  * The statistics and parameter settings in Common are preserved.  The
388  * workspace in Common is freed.  This routine is just another name for
389  * cholmod_free_work.
390  */
391 
CHOLMOD(finish)392 int CHOLMOD(finish)
393 (
394     cholmod_common *Common
395 )
396 {
397     return (CHOLMOD(free_work) (Common)) ;
398 }
399 
400 
401 /* ========================================================================== */
402 /* === cholmod_allocate_work ================================================ */
403 /* ========================================================================== */
404 
405 /* Allocate and initialize workspace for CHOLMOD routines, or increase the size
406  * of already-allocated workspace.  If enough workspace is already allocated,
407  * then nothing happens.
408  *
409  * workspace: Flag (nrow), Head (nrow+1), Iwork (iworksize), Xwork (xworksize)
410  */
411 
CHOLMOD(allocate_work)412 int CHOLMOD(allocate_work)
413 (
414     /* ---- input ---- */
415     size_t nrow,	/* # of rows in the matrix A */
416     size_t iworksize,	/* size of Iwork */
417     size_t xworksize,	/* size of Xwork */
418     /* --------------- */
419     cholmod_common *Common
420 )
421 {
422     double *W ;
423     Int *Head ;
424     Int i ;
425     size_t nrow1 ;
426     int ok = TRUE ;
427 
428     /* ---------------------------------------------------------------------- */
429     /* get inputs */
430     /* ---------------------------------------------------------------------- */
431 
432     RETURN_IF_NULL_COMMON (FALSE) ;
433     Common->status = CHOLMOD_OK ;
434 
435     /* ---------------------------------------------------------------------- */
436     /* Allocate Flag (nrow) and Head (nrow+1) */
437     /* ---------------------------------------------------------------------- */
438 
439     nrow = MAX (1, nrow) ;
440 
441     /* nrow1 = nrow + 1 */
442     nrow1 = CHOLMOD(add_size_t) (nrow, 1, &ok) ;
443     if (!ok)
444     {
445 	/* nrow+1 causes size_t overflow ; problem is too large */
446 	Common->status = CHOLMOD_TOO_LARGE ;
447 	CHOLMOD(free_work) (Common) ;
448 	return (FALSE) ;
449     }
450 
451     if (nrow > Common->nrow)
452     {
453 
454 	if (Common->no_workspace_reallocate)
455 	{
456 	    /* CHOLMOD is not allowed to change the workspace here */
457 	    Common->status = CHOLMOD_INVALID ;
458 	    return (FALSE) ;
459 	}
460 
461 	/* free the old workspace (if any) and allocate new space */
462 	Common->Flag = CHOLMOD(free) (Common->nrow,  sizeof (Int), Common->Flag,
463 		Common) ;
464 	Common->Head = CHOLMOD(free) (Common->nrow+1,sizeof (Int), Common->Head,
465 		Common) ;
466 	Common->Flag = CHOLMOD(malloc) (nrow,   sizeof (Int), Common) ;
467 	Common->Head = CHOLMOD(malloc) (nrow1, sizeof (Int), Common) ;
468 
469 	/* record the new size of Flag and Head */
470 	Common->nrow = nrow ;
471 
472 	if (Common->status < CHOLMOD_OK)
473 	{
474 	    CHOLMOD(free_work) (Common) ;
475 	    return (FALSE) ;
476 	}
477 
478 	/* initialize Flag and Head */
479 	Common->mark = EMPTY ;
480 	CHOLMOD(clear_flag) (Common) ;
481 	Head = Common->Head ;
482 	for (i = 0 ; i <= (Int) (nrow) ; i++)
483 	{
484 	    Head [i] = EMPTY ;
485 	}
486     }
487 
488     /* ---------------------------------------------------------------------- */
489     /* Allocate Iwork (iworksize) */
490     /* ---------------------------------------------------------------------- */
491 
492     iworksize = MAX (1, iworksize) ;
493     if (iworksize > Common->iworksize)
494     {
495 
496 	if (Common->no_workspace_reallocate)
497 	{
498 	    /* CHOLMOD is not allowed to change the workspace here */
499 	    Common->status = CHOLMOD_INVALID ;
500 	    return (FALSE) ;
501 	}
502 
503 	/* free the old workspace (if any) and allocate new space.
504 	 * integer overflow safely detected in cholmod_malloc */
505 	CHOLMOD(free) (Common->iworksize, sizeof (Int), Common->Iwork, Common) ;
506 	Common->Iwork = CHOLMOD(malloc) (iworksize, sizeof (Int), Common) ;
507 
508 	/* record the new size of Iwork */
509 	Common->iworksize = iworksize ;
510 
511 	if (Common->status < CHOLMOD_OK)
512 	{
513 	    CHOLMOD(free_work) (Common) ;
514 	    return (FALSE) ;
515 	}
516 
517 	/* note that Iwork does not need to be initialized */
518     }
519 
520     /* ---------------------------------------------------------------------- */
521     /* Allocate Xwork (xworksize) and set it to ((double) 0.) */
522     /* ---------------------------------------------------------------------- */
523 
524     /* make sure xworksize is >= 1 */
525     xworksize = MAX (1, xworksize) ;
526     if (xworksize > Common->xworksize)
527     {
528 
529 	if (Common->no_workspace_reallocate)
530 	{
531 	    /* CHOLMOD is not allowed to change the workspace here */
532 	    Common->status = CHOLMOD_INVALID ;
533 	    return (FALSE) ;
534 	}
535 
536 	/* free the old workspace (if any) and allocate new space */
537 	CHOLMOD(free) (Common->xworksize, sizeof (double), Common->Xwork,
538 		Common) ;
539 	Common->Xwork = CHOLMOD(malloc) (xworksize, sizeof (double), Common) ;
540 
541 	/* record the new size of Xwork */
542 	Common->xworksize = xworksize ;
543 
544 	if (Common->status < CHOLMOD_OK)
545 	{
546 	    CHOLMOD(free_work) (Common) ;
547 	    return (FALSE) ;
548 	}
549 
550 	/* initialize Xwork */
551 	W = Common->Xwork ;
552 	for (i = 0 ; i < (Int) xworksize ; i++)
553 	{
554 	    W [i] = 0. ;
555 	}
556     }
557 
558     return (TRUE) ;
559 }
560 
561 
562 /* ========================================================================== */
563 /* === cholmod_free_work ==================================================== */
564 /* ========================================================================== */
565 
566 /* Deallocate the CHOLMOD workspace.
567  *
568  * workspace: deallocates all workspace in Common
569  */
570 
CHOLMOD(free_work)571 int CHOLMOD(free_work)
572 (
573     cholmod_common *Common
574 )
575 {
576     RETURN_IF_NULL_COMMON (FALSE) ;
577     Common->Flag  = CHOLMOD(free) (Common->nrow, sizeof (Int),
578 	    Common->Flag, Common) ;
579     Common->Head  = CHOLMOD(free) (Common->nrow+1, sizeof (Int),
580 	    Common->Head, Common) ;
581     Common->Iwork = CHOLMOD(free) (Common->iworksize, sizeof (Int),
582 	    Common->Iwork, Common) ;
583     Common->Xwork = CHOLMOD(free) (Common->xworksize, sizeof (double),
584 	    Common->Xwork, Common) ;
585     Common->nrow = 0 ;
586     Common->iworksize = 0 ;
587     Common->xworksize = 0 ;
588 
589 #ifdef GPU_BLAS
590     CHOLMOD(gpu_deallocate) (Common) ;
591 #endif
592     return (TRUE) ;
593 }
594 
595 
596 /* ========================================================================== */
597 /* === cholmod_clear_flag =================================================== */
598 /* ========================================================================== */
599 
600 /* Increment mark to ensure Flag [0..nrow-1] < mark.  If integer overflow
601  * occurs, or mark was initially negative, reset the entire array.  This is
602  * not an error condition, but an intended function of the Flag workspace.
603  *
604  * workspace: Flag (nrow).  Does not modify Flag if nrow is zero.
605  */
606 
CHOLMOD(clear_flag)607 SuiteSparse_long CHOLMOD(clear_flag)
608 (
609     cholmod_common *Common
610 )
611 {
612     Int i, nrow, *Flag ;
613 
614     RETURN_IF_NULL_COMMON (-1) ;
615 
616     Common->mark++ ;
617     if (Common->mark <= 0)
618     {
619 	nrow = Common->nrow ;
620 	Flag = Common->Flag ;
621 	PRINT2 (("reset Flag: nrow "ID"\n", nrow)) ;
622 	PRINT2 (("reset Flag: mark %ld\n", Common->mark)) ;
623 	for (i = 0 ; i < nrow ; i++)
624 	{
625 	    Flag [i] = EMPTY ;
626 	}
627 	Common->mark = 0 ;
628     }
629     return (Common->mark) ;
630 }
631 
632 
633 /* ========================================================================== */
634 /* ==== cholmod_maxrank ===================================================== */
635 /* ========================================================================== */
636 
637 /* Find a valid value of Common->maxrank.  Returns 0 if error, or 2, 4, or 8
638  * if successful. */
639 
CHOLMOD(maxrank)640 size_t CHOLMOD(maxrank)	/* returns validated value of Common->maxrank */
641 (
642     /* ---- input ---- */
643     size_t n,		/* A and L will have n rows */
644     /* --------------- */
645     cholmod_common *Common
646 )
647 {
648     size_t maxrank ;
649     RETURN_IF_NULL_COMMON (0) ;
650     maxrank = Common->maxrank ;
651     if (n > 0)
652     {
653 	/* Ensure maxrank*n*sizeof(double) does not result in integer overflow.
654 	 * If n is so large that 2*n*sizeof(double) results in integer overflow
655 	 * (n = 268,435,455 if an Int is 32 bits), then maxrank will be 0 or 1,
656 	 * but maxrank will be set to 2 below.  2*n will not result in integer
657 	 * overflow, and CHOLMOD will run out of memory or safely detect integer
658 	 * overflow elsewhere.
659 	 */
660 	maxrank = MIN (maxrank, Size_max / (n * sizeof (double))) ;
661     }
662     if (maxrank <= 2)
663     {
664 	maxrank = 2 ;
665     }
666     else if (maxrank <= 4)
667     {
668 	maxrank = 4 ;
669     }
670     else
671     {
672 	maxrank = 8 ;
673     }
674     return (maxrank) ;
675 }
676 
677 
678 /* ========================================================================== */
679 /* === cholmod_dbound ======================================================= */
680 /* ========================================================================== */
681 
682 /* Ensure the absolute value of a diagonal entry, D (j,j), is greater than
683  * Common->dbound.  This routine is not meant for the user to call.  It is used
684  * by the various LDL' factorization and update/downdate routines.  The
685  * default value of Common->dbound is zero, and in that case this routine is not
686  * called at all.  No change is made if D (j,j) is NaN.  CHOLMOD does not call
687  * this routine if Common->dbound is NaN.
688  */
689 
CHOLMOD(dbound)690 double CHOLMOD(dbound)	/* returns modified diagonal entry of D */
691 (
692     /* ---- input ---- */
693     double dj,		/* diagonal entry of D, for LDL' factorization */
694     /* --------------- */
695     cholmod_common *Common
696 )
697 {
698     double dbound ;
699     RETURN_IF_NULL_COMMON (0) ;
700     if (!IS_NAN (dj))
701     {
702 	dbound = Common->dbound ;
703 	if (dj < 0)
704 	{
705 	    if (dj > -dbound)
706 	    {
707 		dj = -dbound ;
708 		Common->ndbounds_hit++ ;
709 		if (Common->status == CHOLMOD_OK)
710 		{
711 		    ERROR (CHOLMOD_DSMALL, "diagonal below threshold") ;
712 		}
713 	    }
714 	}
715 	else
716 	{
717 	    if (dj < dbound)
718 	    {
719 		dj = dbound ;
720 		Common->ndbounds_hit++ ;
721 		if (Common->status == CHOLMOD_OK)
722 		{
723 		    ERROR (CHOLMOD_DSMALL, "diagonal below threshold") ;
724 		}
725 	    }
726 	}
727     }
728     return (dj) ;
729 }
730 
731 
732 /* ========================================================================== */
733 /* === scorecomp ============================================================ */
734 /* ========================================================================== */
735 
736 /* For sorting descendant supernodes with qsort */
CHOLMOD(score_comp)737 int CHOLMOD(score_comp) (struct cholmod_descendant_score_t *i,
738 			       struct cholmod_descendant_score_t *j)
739 {
740   if ((*i).score < (*j).score)
741     {
742 	return (1) ;
743     }
744     else
745     {
746 	return (-1) ;
747     }
748 }
749