src/glpqmd.c
author Alpar Juttner <alpar@cs.elte.hu>
Mon, 06 Dec 2010 13:09:21 +0100
changeset 1 c445c931472f
permissions -rw-r--r--
Import glpk-4.45

- Generated files and doc/notes are removed
alpar@1
     1
/* glpqmd.c (quotient minimum degree algorithm) */
alpar@1
     2
alpar@1
     3
/***********************************************************************
alpar@1
     4
*  This code is part of GLPK (GNU Linear Programming Kit).
alpar@1
     5
*
alpar@1
     6
*  THIS CODE IS THE RESULT OF TRANSLATION OF THE FORTRAN SUBROUTINES
alpar@1
     7
*  GENQMD, QMDRCH, QMDQT, QMDUPD, AND QMDMRG FROM THE BOOK:
alpar@1
     8
*
alpar@1
     9
*  ALAN GEORGE, JOSEPH W-H LIU. COMPUTER SOLUTION OF LARGE SPARSE
alpar@1
    10
*  POSITIVE DEFINITE SYSTEMS. PRENTICE-HALL, 1981.
alpar@1
    11
*
alpar@1
    12
*  THE TRANSLATION HAS BEEN DONE WITH THE PERMISSION OF THE AUTHORS
alpar@1
    13
*  OF THE ORIGINAL FORTRAN SUBROUTINES: ALAN GEORGE AND JOSEPH LIU,
alpar@1
    14
*  UNIVERSITY OF WATERLOO, WATERLOO, ONTARIO, CANADA.
alpar@1
    15
*
alpar@1
    16
*  The translation was made by Andrew Makhorin <mao@gnu.org>.
alpar@1
    17
*
alpar@1
    18
*  GLPK is free software: you can redistribute it and/or modify it
alpar@1
    19
*  under the terms of the GNU General Public License as published by
alpar@1
    20
*  the Free Software Foundation, either version 3 of the License, or
alpar@1
    21
*  (at your option) any later version.
alpar@1
    22
*
alpar@1
    23
*  GLPK is distributed in the hope that it will be useful, but WITHOUT
alpar@1
    24
*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
alpar@1
    25
*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
alpar@1
    26
*  License for more details.
alpar@1
    27
*
alpar@1
    28
*  You should have received a copy of the GNU General Public License
alpar@1
    29
*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
alpar@1
    30
***********************************************************************/
alpar@1
    31
alpar@1
    32
#include "glpqmd.h"
alpar@1
    33
alpar@1
    34
/***********************************************************************
alpar@1
    35
*  NAME
alpar@1
    36
*
alpar@1
    37
*  genqmd - GENeral Quotient Minimum Degree algorithm
alpar@1
    38
*
alpar@1
    39
*  SYNOPSIS
alpar@1
    40
*
alpar@1
    41
*  #include "glpqmd.h"
alpar@1
    42
*  void genqmd(int *neqns, int xadj[], int adjncy[], int perm[],
alpar@1
    43
*     int invp[], int deg[], int marker[], int rchset[], int nbrhd[],
alpar@1
    44
*     int qsize[], int qlink[], int *nofsub);
alpar@1
    45
*
alpar@1
    46
*  PURPOSE
alpar@1
    47
*
alpar@1
    48
*  This routine implements the minimum degree algorithm. It makes use
alpar@1
    49
*  of the implicit representation of the elimination graph by quotient
alpar@1
    50
*  graphs, and the notion of indistinguishable nodes.
alpar@1
    51
*
alpar@1
    52
*  CAUTION
alpar@1
    53
*
alpar@1
    54
*  The adjancy vector adjncy will be destroyed.
alpar@1
    55
*
alpar@1
    56
*  INPUT PARAMETERS
alpar@1
    57
*
alpar@1
    58
*  neqns  - number of equations;
alpar@1
    59
*  (xadj, adjncy) -
alpar@1
    60
*           the adjancy structure.
alpar@1
    61
*
alpar@1
    62
*  OUTPUT PARAMETERS
alpar@1
    63
*
alpar@1
    64
*  perm   - the minimum degree ordering;
alpar@1
    65
*  invp   - the inverse of perm.
alpar@1
    66
*
alpar@1
    67
*  WORKING PARAMETERS
alpar@1
    68
*
alpar@1
    69
*  deg    - the degree vector. deg[i] is negative means node i has been
alpar@1
    70
*           numbered;
alpar@1
    71
*  marker - a marker vector, where marker[i] is negative means node i
alpar@1
    72
*           has been merged with another nodeand thus can be ignored;
alpar@1
    73
*  rchset - vector used for the reachable set;
alpar@1
    74
*  nbrhd  - vector used for neighborhood set;
alpar@1
    75
*  qsize  - vector used to store the size of indistinguishable
alpar@1
    76
*           supernodes;
alpar@1
    77
*  qlink  - vector used to store indistinguishable nodes, i, qlink[i],
alpar@1
    78
*           qlink[qlink[i]], ... are the members of the supernode
alpar@1
    79
*           represented by i.
alpar@1
    80
*
alpar@1
    81
*  PROGRAM SUBROUTINES
alpar@1
    82
*
alpar@1
    83
*  qmdrch, qmdqt, qmdupd.
alpar@1
    84
***********************************************************************/
alpar@1
    85
