1 /* cfg.c (conflict graph) */
2 
3 /***********************************************************************
4 *  This code is part of GLPK (GNU Linear Programming Kit).
5 *  Copyright (C) 2012-2013 Free Software Foundation, Inc.
6 *  Written by Andrew Makhorin <mao@gnu.org>.
7 *
8 *  GLPK is free software: you can redistribute it and/or modify it
9 *  under the terms of the GNU General Public License as published by
10 *  the Free Software Foundation, either version 3 of the License, or
11 *  (at your option) any later version.
12 *
13 *  GLPK is distributed in the hope that it will be useful, but WITHOUT
14 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 *  License for more details.
17 *
18 *  You should have received a copy of the GNU General Public License
19 *  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
20 ***********************************************************************/
21 
22 #include "cfg.h"
23 #include "env.h"
24 
25 /***********************************************************************
26 *  cfg_create_graph - create conflict graph
27 *
28 *  This routine creates the conflict graph, which initially is empty,
29 *  and returns a pointer to the graph descriptor.
30 *
31 *  The parameter n specifies the number of *all* variables in MIP, for
32 *  which the conflict graph will be built.
33 *
34 *  The parameter nv_max specifies maximal number of vertices in the
35 *  conflict graph. It should be the double number of binary variables
36 *  in corresponding MIP. */
37 
cfg_create_graph(int n,int nv_max)38 CFG *cfg_create_graph(int n, int nv_max)
39 {     CFG *G;
40       xassert(n >= 0);
41       xassert(0 <= nv_max && nv_max <= n + n);
42       G = talloc(1, CFG);
43       G->n = n;
44       G->pos = talloc(1+n, int);
45       memset(&G->pos[1], 0, n * sizeof(int));
46       G->neg = talloc(1+n, int);
47       memset(&G->neg[1], 0, n * sizeof(int));
48       G->pool = dmp_create_pool();
49       G->nv_max = nv_max;
50       G->nv = 0;
51       G->ref = talloc(1+nv_max, int);
52       G->vptr = talloc(1+nv_max, CFGVLE *);
53       G->cptr = talloc(1+nv_max, CFGCLE *);
54       return G;
55 }
56 
57 /***********************************************************************
58 *  cfg_add_clique - add clique to conflict graph
59 *
60 *  This routine adds a clique to the conflict graph.
61 *
62 *  The parameter size specifies the clique size, size >= 2. Note that
63 *  any edge can be considered as a clique of size 2.
64 *
65 *  The array ind specifies vertices constituting the clique in elements
66 *  ind[k], 1 <= k <= size:
67 *
68 *  ind[k] = +j means a vertex of the conflict graph that corresponds to
69 *  original binary variable x[j], 1 <= j <= n.
70 *
71 *  ind[k] = -j means a vertex of the conflict graph that corresponds to
72 *  complement of original binary variable x[j], 1 <= j <= n.
73 *
74 *  Note that if both vertices for x[j] and (1 - x[j]) have appeared in
75 *  the conflict graph, the routine automatically adds an edge incident
76 *  to these vertices. */
77 
add_edge(CFG * G,int v,int w)78 static void add_edge(CFG *G, int v, int w)
79 {     /* add clique of size 2 */
80       DMP *pool = G->pool;
81       int nv = G->nv;
82       CFGVLE **vptr = G->vptr;
83       CFGVLE *vle;
84       xassert(1 <= v && v <= nv);
85       xassert(1 <= w && w <= nv);
86       xassert(v != w);
87       vle = dmp_talloc(pool, CFGVLE);
88       vle->v = w;
89       vle->next = vptr[v];
90       vptr[v] = vle;
91       vle = dmp_talloc(pool, CFGVLE);
92       vle->v = v;
93       vle->next = vptr[w];
94       vptr[w] = vle;
95       return;
96 }
97 
cfg_add_clique(CFG * G,int size,const int ind[])98 void cfg_add_clique(CFG *G, int size, const int ind[])
99 {     int n = G->n;
100       int *pos = G->pos;
101       int *neg = G->neg;
102       DMP *pool = G->pool;
103       int nv_max = G->nv_max;
104       int *ref = G->ref;
105       CFGVLE **vptr = G->vptr;
106       CFGCLE **cptr = G->cptr;
107       int j, k, v;
108       xassert(2 <= size && size <= nv_max);
109       /* add new vertices to the conflict graph */
110       for (k = 1; k <= size; k++)
111       {  j = ind[k];
112          if (j > 0)
113          {  /* vertex corresponds to x[j] */
114             xassert(1 <= j && j <= n);
115             if (pos[j] == 0)
116             {  /* no such vertex exists; add it */
117                v = pos[j] = ++(G->nv);
118                xassert(v <= nv_max);
119                ref[v] = j;
120                vptr[v] = NULL;
121                cptr[v] = NULL;
122                if (neg[j] != 0)
123                {  /* now both vertices for x[j] and (1 - x[j]) exist */
124                   add_edge(G, v, neg[j]);
125                }
126             }
127          }
128          else
129          {  /* vertex corresponds to (1 - x[j]) */
130             j = -j;
131             xassert(1 <= j && j <= n);
132             if (neg[j] == 0)
133             {  /* no such vertex exists; add it */
134                v = neg[j] = ++(G->nv);
135                xassert(v <= nv_max);
136                ref[v] = j;
137                vptr[v] = NULL;
138                cptr[v] = NULL;
139                if (pos[j] != 0)
140                {  /* now both vertices for x[j] and (1 - x[j]) exist */
141                   add_edge(G, v, pos[j]);
142                }
143             }
144          }
145       }
146       /* add specified clique to the conflict graph */
147       if (size == 2)
148          add_edge(G,
149             ind[1] > 0 ? pos[+ind[1]] : neg[-ind[1]],
150             ind[2] > 0 ? pos[+ind[2]] : neg[-ind[2]]);
151       else
152       {  CFGVLE *vp, *vle;
153          CFGCLE *cle;
154          /* build list of clique vertices */
155          vp = NULL;
156          for (k = 1; k <= size; k++)
157          {  vle = dmp_talloc(pool, CFGVLE);
158             vle->v = ind[k] > 0 ? pos[+ind[k]] : neg[-ind[k]];
159             vle->next = vp;
160             vp = vle;
161          }
162          /* attach the clique to all its vertices */
163          for (k = 1; k <= size; k++)
164          {  cle = dmp_talloc(pool, CFGCLE);
165             cle->vptr = vp;
166             v = ind[k] > 0 ? pos[+ind[k]] : neg[-ind[k]];
167             cle->next = cptr[v];
168             cptr[v] = cle;
169          }
170       }
171       return;
172 }
173 
174 /***********************************************************************
175 *  cfg_get_adjacent - get vertices adjacent to specified vertex
176 *
177 *  This routine stores numbers of all vertices adjacent to specified
178 *  vertex v of the conflict graph in locations ind[1], ..., ind[len],
179 *  and returns len, 1 <= len <= nv-1, where nv is the total number of
180 *  vertices in the conflict graph.
181 *
182 *  Note that the conflict graph defined by this routine has neither
183 *  self-loops nor multiple edges. */
184 
cfg_get_adjacent(CFG * G,int v,int ind[])185 int cfg_get_adjacent(CFG *G, int v, int ind[])
186 {     int nv = G->nv;
187       int *ref = G->ref;
188       CFGVLE **vptr = G->vptr;
189       CFGCLE **cptr = G->cptr;
190       CFGVLE *vle;
191       CFGCLE *cle;
192       int k, w, len;
193       xassert(1 <= v && v <= nv);
194       len = 0;
195       /* walk thru the list of adjacent vertices */
196       for (vle = vptr[v]; vle != NULL; vle = vle->next)
197       {  w = vle->v;
198          xassert(1 <= w && w <= nv);
199          xassert(w != v);
200          if (ref[w] > 0)
201          {  ind[++len] = w;
202             ref[w] = -ref[w];
203          }
204       }
205       /* walk thru the list of incident cliques */
206       for (cle = cptr[v]; cle != NULL; cle = cle->next)
207       {  /* walk thru the list of clique vertices */
208          for (vle = cle->vptr; vle != NULL; vle = vle->next)
209          {  w = vle->v;
210             xassert(1 <= w && w <= nv);
211             if (w != v && ref[w] > 0)
212             {  ind[++len] = w;
213                ref[w] = -ref[w];
214             }
215          }
216       }
217       xassert(1 <= len && len < nv);
218       /* unmark vertices included in the resultant adjacency list */
219       for (k = 1; k <= len; k++)
220       {  w = ind[k];
221          ref[w] = -ref[w];
222       }
223       return len;
224 }
225 
226 /***********************************************************************
227 *  cfg_expand_clique - expand specified clique to maximal clique
228 *
229 *  Given some clique in the conflict graph this routine expands it to
230 *  a maximal clique by including in it new vertices.
231 *
232 *  On entry vertex indices constituting the initial clique should be
233 *  stored in locations c_ind[1], ..., c_ind[c_len], where c_len is the
234 *  initial clique size. On exit the routine stores new vertex indices
235 *  to locations c_ind[c_len+1], ..., c_ind[c_len'], where c_len' is the
236 *  size of the maximal clique found, and returns c_len'.
237 *
238 *  ALGORITHM
239 *
240 *  Let G = (V, E) be a graph, C within V be a current clique to be
241 *  expanded, and D within V \ C be a subset of vertices adjacent to all
242 *  vertices from C. On every iteration the routine chooses some vertex
243 *  v in D, includes it into C, and removes from D the vertex v as well
244 *  as all vertices not adjacent to v. Initially C is empty and D = V.
245 *  Iterations repeat until D becomes an empty set. Obviously, the final
246 *  set C is a maximal clique in G.
247 *
248 *  Now let C0 be an initial clique, and we want C0 to be a subset of
249 *  the final maximal clique C. To provide this condition the routine
250 *  starts constructing C by choosing only such vertices v in D, which
251 *  are in C0, until all vertices from C0 have been included in C. May
252 *  note that if on some iteration C0 \ C is non-empty (i.e. if not all
253 *  vertices from C0 have been included in C), C0 \ C is a subset of D,
254 *  because C0 is a clique. */
255 
intersection(int d_len,int d_ind[],int d_pos[],int len,const int ind[])256 static int intersection(int d_len, int d_ind[], int d_pos[], int len,
257       const int ind[])
258 {     /* compute intersection D := D inter W, where W is some specified
259        * set of vertices */
260       int k, t, v, new_len;
261       /* walk thru vertices in W and mark vertices in D */
262       for (t = 1; t <= len; t++)
263       {  /* v in W */
264          v = ind[t];
265          /* determine position of v in D */
266          k = d_pos[v];
267          if (k != 0)
268          {  /* v in D */
269             xassert(d_ind[k] == v);
270             /* mark v to keep it in D */
271             d_ind[k] = -v;
272          }
273       }
274       /* remove all unmarked vertices from D */
275       new_len = 0;
276       for (k = 1; k <= d_len; k++)
277       {  /* v in D */
278          v = d_ind[k];
279          if (v < 0)
280          {  /* v is marked; keep it */
281             v = -v;
282             new_len++;
283             d_ind[new_len] = v;
284             d_pos[v] = new_len;
285          }
286          else
287          {  /* v is not marked; remove it */
288             d_pos[v] = 0;
289          }
290       }
291       return new_len;
292 }
293 
cfg_expand_clique(CFG * G,int c_len,int c_ind[])294 int cfg_expand_clique(CFG *G, int c_len, int c_ind[])
295 {     int nv = G->nv;
296       int d_len, *d_ind, *d_pos, len, *ind;
297       int k, v;
298       xassert(0 <= c_len && c_len <= nv);
299       /* allocate working arrays */
300       d_ind = talloc(1+nv, int);
301       d_pos = talloc(1+nv, int);
302       ind = talloc(1+nv, int);
303       /* initialize C := 0, D := V */
304       d_len = nv;
305       for (k = 1; k <= nv; k++)
306          d_ind[k] = d_pos[k] = k;
307       /* expand C by vertices of specified initial clique C0 */
308       for (k = 1; k <= c_len; k++)
309       {  /* v in C0 */
310          v = c_ind[k];
311          xassert(1 <= v && v <= nv);
312          /* since C0 is clique, v should be in D */
313          xassert(d_pos[v] != 0);
314          /* W := set of vertices adjacent to v */
315          len = cfg_get_adjacent(G, v, ind);
316          /* D := D inter W */
317          d_len = intersection(d_len, d_ind, d_pos, len, ind);
318          /* since v not in W, now v should be not in D */
319          xassert(d_pos[v] == 0);
320       }
321       /* expand C by some other vertices until D is empty */
322       while (d_len > 0)
323       {  /* v in D */
324          v = d_ind[1];
325          xassert(1 <= v && v <= nv);
326          /* note that v is adjacent to all vertices in C (by design),
327           * so add v to C */
328          c_ind[++c_len] = v;
329          /* W := set of vertices adjacent to v */
330          len = cfg_get_adjacent(G, v, ind);
331          /* D := D inter W */
332          d_len = intersection(d_len, d_ind, d_pos, len, ind);
333          /* since v not in W, now v should be not in D */
334          xassert(d_pos[v] == 0);
335       }
336       /* free working arrays */
337       tfree(d_ind);
338       tfree(d_pos);
339       tfree(ind);
340       /* bring maximal clique to calling routine */
341       return c_len;
342 }
343 
344 /***********************************************************************
345 *  cfg_check_clique - check clique in conflict graph
346 *
347 *  This routine checks that vertices of the conflict graph specified
348 *  in locations c_ind[1], ..., c_ind[c_len] constitute a clique.
349 *
350 *  NOTE: for testing/debugging only. */
351 
cfg_check_clique(CFG * G,int c_len,const int c_ind[])352 void cfg_check_clique(CFG *G, int c_len, const int c_ind[])
353 {     int nv = G->nv;
354       int k, kk, v, w, len, *ind;
355       char *flag;
356       ind = talloc(1+nv, int);
357       flag = talloc(1+nv, char);
358       memset(&flag[1], 0, nv);
359       /* walk thru clique vertices */
360       xassert(c_len >= 0);
361       for (k = 1; k <= c_len; k++)
362       {  /* get clique vertex v */
363          v = c_ind[k];
364          xassert(1 <= v && v <= nv);
365          /* get vertices adjacent to vertex v */
366          len = cfg_get_adjacent(G, v, ind);
367          for (kk = 1; kk <= len; kk++)
368          {  w = ind[kk];
369             xassert(1 <= w && w <= nv);
370             xassert(w != v);
371             flag[w] = 1;
372          }
373          /* check that all clique vertices other than v are adjacent
374             to v */
375          for (kk = 1; kk <= c_len; kk++)
376          {  w = c_ind[kk];
377             xassert(1 <= w && w <= nv);
378             if (w != v)
379                xassert(flag[w]);
380          }
381          /* reset vertex flags */
382          for (kk = 1; kk <= len; kk++)
383             flag[ind[kk]] = 0;
384       }
385       tfree(ind);
386       tfree(flag);
387       return;
388 }
389 
390 /***********************************************************************
391 *  cfg_delete_graph - delete conflict graph
392 *
393 *  This routine deletes the conflict graph by freeing all the memory
394 *  allocated to this program object. */
395 
cfg_delete_graph(CFG * G)396 void cfg_delete_graph(CFG *G)
397 {     tfree(G->pos);
398       tfree(G->neg);
399       dmp_delete_pool(G->pool);
400       tfree(G->ref);
401       tfree(G->vptr);
402       tfree(G->cptr);
403       tfree(G);
404       return;
405 }
406 
407 /* eof */
408