alpar@1
|
1 |
/* ========================================================================= */
|
alpar@1
|
2 |
/* === AMD_order =========================================================== */
|
alpar@1
|
3 |
/* ========================================================================= */
|
alpar@1
|
4 |
|
alpar@1
|
5 |
/* ------------------------------------------------------------------------- */
|
alpar@1
|
6 |
/* AMD, Copyright (c) Timothy A. Davis, */
|
alpar@1
|
7 |
/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
|
alpar@1
|
8 |
/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
|
alpar@1
|
9 |
/* web: http://www.cise.ufl.edu/research/sparse/amd */
|
alpar@1
|
10 |
/* ------------------------------------------------------------------------- */
|
alpar@1
|
11 |
|
alpar@1
|
12 |
/* User-callable AMD minimum degree ordering routine. See amd.h for
|
alpar@1
|
13 |
* documentation.
|
alpar@1
|
14 |
*/
|
alpar@1
|
15 |
|
alpar@1
|
16 |
#include "amd_internal.h"
|
alpar@1
|
17 |
|
alpar@1
|
18 |
/* ========================================================================= */
|
alpar@1
|
19 |
/* === AMD_order =========================================================== */
|
alpar@1
|
20 |
/* ========================================================================= */
|
alpar@1
|
21 |
|
alpar@1
|
22 |
GLOBAL Int AMD_order
|
alpar@1
|
23 |
(
|
alpar@1
|
24 |
Int n,
|
alpar@1
|
25 |
const Int Ap [ ],
|
alpar@1
|
26 |
const Int Ai [ ],
|
alpar@1
|
27 |
Int P [ ],
|
alpar@1
|
28 |
double Control [ ],
|
alpar@1
|
29 |
double Info [ ]
|
alpar@1
|
30 |
)
|
alpar@1
|
31 |
{
|
alpar@1
|
32 |
Int *Len, *S, nz, i, *Pinv, info, status, *Rp, *Ri, *Cp, *Ci, ok ;
|
alpar@1
|
33 |
size_t nzaat, slen ;
|
alpar@1
|
34 |
double mem = 0 ;
|
alpar@1
|
35 |
|
alpar@1
|
36 |
#ifndef NDEBUG
|
alpar@1
|
37 |
AMD_debug_init ("amd") ;
|
alpar@1
|
38 |
#endif
|
alpar@1
|
39 |
|
alpar@1
|
40 |
/* clear the Info array, if it exists */
|
alpar@1
|
41 |
info = Info != (double *) NULL ;
|
alpar@1
|
42 |
if (info)
|
alpar@1
|
43 |
{
|
alpar@1
|
44 |
for (i = 0 ; i < AMD_INFO ; i++)
|
alpar@1
|
45 |
{
|
alpar@1
|
46 |
Info [i] = EMPTY ;
|
alpar@1
|
47 |
}
|
alpar@1
|
48 |
Info [AMD_N] = n ;
|
alpar@1
|
49 |
Info [AMD_STATUS] = AMD_OK ;
|
alpar@1
|
50 |
}
|
alpar@1
|
51 |
|
alpar@1
|
52 |
/* make sure inputs exist and n is >= 0 */
|
alpar@1
|
53 |
if (Ai == (Int *) NULL || Ap == (Int *) NULL || P == (Int *) NULL || n < 0)
|
alpar@1
|
54 |
{
|
alpar@1
|
55 |
if (info) Info [AMD_STATUS] = AMD_INVALID ;
|
alpar@1
|
56 |
return (AMD_INVALID) ; /* arguments are invalid */
|
alpar@1
|
57 |
}
|
alpar@1
|
58 |
|
alpar@1
|
59 |
if (n == 0)
|
alpar@1
|
60 |
{
|
alpar@1
|
61 |
return (AMD_OK) ; /* n is 0 so there's nothing to do */
|
alpar@1
|
62 |
}
|
alpar@1
|
63 |
|
alpar@1
|
64 |
nz = Ap [n] ;
|
alpar@1
|
65 |
if (info)
|
alpar@1
|
66 |
{
|
alpar@1
|
67 |
Info [AMD_NZ] = nz ;
|
alpar@1
|
68 |
}
|
alpar@1
|
69 |
if (nz < 0)
|
alpar@1
|
70 |
{
|
alpar@1
|
71 |
if (info) Info [AMD_STATUS] = AMD_INVALID ;
|
alpar@1
|
72 |
return (AMD_INVALID) ;
|
alpar@1
|
73 |
}
|
alpar@1
|
74 |
|
alpar@1
|
75 |
/* check if n or nz will cause size_t overflow */
|
alpar@1
|
76 |
if (((size_t) n) >= SIZE_T_MAX / sizeof (Int)
|
alpar@1
|
77 |
|| ((size_t) nz) >= SIZE_T_MAX / sizeof (Int))
|
alpar@1
|
78 |
{
|
alpar@1
|
79 |
if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
|
alpar@1
|
80 |
return (AMD_OUT_OF_MEMORY) ; /* problem too large */
|
alpar@1
|
81 |
}
|
alpar@1
|
82 |
|
alpar@1
|
83 |
/* check the input matrix: AMD_OK, AMD_INVALID, or AMD_OK_BUT_JUMBLED */
|
alpar@1
|
84 |
status = AMD_valid (n, n, Ap, Ai) ;
|
alpar@1
|
85 |
|
alpar@1
|
86 |
if (status == AMD_INVALID)
|
alpar@1
|
87 |
{
|
alpar@1
|
88 |
if (info) Info [AMD_STATUS] = AMD_INVALID ;
|
alpar@1
|
89 |
return (AMD_INVALID) ; /* matrix is invalid */
|
alpar@1
|
90 |
}
|
alpar@1
|
91 |
|
alpar@1
|
92 |
/* allocate two size-n integer workspaces */
|
alpar@1
|
93 |
Len = amd_malloc (n * sizeof (Int)) ;
|
alpar@1
|
94 |
Pinv = amd_malloc (n * sizeof (Int)) ;
|
alpar@1
|
95 |
mem += n ;
|
alpar@1
|
96 |
mem += n ;
|
alpar@1
|
97 |
if (!Len || !Pinv)
|
alpar@1
|
98 |
{
|
alpar@1
|
99 |
/* :: out of memory :: */
|
alpar@1
|
100 |
amd_free (Len) ;
|
alpar@1
|
101 |
amd_free (Pinv) ;
|
alpar@1
|
102 |
if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
|
alpar@1
|
103 |
return (AMD_OUT_OF_MEMORY) ;
|
alpar@1
|
104 |
}
|
alpar@1
|
105 |
|
alpar@1
|
106 |
if (status == AMD_OK_BUT_JUMBLED)
|
alpar@1
|
107 |
{
|
alpar@1
|
108 |
/* sort the input matrix and remove duplicate entries */
|
alpar@1
|
109 |
AMD_DEBUG1 (("Matrix is jumbled\n")) ;
|
alpar@1
|
110 |
Rp = amd_malloc ((n+1) * sizeof (Int)) ;
|
alpar@1
|
111 |
Ri = amd_malloc (MAX (nz,1) * sizeof (Int)) ;
|
alpar@1
|
112 |
mem += (n+1) ;
|
alpar@1
|
113 |
mem += MAX (nz,1) ;
|
alpar@1
|
114 |
if (!Rp || !Ri)
|
alpar@1
|
115 |
{
|
alpar@1
|
116 |
/* :: out of memory :: */
|
alpar@1
|
117 |
amd_free (Rp) ;
|
alpar@1
|
118 |
amd_free (Ri) ;
|
alpar@1
|
119 |
amd_free (Len) ;
|
alpar@1
|
120 |
amd_free (Pinv) ;
|
alpar@1
|
121 |
if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
|
alpar@1
|
122 |
return (AMD_OUT_OF_MEMORY) ;
|
alpar@1
|
123 |
}
|
alpar@1
|
124 |
/* use Len and Pinv as workspace to create R = A' */
|
alpar@1
|
125 |
AMD_preprocess (n, Ap, Ai, Rp, Ri, Len, Pinv) ;
|
alpar@1
|
126 |
Cp = Rp ;
|
alpar@1
|
127 |
Ci = Ri ;
|
alpar@1
|
128 |
}
|
alpar@1
|
129 |
else
|
alpar@1
|
130 |
{
|
alpar@1
|
131 |
/* order the input matrix as-is. No need to compute R = A' first */
|
alpar@1
|
132 |
Rp = NULL ;
|
alpar@1
|
133 |
Ri = NULL ;
|
alpar@1
|
134 |
Cp = (Int *) Ap ;
|
alpar@1
|
135 |
Ci = (Int *) Ai ;
|
alpar@1
|
136 |
}
|
alpar@1
|
137 |
|
alpar@1
|
138 |
/* --------------------------------------------------------------------- */
|
alpar@1
|
139 |
/* determine the symmetry and count off-diagonal nonzeros in A+A' */
|
alpar@1
|
140 |
/* --------------------------------------------------------------------- */
|
alpar@1
|
141 |
|
alpar@1
|
142 |
nzaat = AMD_aat (n, Cp, Ci, Len, P, Info) ;
|
alpar@1
|
143 |
AMD_DEBUG1 (("nzaat: %g\n", (double) nzaat)) ;
|
alpar@1
|
144 |
ASSERT ((MAX (nz-n, 0) <= nzaat) && (nzaat <= 2 * (size_t) nz)) ;
|
alpar@1
|
145 |
|
alpar@1
|
146 |
/* --------------------------------------------------------------------- */
|
alpar@1
|
147 |
/* allocate workspace for matrix, elbow room, and 6 size-n vectors */
|
alpar@1
|
148 |
/* --------------------------------------------------------------------- */
|
alpar@1
|
149 |
|
alpar@1
|
150 |
S = NULL ;
|
alpar@1
|
151 |
slen = nzaat ; /* space for matrix */
|
alpar@1
|
152 |
ok = ((slen + nzaat/5) >= slen) ; /* check for size_t overflow */
|
alpar@1
|
153 |
slen += nzaat/5 ; /* add elbow room */
|
alpar@1
|
154 |
for (i = 0 ; ok && i < 7 ; i++)
|
alpar@1
|
155 |
{
|
alpar@1
|
156 |
ok = ((slen + n) > slen) ; /* check for size_t overflow */
|
alpar@1
|
157 |
slen += n ; /* size-n elbow room, 6 size-n work */
|
alpar@1
|
158 |
}
|
alpar@1
|
159 |
mem += slen ;
|
alpar@1
|
160 |
ok = ok && (slen < SIZE_T_MAX / sizeof (Int)) ; /* check for overflow */
|
alpar@1
|
161 |
ok = ok && (slen < Int_MAX) ; /* S[i] for Int i must be OK */
|
alpar@1
|
162 |
if (ok)
|
alpar@1
|
163 |
{
|
alpar@1
|
164 |
S = amd_malloc (slen * sizeof (Int)) ;
|
alpar@1
|
165 |
}
|
alpar@1
|
166 |
AMD_DEBUG1 (("slen %g\n", (double) slen)) ;
|
alpar@1
|
167 |
if (!S)
|
alpar@1
|
168 |
{
|
alpar@1
|
169 |
/* :: out of memory :: (or problem too large) */
|
alpar@1
|
170 |
amd_free (Rp) ;
|
alpar@1
|
171 |
amd_free (Ri) ;
|
alpar@1
|
172 |
amd_free (Len) ;
|
alpar@1
|
173 |
amd_free (Pinv) ;
|
alpar@1
|
174 |
if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
|
alpar@1
|
175 |
return (AMD_OUT_OF_MEMORY) ;
|
alpar@1
|
176 |
}
|
alpar@1
|
177 |
if (info)
|
alpar@1
|
178 |
{
|
alpar@1
|
179 |
/* memory usage, in bytes. */
|
alpar@1
|
180 |
Info [AMD_MEMORY] = mem * sizeof (Int) ;
|
alpar@1
|
181 |
}
|
alpar@1
|
182 |
|
alpar@1
|
183 |
/* --------------------------------------------------------------------- */
|
alpar@1
|
184 |
/* order the matrix */
|
alpar@1
|
185 |
/* --------------------------------------------------------------------- */
|
alpar@1
|
186 |
|
alpar@1
|
187 |
AMD_1 (n, Cp, Ci, P, Pinv, Len, slen, S, Control, Info) ;
|
alpar@1
|
188 |
|
alpar@1
|
189 |
/* --------------------------------------------------------------------- */
|
alpar@1
|
190 |
/* free the workspace */
|
alpar@1
|
191 |
/* --------------------------------------------------------------------- */
|
alpar@1
|
192 |
|
alpar@1
|
193 |
amd_free (Rp) ;
|
alpar@1
|
194 |
amd_free (Ri) ;
|
alpar@1
|
195 |
amd_free (Len) ;
|
alpar@1
|
196 |
amd_free (Pinv) ;
|
alpar@1
|
197 |
amd_free (S) ;
|
alpar@1
|
198 |
if (info) Info [AMD_STATUS] = status ;
|
alpar@1
|
199 |
return (status) ; /* successful ordering */
|
alpar@1
|
200 |
}
|