src/glpnet09.c
author Alpar Juttner <alpar@cs.elte.hu>
Sun, 05 Dec 2010 17:35:23 +0100
changeset 2 4c8956a7bdf4
permissions -rw-r--r--
Set up CMAKE build environment
alpar@1
     1
/* glpnet09.c */
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
*  kellerman - cover edges by cliques with Kellerman's heuristic
alpar@1
    32
*
alpar@1
    33
*  SYNOPSIS
alpar@1
    34
*
alpar@1
    35
*  #include "glpnet.h"
alpar@1
    36
*  int kellerman(int n, int (*func)(void *info, int i, int ind[]),
alpar@1
    37
*     void *info, glp_graph *H);
alpar@1
    38
*
alpar@1
    39
*  DESCRIPTION
alpar@1
    40
*
alpar@1
    41
*  The routine kellerman implements Kellerman's heuristic algorithm
alpar@1
    42
*  to find a minimal set of cliques which cover all edges of specified
alpar@1
    43
*  graph G = (V, E).
alpar@1
    44
*
alpar@1
    45
*  The parameter n specifies the number of vertices |V|, n >= 0.
alpar@1
    46
*
alpar@1
    47
*  Formal routine func specifies the set of edges E in the following
alpar@1
    48
*  way. Running the routine kellerman calls the routine func and passes
alpar@1
    49
*  to it parameter i, which is the number of some vertex, 1 <= i <= n.
alpar@1
    50
*  In response the routine func should store numbers of all vertices
alpar@1
    51
*  adjacent to vertex i to locations ind[1], ind[2], ..., ind[len] and
alpar@1
    52
*  return the value of len, which is the number of adjacent vertices,
alpar@1
    53
*  0 <= len <= n. Self-loops are allowed, but ignored. Multiple edges
alpar@1
    54
*  are not allowed.
alpar@1
    55
*
alpar@1
    56
*  The parameter info is a transit pointer (magic cookie) passed to the
alpar@1
    57
*  formal routine func as its first parameter.
alpar@1
    58
*
alpar@1
    59
*  The result provided by the routine kellerman is the bipartite graph
alpar@1
    60
*  H = (V union C, F), which defines the covering found. (The program
alpar@1
    61
*  object of type glp_graph specified by the parameter H should be
alpar@1
    62
*  previously created with the routine glp_create_graph. On entry the
alpar@1
    63
*  routine kellerman erases the content of this object with the routine
alpar@1
    64
*  glp_erase_graph.) Vertices of first part V correspond to vertices of
alpar@1
    65
*  the graph G and have the same ordinal numbers 1, 2, ..., n. Vertices
alpar@1
    66
*  of second part C correspond to cliques and have ordinal numbers
alpar@1
    67
*  n+1, n+2, ..., n+k, where k is the total number of cliques in the
alpar@1
    68
*  edge covering found. Every edge f in F in the program object H is
alpar@1
    69
*  represented as arc f = (i->j), where i in V and j in C, which means
alpar@1
    70
*  that vertex i of the graph G is in clique C[j], 1 <= j <= k. (Thus,
alpar@1
    71
*  if two vertices of the graph G are in the same clique, these vertices
alpar@1
    72
*  are adjacent in G, and corresponding edge is covered by that clique.)
alpar@1
    73
*
alpar@1
    74
*  RETURNS
alpar@1
    75
*
alpar@1
    76
*  The routine Kellerman returns k, the total number of cliques in the
alpar@1
    77
*  edge covering found.
alpar@1
    78
*
alpar@1
    79
*  REFERENCE
alpar@1
    80
*
alpar@1
    81
*  For more details see: glpk/doc/notes/keller.pdf (in Russian). */
alpar@1
    82
alpar@1
    83
struct set
alpar@1
    84
{     /* set of vertices */
alpar@1
    85
      int size;
alpar@1
    86
      /* size (cardinality) of the set, 0 <= card <= n */
alpar@1
    87
      int *list; /* int list[1+n]; */
alpar@1
    88
      /* the set contains vertices list[1,...,size] */
alpar@1
    89
      int *pos; /* int pos[1+n]; */
alpar@1
    90
      /* pos[i] > 0 means that vertex i is in the set and
alpar@1
    91
         list[pos[i]] = i; pos[i] = 0 means that vertex i is not in
alpar@1
    92
         the set */
alpar@1
    93
};
alpar@1
    94
