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