aboutsummaryrefslogtreecommitdiffstats
path: root/test/monniaux/glpk-4.65/src/misc/wclique1.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/monniaux/glpk-4.65/src/misc/wclique1.c')
-rw-r--r--test/monniaux/glpk-4.65/src/misc/wclique1.c317
1 files changed, 317 insertions, 0 deletions
diff --git a/test/monniaux/glpk-4.65/src/misc/wclique1.c b/test/monniaux/glpk-4.65/src/misc/wclique1.c
new file mode 100644
index 00000000..a3d89542
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/wclique1.c
@@ -0,0 +1,317 @@
+/* wclique1.c (maximum weight clique, greedy heuristic) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2018 Andrew Makhorin, Department for Applied
+* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights
+* reserved. E-mail: <mao@gnu.org>.
+*
+* GLPK is free software: you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* GLPK is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+* License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "env.h"
+#include "wclique1.h"
+
+/***********************************************************************
+* NAME
+*
+* wclique1 - find maximum weight clique with greedy heuristic
+*
+* SYNOPSIS
+*
+* #include "wclique1.h"
+* int wclique1(int n, const double w[],
+* int (*func)(void *info, int i, int ind[]), void *info, int c[]);
+*
+* DESCRIPTION
+*
+* The routine wclique1 implements a sequential greedy heuristic to
+* find maximum weight clique in a given (undirected) graph G = (V, E).
+*
+* The parameter n specifies the number of vertices |V| in the graph,
+* n >= 0.
+*
+* The array w specifies vertex weights in locations w[i], i = 1,...,n.
+* All weights must be non-negative.
+*
+* The formal routine func specifies the graph. For a given vertex i,
+* 1 <= i <= n, it stores indices of all vertices adjacent to vertex i
+* in locations ind[1], ..., ind[deg], where deg is the degree of
+* vertex i, 0 <= deg < n, returned on exit. Note that self-loops and
+* multiple edges are not allowed.
+*
+* The parameter info is a cookie passed to the routine func.
+*
+* On exit the routine wclique1 stores vertex indices included in
+* the clique found to locations c[1], ..., c[size], where size is the
+* clique size returned by the routine, 0 <= size <= n.
+*
+* RETURNS
+*
+* The routine wclique1 returns the size of the clique found. */
+
+struct vertex { int i; double cw; };
+
+static int CDECL fcmp(const void *xx, const void *yy)
+{ const struct vertex *x = xx, *y = yy;
+ if (x->cw > y->cw) return -1;
+ if (x->cw < y->cw) return +1;
+ return 0;
+}
+
+int wclique1(int n, const double w[],
+ int (*func)(void *info, int i, int ind[]), void *info, int c[])
+{ struct vertex *v_list;
+ int deg, c_size, d_size, i, j, k, kk, l, *ind, *c_list, *d_list,
+ size = 0;
+ double c_wght, d_wght, *sw, best = 0.0;
+ char *d_flag, *skip;
+ /* perform sanity checks */
+ xassert(n >= 0);
+ for (i = 1; i <= n; i++)
+ xassert(w[i] >= 0.0);
+ /* if the graph is empty, nothing to do */
+ if (n == 0) goto done;
+ /* allocate working arrays */
+ ind = xcalloc(1+n, sizeof(int));
+ v_list = xcalloc(1+n, sizeof(struct vertex));
+ c_list = xcalloc(1+n, sizeof(int));
+ d_list = xcalloc(1+n, sizeof(int));
+ d_flag = xcalloc(1+n, sizeof(char));
+ skip = xcalloc(1+n, sizeof(char));
+ sw = xcalloc(1+n, sizeof(double));
+ /* build the vertex list */
+ for (i = 1; i <= n; i++)
+ { v_list[i].i = i;
+ /* compute the cumulative weight of each vertex i, which is
+ * cw[i] = w[i] + sum{j : (i,j) in E} w[j] */
+ v_list[i].cw = w[i];
+ deg = func(info, i, ind);
+ xassert(0 <= deg && deg < n);
+ for (k = 1; k <= deg; k++)
+ { j = ind[k];
+ xassert(1 <= j && j <= n && j != i);
+ v_list[i].cw += w[j];
+ }
+ }
+ /* sort the vertex list to access vertices in descending order of
+ * cumulative weights */
+ qsort(&v_list[1], n, sizeof(struct vertex), fcmp);
+ /* initially all vertices are unmarked */
+ memset(&skip[1], 0, sizeof(char) * n);
+ /* clear flags of all vertices */
+ memset(&d_flag[1], 0, sizeof(char) * n);
+ /* look through all vertices of the graph */
+ for (l = 1; l <= n; l++)
+ { /* take vertex i */
+ i = v_list[l].i;
+ /* if this vertex was already included in one of previosuly
+ * constructed cliques, skip it */
+ if (skip[i]) continue;
+ /* use vertex i as the initial clique vertex */
+ c_size = 1; /* size of current clique */
+ c_list[1] = i; /* list of vertices in current clique */
+ c_wght = w[i]; /* weight of current clique */
+ /* determine the candidate set D = { j : (i,j) in E } */
+ d_size = func(info, i, d_list);
+ xassert(0 <= d_size && d_size < n);
+ d_wght = 0.0; /* weight of set D */
+ for (k = 1; k <= d_size; k++)
+ { j = d_list[k];
+ xassert(1 <= j && j <= n && j != i);
+ xassert(!d_flag[j]);
+ d_flag[j] = 1;
+ d_wght += w[j];
+ }
+ /* check an upper bound to the final clique weight */
+ if (c_wght + d_wght < best + 1e-5 * (1.0 + fabs(best)))
+ { /* skip constructing the current clique */
+ goto next;
+ }
+ /* compute the summary weight of each vertex i in D, which is
+ * sw[i] = w[i] + sum{j in D and (i,j) in E} w[j] */
+ for (k = 1; k <= d_size; k++)
+ { i = d_list[k];
+ sw[i] = w[i];
+ /* consider vertices adjacent to vertex i */
+ deg = func(info, i, ind);
+ xassert(0 <= deg && deg < n);
+ for (kk = 1; kk <= deg; kk++)
+ { j = ind[kk];
+ xassert(1 <= j && j <= n && j != i);
+ if (d_flag[j]) sw[i] += w[j];
+ }
+ }
+ /* grow the current clique by adding vertices from D */
+ while (d_size > 0)
+ { /* check an upper bound to the final clique weight */
+ if (c_wght + d_wght < best + 1e-5 * (1.0 + fabs(best)))
+ { /* skip constructing the current clique */
+ goto next;
+ }
+ /* choose vertex i in D having maximal summary weight */
+ i = d_list[1];
+ for (k = 2; k <= d_size; k++)
+ { j = d_list[k];
+ if (sw[i] < sw[j]) i = j;
+ }
+ /* include vertex i in the current clique */
+ c_size++;
+ c_list[c_size] = i;
+ c_wght += w[i];
+ /* remove all vertices not adjacent to vertex i, including
+ * vertex i itself, from the candidate set D */
+ deg = func(info, i, ind);
+ xassert(0 <= deg && deg < n);
+ for (k = 1; k <= deg; k++)
+ { j = ind[k];
+ xassert(1 <= j && j <= n && j != i);
+ /* vertex j is adjacent to vertex i */
+ if (d_flag[j])
+ { xassert(d_flag[j] == 1);
+ /* mark vertex j to keep it in D */
+ d_flag[j] = 2;
+ }
+ }
+ kk = d_size, d_size = 0;
+ for (k = 1; k <= kk; k++)
+ { j = d_list[k];
+ if (d_flag[j] == 1)
+ { /* remove vertex j from D */
+ d_flag[j] = 0;
+ d_wght -= w[j];
+ }
+ else if (d_flag[j] == 2)
+ { /* keep vertex j in D */
+ d_list[++d_size] = j;
+ d_flag[j] = 1;
+ }
+ else
+ xassert(d_flag != d_flag);
+ }
+ }
+ /* the current clique has been completely constructed */
+ if (best < c_wght)
+ { best = c_wght;
+ size = c_size;
+ xassert(1 <= size && size <= n);
+ memcpy(&c[1], &c_list[1], size * sizeof(int));
+ }
+next: /* mark the current clique vertices in order not to use them
+ * as initial vertices anymore */
+ for (k = 1; k <= c_size; k++)
+ skip[c_list[k]] = 1;
+ /* set D can be non-empty, so clean up vertex flags */
+ for (k = 1; k <= d_size; k++)
+ d_flag[d_list[k]] = 0;
+ }
+ /* free working arrays */
+ xfree(ind);
+ xfree(v_list);
+ xfree(c_list);
+ xfree(d_list);
+ xfree(d_flag);
+ xfree(skip);
+ xfree(sw);
+done: /* return to the calling program */
+ return size;
+}
+
+/**********************************************************************/
+
+#ifdef GLP_TEST
+#include "glpk.h"
+#include "rng.h"
+
+typedef struct { double w; } v_data;
+
+#define weight(v) (((v_data *)((v)->data))->w)
+
+glp_graph *G;
+
+char *flag;
+
+int func(void *info, int i, int ind[])
+{ glp_arc *e;
+ int j, k, deg = 0;
+ xassert(info == NULL);
+ xassert(1 <= i && i <= G->nv);
+ /* look through incoming arcs */
+ for (e = G->v[i]->in; e != NULL; e = e->h_next)
+ { j = e->tail->i; /* j->i */
+ if (j != i && !flag[j]) ind[++deg] = j, flag[j] = 1;
+ }
+ /* look through outgoing arcs */
+ for (e = G->v[i]->out; e != NULL; e = e->t_next)
+ { j = e->head->i; /* i->j */
+ if (j != i && !flag[j]) ind[++deg] = j, flag[j] = 1;
+ }
+ /* clear the flag array */
+ xassert(deg < G->nv);
+ for (k = 1; k <= deg; k++) flag[ind[k]] = 0;
+ return deg;
+}
+
+int main(int argc, char *argv[])
+{ RNG *rand;
+ int i, k, kk, size, *c, *ind, deg;
+ double *w, sum, t;
+ /* read graph in DIMACS format */
+ G = glp_create_graph(sizeof(v_data), 0);
+ xassert(argc == 2);
+ xassert(glp_read_ccdata(G, offsetof(v_data, w), argv[1]) == 0);
+ /* print the number of connected components */
+ xprintf("nc = %d\n", glp_weak_comp(G, -1));
+ /* assign random weights unformly distributed in [1,100] */
+ w = xcalloc(1+G->nv, sizeof(double));
+ rand = rng_create_rand();
+ for (i = 1; i <= G->nv; i++)
+#if 0
+ w[i] = weight(G->v[i]) = 1.0;
+#else
+ w[i] = weight(G->v[i]) = rng_unif_rand(rand, 100) + 1;
+#endif
+ /* write graph in DIMACS format */
+ xassert(glp_write_ccdata(G, offsetof(v_data, w), "graph") == 0);
+ /* find maximum weight clique */
+ c = xcalloc(1+G->nv, sizeof(int));
+ flag = xcalloc(1+G->nv, sizeof(char));
+ memset(&flag[1], 0, G->nv);
+ t = xtime();
+ size = wclique1(G->nv, w, func, NULL, c);
+ xprintf("Time used: %.1f s\n", xdifftime(xtime(), t));
+ /* check the clique found */
+ ind = xcalloc(1+G->nv, sizeof(int));
+ for (k = 1; k <= size; k++)
+ { i = c[k];
+ deg = func(NULL, i, ind);
+ for (kk = 1; kk <= size; kk++)
+ flag[c[kk]] = 1;
+ flag[i] = 0;
+ for (kk = 1; kk <= deg; kk++)
+ flag[ind[kk]] = 0;
+ for (kk = 1; kk <= size; kk++)
+ xassert(flag[c[kk]] == 0);
+ }
+ /* compute the clique weight */
+ sum = 0.0;
+ for (i = 1; i <= size; i++)
+ sum += w[c[i]];
+ xprintf("size = %d; sum = %g\n", size, sum);
+ return 0;
+}
+#endif
+
+/* eof */