alpar@1
|
1 |
/* ========================================================================= */
|
alpar@1
|
2 |
/* === AMD_1 =============================================================== */
|
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 |
/* AMD_1: Construct A+A' for a sparse matrix A and perform the AMD ordering.
|
alpar@1
|
13 |
*
|
alpar@1
|
14 |
* The n-by-n sparse matrix A can be unsymmetric. It is stored in MATLAB-style
|
alpar@1
|
15 |
* compressed-column form, with sorted row indices in each column, and no
|
alpar@1
|
16 |
* duplicate entries. Diagonal entries may be present, but they are ignored.
|
alpar@1
|
17 |
* Row indices of column j of A are stored in Ai [Ap [j] ... Ap [j+1]-1].
|
alpar@1
|
18 |
* Ap [0] must be zero, and nz = Ap [n] is the number of entries in A. The
|
alpar@1
|
19 |
* size of the matrix, n, must be greater than or equal to zero.
|
alpar@1
|
20 |
*
|
alpar@1
|
21 |
* This routine must be preceded by a call to AMD_aat, which computes the
|
alpar@1
|
22 |
* number of entries in each row/column in A+A', excluding the diagonal.
|
alpar@1
|
23 |
* Len [j], on input, is the number of entries in row/column j of A+A'. This
|
alpar@1
|
24 |
* routine constructs the matrix A+A' and then calls AMD_2. No error checking
|
alpar@1
|
25 |
* is performed (this was done in AMD_valid).
|
alpar@1
|
26 |
*/
|
alpar@1
|
27 |
|
alpar@1
|
28 |
#include "amd_internal.h"
|
alpar@1
|
29 |
|
alpar@1
|
30 |
GLOBAL void AMD_1
|
alpar@1
|
31 |
(
|
alpar@1
|
32 |
Int n, /* n > 0 */
|
alpar@1
|
33 |
const Int Ap [ ], /* input of size n+1, not modified */
|
alpar@1
|
34 |
const Int Ai [ ], /* input of size nz = Ap [n], not modified */
|
alpar@1
|
35 |
Int P [ ], /* size n output permutation */
|
alpar@1
|
36 |
Int Pinv [ ], /* size n output inverse permutation */
|
alpar@1
|
37 |
Int Len [ ], /* size n input, undefined on output */
|
alpar@1
|
38 |
Int slen, /* slen >= sum (Len [0..n-1]) + 7n,
|
alpar@1
|
39 |
* ideally slen = 1.2 * sum (Len) + 8n */
|
alpar@1
|
40 |
Int S [ ], /* size slen workspace */
|
alpar@1
|
41 |
double Control [ ], /* input array of size AMD_CONTROL */
|
alpar@1
|
42 |
double Info [ ] /* output array of size AMD_INFO */
|
alpar@1
|
43 |
)
|
alpar@1
|
44 |
{
|
alpar@1
|
45 |
Int i, j, k, p, pfree, iwlen, pj, p1, p2, pj2, *Iw, *Pe, *Nv, *Head,
|
alpar@1
|
46 |
*Elen, *Degree, *s, *W, *Sp, *Tp ;
|
alpar@1
|
47 |
|
alpar@1
|
48 |
/* --------------------------------------------------------------------- */
|
alpar@1
|
49 |
/* construct the matrix for AMD_2 */
|
alpar@1
|
50 |
/* --------------------------------------------------------------------- */
|
alpar@1
|
51 |
|
alpar@1
|
52 |
ASSERT (n > 0) ;
|
alpar@1
|
53 |
|
alpar@1
|
54 |
iwlen = slen - 6*n ;
|
alpar@1
|
55 |
s = S ;
|
alpar@1
|
56 |
Pe = s ; s += n ;
|
alpar@1
|
57 |
Nv = s ; s += n ;
|
alpar@1
|
58 |
Head = s ; s += n ;
|
alpar@1
|
59 |
Elen = s ; s += n ;
|
alpar@1
|
60 |
Degree = s ; s += n ;
|
alpar@1
|
61 |
W = s ; s += n ;
|
alpar@1
|
62 |
Iw = s ; s += iwlen ;
|
alpar@1
|
63 |
|
alpar@1
|
64 |
ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ;
|
alpar@1
|
65 |
|
alpar@1
|
66 |
/* construct the pointers for A+A' */
|
alpar@1
|
67 |
Sp = Nv ; /* use Nv and W as workspace for Sp and Tp [ */
|
alpar@1
|
68 |
Tp = W ;
|
alpar@1
|
69 |
pfree = 0 ;
|
alpar@1
|
70 |
for (j = 0 ; j < n ; j++)
|
alpar@1
|
71 |
{
|
alpar@1
|
72 |
Pe [j] = pfree ;
|
alpar@1
|
73 |
Sp [j] = pfree ;
|
alpar@1
|
74 |
pfree += Len [j] ;
|
alpar@1
|
75 |
}
|
alpar@1
|
76 |
|
alpar@1
|
77 |
/* Note that this restriction on iwlen is slightly more restrictive than
|
alpar@1
|
78 |
* what is strictly required in AMD_2. AMD_2 can operate with no elbow
|
alpar@1
|
79 |
* room at all, but it will be very slow. For better performance, at
|
alpar@1
|
80 |
* least size-n elbow room is enforced. */
|
alpar@1
|
81 |
ASSERT (iwlen >= pfree + n) ;
|
alpar@1
|
82 |
|
alpar@1
|
83 |
#ifndef NDEBUG
|
alpar@1
|
84 |
for (p = 0 ; p < iwlen ; p++) Iw [p] = EMPTY ;
|
alpar@1
|
85 |
#endif
|
alpar@1
|
86 |
|
alpar@1
|
87 |
for (k = 0 ; k < n ; k++)
|
alpar@1
|
88 |
{
|
alpar@1
|
89 |
AMD_DEBUG1 (("Construct row/column k= "ID" of A+A'\n", k)) ;
|
alpar@1
|
90 |
p1 = Ap [k] ;
|
alpar@1
|
91 |
p2 = Ap [k+1] ;
|
alpar@1
|
92 |
|
alpar@1
|
93 |
/* construct A+A' */
|
alpar@1
|
94 |
for (p = p1 ; p < p2 ; )
|
alpar@1
|
95 |
{
|
alpar@1
|
96 |
/* scan the upper triangular part of A */
|
alpar@1
|
97 |
j = Ai [p] ;
|
alpar@1
|
98 |
ASSERT (j >= 0 && j < n) ;
|
alpar@1
|
99 |
if (j < k)
|
alpar@1
|
100 |
{
|
alpar@1
|
101 |
/* entry A (j,k) in the strictly upper triangular part */
|
alpar@1
|
102 |
ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
|
alpar@1
|
103 |
ASSERT (Sp [k] < (k == n-1 ? pfree : Pe [k+1])) ;
|
alpar@1
|
104 |
Iw [Sp [j]++] = k ;
|
alpar@1
|
105 |
Iw [Sp [k]++] = j ;
|
alpar@1
|
106 |
p++ ;
|
alpar@1
|
107 |
}
|
alpar@1
|
108 |
else if (j == k)
|
alpar@1
|
109 |
{
|
alpar@1
|
110 |
/* skip the diagonal */
|
alpar@1
|
111 |
p++ ;
|
alpar@1
|
112 |
break ;
|
alpar@1
|
113 |
}
|
alpar@1
|
114 |
else /* j > k */
|
alpar@1
|
115 |
{
|
alpar@1
|
116 |
/* first entry below the diagonal */
|
alpar@1
|
117 |
break ;
|
alpar@1
|
118 |
}
|
alpar@1
|
119 |
/* scan lower triangular part of A, in column j until reaching
|
alpar@1
|
120 |
* row k. Start where last scan left off. */
|
alpar@1
|
121 |
ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
|
alpar@1
|
122 |
pj2 = Ap [j+1] ;
|
alpar@1
|
123 |
for (pj = Tp [j] ; pj < pj2 ; )
|
alpar@1
|
124 |
{
|
alpar@1
|
125 |
i = Ai [pj] ;
|
alpar@1
|
126 |
ASSERT (i >= 0 && i < n) ;
|
alpar@1
|
127 |
if (i < k)
|
alpar@1
|
128 |
{
|
alpar@1
|
129 |
/* A (i,j) is only in the lower part, not in upper */
|
alpar@1
|
130 |
ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
|
alpar@1
|
131 |
ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
|
alpar@1
|
132 |
Iw [Sp [i]++] = j ;
|
alpar@1
|
133 |
Iw [Sp [j]++] = i ;
|
alpar@1
|
134 |
pj++ ;
|
alpar@1
|
135 |
}
|
alpar@1
|
136 |
else if (i == k)
|
alpar@1
|
137 |
{
|
alpar@1
|
138 |
/* entry A (k,j) in lower part and A (j,k) in upper */
|
alpar@1
|
139 |
pj++ ;
|
alpar@1
|
140 |
break ;
|
alpar@1
|
141 |
}
|
alpar@1
|
142 |
else /* i > k */
|
alpar@1
|
143 |
{
|
alpar@1
|
144 |
/* consider this entry later, when k advances to i */
|
alpar@1
|
145 |
break ;
|
alpar@1
|
146 |
}
|
alpar@1
|
147 |
}
|
alpar@1
|
148 |
Tp [j] = pj ;
|
alpar@1
|
149 |
}
|
alpar@1
|
150 |
Tp [k] = p ;
|
alpar@1
|
151 |
}
|
alpar@1
|
152 |
|
alpar@1
|
153 |
/* clean up, for remaining mismatched entries */
|
alpar@1
|
154 |
for (j = 0 ; j < n ; j++)
|
alpar@1
|
155 |
{
|
alpar@1
|
156 |
for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
|
alpar@1
|
157 |
{
|
alpar@1
|
158 |
i = Ai [pj] ;
|
alpar@1
|
159 |
ASSERT (i >= 0 && i < n) ;
|
alpar@1
|
160 |
/* A (i,j) is only in the lower part, not in upper */
|
alpar@1
|
161 |
ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
|
alpar@1
|
162 |
ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
|
alpar@1
|
163 |
Iw [Sp [i]++] = j ;
|
alpar@1
|
164 |
Iw [Sp [j]++] = i ;
|
alpar@1
|
165 |
}
|
alpar@1
|
166 |
}
|
alpar@1
|
167 |
|
alpar@1
|
168 |
#ifndef NDEBUG
|
alpar@1
|
169 |
for (j = 0 ; j < n-1 ; j++) ASSERT (Sp [j] == Pe [j+1]) ;
|
alpar@1
|
170 |
ASSERT (Sp [n-1] == pfree) ;
|
alpar@1
|
171 |
#endif
|
alpar@1
|
172 |
|
alpar@1
|
173 |
/* Tp and Sp no longer needed ] */
|
alpar@1
|
174 |
|
alpar@1
|
175 |
/* --------------------------------------------------------------------- */
|
alpar@1
|
176 |
/* order the matrix */
|
alpar@1
|
177 |
/* --------------------------------------------------------------------- */
|
alpar@1
|
178 |
|
alpar@1
|
179 |
AMD_2 (n, Pe, Iw, Len, iwlen, pfree,
|
alpar@1
|
180 |
Nv, Pinv, P, Head, Elen, Degree, W, Control, Info) ;
|
alpar@1
|
181 |
}
|