1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
|
/* ========================================================================== */
/* === Partition/cholmod_camd =============================================== */
/* ========================================================================== */
/* -----------------------------------------------------------------------------
* CHOLMOD/Partition Module. Copyright (C) 2005-2013, Timothy A. Davis
* http://www.suitesparse.com
* -------------------------------------------------------------------------- */
/* CHOLMOD interface to the CAMD ordering routine. Orders A if the matrix is
* symmetric. On output, Perm [k] = i if row/column i of A is the kth
* row/column of P*A*P'. This corresponds to A(p,p) in MATLAB notation.
*
* If A is unsymmetric, cholmod_camd orders A*A'. On output, Perm [k] = i if
* row/column i of A*A' is the kth row/column of P*A*A'*P'. This corresponds to
* A(p,:)*A(p,:)' in MATLAB notation. If f is present, A(p,f)*A(p,f)' is
* ordered.
*
* Computes the flop count for a subsequent LL' factorization, the number
* of nonzeros in L, and the number of nonzeros in the matrix ordered (A,
* A*A' or A(:,f)*A(:,f)').
*
* workspace: Iwork (4*nrow). Head (nrow).
*
* Allocates a temporary copy of A+A' or A*A' (with
* both upper and lower triangular parts) as input to CAMD.
* Also allocates 3*(n+1) additional integer workspace (not in Common).
*
* Supports any xtype (pattern, real, complex, or zomplex)
*/
#ifndef NCAMD
#include "cholmod_internal.h"
#include "camd.h"
#include "cholmod_camd.h"
#if (CAMD_VERSION < CAMD_VERSION_CODE (2,0))
#error "CAMD v2.0 or later is required"
#endif
/* ========================================================================== */
/* === cholmod_camd ========================================================= */
/* ========================================================================== */
int CHOLMOD(camd)
(
/* ---- input ---- */
cholmod_sparse *A, /* matrix to order */
Int *fset, /* subset of 0:(A->ncol)-1 */
size_t fsize, /* size of fset */
Int *Cmember, /* size nrow. see cholmod_ccolamd.c for description.*/
/* ---- output ---- */
Int *Perm, /* size A->nrow, output permutation */
/* --------------- */
cholmod_common *Common
)
{
double Info [CAMD_INFO], Control2 [CAMD_CONTROL], *Control ;
Int *Cp, *Len, *Nv, *Head, *Elen, *Degree, *Wi, *Next, *BucketSet,
*Work3n, *p ;
cholmod_sparse *C ;
Int j, n, cnz ;
size_t s ;
int ok = TRUE ;
/* ---------------------------------------------------------------------- */
/* get inputs */
/* ---------------------------------------------------------------------- */
RETURN_IF_NULL_COMMON (FALSE) ;
RETURN_IF_NULL (A, FALSE) ;
n = A->nrow ;
/* s = 4*n */
s = CHOLMOD(mult_size_t) (n, 4, &ok) ;
if (!ok)
{
ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
return (FALSE) ;
}
RETURN_IF_NULL (Perm, FALSE) ;
RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
Common->status = CHOLMOD_OK ;
if (n == 0)
{
/* nothing to do */
Common->fl = 0 ;
Common->lnz = 0 ;
Common->anz = 0 ;
return (TRUE) ;
}
/* ---------------------------------------------------------------------- */
/* get workspace */
/* ---------------------------------------------------------------------- */
/* cholmod_analyze has allocated Cmember at Common->Iwork + 5*n+uncol, and
* CParent at Common->Iwork + 4*n+uncol, where uncol is 0 if A is symmetric
* or A->ncol otherwise. Thus, only the first 4n integers in Common->Iwork
* can be used here. */
CHOLMOD(allocate_work) (n, s, 0, Common) ;
if (Common->status < CHOLMOD_OK)
{
return (FALSE) ;
}
p = Common->Iwork ;
Degree = p ; p += n ; /* size n */
Elen = p ; p += n ; /* size n */
Len = p ; p += n ; /* size n */
Nv = p ; p += n ; /* size n */
Work3n = CHOLMOD(malloc) (n+1, 3*sizeof (Int), Common) ;
if (Common->status < CHOLMOD_OK)
{
return (FALSE) ;
}
p = Work3n ;
Next = p ; p += n ; /* size n */
Wi = p ; p += (n+1) ; /* size n+1 */
BucketSet = p ; /* size n */
Head = Common->Head ; /* size n+1 */
/* ---------------------------------------------------------------------- */
/* construct the input matrix for CAMD */
/* ---------------------------------------------------------------------- */
if (A->stype == 0)
{
/* C = A*A' or A(:,f)*A(:,f)', add extra space of nnz(C)/2+n to C */
C = CHOLMOD(aat) (A, fset, fsize, -2, Common) ;
}
else
{
/* C = A+A', but use only the upper triangular part of A if A->stype = 1
* and only the lower part of A if A->stype = -1. Add extra space of
* nnz(C)/2+n to C. */
C = CHOLMOD(copy) (A, 0, -2, Common) ;
}
if (Common->status < CHOLMOD_OK)
{
/* out of memory, fset invalid, or other error */
CHOLMOD(free) (n+1, 3*sizeof (Int), Work3n, Common) ;
return (FALSE) ;
}
Cp = C->p ;
for (j = 0 ; j < n ; j++)
{
Len [j] = Cp [j+1] - Cp [j] ;
}
/* C does not include the diagonal, and both upper and lower parts.
* Common->anz includes the diagonal, and just the lower part of C */
cnz = Cp [n] ;
Common->anz = cnz / 2 + n ;
/* ---------------------------------------------------------------------- */
/* order C using CAMD */
/* ---------------------------------------------------------------------- */
/* get parameters */
if (Common->current < 0 || Common->current >= CHOLMOD_MAXMETHODS)
{
/* use CAMD defaults */
Control = NULL ;
}
else
{
Control = Control2 ;
Control [CAMD_DENSE] = Common->method [Common->current].prune_dense ;
Control [CAMD_AGGRESSIVE] = Common->method [Common->current].aggressive;
}
#ifdef LONG
/* DEBUG (camd_l_debug_init ("cholmod_l_camd")) ; */
camd_l2 (n, C->p, C->i, Len, C->nzmax, cnz, Nv, Next, Perm, Head, Elen,
Degree, Wi, Control, Info, Cmember, BucketSet) ;
#else
/* DEBUG (camd_debug_init ("cholmod_camd")) ; */
camd_2 (n, C->p, C->i, Len, C->nzmax, cnz, Nv, Next, Perm, Head, Elen,
Degree, Wi, Control, Info, Cmember, BucketSet) ;
#endif
/* LL' flop count. Need to subtract n for LL' flop count. Note that this
* is a slight upper bound which is often exact (see CAMD/Source/camd_2.c
* for details). cholmod_analyze computes an exact flop count and
* fill-in. */
Common->fl = Info [CAMD_NDIV] + 2 * Info [CAMD_NMULTSUBS_LDL] + n ;
/* Info [CAMD_LNZ] excludes the diagonal */
Common->lnz = n + Info [CAMD_LNZ] ;
/* ---------------------------------------------------------------------- */
/* free the CAMD workspace and clear the persistent workspace in Common */
/* ---------------------------------------------------------------------- */
ASSERT (IMPLIES (Common->status == CHOLMOD_OK,
CHOLMOD(dump_perm) (Perm, n, n, "CAMD2 perm", Common))) ;
CHOLMOD(free_sparse) (&C, Common) ;
for (j = 0 ; j <= n ; j++)
{
Head [j] = EMPTY ;
}
CHOLMOD(free) (n+1, 3*sizeof (Int), Work3n, Common) ;
return (TRUE) ;
}
#endif
|