1 /*! \file
2 Copyright (c) 2003, The Regents of the University of California, through
3 Lawrence Berkeley National Laboratory (subject to receipt of any required
4 approvals from U.S. Dept. of Energy)
5
6 All rights reserved.
7
8 The source code is distributed under BSD license, see the file License.txt
9 at the top-level directory.
10 */
11
12 /*! @file scolumn_dfs.c
13 * \brief Performs a symbolic factorization
14 *
15 * <pre>
16 * -- SuperLU routine (version 3.0) --
17 * Univ. of California Berkeley, Xerox Palo Alto Research Center,
18 * and Lawrence Berkeley National Lab.
19 * October 15, 2003
20 *
21 * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
22 *
23 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
24 * EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
25 *
26 * Permission is hereby granted to use or copy this program for any
27 * purpose, provided the above notices are retained on all copies.
28 * Permission to modify the code and to distribute modified code is
29 * granted, provided the above notices are retained, and a notice that
30 * the code was modified is included with the above copyright notice.
31 * </pre>
32 */
33
34 #include "slu_sdefs.h"
35
36 /*! \brief What type of supernodes we want */
37 #define T2_SUPER
38
39
40 /*! \brief
41 *
42 * <pre>
43 * Purpose
44 * =======
45 * SCOLUMN_DFS performs a symbolic factorization on column jcol, and
46 * decide the supernode boundary.
47 *
48 * This routine does not use numeric values, but only use the RHS
49 * row indices to start the dfs.
50 *
51 * A supernode representative is the last column of a supernode.
52 * The nonzeros in U[*,j] are segments that end at supernodal
53 * representatives. The routine returns a list of such supernodal
54 * representatives in topological order of the dfs that generates them.
55 * The location of the first nonzero in each such supernodal segment
56 * (supernodal entry location) is also returned.
57 *
58 * Local parameters
59 * ================
60 * nseg: no of segments in current U[*,j]
61 * jsuper: jsuper=EMPTY if column j does not belong to the same
62 * supernode as j-1. Otherwise, jsuper=nsuper.
63 *
64 * marker2: A-row --> A-row/col (0/1)
65 * repfnz: SuperA-col --> PA-row
66 * parent: SuperA-col --> SuperA-col
67 * xplore: SuperA-col --> index to L-structure
68 *
69 * Return value
70 * ============
71 * 0 success;
72 * > 0 number of bytes allocated when run out of space.
73 * </pre>
74 */
75 int
scolumn_dfs(const int m,const int jcol,int * perm_r,int * nseg,int * lsub_col,int * segrep,int * repfnz,int * xprune,int * marker,int * parent,int * xplore,GlobalLU_t * Glu)76 scolumn_dfs(
77 const int m, /* in - number of rows in the matrix */
78 const int jcol, /* in */
79 int *perm_r, /* in */
80 int *nseg, /* modified - with new segments appended */
81 int *lsub_col, /* in - defines the RHS vector to start the dfs */
82 int *segrep, /* modified - with new segments appended */
83 int *repfnz, /* modified */
84 int *xprune, /* modified */
85 int *marker, /* modified */
86 int *parent, /* working array */
87 int *xplore, /* working array */
88 GlobalLU_t *Glu /* modified */
89 )
90 {
91
92 int jcolp1, jcolm1, jsuper, nsuper, nextl;
93 int k, krep, krow, kmark, kperm;
94 int *marker2; /* Used for small panel LU */
95 int fsupc; /* First column of a snode */
96 int myfnz; /* First nonz column of a U-segment */
97 int chperm, chmark, chrep, kchild;
98 int xdfs, maxdfs, kpar, oldrep;
99 int jptr, jm1ptr;
100 int ito, ifrom, istop; /* Used to compress row subscripts */
101 int mem_error;
102 int *xsup, *supno, *lsub, *xlsub;
103 int nzlmax;
104 int maxsuper;
105
106 xsup = Glu->xsup;
107 supno = Glu->supno;
108 lsub = Glu->lsub;
109 xlsub = Glu->xlsub;
110 nzlmax = Glu->nzlmax;
111
112 maxsuper = sp_ienv(3);
113 jcolp1 = jcol + 1;
114 jcolm1 = jcol - 1;
115 nsuper = supno[jcol];
116 jsuper = nsuper;
117 nextl = xlsub[jcol];
118 marker2 = &marker[2*m];
119
120 /* For each nonzero in A[*,jcol] do dfs */
121 for (k = 0; lsub_col[k] != EMPTY; k++) {
122
123 krow = lsub_col[k];
124 lsub_col[k] = EMPTY;
125 kmark = marker2[krow];
126
127 /* krow was visited before, go to the next nonz */
128 if ( kmark == jcol ) continue;
129
130 /* For each unmarked nbr krow of jcol
131 * krow is in L: place it in structure of L[*,jcol]
132 */
133 marker2[krow] = jcol;
134 kperm = perm_r[krow];
135
136 if ( kperm == EMPTY ) {
137 lsub[nextl++] = krow; /* krow is indexed into A */
138 if ( nextl >= nzlmax ) {
139 if ( mem_error = sLUMemXpand(jcol, nextl, LSUB, &nzlmax, Glu) )
140 return (mem_error);
141 lsub = Glu->lsub;
142 }
143 if ( kmark != jcolm1 ) jsuper = EMPTY;/* Row index subset testing */
144 } else {
145 /* krow is in U: if its supernode-rep krep
146 * has been explored, update repfnz[*]
147 */
148 krep = xsup[supno[kperm]+1] - 1;
149 myfnz = repfnz[krep];
150
151 if ( myfnz != EMPTY ) { /* Visited before */
152 if ( myfnz > kperm ) repfnz[krep] = kperm;
153 /* continue; */
154 }
155 else {
156 /* Otherwise, perform dfs starting at krep */
157 oldrep = EMPTY;
158 parent[krep] = oldrep;
159 repfnz[krep] = kperm;
160 xdfs = xlsub[krep];
161 maxdfs = xprune[krep];
162
163 do {
164 /*
165 * For each unmarked kchild of krep
166 */
167 while ( xdfs < maxdfs ) {
168
169 kchild = lsub[xdfs];
170 xdfs++;
171 chmark = marker2[kchild];
172
173 if ( chmark != jcol ) { /* Not reached yet */
174 marker2[kchild] = jcol;
175 chperm = perm_r[kchild];
176
177 /* Case kchild is in L: place it in L[*,k] */
178 if ( chperm == EMPTY ) {
179 lsub[nextl++] = kchild;
180 if ( nextl >= nzlmax ) {
181 if ( mem_error =
182 sLUMemXpand(jcol,nextl,LSUB,&nzlmax,Glu) )
183 return (mem_error);
184 lsub = Glu->lsub;
185 }
186 if ( chmark != jcolm1 ) jsuper = EMPTY;
187 } else {
188 /* Case kchild is in U:
189 * chrep = its supernode-rep. If its rep has
190 * been explored, update its repfnz[*]
191 */
192 chrep = xsup[supno[chperm]+1] - 1;
193 myfnz = repfnz[chrep];
194 if ( myfnz != EMPTY ) { /* Visited before */
195 if ( myfnz > chperm )
196 repfnz[chrep] = chperm;
197 } else {
198 /* Continue dfs at super-rep of kchild */
199 xplore[krep] = xdfs;
200 oldrep = krep;
201 krep = chrep; /* Go deeper down G(L^t) */
202 parent[krep] = oldrep;
203 repfnz[krep] = chperm;
204 xdfs = xlsub[krep];
205 maxdfs = xprune[krep];
206 } /* else */
207
208 } /* else */
209
210 } /* if */
211
212 } /* while */
213
214 /* krow has no more unexplored nbrs;
215 * place supernode-rep krep in postorder DFS.
216 * backtrack dfs to its parent
217 */
218 segrep[*nseg] = krep;
219 ++(*nseg);
220 kpar = parent[krep]; /* Pop from stack, mimic recursion */
221 if ( kpar == EMPTY ) break; /* dfs done */
222 krep = kpar;
223 xdfs = xplore[krep];
224 maxdfs = xprune[krep];
225
226 } while ( kpar != EMPTY ); /* Until empty stack */
227
228 } /* else */
229
230 } /* else */
231
232 } /* for each nonzero ... */
233
234 /* Check to see if j belongs in the same supernode as j-1 */
235 if ( jcol == 0 ) { /* Do nothing for column 0 */
236 nsuper = supno[0] = 0;
237 } else {
238 fsupc = xsup[nsuper];
239 jptr = xlsub[jcol]; /* Not compressed yet */
240 jm1ptr = xlsub[jcolm1];
241
242 #ifdef T2_SUPER
243 if ( (nextl-jptr != jptr-jm1ptr-1) ) jsuper = EMPTY;
244 #endif
245 /* Make sure the number of columns in a supernode doesn't
246 exceed threshold. */
247 if ( jcol - fsupc >= maxsuper ) jsuper = EMPTY;
248
249 /* If jcol starts a new supernode, reclaim storage space in
250 * lsub from the previous supernode. Note we only store
251 * the subscript set of the first and last columns of
252 * a supernode. (first for num values, last for pruning)
253 */
254 if ( jsuper == EMPTY ) { /* starts a new supernode */
255 if ( (fsupc < jcolm1-1) ) { /* >= 3 columns in nsuper */
256 #ifdef CHK_COMPRESS
257 printf(" Compress lsub[] at super %d-%d\n", fsupc, jcolm1);
258 #endif
259 ito = xlsub[fsupc+1];
260 xlsub[jcolm1] = ito;
261 istop = ito + jptr - jm1ptr;
262 xprune[jcolm1] = istop; /* Initialize xprune[jcol-1] */
263 xlsub[jcol] = istop;
264 for (ifrom = jm1ptr; ifrom < nextl; ++ifrom, ++ito)
265 lsub[ito] = lsub[ifrom];
266 nextl = ito; /* = istop + length(jcol) */
267 }
268 nsuper++;
269 supno[jcol] = nsuper;
270 } /* if a new supernode */
271
272 } /* else: jcol > 0 */
273
274 /* Tidy up the pointers before exit */
275 xsup[nsuper+1] = jcolp1;
276 supno[jcolp1] = nsuper;
277 xprune[jcol] = nextl; /* Initialize upper bound for pruning */
278 xlsub[jcolp1] = nextl;
279
280 return 0;
281 }
282