src/glpapi16.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
/* glpapi16.c (graph and network analysis routines) */
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
*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
alpar@1
     7
*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
alpar@1
     8
*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
alpar@1
     9
*  E-mail: <mao@gnu.org>.
alpar@1
    10
*
alpar@1
    11
*  GLPK is free software: you can redistribute it and/or modify it
alpar@1
    12
*  under the terms of the GNU General Public License as published by
alpar@1
    13
*  the Free Software Foundation, either version 3 of the License, or
alpar@1
    14
*  (at your option) any later version.
alpar@1
    15
*
alpar@1
    16
*  GLPK is distributed in the hope that it will be useful, but WITHOUT
alpar@1
    17
*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
alpar@1
    18
*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
alpar@1
    19
*  License for more details.
alpar@1
    20
*
alpar@1
    21
*  You should have received a copy of the GNU General Public License
alpar@1
    22
*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
alpar@1
    23
***********************************************************************/
alpar@1
    24
alpar@1
    25
#include "glpapi.h"
alpar@1
    26
#include "glpnet.h"
alpar@1
    27
alpar@1
    28
/***********************************************************************
alpar@1
    29
*  NAME
alpar@1
    30
*
alpar@1
    31
*  glp_weak_comp - find all weakly connected components of graph
alpar@1
    32
*
alpar@1
    33
*  SYNOPSIS
alpar@1
    34
*
alpar@1
    35
*  int glp_weak_comp(glp_graph *G, int v_num);
alpar@1
    36
*
alpar@1
    37
*  DESCRIPTION
alpar@1
    38
*
alpar@1
    39
*  The routine glp_weak_comp finds all weakly connected components of
alpar@1
    40
*  the specified graph.
alpar@1
    41
*
alpar@1
    42
*  The parameter v_num specifies an offset of the field of type int
alpar@1
    43
*  in the vertex data block, to which the routine stores the number of
alpar@1
    44
*  a (weakly) connected component containing that vertex. If v_num < 0,
alpar@1
    45
*  no component numbers are stored.
alpar@1
    46
*
alpar@1
    47
*  The components are numbered in arbitrary order from 1 to nc, where
alpar@1
    48
*  nc is the total number of components found, 0 <= nc <= |V|.
alpar@1
    49
*
alpar@1
    50
*  RETURNS
alpar@1
    51
*
alpar@1
    52
*  The routine returns nc, the total number of components found. */
alpar@1
    53
alpar@1
    54