alpar@1
    95
int kellerman(int n, int (*func)(void *info, int i, int ind[]),
alpar@1
    96
      void *info, void /* glp_graph */ *H_)
alpar@1
    97
{     glp_graph *H = H_;
alpar@1
    98
      struct set W_, *W = &W_, V_, *V = &V_;
alpar@1
    99
      glp_arc *a;
alpar@1
   100
      int i, j, k, m, t, len, card, best;
alpar@1
   101
      xassert(n >= 0);
alpar@1
   102
      /* H := (V, 0; 0), where V is the set of vertices of graph G */
alpar@1
   103
      glp_erase_graph(H, H->v_size, H->a_size);
alpar@1
   104
      glp_add_vertices(H, n);
alpar@1
   105
      /* W := 0 */
alpar@1
   106
      W->size = 0;
alpar@1
   107
      W->list = xcalloc(1+n, sizeof(int));
alpar@1
   108
      W->pos = xcalloc(1+n, sizeof(int));
alpar@1
   109
      memset(&W->pos[1], 0, sizeof(int) * n);
alpar@1
   110
      /* V := 0 */
alpar@1
   111
      V->size = 0;
alpar@1
   112
      V->list = xcalloc(1+n, sizeof(int));
alpar@1
   113
      V->pos = xcalloc(1+n, sizeof(int));
alpar@1
   114
      memset(&V->pos[1], 0, sizeof(int) * n);
alpar@1
   115
      /* main loop */
alpar@1
   116
      for (i = 1; i <= n; i++)
alpar@1
   117
      {  /* W must be empty */
alpar@1
   118
         xassert(W->size == 0);
alpar@1
   119
         /* W := { j : i > j and (i,j) in E } */
alpar@1
   120
         len = func(info, i, W->list);
alpar@1
   121
         xassert(0 <= len && len <= n);
alpar@1
   122
         for (t = 1; t <= len; t++)
alpar@1
   123
         {  j = W->list[t];
alpar@1
   124
            xassert(1 <= j && j <= n);
alpar@1
   125
            if (j >= i) continue;
alpar@1
   126
            xassert(W->pos[j] == 0);
alpar@1
   127
            W->list[++W->size] = j, W->pos[j] = W->size;
alpar@1
   128
         }
alpar@1
   129
         /* on i-th iteration we need to cover edges (i,j) for all
alpar@1
   130
            j in W */
alpar@1
   131
         /* if W is empty, it is a special case */
alpar@1
   132
         if (W->size == 0)
alpar@1
   133
         {  /* set k := k + 1 and create new clique C[k] = { i } */
alpar@1
   134
            k = glp_add_vertices(H, 1) - n;
alpar@1
   135
            glp_add_arc(H, i, n + k);
alpar@1
   136
            continue;
alpar@1
   137
         }
alpar@1
   138
         /* try to include vertex i into existing cliques */
alpar@1
   139
         /* V must be empty */
alpar@1
   140
         xassert(V->size == 0);
alpar@1
   141
         /* k is the number of cliques found so far */
alpar@1
   142
         k = H->nv - n;
alpar@1
   143
         for (m = 1; m <= k; m++)
alpar@1
   144
         {  /* do while V != W; since here V is within W, we can use
alpar@1
   145
               equivalent condition: do while |V| < |W| */
alpar@1
   146
            if (V->size == W->size) break;
alpar@1
   147
            /* check if C[m] is within W */
alpar@1
   148
            for (a = H->v[n + m]->in; a != NULL; a = a->h_next)
alpar@1
   149
            {  j = a->tail->i;
alpar@1
   150
               if (W->pos[j] == 0) break;
alpar@1
   151
            }
alpar@1
   152
            if (a != NULL) continue;
alpar@1
   153
            /* C[m] is within W, expand clique C[m] with vertex i */
alpar@1
   154
            /* C[m] := C[m] union {i} */
alpar@1
   155
            glp_add_arc(H, i, n + m);
alpar@1
   156
            /* V is a set of vertices whose incident edges are already
alpar@1
   157
               covered by existing cliques */
alpar@1
   158
            /* V := V union C[m] */
alpar@1
   159
            for (a = H->v[n + m]->in; a != NULL; a = a->h_next)
alpar@1
   160
            {  j = a->tail->i;
alpar@1
   161
               if (V->pos[j] == 0)
alpar@1
   162
                  V->list[++V->size] = j, V->pos[j] = V->size;
alpar@1
   163
            }
alpar@1
   164
         }
alpar@1
   165
         /* remove from set W the vertices whose incident edges are
alpar@1
   166
            already covered by existing cliques */
alpar@1
   167
         /* W := W \ V, V := 0 */
alpar@1
   168
         for (t = 1; t <= V->size; t++)
alpar@1
   169
         {  j = V->list[t], V->pos[j] = 0;
alpar@1
   170
            if (W->pos[j] != 0)
alpar@1
   171
            {  /* remove vertex j from W */
alpar@1
   172
               if (W->pos[j] != W->size)
alpar@1
   173
               {  int jj = W->list[W->size];
alpar@1
   174
                  W->list[W->pos[j]] = jj;
alpar@1
   175
                  W->pos[jj] = W->pos[j];
alpar@1
   176
               }
alpar@1
   177
               W->size--, W->pos[j] = 0;
alpar@1
   178
            }
alpar@1
   179
         }
alpar@1
   180
         V->size = 0;
alpar@1
   181
         /* now set W contains only vertices whose incident edges are
alpar@1
   182
            still not covered by existing cliques; create new cliques
alpar@1
   183
            to cover remaining edges until set W becomes empty */
alpar@1
   184
         while (W->size > 0)
alpar@1
   185
         {  /* find clique C[m], 1 <= m <= k, which shares maximal
alpar@1
   186
               number of vertices with W; to break ties choose clique
alpar@1
   187
               having smallest number m */
alpar@1
   188
            m = 0, best = -1;
alpar@1
   189
            k = H->nv - n;
alpar@1
   190
            for (t = 1; t <= k; t++)
alpar@1
   191
            {  /* compute cardinality of intersection of W and C[t] */
alpar@1
   192
               card = 0;
alpar@1
   193
               for (a = H->v[n + t]->in; a != NULL; a = a->h_next)
alpar@1
   194
               {  j = a->tail->i;
alpar@1
   195
                  if (W->pos[j] != 0) card++;
alpar@1
   196
               }
alpar@1
   197
               if (best < card)
alpar@1
   198
                  m = t, best = card;
alpar@1
   199
            }
alpar@1
   200
            xassert(m > 0);
alpar@1
   201
            /* set k := k + 1 and create new clique:
alpar@1
   202
               C[k] := (W intersect C[m]) union { i }, which covers all
alpar@1
   203
               edges incident to vertices from (W intersect C[m]) */
alpar@1
   204
            k = glp_add_vertices(H, 1) - n;
alpar@1
   205
            for (a = H->v[n + m]->in; a != NULL; a = a->h_next)
alpar@1
   206
            {  j = a->tail->i;
alpar@1
   207
               if (W->pos[j] != 0)
alpar@1
   208
               {  /* vertex j is in both W and C[m]; include it in new
alpar@1
   209
                     clique C[k] */
alpar@1
   210
                  glp_add_arc(H, j, n + k);
alpar@1
   211
                  /* remove vertex j from W, since edge (i,j) will be
alpar@1
   212
                     covered by new clique C[k] */
alpar@1
   213
                  if (W->pos[j] != W->size)
alpar@1
   214
                  {  int jj = W->list[W->size];
alpar@1
   215
                     W->list[W->pos[j]] = jj;
alpar@1
   216
                     W->pos[jj] = W->pos[j];
alpar@1
   217
                  }
alpar@1
   218
                  W->size--, W->pos[j] = 0;
alpar@1
   219
               }
alpar@1
   220
            }
alpar@1
   221
            /* include vertex i to new clique C[k] to cover edges (i,j)
alpar@1
   222
               incident to all vertices j just removed from W */
alpar@1
   223
            glp_add_arc(H, i, n + k);
alpar@1
   224
         }
alpar@1
   225
      }
alpar@1
   226
      /* free working arrays */
alpar@1
   227
      xfree(W->list);
alpar@1
   228
      xfree(W->pos);
alpar@1
   229
      xfree(V->list);
alpar@1
   230
      xfree(V->pos);
alpar@1
   231
      /* return the number of cliques in the edge covering found */
alpar@1
   232
      return H->nv - n;
alpar@1
   233
}
alpar@1
   234
alpar@1
   235
/* eof */