alpar@1
    86
void genqmd(int *_neqns, int xadj[], int adjncy[], int perm[],
alpar@1
    87
      int invp[], int deg[], int marker[], int rchset[], int nbrhd[],
alpar@1
    88
      int qsize[], int qlink[], int *_nofsub)
alpar@1
    89
{     int inode, ip, irch, j, mindeg, ndeg, nhdsze, node, np, num,
alpar@1
    90
         nump1, nxnode, rchsze, search, thresh;
alpar@1
    91
#     define neqns  (*_neqns)
alpar@1
    92
#     define nofsub (*_nofsub)
alpar@1
    93
      /* Initialize degree vector and other working variables. */
alpar@1
    94
      mindeg = neqns;
alpar@1
    95
      nofsub = 0;
alpar@1
    96
      for (node = 1; node <= neqns; node++)
alpar@1
    97
      {  perm[node] = node;
alpar@1
    98
         invp[node] = node;
alpar@1
    99
         marker[node] = 0;
alpar@1
   100
         qsize[node] = 1;
alpar@1
   101
         qlink[node] = 0;
alpar@1
   102
         ndeg = xadj[node+1] - xadj[node];
alpar@1
   103
         deg[node] = ndeg;
alpar@1
   104
         if (ndeg < mindeg) mindeg = ndeg;
alpar@1
   105
      }
alpar@1
   106
      num = 0;
alpar@1
   107
      /* Perform threshold search to get a node of min degree.
alpar@1
   108
         Variable search point to where search should start. */
alpar@1
   109
s200: search = 1;
alpar@1
   110
      thresh = mindeg;
alpar@1
   111
      mindeg = neqns;
alpar@1
   112
s300: nump1 = num + 1;
alpar@1
   113
      if (nump1 > search) search = nump1;
alpar@1
   114
      for (j = search; j <= neqns; j++)
alpar@1
   115
      {  node = perm[j];
alpar@1
   116
         if (marker[node] >= 0)
alpar@1
   117
         {  ndeg = deg[node];
alpar@1
   118
            if (ndeg <= thresh) goto s500;
alpar@1
   119
            if (ndeg < mindeg) mindeg = ndeg;
alpar@1
   120
         }
alpar@1
   121
      }
alpar@1
   122
      goto s200;
alpar@1
   123
      /* Node has minimum degree. Find its reachable sets by calling
alpar@1
   124
         qmdrch. */
alpar@1
   125
s500: search = j;
alpar@1
   126
      nofsub += deg[node];
alpar@1
   127
      marker[node] = 1;
alpar@1
   128
      qmdrch(&node, xadj, adjncy, deg, marker, &rchsze, rchset, &nhdsze,
alpar@1
   129
         nbrhd);
alpar@1
   130
      /* Eliminate all nodes indistinguishable from node. They are given
alpar@1
   131
         by node, qlink[node], ... . */
alpar@1
   132
      nxnode = node;
alpar@1
   133
s600: num++;
alpar@1
   134
      np = invp[nxnode];
alpar@1
   135
      ip = perm[num];
alpar@1
   136
      perm[np] = ip;
alpar@1
   137
      invp[ip] = np;
alpar@1
   138
      perm[num] = nxnode;
alpar@1
   139
      invp[nxnode] = num;
alpar@1
   140
      deg[nxnode] = -1;
alpar@1
   141
      nxnode = qlink[nxnode];
alpar@1
   142
      if (nxnode > 0) goto s600;
alpar@1
   143
      if (rchsze > 0)
alpar@1
   144
      {  /* Update the degrees of the nodes in the reachable set and
alpar@1
   145
            identify indistinguishable nodes. */
alpar@1
   146
         qmdupd(xadj, adjncy, &rchsze, rchset, deg, qsize, qlink,
alpar@1
   147
            marker, &rchset[rchsze+1], &nbrhd[nhdsze+1]);
alpar@1
   148
         /* Reset marker value of nodes in reach set. Update threshold
alpar@1
   149
            value for cyclic search. Also call qmdqt to form new
alpar@1
   150
            quotient graph. */
alpar@1
   151
         marker[node] = 0;
alpar@1
   152
         for (irch = 1; irch <= rchsze; irch++)
alpar@1
   153
         {  inode = rchset[irch];
alpar@1
   154
            if (marker[inode] >= 0)
alpar@1
   155
            {  marker[inode] = 0;
alpar@1
   156
               ndeg = deg[inode];
alpar@1
   157
               if (ndeg < mindeg) mindeg = ndeg;
alpar@1
   158
               if (ndeg <= thresh)
alpar@1
   159
               {  mindeg = thresh;
alpar@1
   160
                  thresh = ndeg;
alpar@1
   161
                  search = invp[inode];
alpar@1
   162
               }
alpar@1
   163
            }
alpar@1
   164
         }
alpar@1
   165
         if (nhdsze > 0)
alpar@1
   166
            qmdqt(&node, xadj, adjncy, marker, &rchsze, rchset, nbrhd);
alpar@1
   167
      }
alpar@1
   168
      if (num < neqns) goto s300;
alpar@1
   169
      return;
alpar@1
   170
#     undef neqns
alpar@1
   171
#     undef nofsub
alpar@1
   172
}
alpar@1
   173
