1 /*
2 * Copyright 1997, Regents of the University of Minnesota
3 *
4 * minitpart.c
5 *
6 * This file contains code that performs the initial partition of the
7 * coarsest graph
8 *
9 * Started 7/23/97
10 * George
11 *
12 * $Id: minitpart.c,v 1.2 1998/11/30 15:08:37 karypis Exp $
13 *
14 */
15
16 #include <metis.h>
17
18 /*************************************************************************
19 * This function computes the initial bisection of the coarsest graph
20 **************************************************************************/
MocInit2WayPartition(CtrlType * ctrl,GraphType * graph,float * tpwgts,float ubfactor)21 void MocInit2WayPartition(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor)
22 {
23 int i, dbglvl;
24
25 dbglvl = ctrl->dbglvl;
26 IFSET(ctrl->dbglvl, DBG_REFINE, ctrl->dbglvl -= DBG_REFINE);
27 IFSET(ctrl->dbglvl, DBG_MOVEINFO, ctrl->dbglvl -= DBG_MOVEINFO);
28
29 IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr));
30
31 switch (ctrl->IType) {
32 case IPART_GGPKL:
33 MocGrowBisection(ctrl, graph, tpwgts, ubfactor);
34 break;
35 case IPART_RANDOM:
36 MocRandomBisection(ctrl, graph, tpwgts, ubfactor);
37 break;
38 default:
39 errexit("Unknown initial partition type: %d\n", ctrl->IType);
40 }
41
42 IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial Cut: %d [%d]\n", graph->mincut, graph->where[0]));
43 IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr));
44 ctrl->dbglvl = dbglvl;
45
46 }
47
48
49
50
51
52 /*************************************************************************
53 * This function takes a graph and produces a bisection by using a region
54 * growing algorithm. The resulting partition is returned in
55 * graph->where
56 **************************************************************************/
MocGrowBisection(CtrlType * ctrl,GraphType * graph,float * tpwgts,float ubfactor)57 void MocGrowBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor)
58 {
59 int i, j, k, nvtxs, ncon, from, bestcut, mincut, nbfs;
60 idxtype *bestwhere, *where;
61
62 nvtxs = graph->nvtxs;
63
64 MocAllocate2WayPartitionMemory(ctrl, graph);
65 where = graph->where;
66
67 bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere");
68 nbfs = 2*(nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS);
69 bestcut = idxsum(graph->nedges, graph->adjwgt);
70
71 for (; nbfs>0; nbfs--) {
72 idxset(nvtxs, 1, where);
73 where[RandomInRange(nvtxs)] = 0;
74
75 MocCompute2WayPartitionParams(ctrl, graph);
76
77 MocInit2WayBalance(ctrl, graph, tpwgts);
78
79 MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 4);
80
81 MocBalance2Way(ctrl, graph, tpwgts, 1.02);
82 MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 4);
83
84 if (bestcut >= graph->mincut) {
85 bestcut = graph->mincut;
86 idxcopy(nvtxs, where, bestwhere);
87 if (bestcut == 0)
88 break;
89 }
90 }
91
92 graph->mincut = bestcut;
93 idxcopy(nvtxs, bestwhere, where);
94
95 GKfree(&bestwhere, LTERM);
96 }
97
98
99
100 /*************************************************************************
101 * This function takes a graph and produces a bisection by using a region
102 * growing algorithm. The resulting partition is returned in
103 * graph->where
104 **************************************************************************/
MocRandomBisection(CtrlType * ctrl,GraphType * graph,float * tpwgts,float ubfactor)105 void MocRandomBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor)
106 {
107 int i, ii, j, k, nvtxs, ncon, from, bestcut, mincut, nbfs, qnum;
108 idxtype *bestwhere, *where, *perm;
109 int counts[MAXNCON];
110 float *nvwgt;
111
112 nvtxs = graph->nvtxs;
113 ncon = graph->ncon;
114 nvwgt = graph->nvwgt;
115
116 MocAllocate2WayPartitionMemory(ctrl, graph);
117 where = graph->where;
118
119 bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere");
120 nbfs = 2*(nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS);
121 bestcut = idxsum(graph->nedges, graph->adjwgt);
122 perm = idxmalloc(nvtxs, "BisectGraph: perm");
123
124 for (; nbfs>0; nbfs--) {
125 for (i=0; i<ncon; i++)
126 counts[i] = 0;
127
128 RandomPermute(nvtxs, perm, 1);
129
130 /* Partition by spliting the queues randomly */
131 for (ii=0; ii<nvtxs; ii++) {
132 i = perm[ii];
133 qnum = samax(ncon, nvwgt+i*ncon);
134 where[i] = counts[qnum];
135 counts[qnum] = (counts[qnum]+1)%2;
136 }
137
138 MocCompute2WayPartitionParams(ctrl, graph);
139
140 MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 6);
141 MocBalance2Way(ctrl, graph, tpwgts, 1.02);
142 MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 6);
143 MocBalance2Way(ctrl, graph, tpwgts, 1.02);
144 MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 6);
145
146 /*
147 printf("Edgecut: %6d, NPwgts: [", graph->mincut);
148 for (i=0; i<graph->ncon; i++)
149 printf("(%.3f %.3f) ", graph->npwgts[i], graph->npwgts[graph->ncon+i]);
150 printf("]\n");
151 */
152
153 if (bestcut >= graph->mincut) {
154 bestcut = graph->mincut;
155 idxcopy(nvtxs, where, bestwhere);
156 if (bestcut == 0)
157 break;
158 }
159 }
160
161 graph->mincut = bestcut;
162 idxcopy(nvtxs, bestwhere, where);
163
164 GKfree(&bestwhere, &perm, LTERM);
165 }
166
167
168
169
170 /*************************************************************************
171 * This function balances two partitions by moving the highest gain
172 * (including negative gain) vertices to the other domain.
173 * It is used only when tha unbalance is due to non contigous
174 * subdomains. That is, the are no boundary vertices.
175 * It moves vertices from the domain that is overweight to the one that
176 * is underweight.
177 **************************************************************************/
MocInit2WayBalance(CtrlType * ctrl,GraphType * graph,float * tpwgts)178 void MocInit2WayBalance(CtrlType *ctrl, GraphType *graph, float *tpwgts)
179 {
180 int i, ii, j, k, l, kwgt, nvtxs, nbnd, ncon, nswaps, from, to, pass, me, cnum, tmp;
181 idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind;
182 idxtype *perm, *qnum;
183 float *nvwgt, *npwgts;
184 PQueueType parts[MAXNCON][2];
185 int higain, oldgain, mincut;
186
187 nvtxs = graph->nvtxs;
188 ncon = graph->ncon;
189 xadj = graph->xadj;
190 adjncy = graph->adjncy;
191 nvwgt = graph->nvwgt;
192 adjwgt = graph->adjwgt;
193 where = graph->where;
194 id = graph->id;
195 ed = graph->ed;
196 npwgts = graph->npwgts;
197 bndptr = graph->bndptr;
198 bndind = graph->bndind;
199
200 perm = idxwspacemalloc(ctrl, nvtxs);
201 qnum = idxwspacemalloc(ctrl, nvtxs);
202
203 /* This is called for initial partitioning so we know from where to pick nodes */
204 from = 1;
205 to = (from+1)%2;
206
207 if (ctrl->dbglvl&DBG_REFINE) {
208 printf("Parts: [");
209 for (l=0; l<ncon; l++)
210 printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
211 printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: %.3f [B]\n", tpwgts[0], tpwgts[1],
212 graph->nvtxs, graph->nbnd, graph->mincut,
213 Compute2WayHLoadImbalance(ncon, npwgts, tpwgts));
214 }
215
216 for (i=0; i<ncon; i++) {
217 PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1);
218 PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1);
219 }
220
221 ASSERT(ComputeCut(graph, where) == graph->mincut);
222 ASSERT(CheckBnd(graph));
223 ASSERT(CheckGraph(graph));
224
225 /* Compute the queues in which each vertex will be assigned to */
226 for (i=0; i<nvtxs; i++)
227 qnum[i] = samax(ncon, nvwgt+i*ncon);
228
229 /* Insert the nodes of the proper partition in the appropriate priority queue */
230 RandomPermute(nvtxs, perm, 1);
231 for (ii=0; ii<nvtxs; ii++) {
232 i = perm[ii];
233 if (where[i] == from) {
234 if (ed[i] > 0)
235 PQueueInsert(&parts[qnum[i]][0], i, ed[i]-id[i]);
236 else
237 PQueueInsert(&parts[qnum[i]][1], i, ed[i]-id[i]);
238 }
239 }
240
241
242 mincut = graph->mincut;
243 nbnd = graph->nbnd;
244 for (nswaps=0; nswaps<nvtxs; nswaps++) {
245 if (AreAnyVwgtsBelow(ncon, 1.0, npwgts+from*ncon, 0.0, nvwgt, tpwgts[from]))
246 break;
247
248 if ((cnum = SelectQueueOneWay(ncon, npwgts, tpwgts, from, parts)) == -1)
249 break;
250
251 if ((higain = PQueueGetMax(&parts[cnum][0])) == -1)
252 higain = PQueueGetMax(&parts[cnum][1]);
253
254 mincut -= (ed[higain]-id[higain]);
255 saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
256 saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
257
258 where[higain] = to;
259
260 if (ctrl->dbglvl&DBG_MOVEINFO) {
261 printf("Moved %6d from %d(%d). [%5d] %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], mincut);
262 for (l=0; l<ncon; l++)
263 printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
264 printf(", LB: %.3f\n", Compute2WayHLoadImbalance(ncon, npwgts, tpwgts));
265 if (ed[higain] == 0 && id[higain] > 0)
266 printf("\t Pulled from the interior!\n");
267 }
268
269
270 /**************************************************************
271 * Update the id[i]/ed[i] values of the affected nodes
272 ***************************************************************/
273 SWAP(id[higain], ed[higain], tmp);
274 if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1])
275 BNDDelete(nbnd, bndind, bndptr, higain);
276 if (ed[higain] > 0 && bndptr[higain] == -1)
277 BNDInsert(nbnd, bndind, bndptr, higain);
278
279 for (j=xadj[higain]; j<xadj[higain+1]; j++) {
280 k = adjncy[j];
281 oldgain = ed[k]-id[k];
282
283 kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
284 INC_DEC(id[k], ed[k], kwgt);
285
286 /* Update the queue position */
287 if (where[k] == from) {
288 if (ed[k] > 0 && bndptr[k] == -1) { /* It moves in boundary */
289 PQueueDelete(&parts[qnum[k]][1], k, oldgain);
290 PQueueInsert(&parts[qnum[k]][0], k, ed[k]-id[k]);
291 }
292 else { /* It must be in the boundary already */
293 if (bndptr[k] == -1)
294 printf("What you thought was wrong!\n");
295 PQueueUpdate(&parts[qnum[k]][0], k, oldgain, ed[k]-id[k]);
296 }
297 }
298
299 /* Update its boundary information */
300 if (ed[k] == 0 && bndptr[k] != -1)
301 BNDDelete(nbnd, bndind, bndptr, k);
302 else if (ed[k] > 0 && bndptr[k] == -1)
303 BNDInsert(nbnd, bndind, bndptr, k);
304 }
305
306 ASSERTP(ComputeCut(graph, where) == mincut, ("%d != %d\n", ComputeCut(graph, where), mincut));
307
308 }
309
310 if (ctrl->dbglvl&DBG_REFINE) {
311 printf("\tMincut: %6d, NBND: %6d, NPwgts: ", mincut, nbnd);
312 for (l=0; l<ncon; l++)
313 printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
314 printf(", LB: %.3f\n", Compute2WayHLoadImbalance(ncon, npwgts, tpwgts));
315 }
316
317 graph->mincut = mincut;
318 graph->nbnd = nbnd;
319
320 for (i=0; i<ncon; i++) {
321 PQueueFree(ctrl, &parts[i][0]);
322 PQueueFree(ctrl, &parts[i][1]);
323 }
324
325 ASSERT(ComputeCut(graph, where) == graph->mincut);
326 ASSERT(CheckBnd(graph));
327
328 idxwspacefree(ctrl, nvtxs);
329 idxwspacefree(ctrl, nvtxs);
330 }
331
332
333
334
335 /*************************************************************************
336 * This function selects the partition number and the queue from which
337 * we will move vertices out
338 **************************************************************************/
SelectQueueOneWay(int ncon,float * npwgts,float * tpwgts,int from,PQueueType queues[MAXNCON][2])339 int SelectQueueOneWay(int ncon, float *npwgts, float *tpwgts, int from, PQueueType queues[MAXNCON][2])
340 {
341 int i, cnum=-1;
342 float max=0.0;
343
344 for (i=0; i<ncon; i++) {
345 if (npwgts[from*ncon+i]-tpwgts[from] >= max &&
346 PQueueGetSize(&queues[i][0]) + PQueueGetSize(&queues[i][1]) > 0) {
347 max = npwgts[from*ncon+i]-tpwgts[0];
348 cnum = i;
349 }
350 }
351
352 return cnum;
353 }
354
355
356