~ubuntu-branches/ubuntu/trusty/scotch/trusty

« back to all changes in this revision

Viewing changes to src/libscotch/graph_coarsen.c

  • Committer: Bazaar Package Importer
  • Author(s): Christophe Prud'homme
  • Date: 2008-01-25 09:13:53 UTC
  • Revision ID: james.westby@ubuntu.com-20080125091353-zghdao60dfsyc2bt
Tags: upstream-5.0.1.dfsg
ImportĀ upstreamĀ versionĀ 5.0.1.dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2004,2007 ENSEIRB, INRIA & CNRS
 
2
**
 
3
** This file is part of the Scotch software package for static mapping,
 
4
** graph partitioning and sparse matrix ordering.
 
5
**
 
6
** This software is governed by the CeCILL-C license under French law
 
7
** and abiding by the rules of distribution of free software. You can
 
8
** use, modify and/or redistribute the software under the terms of the
 
9
** CeCILL-C license as circulated by CEA, CNRS and INRIA at the following
 
10
** URL: "http://www.cecill.info".
 
11
** 
 
12
** As a counterpart to the access to the source code and rights to copy,
 
13
** modify and redistribute granted by the license, users are provided
 
14
** only with a limited warranty and the software's author, the holder of
 
15
** the economic rights, and the successive licensors have only limited
 
16
** liability.
 
17
** 
 
18
** In this respect, the user's attention is drawn to the risks associated
 
19
** with loading, using, modifying and/or developing or reproducing the
 
20
** software by the user in light of its specific status of free software,
 
21
** that may mean that it is complicated to manipulate, and that also
 
22
** therefore means that it is reserved for developers and experienced
 
23
** professionals having in-depth computer knowledge. Users are therefore
 
24
** encouraged to load and test the software's suitability as regards
 
25
** their requirements in conditions enabling the security of their
 
26
** systems and/or data to be ensured and, more generally, to use and
 
27
** operate it in the same conditions as regards security.
 
28
** 
 
29
** The fact that you are presently reading this means that you have had
 
30
** knowledge of the CeCILL-C license and that you accept its terms.
 
31
*/
 
32
/************************************************************/
 
33
/**                                                        **/
 
34
/**   NAME       : graph_coarsen.c                         **/
 
35
/**                                                        **/
 
36
/**   AUTHOR     : Francois PELLEGRINI                     **/
 
37
/**                                                        **/
 
38
/**   FUNCTION   : This module contains the source graph   **/
 
39
/**                coarsening functions.                   **/
 
40
/**                                                        **/
 
41
/**   DATES      : # Version 0.0  : from : 01 dec 1992     **/
 
42
/**                                 to     18 may 1993     **/
 
43
/**                # Version 1.3  : from : 30 apr 1994     **/
 
44
/**                                 to     18 may 1994     **/
 
45
/**                # Version 2.0  : from : 06 jun 1994     **/
 
46
/**                                 to     31 oct 1994     **/
 
47
/**                # Version 3.0  : from : 07 jul 1995     **/
 
48
/**                                 to     28 sep 1995     **/
 
49
/**                # Version 3.1  : from : 28 nov 1995     **/
 
50
/**                                 to     08 jun 1996     **/
 
51
/**                # Version 3.2  : from : 07 sep 1996     **/
 
52
/**                                 to     17 sep 1998     **/
 
53
/**                # Version 4.0  : from : 13 dec 2001     **/
 
54
/**                                 to     31 aug 2005     **/
 
55
/**                # Version 5.0  : from : 13 dec 2006     **/
 
56
/**                                 to     10 sep 2007     **/
 
57
/**                                                        **/
 
58
/************************************************************/
 
59
 
 
60
/*
 
61
**  The defines and includes.
 
62
*/
 
63
 
 
64
#define GRAPH_COARSEN
 
65
 
 
66
#include "module.h"
 
67
#include "common.h"
 
68
#include "graph.h"
 
69
#include "graph_coarsen.h"
 
70
 
 
71
/*
 
72
**  The static variables.
 
73
*/
 
74
 
 
75
static Gnum              (* graphCoarsenFuncTab[GRAPHCOARNBR]) () = { /* Tables of edge-matching routines */
 
76
                              graphCoarsenMatchHy,
 
77
                              graphCoarsenMatchSc,
 
78
                              graphCoarsenMatchCs,
 
79
                              graphCoarsenMatchCh };
 
80
 
 
81
/***************************/
 
82
/*                         */
 
83
/* The coarsening routine. */
 
84
/*                         */
 
85
/***************************/
 
86
 
 
87
/* This routine coarsens the given "finegraph" into
 
88
** "coargraph", as long as the coarsening ratio remains
 
89
** below some threshold value and the coarsened graph
 
90
** is not too small.
 
91
** It returns:
 
92
** - 0  : if the graph has been coarsened.
 
93
** - 1  : if the graph could not be coarsened.
 
94
** - 2  : on error.
 
95
*/
 
96
 
 
97
int
 
98
graphCoarsen (
 
99
const Graph * restrict const          finegrafptr, /*+ Graph to coarsen                    +*/
 
100
Graph * restrict const                coargrafptr, /*+ Coarse graph to build               +*/
 
101
GraphCoarsenMulti * restrict * const  coarmultptr, /*+ Pointer to multinode table to build +*/
 
102
const Gnum                            coarnbr,    /*+ Minimum number of coarse vertices    +*/
 
103
const double                          coarrat,    /*+ Maximum contraction ratio            +*/
 
104
const GraphCoarsenType                coartype)   /*+ Edge matching type                   +*/
 