alpar@1
   174
/***********************************************************************
alpar@1
   175
*  NAME
alpar@1
   176
*
alpar@1
   177
*  qmdrch - Quotient MD ReaCHable set
alpar@1
   178
*
alpar@1
   179
*  SYNOPSIS
alpar@1
   180
*
alpar@1
   181
*  #include "glpqmd.h"
alpar@1
   182
*  void qmdrch(int *root, int xadj[], int adjncy[], int deg[],
alpar@1
   183
*     int marker[], int *rchsze, int rchset[], int *nhdsze,
alpar@1
   184
*     int nbrhd[]);
alpar@1
   185
*
alpar@1
   186
*  PURPOSE
alpar@1
   187
*
alpar@1
   188
*  This subroutine determines the reachable set of a node through a
alpar@1
   189
*  given subset. The adjancy structure is assumed to be stored in a
alpar@1
   190
*  quotient graph format.
alpar@1
   191
* 
alpar@1
   192
*  INPUT PARAMETERS
alpar@1
   193
*
alpar@1
   194
*  root   - the given node not in the subset;
alpar@1
   195
*  (xadj, adjncy) -
alpar@1
   196
*           the adjancy structure pair;
alpar@1
   197
*  deg    - the degree vector. deg[i] < 0 means the node belongs to the
alpar@1
   198
*           given subset.
alpar@1
   199
*
alpar@1
   200
*  OUTPUT PARAMETERS
alpar@1
   201
*
alpar@1
   202
*  (rchsze, rchset) -
alpar@1
   203
*           the reachable set;
alpar@1
   204
*  (nhdsze, nbrhd) -
alpar@1
   205
*           the neighborhood set.
alpar@1
   206
*
alpar@1
   207
*  UPDATED PARAMETERS
alpar@1
   208
*
alpar@1
   209
*  marker - the marker vector for reach and nbrhd sets. > 0 means the
alpar@1
   210
*           node is in reach set. < 0 means the node has been merged
alpar@1
   211
*           with others in the quotient or it is in nbrhd set.
alpar@1
   212
***********************************************************************/
alpar@1
   213
