lemon-project-template-glpk

annotate deps/glpk/src/glpios08.c @ 11:4fc6ad2fb8a6

Test GLPK in src/main.cc
author Alpar Juttner <alpar@cs.elte.hu>
date Sun, 06 Nov 2011 21:43:29 +0100
parents
children
rev   line source
alpar@9 1 /* glpios08.c (clique cut generator) */
alpar@9 2
alpar@9 3 /***********************************************************************
alpar@9 4 * This code is part of GLPK (GNU Linear Programming Kit).
alpar@9 5 *
alpar@9 6 * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
alpar@9 7 * 2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
alpar@9 8 * Moscow Aviation Institute, Moscow, Russia. All rights reserved.
alpar@9 9 * E-mail: <mao@gnu.org>.
alpar@9 10 *
alpar@9 11 * GLPK is free software: you can redistribute it and/or modify it
alpar@9 12 * under the terms of the GNU General Public License as published by
alpar@9 13 * the Free Software Foundation, either version 3 of the License, or
alpar@9 14 * (at your option) any later version.
alpar@9 15 *
alpar@9 16 * GLPK is distributed in the hope that it will be useful, but WITHOUT
alpar@9 17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
alpar@9 18 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
alpar@9 19 * License for more details.
alpar@9 20 *
alpar@9 21 * You should have received a copy of the GNU General Public License
alpar@9 22 * along with GLPK. If not, see <http://www.gnu.org/licenses/>.
alpar@9 23 ***********************************************************************/
alpar@9 24
alpar@9 25 #include "glpios.h"
alpar@9 26
alpar@9 27 static double get_row_lb(LPX *lp, int i)
alpar@9 28 { /* this routine returns lower bound of row i or -DBL_MAX if the
alpar@9 29 row has no lower bound */
alpar@9 30 double lb;
alpar@9 31 switch (lpx_get_row_type(lp, i))
alpar@9 32 { case LPX_FR:
alpar@9 33 case LPX_UP:
alpar@9 34 lb = -DBL_MAX;
alpar@9 35 break;
alpar@9 36 case LPX_LO:
alpar@9 37 case LPX_DB:
alpar@9 38 case LPX_FX:
alpar@9 39 lb = lpx_get_row_lb(lp, i);
alpar@9 40 break;
alpar@9 41 default:
alpar@9 42 xassert(lp != lp);
alpar@9 43 }
alpar@9 44 return lb;
alpar@9 45 }
alpar@9 46
alpar@9 47 static double get_row_ub(LPX *lp, int i)
alpar@9 48 { /* this routine returns upper bound of row i or +DBL_MAX if the
alpar@9 49 row has no upper bound */
alpar@9 50 double ub;
alpar@9 51 switch (lpx_get_row_type(lp, i))
alpar@9 52 { case LPX_FR:
alpar@9 53 case LPX_LO:
alpar@9 54 ub = +DBL_MAX;
alpar@9 55 break;
alpar@9 56 case LPX_UP:
alpar@9 57 case LPX_DB:
alpar@9 58 case LPX_FX:
alpar@9 59 ub = lpx_get_row_ub(lp, i);
alpar@9 60 break;
alpar@9 61 default:
alpar@9 62 xassert(lp != lp);
alpar@9 63 }
alpar@9 64 return ub;
alpar@9 65 }
alpar@9 66
alpar@9 67 static double get_col_lb(LPX *lp, int j)
alpar@9 68 { /* this routine returns lower bound of column j or -DBL_MAX if
alpar@9 69 the column has no lower bound */
alpar@9 70 double lb;
alpar@9 71 switch (lpx_get_col_type(lp, j))
alpar@9 72 { case LPX_FR:
alpar@9 73 case LPX_UP:
alpar@9 74 lb = -DBL_MAX;
alpar@9 75 break;
alpar@9 76 case LPX_LO:
alpar@9 77 case LPX_DB:
alpar@9 78 case LPX_FX:
alpar@9 79 lb = lpx_get_col_lb(lp, j);
alpar@9 80 break;
alpar@9 81 default:
alpar@9 82 xassert(lp != lp);
alpar@9 83 }
alpar@9 84 return lb;
alpar@9 85 }
alpar@9 86
alpar@9 87 static double get_col_ub(LPX *lp, int j)
alpar@9 88 { /* this routine returns upper bound of column j or +DBL_MAX if
alpar@9 89 the column has no upper bound */
alpar@9 90 double ub;
alpar@9 91 switch (lpx_get_col_type(lp, j))
alpar@9 92 { case LPX_FR:
alpar@9 93 case LPX_LO:
alpar@9 94 ub = +DBL_MAX;
alpar@9 95 break;
alpar@9 96 case LPX_UP:
alpar@9 97 case LPX_DB:
alpar@9 98 case LPX_FX:
alpar@9 99 ub = lpx_get_col_ub(lp, j);
alpar@9 100 break;
alpar@9 101 default:
alpar@9 102 xassert(lp != lp);
alpar@9 103 }
alpar@9 104 return ub;
alpar@9 105 }
alpar@9 106
alpar@9 107 static int is_binary(LPX *lp, int j)
alpar@9 108 { /* this routine checks if variable x[j] is binary */
alpar@9 109 return
alpar@9 110 lpx_get_col_kind(lp, j) == LPX_IV &&
alpar@9 111 lpx_get_col_type(lp, j) == LPX_DB &&
alpar@9 112 lpx_get_col_lb(lp, j) == 0.0 && lpx_get_col_ub(lp, j) == 1.0;
alpar@9 113 }
alpar@9 114
alpar@9 115 static double eval_lf_min(LPX *lp, int len, int ind[], double val[])
alpar@9 116 { /* this routine computes the minimum of a specified linear form
alpar@9 117
alpar@9 118 sum a[j]*x[j]
alpar@9 119 j
alpar@9 120
alpar@9 121 using the formula:
alpar@9 122
alpar@9 123 min = sum a[j]*lb[j] + sum a[j]*ub[j],
alpar@9 124 j in J+ j in J-
alpar@9 125
alpar@9 126 where J+ = {j: a[j] > 0}, J- = {j: a[j] < 0}, lb[j] and ub[j]
alpar@9 127 are lower and upper bound of variable x[j], resp. */
alpar@9 128 int j, t;
alpar@9 129 double lb, ub, sum;
alpar@9 130 sum = 0.0;
alpar@9 131 for (t = 1; t <= len; t++)
alpar@9 132 { j = ind[t];
alpar@9 133 if (val[t] > 0.0)
alpar@9 134 { lb = get_col_lb(lp, j);
alpar@9 135 if (lb == -DBL_MAX)
alpar@9 136 { sum = -DBL_MAX;
alpar@9 137 break;
alpar@9 138 }
alpar@9 139 sum += val[t] * lb;
alpar@9 140 }
alpar@9 141 else if (val[t] < 0.0)
alpar@9 142 { ub = get_col_ub(lp, j);
alpar@9 143 if (ub == +DBL_MAX)
alpar@9 144 { sum = -DBL_MAX;
alpar@9 145 break;
alpar@9 146 }
alpar@9 147 sum += val[t] * ub;
alpar@9 148 }
alpar@9 149 else
alpar@9 150 xassert(val != val);
alpar@9 151 }
alpar@9 152 return sum;
alpar@9 153 }
alpar@9 154
alpar@9 155 static double eval_lf_max(LPX *lp, int len, int ind[], double val[])
alpar@9 156 { /* this routine computes the maximum of a specified linear form
alpar@9 157
alpar@9 158 sum a[j]*x[j]
alpar@9 159 j
alpar@9 160
alpar@9 161 using the formula:
alpar@9 162
alpar@9 163 max = sum a[j]*ub[j] + sum a[j]*lb[j],
alpar@9 164 j in J+ j in J-
alpar@9 165
alpar@9 166 where J+ = {j: a[j] > 0}, J- = {j: a[j] < 0}, lb[j] and ub[j]
alpar@9 167 are lower and upper bound of variable x[j], resp. */
alpar@9 168 int j, t;
alpar@9 169 double lb, ub, sum;
alpar@9 170 sum = 0.0;
alpar@9 171 for (t = 1; t <= len; t++)
alpar@9 172 { j = ind[t];
alpar@9 173 if (val[t] > 0.0)
alpar@9 174 { ub = get_col_ub(lp, j);
alpar@9 175 if (ub == +DBL_MAX)
alpar@9 176 { sum = +DBL_MAX;
alpar@9 177 break;
alpar@9 178 }
alpar@9 179 sum += val[t] * ub;
alpar@9 180 }
alpar@9 181 else if (val[t] < 0.0)
alpar@9 182 { lb = get_col_lb(lp, j);
alpar@9 183 if (lb == -DBL_MAX)
alpar@9 184 { sum = +DBL_MAX;
alpar@9 185 break;
alpar@9 186 }
alpar@9 187 sum += val[t] * lb;
alpar@9 188 }
alpar@9 189 else
alpar@9 190 xassert(val != val);
alpar@9 191 }
alpar@9 192 return sum;
alpar@9 193 }
alpar@9 194
alpar@9 195 /*----------------------------------------------------------------------
alpar@9 196 -- probing - determine logical relation between binary variables.
alpar@9 197 --
alpar@9 198 -- This routine tentatively sets a binary variable to 0 and then to 1
alpar@9 199 -- and examines whether another binary variable is caused to be fixed.
alpar@9 200 --
alpar@9 201 -- The examination is based only on one row (constraint), which is the
alpar@9 202 -- following:
alpar@9 203 --
alpar@9 204 -- L <= sum a[j]*x[j] <= U. (1)
alpar@9 205 -- j
alpar@9 206 --
alpar@9 207 -- Let x[p] be a probing variable, x[q] be an examined variable. Then
alpar@9 208 -- (1) can be written as:
alpar@9 209 --
alpar@9 210 -- L <= sum a[j]*x[j] + a[p]*x[p] + a[q]*x[q] <= U, (2)
alpar@9 211 -- j in J'
alpar@9 212 --
alpar@9 213 -- where J' = {j: j != p and j != q}.
alpar@9 214 --
alpar@9 215 -- Let
alpar@9 216 --
alpar@9 217 -- L' = L - a[p]*x[p], (3)
alpar@9 218 --
alpar@9 219 -- U' = U - a[p]*x[p], (4)
alpar@9 220 --
alpar@9 221 -- where x[p] is assumed to be fixed at 0 or 1. So (2) can be rewritten
alpar@9 222 -- as follows:
alpar@9 223 --
alpar@9 224 -- L' <= sum a[j]*x[j] + a[q]*x[q] <= U', (5)
alpar@9 225 -- j in J'
alpar@9 226 --
alpar@9 227 -- from where we have:
alpar@9 228 --
alpar@9 229 -- L' - sum a[j]*x[j] <= a[q]*x[q] <= U' - sum a[j]*x[j]. (6)
alpar@9 230 -- j in J' j in J'
alpar@9 231 --
alpar@9 232 -- Thus,
alpar@9 233 --
alpar@9 234 -- min a[q]*x[q] = L' - MAX, (7)
alpar@9 235 --
alpar@9 236 -- max a[q]*x[q] = U' - MIN, (8)
alpar@9 237 --
alpar@9 238 -- where
alpar@9 239 --
alpar@9 240 -- MIN = min sum a[j]*x[j], (9)
alpar@9 241 -- j in J'
alpar@9 242 --
alpar@9 243 -- MAX = max sum a[j]*x[j]. (10)
alpar@9 244 -- j in J'
alpar@9 245 --
alpar@9 246 -- Formulae (7) and (8) allows determining implied lower and upper
alpar@9 247 -- bounds of x[q].
alpar@9 248 --
alpar@9 249 -- Parameters len, val, L and U specify the constraint (1).
alpar@9 250 --
alpar@9 251 -- Parameters lf_min and lf_max specify implied lower and upper bounds
alpar@9 252 -- of the linear form (1). It is assumed that these bounds are computed
alpar@9 253 -- with the routines eval_lf_min and eval_lf_max (see above).
alpar@9 254 --
alpar@9 255 -- Parameter p specifies the probing variable x[p], which is set to 0
alpar@9 256 -- (if set is 0) or to 1 (if set is 1).
alpar@9 257 --
alpar@9 258 -- Parameter q specifies the examined variable x[q].
alpar@9 259 --
alpar@9 260 -- On exit the routine returns one of the following codes:
alpar@9 261 --
alpar@9 262 -- 0 - there is no logical relation between x[p] and x[q];
alpar@9 263 -- 1 - x[q] can take only on value 0;
alpar@9 264 -- 2 - x[q] can take only on value 1. */
alpar@9 265
alpar@9 266 static int probing(int len, double val[], double L, double U,
alpar@9 267 double lf_min, double lf_max, int p, int set, int q)
alpar@9 268 { double temp;
alpar@9 269 xassert(1 <= p && p < q && q <= len);
alpar@9 270 /* compute L' (3) */
alpar@9 271 if (L != -DBL_MAX && set) L -= val[p];
alpar@9 272 /* compute U' (4) */
alpar@9 273 if (U != +DBL_MAX && set) U -= val[p];
alpar@9 274 /* compute MIN (9) */
alpar@9 275 if (lf_min != -DBL_MAX)
alpar@9 276 { if (val[p] < 0.0) lf_min -= val[p];
alpar@9 277 if (val[q] < 0.0) lf_min -= val[q];
alpar@9 278 }
alpar@9 279 /* compute MAX (10) */
alpar@9 280 if (lf_max != +DBL_MAX)
alpar@9 281 { if (val[p] > 0.0) lf_max -= val[p];
alpar@9 282 if (val[q] > 0.0) lf_max -= val[q];
alpar@9 283 }
alpar@9 284 /* compute implied lower bound of x[q]; see (7), (8) */
alpar@9 285 if (val[q] > 0.0)
alpar@9 286 { if (L == -DBL_MAX || lf_max == +DBL_MAX)
alpar@9 287 temp = -DBL_MAX;
alpar@9 288 else
alpar@9 289 temp = (L - lf_max) / val[q];
alpar@9 290 }
alpar@9 291 else
alpar@9 292 { if (U == +DBL_MAX || lf_min == -DBL_MAX)
alpar@9 293 temp = -DBL_MAX;
alpar@9 294 else
alpar@9 295 temp = (U - lf_min) / val[q];
alpar@9 296 }
alpar@9 297 if (temp > 0.001) return 2;
alpar@9 298 /* compute implied upper bound of x[q]; see (7), (8) */
alpar@9 299 if (val[q] > 0.0)
alpar@9 300 { if (U == +DBL_MAX || lf_min == -DBL_MAX)
alpar@9 301 temp = +DBL_MAX;
alpar@9 302 else
alpar@9 303 temp = (U - lf_min) / val[q];
alpar@9 304 }
alpar@9 305 else
alpar@9 306 { if (L == -DBL_MAX || lf_max == +DBL_MAX)
alpar@9 307 temp = +DBL_MAX;
alpar@9 308 else
alpar@9 309 temp = (L - lf_max) / val[q];
alpar@9 310 }
alpar@9 311 if (temp < 0.999) return 1;
alpar@9 312 /* there is no logical relation between x[p] and x[q] */
alpar@9 313 return 0;
alpar@9 314 }
alpar@9 315
alpar@9 316 struct COG
alpar@9 317 { /* conflict graph; it represents logical relations between binary
alpar@9 318 variables and has a vertex for each binary variable and its
alpar@9 319 complement, and an edge between two vertices when at most one
alpar@9 320 of the variables represented by the vertices can equal one in
alpar@9 321 an optimal solution */
alpar@9 322 int n;
alpar@9 323 /* number of variables */
alpar@9 324 int nb;
alpar@9 325 /* number of binary variables represented in the graph (note that
alpar@9 326 not all binary variables can be represented); vertices which
alpar@9 327 correspond to binary variables have numbers 1, ..., nb while
alpar@9 328 vertices which correspond to complements of binary variables
alpar@9 329 have numbers nb+1, ..., nb+nb */
alpar@9 330 int ne;
alpar@9 331 /* number of edges in the graph */
alpar@9 332 int *vert; /* int vert[1+n]; */
alpar@9 333 /* if x[j] is a binary variable represented in the graph, vert[j]
alpar@9 334 is the vertex number corresponding to x[j]; otherwise vert[j]
alpar@9 335 is zero */
alpar@9 336 int *orig; /* int list[1:nb]; */
alpar@9 337 /* if vert[j] = k > 0, then orig[k] = j */
alpar@9 338 unsigned char *a;
alpar@9 339 /* adjacency matrix of the graph having 2*nb rows and columns;
alpar@9 340 only strict lower triangle is stored in dense packed form */
alpar@9 341 };
alpar@9 342
alpar@9 343 /*----------------------------------------------------------------------
alpar@9 344 -- lpx_create_cog - create the conflict graph.
alpar@9 345 --
alpar@9 346 -- SYNOPSIS
alpar@9 347 --
alpar@9 348 -- #include "glplpx.h"
alpar@9 349 -- void *lpx_create_cog(LPX *lp);
alpar@9 350 --
alpar@9 351 -- DESCRIPTION
alpar@9 352 --
alpar@9 353 -- The routine lpx_create_cog creates the conflict graph for a given
alpar@9 354 -- problem instance.
alpar@9 355 --
alpar@9 356 -- RETURNS
alpar@9 357 --
alpar@9 358 -- If the graph has been created, the routine returns a pointer to it.
alpar@9 359 -- Otherwise the routine returns NULL. */
alpar@9 360
alpar@9 361 #define MAX_NB 4000
alpar@9 362 #define MAX_ROW_LEN 500
alpar@9 363
alpar@9 364 static void lpx_add_cog_edge(void *_cog, int i, int j);
alpar@9 365
alpar@9 366 static void *lpx_create_cog(LPX *lp)
alpar@9 367 { struct COG *cog = NULL;
alpar@9 368 int m, n, nb, i, j, p, q, len, *ind, *vert, *orig;
alpar@9 369 double L, U, lf_min, lf_max, *val;
alpar@9 370 xprintf("Creating the conflict graph...\n");
alpar@9 371 m = lpx_get_num_rows(lp);
alpar@9 372 n = lpx_get_num_cols(lp);
alpar@9 373 /* determine which binary variables should be included in the
alpar@9 374 conflict graph */
alpar@9 375 nb = 0;
alpar@9 376 vert = xcalloc(1+n, sizeof(int));
alpar@9 377 for (j = 1; j <= n; j++) vert[j] = 0;
alpar@9 378 orig = xcalloc(1+n, sizeof(int));
alpar@9 379 ind = xcalloc(1+n, sizeof(int));
alpar@9 380 val = xcalloc(1+n, sizeof(double));
alpar@9 381 for (i = 1; i <= m; i++)
alpar@9 382 { L = get_row_lb(lp, i);
alpar@9 383 U = get_row_ub(lp, i);
alpar@9 384 if (L == -DBL_MAX && U == +DBL_MAX) continue;
alpar@9 385 len = lpx_get_mat_row(lp, i, ind, val);
alpar@9 386 if (len > MAX_ROW_LEN) continue;
alpar@9 387 lf_min = eval_lf_min(lp, len, ind, val);
alpar@9 388 lf_max = eval_lf_max(lp, len, ind, val);
alpar@9 389 for (p = 1; p <= len; p++)
alpar@9 390 { if (!is_binary(lp, ind[p])) continue;
alpar@9 391 for (q = p+1; q <= len; q++)
alpar@9 392 { if (!is_binary(lp, ind[q])) continue;
alpar@9 393 if (probing(len, val, L, U, lf_min, lf_max, p, 0, q) ||
alpar@9 394 probing(len, val, L, U, lf_min, lf_max, p, 1, q))
alpar@9 395 { /* there is a logical relation */
alpar@9 396 /* include the first variable in the graph */
alpar@9 397 j = ind[p];
alpar@9 398 if (vert[j] == 0) nb++, vert[j] = nb, orig[nb] = j;
alpar@9 399 /* incude the second variable in the graph */
alpar@9 400 j = ind[q];
alpar@9 401 if (vert[j] == 0) nb++, vert[j] = nb, orig[nb] = j;
alpar@9 402 }
alpar@9 403 }
alpar@9 404 }
alpar@9 405 }
alpar@9 406 /* if the graph is either empty or has too many vertices, do not
alpar@9 407 create it */
alpar@9 408 if (nb == 0 || nb > MAX_NB)
alpar@9 409 { xprintf("The conflict graph is either empty or too big\n");
alpar@9 410 xfree(vert);
alpar@9 411 xfree(orig);
alpar@9 412 goto done;
alpar@9 413 }
alpar@9 414 /* create the conflict graph */
alpar@9 415 cog = xmalloc(sizeof(struct COG));
alpar@9 416 cog->n = n;
alpar@9 417 cog->nb = nb;
alpar@9 418 cog->ne = 0;
alpar@9 419 cog->vert = vert;
alpar@9 420 cog->orig = orig;
alpar@9 421 len = nb + nb; /* number of vertices */
alpar@9 422 len = (len * (len - 1)) / 2; /* number of entries in triangle */
alpar@9 423 len = (len + (CHAR_BIT - 1)) / CHAR_BIT; /* bytes needed */
alpar@9 424 cog->a = xmalloc(len);
alpar@9 425 memset(cog->a, 0, len);
alpar@9 426 for (j = 1; j <= nb; j++)
alpar@9 427 { /* add edge between variable and its complement */
alpar@9 428 lpx_add_cog_edge(cog, +orig[j], -orig[j]);
alpar@9 429 }
alpar@9 430 for (i = 1; i <= m; i++)
alpar@9 431 { L = get_row_lb(lp, i);
alpar@9 432 U = get_row_ub(lp, i);
alpar@9 433 if (L == -DBL_MAX && U == +DBL_MAX) continue;
alpar@9 434 len = lpx_get_mat_row(lp, i, ind, val);
alpar@9 435 if (len > MAX_ROW_LEN) continue;
alpar@9 436 lf_min = eval_lf_min(lp, len, ind, val);
alpar@9 437 lf_max = eval_lf_max(lp, len, ind, val);
alpar@9 438 for (p = 1; p <= len; p++)
alpar@9 439 { if (!is_binary(lp, ind[p])) continue;
alpar@9 440 for (q = p+1; q <= len; q++)
alpar@9 441 { if (!is_binary(lp, ind[q])) continue;
alpar@9 442 /* set x[p] to 0 and examine x[q] */
alpar@9 443 switch (probing(len, val, L, U, lf_min, lf_max, p, 0, q))
alpar@9 444 { case 0:
alpar@9 445 /* no logical relation */
alpar@9 446 break;
alpar@9 447 case 1:
alpar@9 448 /* x[p] = 0 implies x[q] = 0 */
alpar@9 449 lpx_add_cog_edge(cog, -ind[p], +ind[q]);
alpar@9 450 break;
alpar@9 451 case 2:
alpar@9 452 /* x[p] = 0 implies x[q] = 1 */
alpar@9 453 lpx_add_cog_edge(cog, -ind[p], -ind[q]);
alpar@9 454 break;
alpar@9 455 default:
alpar@9 456 xassert(lp != lp);
alpar@9 457 }
alpar@9 458 /* set x[p] to 1 and examine x[q] */
alpar@9 459 switch (probing(len, val, L, U, lf_min, lf_max, p, 1, q))
alpar@9 460 { case 0:
alpar@9 461 /* no logical relation */
alpar@9 462 break;
alpar@9 463 case 1:
alpar@9 464 /* x[p] = 1 implies x[q] = 0 */
alpar@9 465 lpx_add_cog_edge(cog, +ind[p], +ind[q]);
alpar@9 466 break;
alpar@9 467 case 2:
alpar@9 468 /* x[p] = 1 implies x[q] = 1 */
alpar@9 469 lpx_add_cog_edge(cog, +ind[p], -ind[q]);
alpar@9 470 break;
alpar@9 471 default:
alpar@9 472 xassert(lp != lp);
alpar@9 473 }
alpar@9 474 }
alpar@9 475 }
alpar@9 476 }
alpar@9 477 xprintf("The conflict graph has 2*%d vertices and %d edges\n",
alpar@9 478 cog->nb, cog->ne);
alpar@9 479 done: xfree(ind);
alpar@9 480 xfree(val);
alpar@9 481 return cog;
alpar@9 482 }
alpar@9 483
alpar@9 484 /*----------------------------------------------------------------------
alpar@9 485 -- lpx_add_cog_edge - add edge to the conflict graph.
alpar@9 486 --
alpar@9 487 -- SYNOPSIS
alpar@9 488 --
alpar@9 489 -- #include "glplpx.h"
alpar@9 490 -- void lpx_add_cog_edge(void *cog, int i, int j);
alpar@9 491 --
alpar@9 492 -- DESCRIPTION
alpar@9 493 --
alpar@9 494 -- The routine lpx_add_cog_edge adds an edge to the conflict graph.
alpar@9 495 -- The edge connects x[i] (if i > 0) or its complement (if i < 0) and
alpar@9 496 -- x[j] (if j > 0) or its complement (if j < 0), where i and j are
alpar@9 497 -- original ordinal numbers of corresponding variables. */
alpar@9 498
alpar@9 499 static void lpx_add_cog_edge(void *_cog, int i, int j)
alpar@9 500 { struct COG *cog = _cog;
alpar@9 501 int k;
alpar@9 502 xassert(i != j);
alpar@9 503 /* determine indices of corresponding vertices */
alpar@9 504 if (i > 0)
alpar@9 505 { xassert(1 <= i && i <= cog->n);
alpar@9 506 i = cog->vert[i];
alpar@9 507 xassert(i != 0);
alpar@9 508 }
alpar@9 509 else
alpar@9 510 { i = -i;
alpar@9 511 xassert(1 <= i && i <= cog->n);
alpar@9 512 i = cog->vert[i];
alpar@9 513 xassert(i != 0);
alpar@9 514 i += cog->nb;
alpar@9 515 }
alpar@9 516 if (j > 0)
alpar@9 517 { xassert(1 <= j && j <= cog->n);
alpar@9 518 j = cog->vert[j];
alpar@9 519 xassert(j != 0);
alpar@9 520 }
alpar@9 521 else
alpar@9 522 { j = -j;
alpar@9 523 xassert(1 <= j && j <= cog->n);
alpar@9 524 j = cog->vert[j];
alpar@9 525 xassert(j != 0);
alpar@9 526 j += cog->nb;
alpar@9 527 }
alpar@9 528 /* only lower triangle is stored, so we need i > j */
alpar@9 529 if (i < j) k = i, i = j, j = k;
alpar@9 530 k = ((i - 1) * (i - 2)) / 2 + (j - 1);
alpar@9 531 cog->a[k / CHAR_BIT] |=
alpar@9 532 (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT));
alpar@9 533 cog->ne++;
alpar@9 534 return;
alpar@9 535 }
alpar@9 536
alpar@9 537 /*----------------------------------------------------------------------
alpar@9 538 -- MAXIMUM WEIGHT CLIQUE
alpar@9 539 --
alpar@9 540 -- Two subroutines sub() and wclique() below are intended to find a
alpar@9 541 -- maximum weight clique in a given undirected graph. These subroutines
alpar@9 542 -- are slightly modified version of the program WCLIQUE developed by
alpar@9 543 -- Patric Ostergard <http://www.tcs.hut.fi/~pat/wclique.html> and based
alpar@9 544 -- on ideas from the article "P. R. J. Ostergard, A new algorithm for
alpar@9 545 -- the maximum-weight clique problem, submitted for publication", which
alpar@9 546 -- in turn is a generalization of the algorithm for unweighted graphs
alpar@9 547 -- presented in "P. R. J. Ostergard, A fast algorithm for the maximum
alpar@9 548 -- clique problem, submitted for publication".
alpar@9 549 --
alpar@9 550 -- USED WITH PERMISSION OF THE AUTHOR OF THE ORIGINAL CODE. */
alpar@9 551
alpar@9 552 struct dsa
alpar@9 553 { /* dynamic storage area */
alpar@9 554 int n;
alpar@9 555 /* number of vertices */
alpar@9 556 int *wt; /* int wt[0:n-1]; */
alpar@9 557 /* weights */
alpar@9 558 unsigned char *a;
alpar@9 559 /* adjacency matrix (packed lower triangle without main diag.) */
alpar@9 560 int record;
alpar@9 561 /* weight of best clique */
alpar@9 562 int rec_level;
alpar@9 563 /* number of vertices in best clique */
alpar@9 564 int *rec; /* int rec[0:n-1]; */
alpar@9 565 /* best clique so far */
alpar@9 566 int *clique; /* int clique[0:n-1]; */
alpar@9 567 /* table for pruning */
alpar@9 568 int *set; /* int set[0:n-1]; */
alpar@9 569 /* current clique */
alpar@9 570 };
alpar@9 571
alpar@9 572 #define n (dsa->n)
alpar@9 573 #define wt (dsa->wt)
alpar@9 574 #define a (dsa->a)
alpar@9 575 #define record (dsa->record)
alpar@9 576 #define rec_level (dsa->rec_level)
alpar@9 577 #define rec (dsa->rec)
alpar@9 578 #define clique (dsa->clique)
alpar@9 579 #define set (dsa->set)
alpar@9 580
alpar@9 581 #if 0
alpar@9 582 static int is_edge(struct dsa *dsa, int i, int j)
alpar@9 583 { /* if there is arc (i,j), the routine returns true; otherwise
alpar@9 584 false; 0 <= i, j < n */
alpar@9 585 int k;
alpar@9 586 xassert(0 <= i && i < n);
alpar@9 587 xassert(0 <= j && j < n);
alpar@9 588 if (i == j) return 0;
alpar@9 589 if (i < j) k = i, i = j, j = k;
alpar@9 590 k = (i * (i - 1)) / 2 + j;
alpar@9 591 return a[k / CHAR_BIT] &
alpar@9 592 (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT));
alpar@9 593 }
alpar@9 594 #else
alpar@9 595 #define is_edge(dsa, i, j) ((i) == (j) ? 0 : \
alpar@9 596 (i) > (j) ? is_edge1(i, j) : is_edge1(j, i))
alpar@9 597 #define is_edge1(i, j) is_edge2(((i) * ((i) - 1)) / 2 + (j))
alpar@9 598 #define is_edge2(k) (a[(k) / CHAR_BIT] & \
alpar@9 599 (unsigned char)(1 << ((CHAR_BIT - 1) - (k) % CHAR_BIT)))
alpar@9 600 #endif
alpar@9 601
alpar@9 602 static void sub(struct dsa *dsa, int ct, int table[], int level,
alpar@9 603 int weight, int l_weight)
alpar@9 604 { int i, j, k, curr_weight, left_weight, *p1, *p2, *newtable;
alpar@9 605 newtable = xcalloc(n, sizeof(int));
alpar@9 606 if (ct <= 0)
alpar@9 607 { /* 0 or 1 elements left; include these */
alpar@9 608 if (ct == 0)
alpar@9 609 { set[level++] = table[0];
alpar@9 610 weight += l_weight;
alpar@9 611 }
alpar@9 612 if (weight > record)
alpar@9 613 { record = weight;
alpar@9 614 rec_level = level;
alpar@9 615 for (i = 0; i < level; i++) rec[i] = set[i];
alpar@9 616 }
alpar@9 617 goto done;
alpar@9 618 }
alpar@9 619 for (i = ct; i >= 0; i--)
alpar@9 620 { if ((level == 0) && (i < ct)) goto done;
alpar@9 621 k = table[i];
alpar@9 622 if ((level > 0) && (clique[k] <= (record - weight)))
alpar@9 623 goto done; /* prune */
alpar@9 624 set[level] = k;
alpar@9 625 curr_weight = weight + wt[k];
alpar@9 626 l_weight -= wt[k];
alpar@9 627 if (l_weight <= (record - curr_weight))
alpar@9 628 goto done; /* prune */
alpar@9 629 p1 = newtable;
alpar@9 630 p2 = table;
alpar@9 631 left_weight = 0;
alpar@9 632 while (p2 < table + i)
alpar@9 633 { j = *p2++;
alpar@9 634 if (is_edge(dsa, j, k))
alpar@9 635 { *p1++ = j;
alpar@9 636 left_weight += wt[j];
alpar@9 637 }
alpar@9 638 }
alpar@9 639 if (left_weight <= (record - curr_weight)) continue;
alpar@9 640 sub(dsa, p1 - newtable - 1, newtable, level + 1, curr_weight,
alpar@9 641 left_weight);
alpar@9 642 }
alpar@9 643 done: xfree(newtable);
alpar@9 644 return;
alpar@9 645 }
alpar@9 646
alpar@9 647 static int wclique(int _n, int w[], unsigned char _a[], int sol[])
alpar@9 648 { struct dsa _dsa, *dsa = &_dsa;
alpar@9 649 int i, j, p, max_wt, max_nwt, wth, *used, *nwt, *pos;
alpar@9 650 glp_long timer;
alpar@9 651 n = _n;
alpar@9 652 wt = &w[1];
alpar@9 653 a = _a;
alpar@9 654 record = 0;
alpar@9 655 rec_level = 0;
alpar@9 656 rec = &sol[1];
alpar@9 657 clique = xcalloc(n, sizeof(int));
alpar@9 658 set = xcalloc(n, sizeof(int));
alpar@9 659 used = xcalloc(n, sizeof(int));
alpar@9 660 nwt = xcalloc(n, sizeof(int));
alpar@9 661 pos = xcalloc(n, sizeof(int));
alpar@9 662 /* start timer */
alpar@9 663 timer = xtime();
alpar@9 664 /* order vertices */
alpar@9 665 for (i = 0; i < n; i++)
alpar@9 666 { nwt[i] = 0;
alpar@9 667 for (j = 0; j < n; j++)
alpar@9 668 if (is_edge(dsa, i, j)) nwt[i] += wt[j];
alpar@9 669 }
alpar@9 670 for (i = 0; i < n; i++)
alpar@9 671 used[i] = 0;
alpar@9 672 for (i = n-1; i >= 0; i--)
alpar@9 673 { max_wt = -1;
alpar@9 674 max_nwt = -1;
alpar@9 675 for (j = 0; j < n; j++)
alpar@9 676 { if ((!used[j]) && ((wt[j] > max_wt) || (wt[j] == max_wt
alpar@9 677 && nwt[j] > max_nwt)))
alpar@9 678 { max_wt = wt[j];
alpar@9 679 max_nwt = nwt[j];
alpar@9 680 p = j;
alpar@9 681 }
alpar@9 682 }
alpar@9 683 pos[i] = p;
alpar@9 684 used[p] = 1;
alpar@9 685 for (j = 0; j < n; j++)
alpar@9 686 if ((!used[j]) && (j != p) && (is_edge(dsa, p, j)))
alpar@9 687 nwt[j] -= wt[p];
alpar@9 688 }
alpar@9 689 /* main routine */
alpar@9 690 wth = 0;
alpar@9 691 for (i = 0; i < n; i++)
alpar@9 692 { wth += wt[pos[i]];
alpar@9 693 sub(dsa, i, pos, 0, 0, wth);
alpar@9 694 clique[pos[i]] = record;
alpar@9 695 #if 0
alpar@9 696 if (utime() >= timer + 5.0)
alpar@9 697 #else
alpar@9 698 if (xdifftime(xtime(), timer) >= 5.0 - 0.001)
alpar@9 699 #endif
alpar@9 700 { /* print current record and reset timer */
alpar@9 701 xprintf("level = %d (%d); best = %d\n", i+1, n, record);
alpar@9 702 #if 0
alpar@9 703 timer = utime();
alpar@9 704 #else
alpar@9 705 timer = xtime();
alpar@9 706 #endif
alpar@9 707 }
alpar@9 708 }
alpar@9 709 xfree(clique);
alpar@9 710 xfree(set);
alpar@9 711 xfree(used);
alpar@9 712 xfree(nwt);
alpar@9 713 xfree(pos);
alpar@9 714 /* return the solution found */
alpar@9 715 for (i = 1; i <= rec_level; i++) sol[i]++;
alpar@9 716 return rec_level;
alpar@9 717 }
alpar@9 718
alpar@9 719 #undef n
alpar@9 720 #undef wt
alpar@9 721 #undef a
alpar@9 722 #undef record
alpar@9 723 #undef rec_level
alpar@9 724 #undef rec
alpar@9 725 #undef clique
alpar@9 726 #undef set
alpar@9 727
alpar@9 728 /*----------------------------------------------------------------------
alpar@9 729 -- lpx_clique_cut - generate cluque cut.
alpar@9 730 --
alpar@9 731 -- SYNOPSIS
alpar@9 732 --
alpar@9 733 -- #include "glplpx.h"
alpar@9 734 -- int lpx_clique_cut(LPX *lp, void *cog, int ind[], double val[]);
alpar@9 735 --
alpar@9 736 -- DESCRIPTION
alpar@9 737 --
alpar@9 738 -- The routine lpx_clique_cut generates a clique cut using the conflict
alpar@9 739 -- graph specified by the parameter cog.
alpar@9 740 --
alpar@9 741 -- If a violated clique cut has been found, it has the following form:
alpar@9 742 --
alpar@9 743 -- sum{j in J} a[j]*x[j] <= b.
alpar@9 744 --
alpar@9 745 -- Variable indices j in J are stored in elements ind[1], ..., ind[len]
alpar@9 746 -- while corresponding constraint coefficients are stored in elements
alpar@9 747 -- val[1], ..., val[len], where len is returned on exit. The right-hand
alpar@9 748 -- side b is stored in element val[0].
alpar@9 749 --
alpar@9 750 -- RETURNS
alpar@9 751 --
alpar@9 752 -- If the cutting plane has been successfully generated, the routine
alpar@9 753 -- returns 1 <= len <= n, which is the number of non-zero coefficients
alpar@9 754 -- in the inequality constraint. Otherwise, the routine returns zero. */
alpar@9 755
alpar@9 756 static int lpx_clique_cut(LPX *lp, void *_cog, int ind[], double val[])
alpar@9 757 { struct COG *cog = _cog;
alpar@9 758 int n = lpx_get_num_cols(lp);
alpar@9 759 int j, t, v, card, temp, len = 0, *w, *sol;
alpar@9 760 double x, sum, b, *vec;
alpar@9 761 /* allocate working arrays */
alpar@9 762 w = xcalloc(1 + 2 * cog->nb, sizeof(int));
alpar@9 763 sol = xcalloc(1 + 2 * cog->nb, sizeof(int));
alpar@9 764 vec = xcalloc(1+n, sizeof(double));
alpar@9 765 /* assign weights to vertices of the conflict graph */
alpar@9 766 for (t = 1; t <= cog->nb; t++)
alpar@9 767 { j = cog->orig[t];
alpar@9 768 x = lpx_get_col_prim(lp, j);
alpar@9 769 temp = (int)(100.0 * x + 0.5);
alpar@9 770 if (temp < 0) temp = 0;
alpar@9 771 if (temp > 100) temp = 100;
alpar@9 772 w[t] = temp;
alpar@9 773 w[cog->nb + t] = 100 - temp;
alpar@9 774 }
alpar@9 775 /* find a clique of maximum weight */
alpar@9 776 card = wclique(2 * cog->nb, w, cog->a, sol);
alpar@9 777 /* compute the clique weight for unscaled values */
alpar@9 778 sum = 0.0;
alpar@9 779 for ( t = 1; t <= card; t++)
alpar@9 780 { v = sol[t];
alpar@9 781 xassert(1 <= v && v <= 2 * cog->nb);
alpar@9 782 if (v <= cog->nb)
alpar@9 783 { /* vertex v corresponds to binary variable x[j] */
alpar@9 784 j = cog->orig[v];
alpar@9 785 x = lpx_get_col_prim(lp, j);
alpar@9 786 sum += x;
alpar@9 787 }
alpar@9 788 else
alpar@9 789 { /* vertex v corresponds to the complement of x[j] */
alpar@9 790 j = cog->orig[v - cog->nb];
alpar@9 791 x = lpx_get_col_prim(lp, j);
alpar@9 792 sum += 1.0 - x;
alpar@9 793 }
alpar@9 794 }
alpar@9 795 /* if the sum of binary variables and their complements in the
alpar@9 796 clique greater than 1, the clique cut is violated */
alpar@9 797 if (sum >= 1.01)
alpar@9 798 { /* construct the inquality */
alpar@9 799 for (j = 1; j <= n; j++) vec[j] = 0;
alpar@9 800 b = 1.0;
alpar@9 801 for (t = 1; t <= card; t++)
alpar@9 802 { v = sol[t];
alpar@9 803 if (v <= cog->nb)
alpar@9 804 { /* vertex v corresponds to binary variable x[j] */
alpar@9 805 j = cog->orig[v];
alpar@9 806 xassert(1 <= j && j <= n);
alpar@9 807 vec[j] += 1.0;
alpar@9 808 }
alpar@9 809 else
alpar@9 810 { /* vertex v corresponds to the complement of x[j] */
alpar@9 811 j = cog->orig[v - cog->nb];
alpar@9 812 xassert(1 <= j && j <= n);
alpar@9 813 vec[j] -= 1.0;
alpar@9 814 b -= 1.0;
alpar@9 815 }
alpar@9 816 }
alpar@9 817 xassert(len == 0);
alpar@9 818 for (j = 1; j <= n; j++)
alpar@9 819 { if (vec[j] != 0.0)
alpar@9 820 { len++;
alpar@9 821 ind[len] = j, val[len] = vec[j];
alpar@9 822 }
alpar@9 823 }
alpar@9 824 ind[0] = 0, val[0] = b;
alpar@9 825 }
alpar@9 826 /* free working arrays */
alpar@9 827 xfree(w);
alpar@9 828 xfree(sol);
alpar@9 829 xfree(vec);
alpar@9 830 /* return to the calling program */
alpar@9 831 return len;
alpar@9 832 }
alpar@9 833
alpar@9 834 /*----------------------------------------------------------------------
alpar@9 835 -- lpx_delete_cog - delete the conflict graph.
alpar@9 836 --
alpar@9 837 -- SYNOPSIS
alpar@9 838 --
alpar@9 839 -- #include "glplpx.h"
alpar@9 840 -- void lpx_delete_cog(void *cog);
alpar@9 841 --
alpar@9 842 -- DESCRIPTION
alpar@9 843 --
alpar@9 844 -- The routine lpx_delete_cog deletes the conflict graph, which the
alpar@9 845 -- parameter cog points to, freeing all the memory allocated to this
alpar@9 846 -- object. */
alpar@9 847
alpar@9 848 static void lpx_delete_cog(void *_cog)
alpar@9 849 { struct COG *cog = _cog;
alpar@9 850 xfree(cog->vert);
alpar@9 851 xfree(cog->orig);
alpar@9 852 xfree(cog->a);
alpar@9 853 xfree(cog);
alpar@9 854 }
alpar@9 855
alpar@9 856 /**********************************************************************/
alpar@9 857
alpar@9 858 void *ios_clq_init(glp_tree *tree)
alpar@9 859 { /* initialize clique cut generator */
alpar@9 860 glp_prob *mip = tree->mip;
alpar@9 861 xassert(mip != NULL);
alpar@9 862 return lpx_create_cog(mip);
alpar@9 863 }
alpar@9 864
alpar@9 865 /***********************************************************************
alpar@9 866 * NAME
alpar@9 867 *
alpar@9 868 * ios_clq_gen - generate clique cuts
alpar@9 869 *
alpar@9 870 * SYNOPSIS
alpar@9 871 *
alpar@9 872 * #include "glpios.h"
alpar@9 873 * void ios_clq_gen(glp_tree *tree, void *gen);
alpar@9 874 *
alpar@9 875 * DESCRIPTION
alpar@9 876 *
alpar@9 877 * The routine ios_clq_gen generates clique cuts for the current point
alpar@9 878 * and adds them to the clique pool. */
alpar@9 879
alpar@9 880 void ios_clq_gen(glp_tree *tree, void *gen)
alpar@9 881 { int n = lpx_get_num_cols(tree->mip);
alpar@9 882 int len, *ind;
alpar@9 883 double *val;
alpar@9 884 xassert(gen != NULL);
alpar@9 885 ind = xcalloc(1+n, sizeof(int));
alpar@9 886 val = xcalloc(1+n, sizeof(double));
alpar@9 887 len = lpx_clique_cut(tree->mip, gen, ind, val);
alpar@9 888 if (len > 0)
alpar@9 889 { /* xprintf("len = %d\n", len); */
alpar@9 890 glp_ios_add_row(tree, NULL, GLP_RF_CLQ, 0, len, ind, val,
alpar@9 891 GLP_UP, val[0]);
alpar@9 892 }
alpar@9 893 xfree(ind);
alpar@9 894 xfree(val);
alpar@9 895 return;
alpar@9 896 }
alpar@9 897
alpar@9 898 /**********************************************************************/
alpar@9 899
alpar@9 900 void ios_clq_term(void *gen)
alpar@9 901 { /* terminate clique cut generator */
alpar@9 902 xassert(gen != NULL);
alpar@9 903 lpx_delete_cog(gen);
alpar@9 904 return;
alpar@9 905 }
alpar@9 906
alpar@9 907 /* eof */