105
{
 
106
  Gnum                          coarhashnbr;      /* Size of the hash table                   */
 
107
  Gnum                          coarhashmsk;      /* Mask for access to hash table            */
 
108
  GraphCoarsenHash * restrict   coarhashtab;      /* Table of edges to other multinodes       */
 
109
  Gnum                          coarvertnbr;      /* Number of coarse vertices                */
 
110
  Gnum                          coarvertnum;      /* Number of current multinode vertex       */
 
111
  Gnum                          coarvertmax;      /* Maximum number of multinode vertices     */
 
112
  Gnum                          coarvelomax;      /* Maximum vertex weight allowed            */
 
113
  GraphCoarsenMulti * restrict  coarmulttax;      /* Multinode array                          */
 
114
  Gnum * restrict               finecoartax;      /* Based access to finecoartab              */
 
115
  Gnum                          finevertnum;      /* Number of currently selected fine vertex */
 
116
  size_t                        coarmultoftval;
 
117
  size_t                        coarvelooftval;
 
118
  size_t                        coaredgeoftval;
 
119
  size_t                        coaredlooftval;
 
120
 
 
121
#ifdef SCOTCH_DEBUG_GRAPH2
 
122
  if (coartype >= GRAPHCOARNBR) {
 
123
    errorPrint ("graphCoarsen: invalid parameter");
 
124
    return     (2);
 
125
  }
 
126
#endif /* SCOTCH_DEBUG_GRAPH2 */
 
127
#ifdef SCOTCH_DEBUG_GRAPH1
 
128
  if (coarrat < 0.5L)                             /* If impossible coarsening ratio wanted */
 
129
    return (1);                                   /* We will never succeed                 */
 
130
#endif /* SCOTCH_DEBUG_GRAPH1 */
 
131
 
 
132
  coarvertmax = (Gnum) ((double) finegrafptr->vertnbr * coarrat); /* Maximum number of coarse vertices */
 
133
  if (coarvertmax < coarnbr)                      /* If there will be too few vertices in graph        */
 
134
    return (1);                                   /* It is useless to go any further                   */
 
135
 
 
136
  if ((finecoartax = (Gnum *) memAlloc (finegrafptr->vertnbr * sizeof (Gnum))) == NULL) {
 
137
    errorPrint ("graphCoarsen: out of memory (1)"); /* Allocate coarse graph uncoarsening array */
 
138
    return     (2);
 
139
  }
 
140
  memSet (finecoartax, ~0, finegrafptr->vertnbr * sizeof (Gnum));
 
141
  finecoartax -= finegrafptr->baseval;            /* Set based access to finecoartab */
 
142
 
 
143
  coarvelomax = (3 * finegrafptr->velosum) / (2 * coarnbr) + 1;
 
144
 
 
145
  coarvertnbr = graphCoarsenFuncTab[coartype] (finegrafptr, finecoartax, coarvertmax, coarvelomax); /* Call proper matching function */
 
146
 
 
147
  if (coarvertnbr >= coarvertmax) {               /* If coarsened graph too large */
 
148
    memFree (finecoartax + finegrafptr->baseval); /* Do not proceed any further   */
 
149
    return  (1);
 
150
  }
 
151
 
 
152
#ifdef SCOTCH_DEBUG_GRAPH2
 
153
  for (finevertnum = finegrafptr->baseval; finevertnum < finegrafptr->vertnnd; finevertnum ++) {
 
154
    if (finecoartax[finevertnum] <= ~0) {         /* If coarsening not aborted, this should not happen */
 
155
      errorPrint ("graphCoarsen: internal error (1)");
 
156
      memFree    (finecoartax + finegrafptr->baseval);
 
157
      return     (2);
 
158
    }
 
159
  }
 
160
#endif /* SCOTCH_DEBUG_GRAPH2 */
 
161
 
 
162
  memSet (coargrafptr, 0, sizeof (Graph));        /* Initialize coarse graph */
 
163
  coargrafptr->flagval = GRAPHFREEVERT | GRAPHVERTGROUP | GRAPHEDGEGROUP;
 
164
  coargrafptr->baseval = finegrafptr->baseval;
 
165
  coargrafptr->vertnbr = coarvertnbr;
 
166
  coargrafptr->vertnnd = coarvertnbr + coargrafptr->baseval;
 
167
  coargrafptr->velosum = finegrafptr->velosum;    /* Keep load of finer graph */
 
168
 
 
169
  for (coarhashmsk = 31; coarhashmsk < finegrafptr->degrmax; coarhashmsk = coarhashmsk * 2 + 1) ;
 
170
  coarhashmsk = coarhashmsk * 4 + 3;
 
171
  coarhashnbr = coarhashmsk + 1;
 
172
 
 
173
  if (memAllocGroup ((void **) (void *)
 
174
                     &coargrafptr->verttax, (size_t) ((coarvertnbr + 1)    * sizeof (Gnum)),
 
175
                     &coargrafptr->velotax, (size_t) (coarvertnbr          * sizeof (Gnum)),
 
176
                     &coarmulttax,          (size_t) (coarvertnbr          * sizeof (GraphCoarsenMulti)),
 
177
                     &coargrafptr->edgetax, (size_t) (finegrafptr->edgenbr * sizeof (Gnum)), /* Pre-allocate space for edge arrays */ 
 
178
                     &coargrafptr->edlotax, (size_t) (finegrafptr->edgenbr * sizeof (Gnum)),
 
179
                     &coarhashtab,          (size_t) (coarhashnbr          * sizeof (GraphCoarsenHash)), NULL) == NULL) {
 
180
    errorPrint ("graphCoarsen: out of memory (2)"); /* Allocate coarser graph structure */
 
181
    memFree    (finecoartax + finegrafptr->baseval);
 
182
    return     (2);
 
183
  }
 
184
  coargrafptr->verttax -= coargrafptr->baseval;   /* Base coarse graph arrays */
 
185
  coargrafptr->velotax -= coargrafptr->baseval;
 
186
  coargrafptr->edgetax -= coargrafptr->baseval;
 
187
  coargrafptr->edlotax -= coargrafptr->baseval;
 
188
  coarmulttax          -= coargrafptr->baseval;
 
189
 
 
190
  for (finevertnum = finegrafptr->baseval, coarvertnum = coargrafptr->baseval; /* Finalize finecoartab array */
 
191
       finevertnum < finegrafptr->vertnnd; finevertnum ++) {
 
192
    Gnum                finematenum;              /* Number of current mate vertex */
 
193
 
 
194
    finematenum = finecoartax[finevertnum];       /* Get mate number                               */
 
195
    if (finematenum >= finevertnum) {             /* If mate has larger number                     */
 
196
      coarmulttax[coarvertnum].vertnum[0] = finevertnum; /* Build new multinode                    */
 
197
      coarmulttax[coarvertnum].vertnum[1] = finematenum; /* Second index always biggest            */
 
198
      finecoartax[finematenum] =                  /* Point to coarse vertex                        */
 
199
      finecoartax[finevertnum] = coarvertnum;     /* Always valid since coarvertnum <= finevertnum */
 
200
      coarvertnum ++;                             /* One more multinode created                    */
 
201
    }
 
202
  }
 
203
#ifdef SCOTCH_DEBUG_GRAPH2
 
204
  if ((coarvertnum - coargrafptr->baseval) != coarvertnbr) {
 
205
    errorPrint ("graphCoarsen: internal error (2)");
 
206
    graphFree  (coargrafptr);
 
207
    memFree    (finecoartax + finegrafptr->baseval);
 
208
    return     (2);
 
209
  }
 
210
#endif /* SCOTCH_DEBUG_GRAPH2 */
 
211
 
 
212
  if (finegrafptr->velotax != NULL) {             /* If fine graph is weighted */
 
213
    for (coarvertnum = coargrafptr->baseval; coarvertnum < coargrafptr->vertnnd; coarvertnum ++) {
 
214
      Gnum                coarveloval;
 
215
 
 
216
      coarveloval = finegrafptr->velotax[coarmulttax[coarvertnum].vertnum[0]];
 
217
      if (coarmulttax[coarvertnum].vertnum[0] != coarmulttax[coarvertnum].vertnum[1])
 
218
        coarveloval += finegrafptr->velotax[coarmulttax[coarvertnum].vertnum[1]];
 
219
      coargrafptr->velotax[coarvertnum] = coarveloval;
 
220
    }
 
221
  }
 
222
  else {                                          /* Fine graph is not weighted */
 
223
    for (coarvertnum = coargrafptr->baseval; coarvertnum < coargrafptr->vertnnd; coarvertnum ++)
 
224
      coargrafptr->velotax[coarvertnum] = (coarmulttax[coarvertnum].vertnum[0] != coarmulttax[coarvertnum].vertnum[1]) ? 2 : 1;
 
225
  }
 
226
 
 
227
  memSet (coarhashtab, ~0, coarhashnbr * sizeof (GraphCoarsenHash));
 
228
  if (finegrafptr->edlotax != NULL)               /* If edge loads available */
 
229
    graphCoarsenEdgeLl (finegrafptr, finecoartax, coarmulttax, coargrafptr, coarhashtab, coarhashmsk);
 
230
  else                                            /* Fine edges not weighted */
 
231
    graphCoarsenEdgeLu (finegrafptr, finecoartax, coarmulttax, coargrafptr, coarhashtab, coarhashmsk);
 
232
  coargrafptr->edgenbr = coargrafptr->verttax[coargrafptr->vertnnd] - coargrafptr->baseval; /* Set exact number of edges */
 
233
 
 
234
  memFree (finecoartax + finegrafptr->baseval);
 
235
 
 
236
  coarvelooftval = coargrafptr->velotax - coargrafptr->verttax;
 
237
  coarmultoftval = (Gnum *) coarmulttax - coargrafptr->verttax;
 
238
  coaredgeoftval = coargrafptr->edgetax - coargrafptr->verttax;
 
239
  coaredlooftval = coargrafptr->edlotax - coargrafptr->verttax;
 
240
  memReallocGroup ((void *) (coargrafptr->verttax + coargrafptr->baseval), /* Re-allocate data, wiping temporary arrays */
 
241
                   &coargrafptr->verttax, (size_t) ((coarvertnbr + 1)    * sizeof (Gnum)),
 
242
                   &coargrafptr->velotax, (size_t) (coarvertnbr          * sizeof (Gnum)),
 
243
                   &coarmulttax,          (size_t) (coarvertnbr          * sizeof (GraphCoarsenMulti)),
 
244
                   &coargrafptr->edgetax, (size_t) (finegrafptr->edgenbr * sizeof (Gnum)),
 
245
                   &coargrafptr->edlotax, (size_t) (coargrafptr->edgenbr * sizeof (Gnum)), NULL);
 
246
  coargrafptr->verttax -= coargrafptr->baseval;
 
247
  coargrafptr->vendtax  = coargrafptr->verttax + 1; /* Use compact representation of arrays */
 
248
  coargrafptr->velotax  = coargrafptr->verttax + coarvelooftval;
 
249
  coargrafptr->edgetax  = coargrafptr->verttax + coaredgeoftval;
 
250
  coargrafptr->edlotax  = coargrafptr->verttax + coaredlooftval;
 
251
  coarmulttax           = (GraphCoarsenMulti *) (coargrafptr->verttax + coarmultoftval);
 
252
  *coarmultptr          = coarmulttax;            /* Return pointer to multinode array */
 
253
 
 
254
#ifdef SCOTCH_DEBUG_GRAPH2
 
255
  if (graphCheck (coargrafptr) != 0) {            /* Check graph consistency */
 
256
    errorPrint ("graphCoarsen: inconsistent graph data");
 
257
    graphFree  (coargrafptr);
 
258
    return     (2);
 
259
  }
 
260
#endif /* SCOTCH_DEBUG_GRAPH2 */
 
261
 
 
262
  return (0);
 
263
}
 