alpar@1
   214
void qmdrch(int *_root, int xadj[], int adjncy[], int deg[],
alpar@1
   215
      int marker[], int *_rchsze, int rchset[], int *_nhdsze,
alpar@1
   216
      int nbrhd[])
alpar@1
   217
{     int i, istop, istrt, j, jstop, jstrt, nabor, node;
alpar@1
   218
#     define root   (*_root)
alpar@1
   219
#     define rchsze (*_rchsze)
alpar@1
   220
#     define nhdsze (*_nhdsze)
alpar@1
   221
      /* Loop through the neighbors of root in the quotient graph. */
alpar@1
   222
      nhdsze = 0;
alpar@1
   223
      rchsze = 0;
alpar@1
   224
      istrt = xadj[root];
alpar@1
   225
      istop = xadj[root+1] - 1;
alpar@1
   226
      if (istop < istrt) return;
alpar@1
   227
      for (i = istrt; i <= istop; i++)
alpar@1
   228
      {  nabor = adjncy[i];
alpar@1
   229
         if (nabor == 0) return;
alpar@1
   230
         if (marker[nabor] == 0)
alpar@1
   231
         {  if (deg[nabor] >= 0)
alpar@1
   232
            {  /* Include nabor into the reachable set. */
alpar@1
   233
               rchsze++;
alpar@1
   234
               rchset[rchsze] = nabor;
alpar@1
   235
               marker[nabor] = 1;
alpar@1
   236
               goto s600;
alpar@1
   237
            }
alpar@1
   238
            /* nabor has been eliminated. Find nodes reachable from
alpar@1
   239
               it. */
alpar@1
   240
            marker[nabor] = -1;
alpar@1
   241
            nhdsze++;
alpar@1
   242
            nbrhd[nhdsze] = nabor;
alpar@1
   243
s300:       jstrt = xadj[nabor];
alpar@1
   244
            jstop = xadj[nabor+1] - 1;
alpar@1
   245
            for (j = jstrt; j <= jstop; j++)
alpar@1
   246
            {  node = adjncy[j];
alpar@1
   247
               nabor = - node;
alpar@1
   248
               if (node < 0) goto s300;
alpar@1
   249
               if (node == 0) goto s600;
alpar@1
   250
               if (marker[node] == 0)
alpar@1
   251
               {  rchsze++;
alpar@1
   252
                  rchset[rchsze] = node;
alpar@1
   253
                  marker[node] = 1;
alpar@1
   254
               }
alpar@1
   255
            }
alpar@1
   256
         }
alpar@1
   257
s600:    ;
alpar@1
   258
      }
alpar@1
   259
      return;
alpar@1
   260
#     undef root
alpar@1
   261
#     undef rchsze
alpar@1
   262
#     undef nhdsze
alpar@1
   263
}
alpar@1
   264
alpar@1
   265
/***********************************************************************
alpar@1
   266
*  NAME
alpar@1
   267
*
alpar@1
   268
*  qmdqt - Quotient MD Quotient graph Transformation
alpar@1
   269
*
alpar@1
   270
*  SYNOPSIS
alpar@1
   271
*
alpar@1
   272
*  #include "glpqmd.h"
alpar@1
   273
*  void qmdqt(int *root, int xadj[], int adjncy[], int marker[],
alpar@1
   274
*     int *rchsze, int rchset[], int nbrhd[]);
alpar@1
   275
*
alpar@1
   276
*  PURPOSE
alpar@1
   277
*
alpar@1
   278
*  This subroutine performs the quotient graph transformation after a
alpar@1
   279
*  node has been eliminated.
alpar@1
   280
*
alpar@1
   281
*  INPUT PARAMETERS
alpar@1
   282
*
alpar@1
   283
*  root   - the node just eliminated. It becomes the representative of
alpar@1
   284
*           the new supernode;
alpar@1
   285
*  (xadj, adjncy) -
alpar@1
   286
*           the adjancy structure;
alpar@1
   287
*  (rchsze, rchset) -
alpar@1
   288
*           the reachable set of root in the old quotient graph;
alpar@1
   289
*  nbrhd  - the neighborhood set which will be merged with root to form
alpar@1
   290
*           the new supernode;
alpar@1
   291
*  marker - the marker vector.
alpar@1
   292
*
alpar@1
   293
*  UPDATED PARAMETERS
alpar@1
   294
*
alpar@1
   295
*  adjncy - becomes the adjncy of the quotient graph.
alpar@1
   296
***********************************************************************/
alpar@1
   297