int glp_weak_comp(glp_graph *G, int v_num)
alpar@1
    55
{     glp_vertex *v;
alpar@1
    56
      glp_arc *a;
alpar@1
    57
      int f, i, j, nc, nv, pos1, pos2, *prev, *next, *list;
alpar@1
    58
      if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
alpar@1
    59
         xerror("glp_weak_comp: v_num = %d; invalid offset\n", v_num);
alpar@1
    60
      nv = G->nv;
alpar@1
    61
      if (nv == 0)
alpar@1
    62
      {  nc = 0;
alpar@1
    63
         goto done;
alpar@1
    64
      }
alpar@1
    65
      /* allocate working arrays */
alpar@1
    66
      prev = xcalloc(1+nv, sizeof(int));
alpar@1
    67
      next = xcalloc(1+nv, sizeof(int));
alpar@1
    68
      list = xcalloc(1+nv, sizeof(int));
alpar@1
    69
      /* if vertex i is unlabelled, prev[i] is the index of previous
alpar@1
    70
         unlabelled vertex, and next[i] is the index of next unlabelled
alpar@1
    71
         vertex; if vertex i is labelled, then prev[i] < 0, and next[i]
alpar@1
    72
         is the connected component number */
alpar@1
    73
      /* initially all vertices are unlabelled */
alpar@1
    74
      f = 1;
alpar@1
    75
      for (i = 1; i <= nv; i++)
alpar@1
    76
         prev[i] = i - 1, next[i] = i + 1;
alpar@1
    77
      next[nv] = 0;
alpar@1
    78
      /* main loop (until all vertices have been labelled) */
alpar@1
    79
      nc = 0;
alpar@1
    80
      while (f != 0)
alpar@1
    81
      {  /* take an unlabelled vertex */
alpar@1
    82
         i = f;
alpar@1
    83
         /* and remove it from the list of unlabelled vertices */
alpar@1
    84
         f = next[i];
alpar@1
    85
         if (f != 0) prev[f] = 0;
alpar@1
    86
         /* label the vertex; it begins a new component */
alpar@1
    87
         prev[i] = -1, next[i] = ++nc;
alpar@1
    88
         /* breadth first search */
alpar@1
    89
         list[1] = i, pos1 = pos2 = 1;
alpar@1
    90
         while (pos1 <= pos2)
alpar@1
    91
         {  /* dequeue vertex i */
alpar@1
    92
            i = list[pos1++];
alpar@1
    93
            /* consider all arcs incoming to vertex i */
alpar@1
    94
            for (a = G->v[i]->in; a != NULL; a = a->h_next)
alpar@1
    95
            {  /* vertex j is adjacent to vertex i */
alpar@1
    96
               j = a->tail->i;
alpar@1
    97
               if (prev[j] >= 0)
alpar@1
    98
               {  /* vertex j is unlabelled */
alpar@1
    99
                  /* remove it from the list of unlabelled vertices */
alpar@1
   100
                  if (prev[j] == 0)
alpar@1
   101
                     f = next[j];
alpar@1
   102
                  else
alpar@1
   103
                     next[prev[j]] = next[j];
alpar@1
   104
                  if (next[j] == 0)
alpar@1
   105
                     ;
alpar@1
   106
                  else
alpar@1
   107
                     prev[next[j]] = prev[j];
alpar@1
   108
                  /* label the vertex */
alpar@1
   109
                  prev[j] = -1, next[j] = nc;
alpar@1
   110
                  /* and enqueue it for further consideration */
alpar@1
   111
                  list[++pos2] = j;
alpar@1
   112
               }
alpar@1
   113
            }
alpar@1
   114
            /* consider all arcs outgoing from vertex i */
alpar@1
   115
            for (a = G->v[i]->out; a != NULL; a = a->t_next)
alpar@1
   116
            {  /* vertex j is adjacent to vertex i */
alpar@1
   117
               j = a->head->i;
alpar@1
   118
               if (prev[j] >= 0)
alpar@1
   119
               {  /* vertex j is unlabelled */
alpar@1
   120
                  /* remove it from the list of unlabelled vertices */
alpar@1
   121
                  if (prev[j] == 0)
alpar@1
   122
                     f = next[j];
alpar@1
   123
                  else
alpar@1
   124
                     next[prev[j]] = next[j];
alpar@1
   125
                  if (next[j] == 0)
alpar@1
   126
                     ;
alpar@1
   127
                  else
alpar@1
   128
                     prev[next[j]] = prev[j];
alpar@1
   129
                  /* label the vertex */
alpar@1
   130
                  prev[j] = -1, next[j] = nc;
alpar@1
   131
                  /* and enqueue it for further consideration */
alpar@1
   132
                  list[++pos2] = j;
alpar@1
   133
               }
alpar@1
   134
            }
alpar@1
   135
         }
alpar@1
   136
      }
alpar@1
   137
      /* store component numbers */
alpar@1
   138
      if (v_num >= 0)
alpar@1
   139
      {  for (i = 1; i <= nv; i++)
alpar@1
   140
         {  v = G->v[i];
alpar@1
   141
            memcpy((char *)v->data + v_num, &next[i], sizeof(int));
alpar@1
   142
         }
alpar@1
   143
      }
alpar@1
   144
      /* free working arrays */
alpar@1
   145
      xfree(prev);
alpar@1
   146
      xfree(next);
alpar@1
   147
      xfree(list);
alpar@1
   148
done: return nc;
alpar@1
   149
}
alpar@1
   150
alpar@1
   151
/***********************************************************************
alpar@1
   152
*  NAME
alpar@1
   153
*
alpar@1
   154
*  glp_strong_comp - find all strongly connected components of graph
alpar@1
   155
*
alpar@1
   156
*  SYNOPSIS
alpar@1
   157
*
alpar@1
   158
*  int glp_strong_comp(glp_graph *G, int v_num);
alpar@1
   159
*
alpar@1
   160
*  DESCRIPTION
alpar@1
   161
*
alpar@1
   162
*  The routine glp_strong_comp finds all strongly connected components
alpar@1
   163
*  of the specified graph.
alpar@1
   164
*
alpar@1
   165
*  The parameter v_num specifies an offset of the field of type int
alpar@1
   166
*  in the vertex data block, to which the routine stores the number of
alpar@1
   167
*  a strongly connected component containing that vertex. If v_num < 0,
alpar@1
   168
*  no component numbers are stored.
alpar@1
   169
*
alpar@1
   170
*  The components are numbered in arbitrary order from 1 to nc, where
alpar@1
   171
*  nc is the total number of components found, 0 <= nc <= |V|. However,
alpar@1
   172
*  the component numbering has the property that for every arc (i->j)
alpar@1
   173
*  in the graph the condition num(i) >= num(j) holds.
alpar@1
   174
*
alpar@1
   175
*  RETURNS
alpar@1
   176
*
alpar@1
   177
*  The routine returns nc, the total number of components found. */
alpar@1
   178