264
 
 
265
/****************************************/
 
266
/*                                      */
 
267
/* The edge array building subroutines. */
 
268
/*                                      */
 
269
/****************************************/
 
270
 
 
271
#define GRAPHCOARSENEDGENAME        graphCoarsenEdgeLl
 
272
#define GRAPHCOARSENEDGEEDLOINIT    coargrafptr->edlotax[coaredgenum] = finegrafptr->edlotax[fineedgenum]
 
273
#define GRAPHCOARSENEDGEEDLOADD     coargrafptr->edlotax[coarhashtab[h].edgenum] += finegrafptr->edlotax[fineedgenum]
 
274
#define GRAPHCOARSENEDGEEDLOSUB     coaredlosum -= finegrafptr->edlotax[fineedgenum]
 
275
#include "graph_coarsen_edge.c"
 
276
#undef GRAPHCOARSENEDGENAME
 
277
#undef GRAPHCOARSENEDGEEDLOINIT
 
278
#undef GRAPHCOARSENEDGEEDLOADD
 
279
#undef GRAPHCOARSENEDGEEDLOSUB
 
280
 
 
281
#define GRAPHCOARSENEDGENAME        graphCoarsenEdgeLu
 
282
#define GRAPHCOARSENEDGEEDLOINIT    coargrafptr->edlotax[coaredgenum] = 1
 
283
#define GRAPHCOARSENEDGEEDLOADD     coargrafptr->edlotax[coarhashtab[h].edgenum] ++
 