alpar@1
   298
void qmdqt(int *_root, int xadj[], int adjncy[], int marker[],
alpar@1
   299
      int *_rchsze, int rchset[], int nbrhd[])
alpar@1
   300
{     int inhd, irch, j, jstop, jstrt, link, nabor, node;
alpar@1
   301
#     define root   (*_root)
alpar@1
   302
#     define rchsze (*_rchsze)
alpar@1
   303
      irch = 0;
alpar@1
   304
      inhd = 0;
alpar@1
   305
      node = root;
alpar@1
   306
s100: jstrt = xadj[node];
alpar@1
   307
      jstop = xadj[node+1] - 2;
alpar@1
   308
      if (jstop >= jstrt)
alpar@1
   309
      {  /* Place reach nodes into the adjacent list of node. */
alpar@1
   310
         for (j = jstrt; j <= jstop; j++)
alpar@1
   311
         {  irch++;
alpar@1
   312
            adjncy[j] = rchset[irch];
alpar@1
   313
            if (irch >= rchsze) goto s400;
alpar@1
   314
         }
alpar@1
   315
      }
alpar@1
   316
      /* Link to other space provided by the nbrhd set. */
alpar@1
   317
      link = adjncy[jstop+1];
alpar@1
   318
      node = - link;
alpar@1
   319
      if (link >= 0)
alpar@1
   320
      {  inhd++;
alpar@1
   321
         node = nbrhd[inhd];
alpar@1
   322
         adjncy[jstop+1] = - node;
alpar@1
   323
      }
alpar@1
   324
      goto s100;
alpar@1
   325
      /* All reachable nodes have been saved. End the adjacent list.
alpar@1
   326
         Add root to the neighborhood list of each node in the reach
alpar@1
   327
         set. */
alpar@1
   328
s400: adjncy[j+1] = 0;
alpar@1
   329
      for (irch = 1; irch <= rchsze; irch++)
alpar@1
   330
      {  node = rchset[irch];
alpar@1
   331
         if (marker[node] >= 0)
alpar@1
   332
         {  jstrt = xadj[node];
alpar@1
   333
            jstop = xadj[node+1] - 1;
alpar@1
   334
            for (j = jstrt; j <= jstop; j++)
alpar@1
   335
            {  nabor = adjncy[j];
alpar@1
   336
               if (marker[nabor] < 0)
alpar@1
   337
               {  adjncy[j] = root;
alpar@1
   338
                  goto s600;
alpar@1
   339
               }
alpar@1
   340
            }
alpar@1
   341
         }
alpar@1
   342
s600:    ;
alpar@1
   343
      }
alpar@1
   344
      return;
alpar@1
   345
#     undef root
alpar@1
   346
#     undef rchsze
alpar@1
   347
}
alpar@1
   348
alpar@1
   349
