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