284
#define GRAPHCOARSENEDGEEDLOSUB     coaredlosum --
 
285
#include "graph_coarsen_edge.c"
 
286
#undef GRAPHCOARSENEDGENAME
 
287
#undef GRAPHCOARSENEDGEEDLOINIT
 
288
#undef GRAPHCOARSENEDGEEDLOADD
 
289
#undef GRAPHCOARSENEDGEEDLOSUB
 
290
 
 
291
/*****************************/
 
292
/*                           */
 
293
/* The matching subroutines. */
 
294
/*                           */
 
295
/*****************************/
 
296
 
 
297
static
 
298
Gnum
 
299
graphCoarsenMatchHy (
 
300
const Graph * restrict const  finegrafptr,        /* Fine graph to perform matching on */
 
301
Gnum * restrict               finecoartax,        /* Fine to coarse vertex index array */
 
302
const Gnum                    coarvertmax,        /* Maximum number of vertices to get */
 
303
const Gnum                    coarvelomax)        /* Maximum vertex weight allowed     */
 
304
{
 
305
  Gnum                  coarvertnum;              /* Number of current multinode vertex       */
 
306
  Gnum                  finepertbas;              /* Index of base of perturbation area       */
 
307
  Gnum                  finepertnbr;              /* Size of perturbation area                */
 
308
  const Gnum * restrict fineverttax;              /* Based access to vertex array             */
 
309
  const Gnum * restrict finevendtax;              /* Based access to end vertex array         */
 
310
  const Gnum * restrict finevelotax;              /* Based access to end vertex array         */
 
311
  const Gnum * restrict fineedgetax;              /* Based access to end vertex array         */
 
312
  const Gnum * restrict fineedlotax;              /* Based access to end vertex array         */
 
313
  Gnum                  finevertnnd;              /* Current end of vertex array              */
 
314
  Gnum                  finevertnum;              /* Number of currently selected fine vertex */
 
315
 
 
316
  if (finegrafptr->edlotax == NULL)               /* If no edge loads, perform scan matching instead */
 
317
    return (graphCoarsenMatchSc (finegrafptr, finecoartax, coarvertmax, coarvelomax));
 
318
 
 
319
  fineverttax = finegrafptr->verttax;
 
320
  finevendtax = finegrafptr->vendtax;
 
321
  finevelotax = finegrafptr->velotax;
 
322
  fineedgetax = finegrafptr->edgetax;
 
323
  fineedlotax = finegrafptr->edlotax;
 
324
  finevertnnd = finegrafptr->vertnnd;
 
325
  coarvertnum = 0;
 
326
 
 
327
  if (finegrafptr->velotax != NULL) {
 
328
    Gnum                finevelodlt;              /* Minimum load of neighbor */
 
329
 
 
330
    finevelodlt = (3 * finegrafptr->velosum) / (5 * (finevertnnd - finegrafptr->baseval));
 
331
 
 
332
    for (finevertnum = finegrafptr->baseval;      /* Pre-selection loop for isolated and lightest vertices */
 
333
         finevertnum < finevertnnd; finevertnum ++) {
 
334
      if (fineverttax[finevertnum] == finevendtax[finevertnum]) { /* If isolated vertex      */
 
335
        while (finecoartax[-- finevertnnd] != ~0) ; /* Search for first matchable "neighbor" */
 
336
 
 
337
        finecoartax[finevertnum] = finevertnnd;   /* At worst we will stop at finevertnum */
 
338
        finecoartax[finevertnnd] = finevertnum;
 
339
        coarvertnum ++;                           /* One more coarse vertex created */
 
340
      }
 
341
      else {                                      /* Vertex has neighbors */
 
342
        if ((finevelotax[finevertnum] < finevelodlt) &&
 
343
            (finecoartax[finevertnum] == ~0)) {   /* If vertex is too light on average  */
 
344
          Gnum                finevertbst;        /* Number of current best neighbor    */
 
345
          Gnum                fineedlobst;        /* Edge load of current best neighbor */
 
346
          Gnum                fineedgenum;
 
347
 
 
348
          if (coarvertnum >= coarvertmax)         /* If coarse graph is too large       */
 
349
            return (coarvertmax);                 /* Return that we cannot coarsen more */
 
350
 
 
351
          finevertbst = finevertnum;              /* No matching neighbor found yet */
 
352
          fineedlobst = 0;
 
353
          for (fineedgenum = fineverttax[finevertnum]; /* For all adjacent vertices */
 
354
               fineedgenum < finevendtax[finevertnum]; fineedgenum ++) {
 
355
            if ((finecoartax[fineedgetax[fineedgenum]] == ~0) && /* If unmatched vertex */
 
356
                (fineedlotax[fineedgenum] > fineedlobst)) { /* And is better candidate  */
 
357
              fineedlobst = fineedlotax[fineedgenum];
 
358
              finevertbst = fineedgetax[fineedgenum];
 
359
            }
 
360
          }
 
361
 
 
362
          finecoartax[finevertnum] = finevertbst;
 
363
          finecoartax[finevertbst] = finevertnum;
 
364
          coarvertnum ++;                         /* One more coarse vertex created */
 
365
        }
 
366
      }
 
367
    }
 
368
  }
 
369
 
 
370
  finepertnbr = 2 + intRandVal (GRAPHCOARPERTPRIME - 2); /* Compute perturbation area size (avoid DIV0 in random) */
 
371
  for (finepertbas = finegrafptr->baseval; finepertbas < finevertnnd; /* Run cache-friendly perturbation          */
 
372
       finepertbas += finepertnbr) {
 
373
    Gnum                finepertval;              /* Current index in perturbation area */
 
374
 
 
375
    if (finepertbas + finepertnbr > finevertnnd)
 
376
      finepertnbr = finevertnnd - finepertbas;
 
377
 
 
378
    finepertval = 0;                              /* Start from first perturbation vertex */
 
379
    do {                                          /* Loop on perturbation vertices        */
 
380
      finevertnum = finepertbas + finepertval;    /* Compute corresponding vertex number  */
 
381
 
 
382
      if (finecoartax[finevertnum] == ~0) {       /* If vertex has not been picked already */
 
383
        Gnum                finevertbst;          /* Number of current best neighbor       */
 
384
        Gnum                fineedlobst;          /* Edge load of current best neighbor    */
 
385
        Gnum                finevelodlt;          /* Maximum load of neighbor              */
 
386
        Gnum                fineedgenum;
 
387
 
 
388
        if (coarvertnum >= coarvertmax)           /* If coarse graph too large       */
 
389
          return (coarvertmax);                   /* Return that cannot coarsen more */
 
390
 
 
391
        finevertbst = finevertnum;                /* No matching vertex found yet */
 
392
        fineedlobst = 0;
 
393
        finevelodlt = coarvelomax - ((finevelotax != NULL) ? finevelotax[finevertnum] : 1);
 
394
 
 
395
        for (fineedgenum = fineverttax[finevertnum]; /* For all adjacent vertices */
 
396
             fineedgenum < finevendtax[finevertnum]; fineedgenum ++) {
 
397
          if ((finecoartax[fineedgetax[fineedgenum]] == ~0) && /* If unmatched vertex */
 
398
              (fineedlotax[fineedgenum] > fineedlobst) && /* And better candidate     */
 
399
              ((finevelotax == NULL) ||  /* And does not create overloads             */
 
400
               (finevelodlt >= finevelotax[fineedgetax[fineedgenum]]))) {
 
401
            fineedlobst = fineedlotax[fineedgenum];
 
402
            finevertbst = fineedgetax[fineedgenum];
 
403
          }
 
404
        }
 
405
 
 
406
        finecoartax[finevertnum] = finevertbst;
 
407
        finecoartax[finevertbst] = finevertnum;
 
408
        coarvertnum ++;                           /* One more coarse vertex created */
 
409
      }
 
410
 
 
411
      finepertval = (finepertval + GRAPHCOARPERTPRIME) % finepertnbr; /* Compute next perturbation index */
 
412
    } while (finepertval != 0);
 
413
  }
 
414
 
 
415
  return (coarvertnum);                           /* Return number of coarse vertices */
 
416
}
 