/***********************************************************************
alpar@1
   350
*  NAME
alpar@1
   351
*
alpar@1
   352
*  qmdupd - Quotient MD UPDate
alpar@1
   353
*
alpar@1
   354
*  SYNOPSIS
alpar@1
   355
*
alpar@1
   356
*  #include "glpqmd.h"
alpar@1
   357
*  void qmdupd(int xadj[], int adjncy[], int *nlist, int list[],
alpar@1
   358
*     int deg[], int qsize[], int qlink[], int marker[], int rchset[],
alpar@1
   359
*     int nbrhd[]);
alpar@1
   360
*
alpar@1
   361
*  PURPOSE
alpar@1
   362
*
alpar@1
   363
*  This routine performs degree update for a set of nodes in the minimum
alpar@1
   364
*  degree algorithm.
alpar@1
   365
*
alpar@1
   366
*  INPUT PARAMETERS
alpar@1
   367
*
alpar@1
   368
*  (xadj, adjncy) -
alpar@1
   369
*           the adjancy structure;
alpar@1
   370
*  (nlist, list) -
alpar@1
   371
*           the list of nodes whose degree has to be updated.
alpar@1
   372
*
alpar@1
   373
*  UPDATED PARAMETERS
alpar@1
   374
*
alpar@1
   375
*  deg    - the degree vector;
alpar@1
   376
*  qsize  - size of indistinguishable supernodes;
alpar@1
   377
*  qlink  - linked list for indistinguishable nodes;
alpar@1
   378
*  marker - used to mark those nodes in reach/nbrhd sets.
alpar@1
   379
*
alpar@1
   380
*  WORKING PARAMETERS
alpar@1
   381
*
alpar@1
   382
*  rchset - the reachable set;
alpar@1
   383
*  nbrhd  - the neighborhood set.
alpar@1
   384
*
alpar@1
   385
*  PROGRAM SUBROUTINES
alpar@1
   386
*
alpar@1
   387
*  qmdmrg.
alpar@1
   388
***********************************************************************/
alpar@1
   389
alpar@1
   390
void qmdupd(int xadj[], int adjncy[], int *_nlist, int list[],
alpar@1
   391
      int deg[], int qsize[], int qlink[], int marker[], int rchset[],
alpar@1
   392
      int nbrhd[])
alpar@1
   393
{     int deg0, deg1, il, inhd, inode, irch, j, jstop, jstrt, mark,
alpar@1
   394
         nabor, nhdsze, node, rchsze;
alpar@1
   395
#     define nlist  (*_nlist)
alpar@1
   396
      /* Find all eliminated supernodes that are adjacent to some nodes
alpar@1
   397
         in the given list. Put them into (nhdsze, nbrhd). deg0 contains
alpar@1
   398
         the number of nodes in the list. */
alpar@1
   399
      if (nlist <= 0) return;
alpar@1
   400
      deg0 = 0;
alpar@1
   401
      nhdsze = 0;
alpar@1
   402
      for (il = 1; il <= nlist; il++)
alpar@1
   403
      {  node = list[il];
alpar@1
   404
         deg0 += qsize[node];
alpar@1
   405
         jstrt = xadj[node];
alpar@1
   406
         jstop = xadj[node+1] - 1;
alpar@1
   407
         for (j = jstrt; j <= jstop; j++)
alpar@1
   408
         {  nabor = adjncy[j];
alpar@1
   409
            if (marker[nabor] == 0 && deg[nabor] < 0)
alpar@1
   410
            {  marker[nabor] = -1;
alpar@1
   411
               nhdsze++;
alpar@1
   412
               nbrhd[nhdsze] = nabor;
alpar@1
   413
            }
alpar@1
   414
         }
alpar@1
   415
      }
alpar@1
   416
      /* Merge indistinguishable nodes in the list by calling the
alpar@1
   417
         subroutine qmdmrg. */
alpar@1
   418
      if (nhdsze > 0)
alpar@1
   419
         qmdmrg(xadj, adjncy, deg, qsize, qlink, marker, &deg0, &nhdsze,
alpar@1
   420
            nbrhd, rchset, &nbrhd[nhdsze+1]);
alpar@1
   421
      /* Find the new degrees of the nodes that have not been merged. */
alpar@1
   422
      for (il = 1; il <= nlist; il++)
alpar@1
   423
      {  node = list[il];
alpar@1
   424
         mark = marker[node];
alpar@1
   425
         if (mark == 0 || mark == 1)
alpar@1
   426
         {  marker[node] = 2;
alpar@1
   427
            qmdrch(&node, xadj, adjncy, deg, marker, &rchsze, rchset,
alpar@1
   428
               &nhdsze, nbrhd);
alpar@1
   429
            deg1 = deg0;
alpar@1
   430
            if (rchsze > 0)
alpar@1
   431
            {  for (irch = 1; irch <= rchsze; irch++)
alpar@1
   432
               {  inode = rchset[irch];
alpar@1
   433
                  deg1 += qsize[inode];
alpar@1
   434
                  marker[inode] = 0;
alpar@1
   435
               }
alpar@1
   436
            }
alpar@1
   437
            deg[node] = deg1 - 1;
alpar@1
   438
            if (nhdsze > 0)
alpar@1
   439
            {  for (inhd = 1; inhd <= nhdsze; inhd++)
alpar@1
   440
               {  inode = nbrhd[inhd];
alpar@1
   441
                  marker[inode] = 0;
alpar@1
   442
               }
alpar@1
   443
            }
alpar@1
   444
         }
alpar@1
   445
      }
alpar@1
   446
      return;
alpar@1
   447
#     undef nlist
alpar@1
   448
}
alpar@1
   449