alpar@1
   179
int glp_strong_comp(glp_graph *G, int v_num)
alpar@1
   180
{     glp_vertex *v;
alpar@1
   181
      glp_arc *a;
alpar@1
   182
      int i, k, last, n, na, nc, *icn, *ip, *lenr, *ior, *ib, *lowl,
alpar@1
   183
         *numb, *prev;
alpar@1
   184
      if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
alpar@1
   185
         xerror("glp_strong_comp: v_num = %d; invalid offset\n",
alpar@1
   186
            v_num);
alpar@1
   187
      n = G->nv;
alpar@1
   188
      if (n == 0)
alpar@1
   189
      {  nc = 0;
alpar@1
   190
         goto done;
alpar@1
   191
      }
alpar@1
   192
      na = G->na;
alpar@1
   193
      icn = xcalloc(1+na, sizeof(int));
alpar@1
   194
      ip = xcalloc(1+n, sizeof(int));
alpar@1
   195
      lenr = xcalloc(1+n, sizeof(int));
alpar@1
   196
      ior = xcalloc(1+n, sizeof(int));
alpar@1
   197
      ib = xcalloc(1+n, sizeof(int));
alpar@1
   198
      lowl = xcalloc(1+n, sizeof(int));
alpar@1
   199
      numb = xcalloc(1+n, sizeof(int));
alpar@1
   200
      prev = xcalloc(1+n, sizeof(int));
alpar@1
   201
      k = 1;
alpar@1
   202
      for (i = 1; i <= n; i++)
alpar@1
   203
      {  v = G->v[i];
alpar@1
   204
         ip[i] = k;
alpar@1
   205
         for (a = v->out; a != NULL; a = a->t_next)
alpar@1
   206
            icn[k++] = a->head->i;
alpar@1
   207
         lenr[i] = k - ip[i];
alpar@1
   208
      }
alpar@1
   209
      xassert(na == k-1);
alpar@1
   210
      nc = mc13d(n, icn, ip, lenr, ior, ib, lowl, numb, prev);
alpar@1
   211
      if (v_num >= 0)
alpar@1
   212
      {  xassert(ib[1] == 1);
alpar@1
   213
         for (k = 1; k <= nc; k++)
alpar@1
   214
         {  last = (k < nc ? ib[k+1] : n+1);
alpar@1
   215
            xassert(ib[k] < last);
alpar@1
   216
            for (i = ib[k]; i < last; i++)
alpar@1
   217
            {  v = G->v[ior[i]];
alpar@1
   218
               memcpy((char *)v->data + v_num, &k, sizeof(int));
alpar@1
   219
            }
alpar@1
   220
         }
alpar@1
   221
      }
alpar@1
   222
      xfree(icn);
alpar@1
   223
      xfree(ip);
alpar@1
   224
      xfree(lenr);
alpar@1
   225
      xfree(ior);
alpar@1
   226
      xfree(ib);
alpar@1
   227
      xfree(lowl);
alpar@1
   228
      xfree(numb);
alpar@1
   229
      xfree(prev);
alpar@1
   230
done: return nc;
alpar@1
   231
}
alpar@1
   232
alpar@1
   233
/***********************************************************************
alpar@1
   234
*  NAME
alpar@1
   235
*
alpar@1
   236
*  glp_top_sort - topological sorting of acyclic digraph
alpar@1
   237
*
alpar@1
   238
*  SYNOPSIS
alpar@1
   239
*
alpar@1
   240
*  int glp_top_sort(glp_graph *G, int v_num);
alpar@1
   241
*
alpar@1
   242
*  DESCRIPTION
alpar@1
   243
*
alpar@1
   244
*  The routine glp_top_sort performs topological sorting of vertices of
alpar@1
   245
*  the specified acyclic digraph.
alpar@1
   246
*
alpar@1
   247
*  The parameter v_num specifies an offset of the field of type int in
alpar@1
   248
*  the vertex data block, to which the routine stores the vertex number
alpar@1
   249
*  assigned. If v_num < 0, vertex numbers are not stored.
alpar@1
   250
*
alpar@1
   251
*  The vertices are numbered from 1 to n, where n is the total number
alpar@1
   252
*  of vertices in the graph. The vertex numbering has the property that
alpar@1
   253
*  for every arc (i->j) in the graph the condition num(i) < num(j)
alpar@1
   254
*  holds. Special case num(i) = 0 means that vertex i is not assigned a
alpar@1
   255
*  number, because the graph is *not* acyclic.
alpar@1
   256
*
alpar@1
   257
*  RETURNS
alpar@1
   258
*
alpar@1
   259
*  If the graph is acyclic and therefore all the vertices have been
alpar@1
   260
*  assigned numbers, the routine glp_top_sort returns zero. Otherwise,
alpar@1
   261
*  if the graph is not acyclic, the routine returns the number of
alpar@1
   262
*  vertices which have not been numbered, i.e. for which num(i) = 0. */
alpar@1
   263