417
 
 
418
static
 
419
Gnum
 
420
graphCoarsenMatchSc (
 
421
const Graph * restrict const  finegrafptr,        /* Fine graph to perform matching on */
 
422
Gnum * restrict               finecoartax,        /* Fine to coarse vertex index array */
 
423
const Gnum                    coarvertmax,        /* Maximum number of vertices to get */
 
424
const Gnum                    coarvelomax)        /* Maximum vertex weight allowed     */
 
425
{
 
426
  Gnum                  coarvertnum;              /* Number of current multinode vertex       */
 
427
  Gnum                  finepertbas;              /* Index of base of perturbation area       */
 
428
  const Gnum * restrict fineverttax;              /* Based access to vertex array             */
 
429
  Gnum                  finepertnbr;              /* Size of perturbation area                */
 
430
  Gnum                  finevertnnd;              /* Current end of vertex array              */
 
431
  Gnum                  finevertnum;              /* Number of currently selected fine vertex */
 
432
 
 
433
  fineverttax = finegrafptr->verttax;
 
434
 
 
435
  coarvertnum = 0;
 
436
  for (finepertbas = finegrafptr->baseval, finevertnnd = finegrafptr->vertnnd;
 
437
       finepertbas < finevertnnd; finepertbas += finepertnbr) { /* Run cache-friendly perturbation */
 
438
    Gnum                finepertval;              /* Current index in perturbation area            */
 
439
 
 
440
    finepertnbr = finegrafptr->degrmax * 2 + intRandVal (finegrafptr->degrmax + 1) + 1; /* Compute perturbation area size (avoid DIV0 in random) */
 
441
    if (finepertnbr >= GRAPHCOARPERTPRIME)
 
442
      finepertnbr = 32 + intRandVal (GRAPHCOARPERTPRIME - 34);
 
443
 
 
444
    if (finepertbas + finepertnbr > finevertnnd)
 
445
      finepertnbr = finevertnnd - finepertbas;
 
446
 
 
447
    finepertval = 0;                              /* Start from first perturbation vertex */
 
448
    do {                                          /* Loop on perturbation vertices        */
 
449
      finevertnum = finepertbas + finepertval;    /* Compute corresponding vertex number  */
 
450
 
 
451
      if (finecoartax[finevertnum] == ~0) {       /* If vertex has not been picked already  */
 
452
        Gnum                finevertbst;          /* Number of current best matching vertex */
 
453
 
 
454
        if (coarvertnum >= coarvertmax)           /* If coarse graph is too large          */
 
455
          return (coarvertmax);                   /* Return that we cannot coarsen more    */
 
456
 
 
457
        if (fineverttax[finevertnum] == finegrafptr->vendtax[finevertnum]) { /* If isolated vertex */
 
458
          while (finecoartax[-- finevertnnd] != ~0) ; /* Search for first matchable "neighbor"     */
 
459
          finevertbst = finevertnnd;              /* Unmatched vertex will act as neighbor         */
 
460
        }
 
461
        else {                                    /* Vertex has neighbors */
 
462
          Gnum                finevelodlt;        /* Overload limit       */
 
463
          Gnum                fineedgenum;        /* Current edge number  */
 
464
 
 
465
          finevertbst = finevertnum;              /* No matching vertex found yet */
 
466
          finevelodlt = coarvelomax - ((finegrafptr->velotax != NULL) ? finegrafptr->velotax[finevertnum] : 1);
 
467
 
 
468
          for (fineedgenum = fineverttax[finevertnum]; /* For all adjacent vertices */
 
469
               fineedgenum < finegrafptr->vendtax[finevertnum]; fineedgenum ++) {
 
470
            if ((finecoartax[finegrafptr->edgetax[fineedgenum]] == ~0) && /* If unmatched vertex */
 
471
                ((finegrafptr->velotax == NULL) || /* And does not create overloads              */
 
472
                 (finevelodlt >= finegrafptr->velotax[finegrafptr->edgetax[fineedgenum]]))) {
 
473
              finevertbst = finegrafptr->edgetax[fineedgenum];
 
474
              break;
 
475
            }
 
476
          }
 
477
        }
 
478
 
 
479
        finecoartax[finevertnum] = finevertbst;
 
480
        finecoartax[finevertbst] = finevertnum;
 
481
        coarvertnum ++;                           /* One more coarse vertex created */
 
482
      }
 
483
 
 
484
      finepertval = (finepertval + GRAPHCOARPERTPRIME) % finepertnbr; /* Compute next perturbation index */
 
485
    } while (finepertval != 0);
 
486
  }
 
487
 
 
488
  return (coarvertnum);                           /* Return number of coarse vertices */
 
489
}
 
