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