alpar@1
   450
/***********************************************************************
alpar@1
   451
*  NAME
alpar@1
   452
*
alpar@1
   453
*  qmdmrg - Quotient MD MeRGe
alpar@1
   454
*
alpar@1
   455
*  SYNOPSIS
alpar@1
   456
*
alpar@1
   457
*  #include "qmdmrg.h"
alpar@1
   458
*  void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[],
alpar@1
   459
*     int qlink[], int marker[], int *deg0, int *nhdsze, int nbrhd[],
alpar@1
   460
*     int rchset[], int ovrlp[]);
alpar@1
   461
*
alpar@1
   462
*  PURPOSE
alpar@1
   463
*
alpar@1
   464
*  This routine merges indistinguishable nodes in the minimum degree
alpar@1
   465
*  ordering algorithm. It also computes the new degrees of these new
alpar@1
   466
*  supernodes.
alpar@1
   467
*
alpar@1
   468
*  INPUT PARAMETERS
alpar@1
   469
*
alpar@1
   470
*  (xadj, adjncy) -
alpar@1
   471
*           the adjancy structure;
alpar@1
   472
*  deg0   - the number of nodes in the given set;
alpar@1
   473
*  (nhdsze, nbrhd) -
alpar@1
   474
*           the set of eliminated supernodes adjacent to some nodes in
alpar@1
   475
*           the set.
alpar@1
   476
*
alpar@1
   477
*  UPDATED PARAMETERS
alpar@1
   478
*
alpar@1
   479
*  deg    - the degree vector;
alpar@1
   480
*  qsize  - size of indistinguishable nodes;
alpar@1
   481
*  qlink  - linked list for indistinguishable nodes;
alpar@1
   482
*  marker - the given set is given by those nodes with marker value set
alpar@1
   483
*           to 1. Those nodes with degree updated will have marker value
alpar@1
   484
*           set to 2.
alpar@1
   485
*
alpar@1
   486
*  WORKING PARAMETERS
alpar@1
   487
*
alpar@1
   488
*  rchset - the reachable set;
alpar@1
   489
*  ovrlp  - temp vector to store the intersection of two reachable sets.
alpar@1
   490
***********************************************************************/
alpar@1
   491
alpar@1
   492
void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[],
alpar@1
   493
      int qlink[], int marker[], int *_deg0, int *_nhdsze, int nbrhd[],
alpar@1
   494
      int rchset[], int ovrlp[])