490
 
 
491
static
 
492
Gnum
 
493
graphCoarsenMatchCs (                             /* Crystallographic scan             */
 
494
const Graph * restrict const  finegrafptr,        /* Fine graph to perform matching on */
 
495
Gnum * restrict               finecoartax,        /* Fine to coarse vertex index array */
 
496
const Gnum                    coarvertmax,        /* Maximum number of vertices to get */
 
497
const Gnum                    coarvelomax)        /* Maximum vertex weight allowed     */
 
498
{
 
499
  Gnum                  coarvertnum;              /* Number of current multinode vertex       */
 
500
  const Gnum * restrict fineverttax;              /* Based access to vertex array             */
 
501
  const Gnum * restrict finevendtax;              /* Based access to end vertex array         */
 
502
  const Gnum * restrict finevelotax;              /* Based access to vertex load array        */
 
503
  const Gnum * restrict fineedgetax;              /* Based access to edge array               */
 
504
  Gnum                  finevertnum;              /* Number of currently selected fine vertex */
 
505
  Gnum * restrict       finequeutab;
 
506
  Gnum                  finequeuheadval;
 
507
  Gnum                  finequeutailval;
 
508
  Gnum                  finepermnum;              /* Permutation number for finding connected components */
 
509
 
 
510
  fineverttax = finegrafptr->verttax;
 
511
  finevendtax = finegrafptr->vendtax;
 
512
  finevelotax = finegrafptr->velotax;
 
513
  fineedgetax = finegrafptr->edgetax;
 
514
  if ((finequeutab = memAlloc (finegrafptr->vertnbr * sizeof (Gnum))) == NULL) {
 
515
    errorPrint ("graphCoarsenMatchCs: out of memory");
 
516
    return     (graphCoarsenMatchSc (finegrafptr, finecoartax, coarvertmax, coarvelomax)); /* Fallback strategy */
 
517
  }
 
518
 
 
519
  coarvertnum     = 0;
 
520
  finequeuheadval = 1;
 
521
  finequeutailval = 0;
 
522
  finequeutab[0] = finegrafptr->baseval + intRandVal (finegrafptr->vertnbr); /* Start from random vertex */
 
523
  finecoartax[finequeutab[0]] = -2;               /* Set vertex as enqueued */
 
524
  
 
525
  for (finepermnum = finegrafptr->baseval; finequeutailval < finegrafptr->vertnbr; ) {
 
526
    if (finequeutailval < finequeuheadval) {      /* If vertices remain in queue */
 
527
      Gnum                finevertbst;            /* Best vertex found till now  */
 
528
      Gnum                finevelodlt;            /* Overload limit              */
 
529
      Gnum                fineedgenum;            /* Current edge number         */
 
530
 
 
531
      finevertnum = finequeutab[finequeutailval ++]; /* Select a vertex from the queue */
 
532
 
 
533
      if (finecoartax[finevertnum] >= 0) {        /* If selected vertex already matched */
 
534
        for (fineedgenum = fineverttax[finevertnum]; /* For all adjacent vertices       */
 
535
             fineedgenum < finevendtax[finevertnum]; fineedgenum ++) {
 
536
          Gnum                finevertend;
 
537
 
 
538
          finevertend = fineedgetax[fineedgenum];
 
539
          if (finecoartax[finevertend] == ~0) {
 
540
            finequeutab[finequeuheadval ++] = finevertend;
 
541
            finecoartax[finevertend] = -2;
 
542
          }
 
543
        }
 
544
        continue;                                 /* Skip to next vertex */
 
545
      }
 
546
 
 
547
      if (coarvertnum >= coarvertmax)             /* If coarse graph is too large       */
 
548
        break;                                    /* Return that we cannot coarsen more */
 
549
 
 
550
      finevertbst = finevertnum;                  /* No matching vertex found yet */
 
551
      finevelodlt = coarvelomax - ((finegrafptr->velotax != NULL) ? finegrafptr->velotax[finevertnum] : 1);
 
552
 
 
553
      for (fineedgenum = fineverttax[finevertnum]; /* For all adjacent vertices */
 
554
           fineedgenum < finevendtax[finevertnum]; fineedgenum ++) {
 
555
        Gnum                finevertend;
 
556
        Gnum                finecoarval;
 
557
 
 
558
        finevertend = fineedgetax[fineedgenum];
 
559
        finecoarval = finecoartax[finevertend];
 
560
 
 
561
        if (finecoarval < 0) {                    /* If vertex not matched  */
 
562
          if (finecoartax[finevertend] == ~0) {   /* If vertex not enqueued */
 
563
            finequeutab[finequeuheadval ++] = finevertend; /* Enqueue it    */
 
564
            finecoartax[finevertend] = -2;
 
565
          }
 
566
          if ((finevelotax == NULL) ||            /* And does not create overloads */
 
567
              (finevelodlt >= finevelotax[finevertend])) {
 
568
            finevertbst = finevertend;            /* Get matching vertex */
 
569
 
 
570
            while (++ fineedgenum < finevendtax[finevertnum]) { /* Scan and enqueue remaining neighbors */
 
571
              finevertend = fineedgetax[fineedgenum];
 
572
              if (finecoartax[finevertend] == ~0) {
 
573
                finequeutab[finequeuheadval ++] = finevertend;
 
574
                finecoartax[finevertend] = -2;
 
575
              }
 
576
            }
 
577
          }
 
578
        }
 
579
      }
 
580
 
 
581
      finecoartax[finevertnum] = finevertbst;     /* Match both vertices */
 
582
      finecoartax[finevertbst] = finevertnum;
 
583
      coarvertnum ++;                             /* One more coarse vertex created */
 
584
    }
 
585
    else {                                        /* Search for other connected component */
 
586
      Gnum                finevertbst;
 
587
 
 
588
      for ( ; finecoartax[finepermnum] >= 0; finepermnum ++) { /* Scan vertices in ascending order */
 
589
#ifdef SCOTCH_DEBUG_GRAPH2
 
590
        if (finepermnum >= finegrafptr->vertnnd) {
 
591
          errorPrint ("graphCoarsenMatchCs: internal error (1)");
 
592
          memFree    (finequeutab);
 
593
          return     (finegrafptr->vertnbr);      /* Coarsening aborted */
 
594
        }
 
595
#endif /* SCOTCH_DEBUG_GRAPH2 */
 
596
      }
 
597
#ifdef SCOTCH_DEBUG_GRAPH2
 
598
      if (finecoartax[finepermnum] != ~0) {
 
599
        errorPrint ("graphCoarsenMatchCs: internal error (2)");
 
600
        memFree    (finequeutab);
 
601
        return     (finegrafptr->vertnbr);        /* Coarsening aborted */
 
602
      }
 
603
#endif /* SCOTCH_DEBUG_GRAPH2 */
 
604
      finevertnum = finepermnum ++;               /* Start from found vertex */
 
605
 
 
606
      if (fineverttax[finevertnum] != finevendtax[finevertnum]) { /* If vertex not isolated */
 
607
        finequeutab[finequeuheadval ++] = finevertnum; /* Enqueue it for normal processing  */
 
608
        continue;                                 /* Skip to main loop to process it        */
 
609
      }
 
610
 
 
611
      finequeuheadval = ++ finequeutailval;       /* One more vertex enqueued-edqueued */
 
612
 
 
613
      if (coarvertnum >= coarvertmax)             /* If coarse graph is too large       */
 
614
        break;                                    /* Return that we cannot coarsen more */
 
615
 
 
616
      if (finequeutailval >= finegrafptr->vertnbr) /* If isolated vertex is last available vertex */
 
617
        finevertbst = finevertnum;
 
618
      else {
 
619
        for ( ; finecoartax[finepermnum] >= 0; finepermnum ++) {
 
620
#ifdef SCOTCH_DEBUG_GRAPH2
 
621
          if (finepermnum >= finegrafptr->vertnnd) {
 
622
            errorPrint ("graphCoarsenMatchCs: internal error (3)");
 
623
            memFree    (finequeutab);
 
624
            return     (finegrafptr->vertnbr);    /* Coarsening aborted */
 
625
          }
 
626
#endif /* SCOTCH_DEBUG_GRAPH2 */
 
627
        }
 
628
#ifdef SCOTCH_DEBUG_GRAPH2
 
629
        if (finecoartax[finepermnum] != ~0) {
 
630
          errorPrint ("graphCoarsenMatchCs: internal error (4)");
 
631
          memFree    (finequeutab);
 
632
          return     (finegrafptr->vertnbr);      /* Coarsening aborted */
 
633
        }
 
634
#endif /* SCOTCH_DEBUG_GRAPH2 */
 
635
        finevertbst     = finepermnum ++;         /* Get found vertex                  */
 
636
        finequeuheadval = ++ finequeutailval;     /* One more vertex enqueued-edqueued */
 
637
      }
 
638
 
 
639
      finecoartax[finevertnum] = finevertbst;     /* Match both vertices */
 
640
      finecoartax[finevertbst] = finevertnum;
 
641
      coarvertnum ++;                             /* One more coarse vertex created */
 
642
    }
 
643
  }
 
644
 
 
645
  memFree (finequeutab);
 
646
 
 
647
  return (coarvertnum);                           /* Return number of coarse vertices */
 
648
}
 