alpar@1
   264
static int top_sort(glp_graph *G, int num[])
alpar@1
   265
{     glp_arc *a;
alpar@1
   266
      int i, j, cnt, top, *stack, *indeg;
alpar@1
   267
      /* allocate working arrays */
alpar@1
   268
      indeg = xcalloc(1+G->nv, sizeof(int));
alpar@1
   269
      stack = xcalloc(1+G->nv, sizeof(int));
alpar@1
   270
      /* determine initial indegree of each vertex; push into the stack
alpar@1
   271
         the vertices having zero indegree */
alpar@1
   272
      top = 0;
alpar@1
   273
      for (i = 1; i <= G->nv; i++)
alpar@1
   274
      {  num[i] = indeg[i] = 0;
alpar@1
   275
         for (a = G->v[i]->in; a != NULL; a = a->h_next)
alpar@1
   276
            indeg[i]++;
alpar@1
   277
         if (indeg[i] == 0)
alpar@1
   278
            stack[++top] = i;
alpar@1
   279
      }
alpar@1
   280
      /* assign numbers to vertices in the sorted order */
alpar@1
   281
      cnt = 0;
alpar@1
   282
      while (top > 0)
alpar@1
   283
      {  /* pull vertex i from the stack */
alpar@1
   284
         i = stack[top--];
alpar@1
   285
         /* it has zero indegree in the current graph */
alpar@1
   286
         xassert(indeg[i] == 0);
alpar@1
   287
         /* so assign it a next number */
alpar@1
   288
         xassert(num[i] == 0);
alpar@1
   289
         num[i] = ++cnt;
alpar@1
   290
         /* remove vertex i from the current graph, update indegree of
alpar@1
   291
            its adjacent vertices, and push into the stack new vertices
alpar@1
   292
            whose indegree becomes zero */
alpar@1
   293
         for (a = G->v[i]->out; a != NULL; a = a->t_next)
alpar@1
   294
         {  j = a->head->i;
alpar@1
   295
            /* there exists arc (i->j) in the graph */
alpar@1
   296
            xassert(indeg[j] > 0);
alpar@1
   297
            indeg[j]--;
alpar@1
   298
            if (indeg[j] == 0)
alpar@1
   299
               stack[++top] = j;
alpar@1
   300
         }
alpar@1
   301
      }
alpar@1
   302
      /* free working arrays */
alpar@1
   303
      xfree(indeg);
alpar@1
   304
      xfree(stack);
alpar@1
   305
      return G->nv - cnt;
alpar@1
   306
}
alpar@1
   307
alpar@1
   308
int glp_top_sort(glp_graph *G, int v_num)
alpar@1
   309
{     glp_vertex *v;
alpar@1
   310
      int i, cnt, *num;
alpar@1
   311
      if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
alpar@1
   312
         xerror("glp_top_sort: v_num = %d; invalid offset\n", v_num);
alpar@1
   313
      if (G->nv == 0)
alpar@1
   314
      {  cnt = 0;
alpar@1
   315
         goto done;
alpar@1
   316
      }
alpar@1
   317
      num = xcalloc(1+G->nv, sizeof(int));
alpar@1
   318
      cnt = top_sort(G, num);
alpar@1
   319
      if (v_num >= 0)
alpar@1
   320
      {  for (i = 1; i <= G->nv; i++)
alpar@1
   321
         {  v = G->v[i];
alpar@1
   322
            memcpy((char *)v->data + v_num, &num[i], sizeof(int));
alpar@1
   323
         }
alpar@1
   324
      }
alpar@1
   325
      xfree(num);
alpar@1
   326
done: return cnt;
alpar@1
   327
}
alpar@1
   328
alpar@1
   329
/* eof */