alpar@1
   495
{     int deg1, head, inhd, iov, irch, j, jstop, jstrt, link, lnode,
alpar@1
   496
         mark, mrgsze, nabor, node, novrlp, rchsze, root;
alpar@1
   497
#     define deg0   (*_deg0)
alpar@1
   498
#     define nhdsze (*_nhdsze)
alpar@1
   499
      /* Initialization. */
alpar@1
   500
      if (nhdsze <= 0) return;
alpar@1
   501
      for (inhd = 1; inhd <= nhdsze; inhd++)
alpar@1
   502
      {  root = nbrhd[inhd];
alpar@1
   503
         marker[root] = 0;
alpar@1
   504
      }
alpar@1
   505
      /* Loop through each eliminated supernode in the set
alpar@1
   506
         (nhdsze, nbrhd). */
alpar@1
   507
      for (inhd = 1; inhd <= nhdsze; inhd++)
alpar@1
   508
      {  root = nbrhd[inhd];
alpar@1
   509
         marker[root] = -1;
alpar@1
   510
         rchsze = 0;
alpar@1
   511
         novrlp = 0;
alpar@1
   512
         deg1 = 0;
alpar@1
   513
s200:    jstrt = xadj[root];
alpar@1
   514
         jstop = xadj[root+1] - 1;
alpar@1
   515
         /* Determine the reachable set and its intersection with the
alpar@1
   516
            input reachable set. */
alpar@1
   517
         for (j = jstrt; j <= jstop; j++)
alpar@1
   518
         {  nabor = adjncy[j];
alpar@1
   519
            root = - nabor;
alpar@1
   520
            if (nabor < 0) goto s200;
alpar@1
   521
            if (nabor == 0) break;
alpar@1
   522
            mark = marker[nabor];
alpar@1
   523
            if (mark == 0)
alpar@1
   524
            {  rchsze++;
alpar@1
   525
               rchset[rchsze] = nabor;
alpar@1
   526
               deg1 += qsize[nabor];
alpar@1
   527
               marker[nabor] = 1;
alpar@1
   528
            }
alpar@1
   529
            else if (mark == 1)
alpar@1
   530
            {  novrlp++;
alpar@1
   531
               ovrlp[novrlp] = nabor;
alpar@1
   532
               marker[nabor] = 2;
alpar@1
   533
            }
alpar@1
   534
         }
alpar@1
   535
         /* From the overlapped set, determine the nodes that can be
alpar@1
   536
            merged together. */
alpar@1
   537
         head = 0;
alpar@1
   538
         mrgsze = 0;
alpar@1
   539
         for (iov = 1; iov <= novrlp; iov++)
alpar@1
   540
         {  node = ovrlp[iov];
alpar@1
   541
            jstrt = xadj[node];
alpar@1
   542
            jstop = xadj[node+1] - 1;
alpar@1
   543
            for (j = jstrt; j <= jstop; j++)
alpar@1
   544
            {  nabor = adjncy[j];
alpar@1
   545
               if (marker[nabor] == 0)
alpar@1
   546
               {  marker[node] = 1;
alpar@1
   547
                  goto s1100;
alpar@1
   548
               }
alpar@1
   549
            }
alpar@1
   550
            /* Node belongs to the new merged supernode. Update the
alpar@1
   551
               vectors qlink and qsize. */
alpar@1
   552
            mrgsze += qsize[node];
alpar@1
   553
            marker[node] = -1;
alpar@1
   554
            lnode = node;
alpar@1
   555
s900:       link = qlink[lnode];
alpar@1
   556
            if (link > 0)
alpar@1
   557
            {  lnode = link;
alpar@1
   558
               goto s900;
alpar@1
   559
            }
alpar@1
   560
            qlink[lnode] = head;
alpar@1
   561
            head = node;
alpar@1
   562
s1100:      ;
alpar@1
   563
         }
alpar@1
   564
         if (head > 0)
alpar@1
   565
         {  qsize[head] = mrgsze;
alpar@1
   566
            deg[head] = deg0 + deg1 - 1;
alpar@1
   567
            marker[head] = 2;
alpar@1
   568
         }
alpar@1
   569
         /* Reset marker values. */
alpar@1
   570
         root = nbrhd[inhd];
alpar@1
   571
         marker[root] = 0;
alpar@1
   572
         if (rchsze > 0)
alpar@1
   573
         {  for (irch = 1; irch <= rchsze; irch++)
alpar@1
   574
            {  node = rchset[irch];
alpar@1
   575
               marker[node] = 0;
alpar@1
   576
            }
alpar@1
   577
         }
alpar@1
   578
      }
alpar@1
   579
      return;
alpar@1
   580
#     undef deg0
alpar@1
   581
#     undef nhdsze
alpar@1
   582
}
alpar@1
   583
alpar@1
   584
/* eof */