649
 
 
650
static
 
651
Gnum
 
652
graphCoarsenMatchCh (                             /* Crystallographic heavy edge       */
 
653
const Graph * restrict const  finegrafptr,        /* Fine graph to perform matching on */
 
654
Gnum * restrict               finecoartax,        /* Fine to coarse vertex index array */
 
655
const Gnum                    coarvertmax,        /* Maximum number of vertices to get */
 
656
const Gnum                    coarvelomax)        /* Maximum vertex weight allowed     */
 
657
{
 
658
  Gnum                  coarvertnum;              /* Number of current multinode vertex       */
 
659
  const Gnum * restrict fineverttax;              /* Based access to vertex array             */
 
660
  const Gnum * restrict finevendtax;              /* Based access to end vertex array         */
 
661
  const Gnum * restrict finevelotax;              /* Based access to vertex load array        */
 
662
  const Gnum * restrict fineedgetax;              /* Based access to edge array               */
 
663
  const Gnum * restrict fineedlotax;              /* Based access to edge load array          */
 
664
  Gnum                  finevertnum;              /* Number of currently selected fine vertex */
 
665
  Gnum * restrict       finequeutab;
 
666
  Gnum                  finequeuheadval;
 
667
  Gnum                  finequeutailval;
 
668
  Gnum                  finepermnum;              /* Permutation number for finding connected components */
 
669
 
 
670
  if (finegrafptr->edlotax == NULL)               /* If no edge loads, perform scan matching instead */
 
671
    return (graphCoarsenMatchCs (finegrafptr, finecoartax, coarvertmax, coarvelomax));
 
672
 
 
673
  fineverttax = finegrafptr->verttax;
 
674
  finevendtax = finegrafptr->vendtax;
 
675
  finevelotax = finegrafptr->velotax;
 
676
  fineedgetax = finegrafptr->edgetax;
 
677
  fineedlotax = finegrafptr->edlotax;
 
678
  if ((finequeutab = memAlloc (finegrafptr->vertnbr * sizeof (Gnum))) == NULL) {
 
679
    errorPrint ("graphCoarsenMatchCh: out of memory");
 
680
    return     (graphCoarsenMatchSc (finegrafptr, finecoartax, coarvertmax, coarvelomax)); /* Fallback strategy */
 
681
  }
 
682
 
 
683
  coarvertnum     = 0;
 
684
  finequeuheadval = 1;
 
685
  finequeutailval = 0;
 
686
  finequeutab[0] = finegrafptr->baseval + intRandVal (finegrafptr->vertnbr); /* Start from random vertex */
 
687
  finecoartax[finequeutab[0]] = -2;               /* Set vertex as enqueued */
 
688
  
 
689
  for (finepermnum = finegrafptr->baseval; finequeutailval < finegrafptr->vertnbr; ) {
 
690
    if (finequeutailval < finequeuheadval) {      /* If vertices remain in queue        */
 
691
      Gnum                finevertbst;            /* Best vertex found till now         */
 
692
      Gnum                fineedlobst;            /* Edge load of current best neighbor */
 
693
      Gnum                finevelodlt;            /* Overload limit                     */
 
694
      Gnum                fineedgenum;            /* Current edge number                */
 
695
 
 
696
      finevertnum = finequeutab[finequeutailval ++]; /* Select a vertex from the queue */
 
697
 
 
698
      if (finecoartax[finevertnum] >= 0) {        /* If selected vertex already matched */
 
699
        for (fineedgenum = fineverttax[finevertnum]; /* For all adjacent vertices       */
 
700
             fineedgenum < finevendtax[finevertnum]; fineedgenum ++) {
 
701
          Gnum                finevertend;
 
702
 
 
703
          finevertend = fineedgetax[fineedgenum];
 
704
          if (finecoartax[finevertend] == ~0) {
 
705
            finequeutab[finequeuheadval ++] = finevertend;
 
706
            finecoartax[finevertend] = -2;
 
707
          }
 
708
        }
 
709
        continue;                                 /* Skip to next vertex */
 
710
      }
 
711
 
 
712
      if (coarvertnum >= coarvertmax)             /* If coarse graph is too large       */
 
713
        break;                                    /* Return that we cannot coarsen more */
 
714
 
 
715
      finevertbst = finevertnum;                  /* No matching vertex found yet */
 
716
      fineedlobst = 0;
 
717
      finevelodlt = coarvelomax - ((finegrafptr->velotax != NULL) ? finegrafptr->velotax[finevertnum] : 1);
 
718
 
 
719
      for (fineedgenum = fineverttax[finevertnum]; /* For all adjacent vertices */
 
720
           fineedgenum < finevendtax[finevertnum]; fineedgenum ++) {
 
721
        Gnum                finevertend;
 
722
        Gnum                finecoarval;
 
723
 
 
724
        finevertend = fineedgetax[fineedgenum];
 
725
        finecoarval = finecoartax[finevertend];
 
726
 
 
727
        if (finecoarval < 0) {                    /* If vertex not matched */
 
728
          Gnum                fineedloval;
 
729
 
 
730
          fineedloval = fineedlotax[fineedgenum];
 
731
          if (finecoartax[finevertend] == ~0) {   /* If vertex not enqueued */
 
732
            finequeutab[finequeuheadval ++] = finevertend; /* Enqueue it    */
 
733
            finecoartax[finevertend] = -2;
 
734
          }
 
735
          if (((finevelotax == NULL) ||            /* And does not create overloads */
 
736
               (finevelodlt >= finevelotax[finevertend])) &&
 
737
              (fineedloval > fineedlobst)) {
 
738
            finevertbst = finevertend;            /* Get matching vertex */
 
739
            fineedlobst = fineedloval;
 
740
          }
 
741
        }
 
742
      }
 
743
 
 
744
      finecoartax[finevertnum] = finevertbst;     /* Match both vertices */
 
745
      finecoartax[finevertbst] = finevertnum;
 
746
      coarvertnum ++;                             /* One more coarse vertex created */
 
747
    }
 
748
    else {                                        /* Search for other connected component */
 
749
      Gnum                finevertbst;
 
750
 
 
751
      for ( ; finecoartax[finepermnum] >= 0; finepermnum ++) { /* Scan vertices in ascending order */
 
752
#ifdef SCOTCH_DEBUG_GRAPH2
 
753
        if (finepermnum >= finegrafptr->vertnnd) {
 
754
          errorPrint ("graphCoarsenMatchCh: internal error (1)");
 
755
          memFree    (finequeutab);
 
756
          return     (finegrafptr->vertnbr);      /* Coarsening aborted */
 
757
        }
 
758
#endif /* SCOTCH_DEBUG_GRAPH2 */
 
759
      }
 
760
#ifdef SCOTCH_DEBUG_GRAPH2
 
761
      if (finecoartax[finepermnum] != ~0) {
 
762
        errorPrint ("graphCoarsenMatchCh: internal error (2)");
 
763
        memFree    (finequeutab);
 
764
        return     (finegrafptr->vertnbr);        /* Coarsening aborted */
 
765
      }
 
766
#endif /* SCOTCH_DEBUG_GRAPH2 */
 
767
      finevertnum = finepermnum ++;               /* Start from found vertex */
 
768
 
 
769
      if (fineverttax[finevertnum] != finevendtax[finevertnum]) { /* If vertex not isolated */
 
770
        finequeutab[finequeuheadval ++] = finevertnum; /* Enqueue it for normal processing  */
 
771
        continue;                                 /* Skip to main loop to process it        */
 
772
      }
 
773
 
 
774
      finequeuheadval = ++ finequeutailval;       /* One more vertex enqueued-edqueued */
 
775
 
 
776
      if (coarvertnum >= coarvertmax)             /* If coarse graph is too large       */
 
777
        break;                                    /* Return that we cannot coarsen more */
 
778
 
 
779
      if (finequeutailval >= finegrafptr->vertnbr) /* If isolated vertex is last available vertex */
 
780
        finevertbst = finevertnum;
 
781
      else {
 
782
        for ( ; finecoartax[finepermnum] >= 0; finepermnum ++) {
 
783
#ifdef SCOTCH_DEBUG_GRAPH2
 
784
          if (finepermnum >= finegrafptr->vertnnd) {
 
785
            errorPrint ("graphCoarsenMatchCh: internal error (3)");
 
786
            memFree    (finequeutab);
 
787
            return     (finegrafptr->vertnbr);    /* Coarsening aborted */
 
788
          }
 
789
#endif /* SCOTCH_DEBUG_GRAPH2 */
 
790
        }
 
791
#ifdef SCOTCH_DEBUG_GRAPH2
 
792
        if (finecoartax[finepermnum] != ~0) {
 
793
          errorPrint ("graphCoarsenMatchCh: internal error (4)");
 
794
          memFree    (finequeutab);
 
795
          return     (finegrafptr->vertnbr);      /* Coarsening aborted */
 
796
        }
 
797
#endif /* SCOTCH_DEBUG_GRAPH2 */
 
798
        finevertbst     = finepermnum ++;         /* Get found vertex                  */
 
799
        finequeuheadval = ++ finequeutailval;     /* One more vertex enqueued-edqueued */
 
800
      }
 
801
 
 
802
      finecoartax[finevertnum] = finevertbst;     /* Match both vertices */
 
803
      finecoartax[finevertbst] = finevertnum;
 
804
      coarvertnum ++;                             /* One more coarse vertex created */
 
805
    }
 
806
  }
 
807
 
 
808
  memFree (finequeutab);
 
809
 
 
810
  return (coarvertnum);                           /* Return number of coarse vertices */
 
811
}