alpar@1
|
1 |
/* glpapi09.c (mixed integer programming routines) */
|
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 |
#include "glpnpp.h"
|
alpar@1
|
27 |
|
alpar@1
|
28 |
/***********************************************************************
|
alpar@1
|
29 |
* NAME
|
alpar@1
|
30 |
*
|
alpar@1
|
31 |
* glp_set_col_kind - set (change) column kind
|
alpar@1
|
32 |
*
|
alpar@1
|
33 |
* SYNOPSIS
|
alpar@1
|
34 |
*
|
alpar@1
|
35 |
* void glp_set_col_kind(glp_prob *mip, int j, int kind);
|
alpar@1
|
36 |
*
|
alpar@1
|
37 |
* DESCRIPTION
|
alpar@1
|
38 |
*
|
alpar@1
|
39 |
* The routine glp_set_col_kind sets (changes) the kind of j-th column
|
alpar@1
|
40 |
* (structural variable) as specified by the parameter kind:
|
alpar@1
|
41 |
*
|
alpar@1
|
42 |
* GLP_CV - continuous variable;
|
alpar@1
|
43 |
* GLP_IV - integer variable;
|
alpar@1
|
44 |
* GLP_BV - binary variable. */
|
alpar@1
|
45 |
|
alpar@1
|
46 |
void glp_set_col_kind(glp_prob *mip, int j, int kind)
|
alpar@1
|
47 |
{ GLPCOL *col;
|
alpar@1
|
48 |
if (!(1 <= j && j <= mip->n))
|
alpar@1
|
49 |
xerror("glp_set_col_kind: j = %d; column number out of range\n"
|
alpar@1
|
50 |
, j);
|
alpar@1
|
51 |
col = mip->col[j];
|
alpar@1
|
52 |
switch (kind)
|
alpar@1
|
53 |
{ case GLP_CV:
|
alpar@1
|
54 |
col->kind = GLP_CV;
|
alpar@1
|
55 |
break;
|
alpar@1
|
56 |
case GLP_IV:
|
alpar@1
|
57 |
col->kind = GLP_IV;
|
alpar@1
|
58 |
break;
|
alpar@1
|
59 |
case GLP_BV:
|
alpar@1
|
60 |
col->kind = GLP_IV;
|
alpar@1
|
61 |
if (!(col->type == GLP_DB && col->lb == 0.0 && col->ub ==
|
alpar@1
|
62 |
1.0)) glp_set_col_bnds(mip, j, GLP_DB, 0.0, 1.0);
|
alpar@1
|
63 |
break;
|
alpar@1
|
64 |
default:
|
alpar@1
|
65 |
xerror("glp_set_col_kind: j = %d; kind = %d; invalid column"
|
alpar@1
|
66 |
" kind\n", j, kind);
|
alpar@1
|
67 |
}
|
alpar@1
|
68 |
return;
|
alpar@1
|
69 |
}
|
alpar@1
|
70 |
|
alpar@1
|
71 |
/***********************************************************************
|
alpar@1
|
72 |
* NAME
|
alpar@1
|
73 |
*
|
alpar@1
|
74 |
* glp_get_col_kind - retrieve column kind
|
alpar@1
|
75 |
*
|
alpar@1
|
76 |
* SYNOPSIS
|
alpar@1
|
77 |
*
|
alpar@1
|
78 |
* int glp_get_col_kind(glp_prob *mip, int j);
|
alpar@1
|
79 |
*
|
alpar@1
|
80 |
* RETURNS
|
alpar@1
|
81 |
*
|
alpar@1
|
82 |
* The routine glp_get_col_kind returns the kind of j-th column, i.e.
|
alpar@1
|
83 |
* the kind of corresponding structural variable, as follows:
|
alpar@1
|
84 |
*
|
alpar@1
|
85 |
* GLP_CV - continuous variable;
|
alpar@1
|
86 |
* GLP_IV - integer variable;
|
alpar@1
|
87 |
* GLP_BV - binary variable */
|
alpar@1
|
88 |
|
alpar@1
|
89 |
int glp_get_col_kind(glp_prob *mip, int j)
|
alpar@1
|
90 |
{ GLPCOL *col;
|
alpar@1
|
91 |
int kind;
|
alpar@1
|
92 |
if (!(1 <= j && j <= mip->n))
|
alpar@1
|
93 |
xerror("glp_get_col_kind: j = %d; column number out of range\n"
|
alpar@1
|
94 |
, j);
|
alpar@1
|
95 |
col = mip->col[j];
|
alpar@1
|
96 |
kind = col->kind;
|
alpar@1
|
97 |
switch (kind)
|
alpar@1
|
98 |
{ case GLP_CV:
|
alpar@1
|
99 |
break;
|
alpar@1
|
100 |
case GLP_IV:
|
alpar@1
|
101 |
if (col->type == GLP_DB && col->lb == 0.0 && col->ub == 1.0)
|
alpar@1
|
102 |
kind = GLP_BV;
|
alpar@1
|
103 |
break;
|
alpar@1
|
104 |
default:
|
alpar@1
|
105 |
xassert(kind != kind);
|
alpar@1
|
106 |
}
|
alpar@1
|
107 |
return kind;
|
alpar@1
|
108 |
}
|
alpar@1
|
109 |
|
alpar@1
|
110 |
/***********************************************************************
|
alpar@1
|
111 |
* NAME
|
alpar@1
|
112 |
*
|
alpar@1
|
113 |
* glp_get_num_int - retrieve number of integer columns
|
alpar@1
|
114 |
*
|
alpar@1
|
115 |
* SYNOPSIS
|
alpar@1
|
116 |
*
|
alpar@1
|
117 |
* int glp_get_num_int(glp_prob *mip);
|
alpar@1
|
118 |
*
|
alpar@1
|
119 |
* RETURNS
|
alpar@1
|
120 |
*
|
alpar@1
|
121 |
* The routine glp_get_num_int returns the current number of columns,
|
alpar@1
|
122 |
* which are marked as integer. */
|
alpar@1
|
123 |
|
alpar@1
|
124 |
int glp_get_num_int(glp_prob *mip)
|
alpar@1
|
125 |
{ GLPCOL *col;
|
alpar@1
|
126 |
int j, count = 0;
|
alpar@1
|
127 |
for (j = 1; j <= mip->n; j++)
|
alpar@1
|
128 |
{ col = mip->col[j];
|
alpar@1
|
129 |
if (col->kind == GLP_IV) count++;
|
alpar@1
|
130 |
}
|
alpar@1
|
131 |
return count;
|
alpar@1
|
132 |
}
|
alpar@1
|
133 |
|
alpar@1
|
134 |
/***********************************************************************
|
alpar@1
|
135 |
* NAME
|
alpar@1
|
136 |
*
|
alpar@1
|
137 |
* glp_get_num_bin - retrieve number of binary columns
|
alpar@1
|
138 |
*
|
alpar@1
|
139 |
* SYNOPSIS
|
alpar@1
|
140 |
*
|
alpar@1
|
141 |
* int glp_get_num_bin(glp_prob *mip);
|
alpar@1
|
142 |
*
|
alpar@1
|
143 |
* RETURNS
|
alpar@1
|
144 |
*
|
alpar@1
|
145 |
* The routine glp_get_num_bin returns the current number of columns,
|
alpar@1
|
146 |
* which are marked as binary. */
|
alpar@1
|
147 |
|
alpar@1
|
148 |
int glp_get_num_bin(glp_prob *mip)
|
alpar@1
|
149 |
{ GLPCOL *col;
|
alpar@1
|
150 |
int j, count = 0;
|
alpar@1
|
151 |
for (j = 1; j <= mip->n; j++)
|
alpar@1
|
152 |
{ col = mip->col[j];
|
alpar@1
|
153 |
if (col->kind == GLP_IV && col->type == GLP_DB && col->lb ==
|
alpar@1
|
154 |
0.0 && col->ub == 1.0) count++;
|
alpar@1
|
155 |
}
|
alpar@1
|
156 |
return count;
|
alpar@1
|
157 |
}
|
alpar@1
|
158 |
|
alpar@1
|
159 |
/***********************************************************************
|
alpar@1
|
160 |
* NAME
|
alpar@1
|
161 |
*
|
alpar@1
|
162 |
* glp_intopt - solve MIP problem with the branch-and-bound method
|
alpar@1
|
163 |
*
|
alpar@1
|
164 |
* SYNOPSIS
|
alpar@1
|
165 |
*
|
alpar@1
|
166 |
* int glp_intopt(glp_prob *P, const glp_iocp *parm);
|
alpar@1
|
167 |
*
|
alpar@1
|
168 |
* DESCRIPTION
|
alpar@1
|
169 |
*
|
alpar@1
|
170 |
* The routine glp_intopt is a driver to the MIP solver based on the
|
alpar@1
|
171 |
* branch-and-bound method.
|
alpar@1
|
172 |
*
|
alpar@1
|
173 |
* On entry the problem object should contain optimal solution to LP
|
alpar@1
|
174 |
* relaxation (which can be obtained with the routine glp_simplex).
|
alpar@1
|
175 |
*
|
alpar@1
|
176 |
* The MIP solver has a set of control parameters. Values of the control
|
alpar@1
|
177 |
* parameters can be passed in a structure glp_iocp, which the parameter
|
alpar@1
|
178 |
* parm points to.
|
alpar@1
|
179 |
*
|
alpar@1
|
180 |
* The parameter parm can be specified as NULL, in which case the MIP
|
alpar@1
|
181 |
* solver uses default settings.
|
alpar@1
|
182 |
*
|
alpar@1
|
183 |
* RETURNS
|
alpar@1
|
184 |
*
|
alpar@1
|
185 |
* 0 The MIP problem instance has been successfully solved. This code
|
alpar@1
|
186 |
* does not necessarily mean that the solver has found optimal
|
alpar@1
|
187 |
* solution. It only means that the solution process was successful.
|
alpar@1
|
188 |
*
|
alpar@1
|
189 |
* GLP_EBOUND
|
alpar@1
|
190 |
* Unable to start the search, because some double-bounded variables
|
alpar@1
|
191 |
* have incorrect bounds or some integer variables have non-integer
|
alpar@1
|
192 |
* (fractional) bounds.
|
alpar@1
|
193 |
*
|
alpar@1
|
194 |
* GLP_EROOT
|
alpar@1
|
195 |
* Unable to start the search, because optimal basis for initial LP
|
alpar@1
|
196 |
* relaxation is not provided.
|
alpar@1
|
197 |
*
|
alpar@1
|
198 |
* GLP_EFAIL
|
alpar@1
|
199 |
* The search was prematurely terminated due to the solver failure.
|
alpar@1
|
200 |
*
|
alpar@1
|
201 |
* GLP_EMIPGAP
|
alpar@1
|
202 |
* The search was prematurely terminated, because the relative mip
|
alpar@1
|
203 |
* gap tolerance has been reached.
|
alpar@1
|
204 |
*
|
alpar@1
|
205 |
* GLP_ETMLIM
|
alpar@1
|
206 |
* The search was prematurely terminated, because the time limit has
|
alpar@1
|
207 |
* been exceeded.
|
alpar@1
|
208 |
*
|
alpar@1
|
209 |
* GLP_ENOPFS
|
alpar@1
|
210 |
* The MIP problem instance has no primal feasible solution (only if
|
alpar@1
|
211 |
* the MIP presolver is used).
|
alpar@1
|
212 |
*
|
alpar@1
|
213 |
* GLP_ENODFS
|
alpar@1
|
214 |
* LP relaxation of the MIP problem instance has no dual feasible
|
alpar@1
|
215 |
* solution (only if the MIP presolver is used).
|
alpar@1
|
216 |
*
|
alpar@1
|
217 |
* GLP_ESTOP
|
alpar@1
|
218 |
* The search was prematurely terminated by application. */
|
alpar@1
|
219 |
|
alpar@1
|
220 |
static int solve_mip(glp_prob *P, const glp_iocp *parm)
|
alpar@1
|
221 |
{ /* solve MIP directly without using the preprocessor */
|
alpar@1
|
222 |
glp_tree *T;
|
alpar@1
|
223 |
int ret;
|
alpar@1
|
224 |
/* optimal basis to LP relaxation must be provided */
|
alpar@1
|
225 |
if (glp_get_status(P) != GLP_OPT)
|
alpar@1
|
226 |
{ if (parm->msg_lev >= GLP_MSG_ERR)
|
alpar@1
|
227 |
xprintf("glp_intopt: optimal basis to initial LP relaxation"
|
alpar@1
|
228 |
" not provided\n");
|
alpar@1
|
229 |
ret = GLP_EROOT;
|
alpar@1
|
230 |
goto done;
|
alpar@1
|
231 |
}
|
alpar@1
|
232 |
/* it seems all is ok */
|
alpar@1
|
233 |
if (parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
234 |
xprintf("Integer optimization begins...\n");
|
alpar@1
|
235 |
/* create the branch-and-bound tree */
|
alpar@1
|
236 |
T = ios_create_tree(P, parm);
|
alpar@1
|
237 |
/* solve the problem instance */
|
alpar@1
|
238 |
ret = ios_driver(T);
|
alpar@1
|
239 |
/* delete the branch-and-bound tree */
|
alpar@1
|
240 |
ios_delete_tree(T);
|
alpar@1
|
241 |
/* analyze exit code reported by the mip driver */
|
alpar@1
|
242 |
if (ret == 0)
|
alpar@1
|
243 |
{ if (P->mip_stat == GLP_FEAS)
|
alpar@1
|
244 |
{ if (parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
245 |
xprintf("INTEGER OPTIMAL SOLUTION FOUND\n");
|
alpar@1
|
246 |
P->mip_stat = GLP_OPT;
|
alpar@1
|
247 |
}
|
alpar@1
|
248 |
else
|
alpar@1
|
249 |
{ if (parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
250 |
xprintf("PROBLEM HAS NO INTEGER FEASIBLE SOLUTION\n");
|
alpar@1
|
251 |
P->mip_stat = GLP_NOFEAS;
|
alpar@1
|
252 |
}
|
alpar@1
|
253 |
}
|
alpar@1
|
254 |
else if (ret == GLP_EMIPGAP)
|
alpar@1
|
255 |
{ if (parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
256 |
xprintf("RELATIVE MIP GAP TOLERANCE REACHED; SEARCH TERMINA"
|
alpar@1
|
257 |
"TED\n");
|
alpar@1
|
258 |
}
|
alpar@1
|
259 |
else if (ret == GLP_ETMLIM)
|
alpar@1
|
260 |
{ if (parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
261 |
xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
|
alpar@1
|
262 |
}
|
alpar@1
|
263 |
else if (ret == GLP_EFAIL)
|
alpar@1
|
264 |
{ if (parm->msg_lev >= GLP_MSG_ERR)
|
alpar@1
|
265 |
xprintf("glp_intopt: cannot solve current LP relaxation\n");
|
alpar@1
|
266 |
}
|
alpar@1
|
267 |
else if (ret == GLP_ESTOP)
|
alpar@1
|
268 |
{ if (parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
269 |
xprintf("SEARCH TERMINATED BY APPLICATION\n");
|
alpar@1
|
270 |
}
|
alpar@1
|
271 |
else
|
alpar@1
|
272 |
xassert(ret != ret);
|
alpar@1
|
273 |
done: return ret;
|
alpar@1
|
274 |
}
|
alpar@1
|
275 |
|
alpar@1
|
276 |
static int preprocess_and_solve_mip(glp_prob *P, const glp_iocp *parm)
|
alpar@1
|
277 |
{ /* solve MIP using the preprocessor */
|
alpar@1
|
278 |
ENV *env = get_env_ptr();
|
alpar@1
|
279 |
int term_out = env->term_out;
|
alpar@1
|
280 |
NPP *npp;
|
alpar@1
|
281 |
glp_prob *mip = NULL;
|
alpar@1
|
282 |
glp_bfcp bfcp;
|
alpar@1
|
283 |
glp_smcp smcp;
|
alpar@1
|
284 |
int ret;
|
alpar@1
|
285 |
if (parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
286 |
xprintf("Preprocessing...\n");
|
alpar@1
|
287 |
/* create preprocessor workspace */
|
alpar@1
|
288 |
npp = npp_create_wksp();
|
alpar@1
|
289 |
/* load original problem into the preprocessor workspace */
|
alpar@1
|
290 |
npp_load_prob(npp, P, GLP_OFF, GLP_MIP, GLP_OFF);
|
alpar@1
|
291 |
/* process MIP prior to applying the branch-and-bound method */
|
alpar@1
|
292 |
if (!term_out || parm->msg_lev < GLP_MSG_ALL)
|
alpar@1
|
293 |
env->term_out = GLP_OFF;
|
alpar@1
|
294 |
else
|
alpar@1
|
295 |
env->term_out = GLP_ON;
|
alpar@1
|
296 |
ret = npp_integer(npp, parm);
|
alpar@1
|
297 |
env->term_out = term_out;
|
alpar@1
|
298 |
if (ret == 0)
|
alpar@1
|
299 |
;
|
alpar@1
|
300 |
else if (ret == GLP_ENOPFS)
|
alpar@1
|
301 |
{ if (parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
302 |
xprintf("PROBLEM HAS NO PRIMAL FEASIBLE SOLUTION\n");
|
alpar@1
|
303 |
}
|
alpar@1
|
304 |
else if (ret == GLP_ENODFS)
|
alpar@1
|
305 |
{ if (parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
306 |
xprintf("LP RELAXATION HAS NO DUAL FEASIBLE SOLUTION\n");
|
alpar@1
|
307 |
}
|
alpar@1
|
308 |
else
|
alpar@1
|
309 |
xassert(ret != ret);
|
alpar@1
|
310 |
if (ret != 0) goto done;
|
alpar@1
|
311 |
/* build transformed MIP */
|
alpar@1
|
312 |
mip = glp_create_prob();
|
alpar@1
|
313 |
npp_build_prob(npp, mip);
|
alpar@1
|
314 |
/* if the transformed MIP is empty, it has empty solution, which
|
alpar@1
|
315 |
is optimal */
|
alpar@1
|
316 |
if (mip->m == 0 && mip->n == 0)
|
alpar@1
|
317 |
{ mip->mip_stat = GLP_OPT;
|
alpar@1
|
318 |
mip->mip_obj = mip->c0;
|
alpar@1
|
319 |
if (parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
320 |
{ xprintf("Objective value = %17.9e\n", mip->mip_obj);
|
alpar@1
|
321 |
xprintf("INTEGER OPTIMAL SOLUTION FOUND BY MIP PREPROCESSOR"
|
alpar@1
|
322 |
"\n");
|
alpar@1
|
323 |
}
|
alpar@1
|
324 |
goto post;
|
alpar@1
|
325 |
}
|
alpar@1
|
326 |
/* display some statistics */
|
alpar@1
|
327 |
if (parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
328 |
{ int ni = glp_get_num_int(mip);
|
alpar@1
|
329 |
int nb = glp_get_num_bin(mip);
|
alpar@1
|
330 |
char s[50];
|
alpar@1
|
331 |
xprintf("%d row%s, %d column%s, %d non-zero%s\n",
|
alpar@1
|
332 |
mip->m, mip->m == 1 ? "" : "s", mip->n, mip->n == 1 ? "" :
|
alpar@1
|
333 |
"s", mip->nnz, mip->nnz == 1 ? "" : "s");
|
alpar@1
|
334 |
if (nb == 0)
|
alpar@1
|
335 |
strcpy(s, "none of");
|
alpar@1
|
336 |
else if (ni == 1 && nb == 1)
|
alpar@1
|
337 |
strcpy(s, "");
|
alpar@1
|
338 |
else if (nb == 1)
|
alpar@1
|
339 |
strcpy(s, "one of");
|
alpar@1
|
340 |
else if (nb == ni)
|
alpar@1
|
341 |
strcpy(s, "all of");
|
alpar@1
|
342 |
else
|
alpar@1
|
343 |
sprintf(s, "%d of", nb);
|
alpar@1
|
344 |
xprintf("%d integer variable%s, %s which %s binary\n",
|
alpar@1
|
345 |
ni, ni == 1 ? "" : "s", s, nb == 1 ? "is" : "are");
|
alpar@1
|
346 |
}
|
alpar@1
|
347 |
/* inherit basis factorization control parameters */
|
alpar@1
|
348 |
glp_get_bfcp(P, &bfcp);
|
alpar@1
|
349 |
glp_set_bfcp(mip, &bfcp);
|
alpar@1
|
350 |
/* scale the transformed problem */
|
alpar@1
|
351 |
if (!term_out || parm->msg_lev < GLP_MSG_ALL)
|
alpar@1
|
352 |
env->term_out = GLP_OFF;
|
alpar@1
|
353 |
else
|
alpar@1
|
354 |
env->term_out = GLP_ON;
|
alpar@1
|
355 |
glp_scale_prob(mip,
|
alpar@1
|
356 |
GLP_SF_GM | GLP_SF_EQ | GLP_SF_2N | GLP_SF_SKIP);
|
alpar@1
|
357 |
env->term_out = term_out;
|
alpar@1
|
358 |
/* build advanced initial basis */
|
alpar@1
|
359 |
if (!term_out || parm->msg_lev < GLP_MSG_ALL)
|
alpar@1
|
360 |
env->term_out = GLP_OFF;
|
alpar@1
|
361 |
else
|
alpar@1
|
362 |
env->term_out = GLP_ON;
|
alpar@1
|
363 |
glp_adv_basis(mip, 0);
|
alpar@1
|
364 |
env->term_out = term_out;
|
alpar@1
|
365 |
/* solve initial LP relaxation */
|
alpar@1
|
366 |
if (parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
367 |
xprintf("Solving LP relaxation...\n");
|
alpar@1
|
368 |
glp_init_smcp(&smcp);
|
alpar@1
|
369 |
smcp.msg_lev = parm->msg_lev;
|
alpar@1
|
370 |
mip->it_cnt = P->it_cnt;
|
alpar@1
|
371 |
ret = glp_simplex(mip, &smcp);
|
alpar@1
|
372 |
P->it_cnt = mip->it_cnt;
|
alpar@1
|
373 |
if (ret != 0)
|
alpar@1
|
374 |
{ if (parm->msg_lev >= GLP_MSG_ERR)
|
alpar@1
|
375 |
xprintf("glp_intopt: cannot solve LP relaxation\n");
|
alpar@1
|
376 |
ret = GLP_EFAIL;
|
alpar@1
|
377 |
goto done;
|
alpar@1
|
378 |
}
|
alpar@1
|
379 |
/* check status of the basic solution */
|
alpar@1
|
380 |
ret = glp_get_status(mip);
|
alpar@1
|
381 |
if (ret == GLP_OPT)
|
alpar@1
|
382 |
ret = 0;
|
alpar@1
|
383 |
else if (ret == GLP_NOFEAS)
|
alpar@1
|
384 |
ret = GLP_ENOPFS;
|
alpar@1
|
385 |
else if (ret == GLP_UNBND)
|
alpar@1
|
386 |
ret = GLP_ENODFS;
|
alpar@1
|
387 |
else
|
alpar@1
|
388 |
xassert(ret != ret);
|
alpar@1
|
389 |
if (ret != 0) goto done;
|
alpar@1
|
390 |
/* solve the transformed MIP */
|
alpar@1
|
391 |
mip->it_cnt = P->it_cnt;
|
alpar@1
|
392 |
ret = solve_mip(mip, parm);
|
alpar@1
|
393 |
P->it_cnt = mip->it_cnt;
|
alpar@1
|
394 |
/* only integer feasible solution can be postprocessed */
|
alpar@1
|
395 |
if (!(mip->mip_stat == GLP_OPT || mip->mip_stat == GLP_FEAS))
|
alpar@1
|
396 |
{ P->mip_stat = mip->mip_stat;
|
alpar@1
|
397 |
goto done;
|
alpar@1
|
398 |
}
|
alpar@1
|
399 |
/* postprocess solution from the transformed MIP */
|
alpar@1
|
400 |
post: npp_postprocess(npp, mip);
|
alpar@1
|
401 |
/* the transformed MIP is no longer needed */
|
alpar@1
|
402 |
glp_delete_prob(mip), mip = NULL;
|
alpar@1
|
403 |
/* store solution to the original problem */
|
alpar@1
|
404 |
npp_unload_sol(npp, P);
|
alpar@1
|
405 |
done: /* delete the transformed MIP, if it exists */
|
alpar@1
|
406 |
if (mip != NULL) glp_delete_prob(mip);
|
alpar@1
|
407 |
/* delete preprocessor workspace */
|
alpar@1
|
408 |
npp_delete_wksp(npp);
|
alpar@1
|
409 |
return ret;
|
alpar@1
|
410 |
}
|
alpar@1
|
411 |
|
alpar@1
|
412 |
#ifndef HAVE_ALIEN_SOLVER /* 28/V-2010 */
|
alpar@1
|
413 |
int _glp_intopt1(glp_prob *P, const glp_iocp *parm)
|
alpar@1
|
414 |
{ xassert(P == P);
|
alpar@1
|
415 |
xassert(parm == parm);
|
alpar@1
|
416 |
xprintf("glp_intopt: no alien solver is available\n");
|
alpar@1
|
417 |
return GLP_EFAIL;
|
alpar@1
|
418 |
}
|
alpar@1
|
419 |
#endif
|
alpar@1
|
420 |
|
alpar@1
|
421 |
int glp_intopt(glp_prob *P, const glp_iocp *parm)
|
alpar@1
|
422 |
{ /* solve MIP problem with the branch-and-bound method */
|
alpar@1
|
423 |
glp_iocp _parm;
|
alpar@1
|
424 |
int i, j, ret;
|
alpar@1
|
425 |
/* check problem object */
|
alpar@1
|
426 |
if (P == NULL || P->magic != GLP_PROB_MAGIC)
|
alpar@1
|
427 |
xerror("glp_intopt: P = %p; invalid problem object\n", P);
|
alpar@1
|
428 |
if (P->tree != NULL)
|
alpar@1
|
429 |
xerror("glp_intopt: operation not allowed\n");
|
alpar@1
|
430 |
/* check control parameters */
|
alpar@1
|
431 |
if (parm == NULL)
|
alpar@1
|
432 |
parm = &_parm, glp_init_iocp((glp_iocp *)parm);
|
alpar@1
|
433 |
if (!(parm->msg_lev == GLP_MSG_OFF ||
|
alpar@1
|
434 |
parm->msg_lev == GLP_MSG_ERR ||
|
alpar@1
|
435 |
parm->msg_lev == GLP_MSG_ON ||
|
alpar@1
|
436 |
parm->msg_lev == GLP_MSG_ALL ||
|
alpar@1
|
437 |
parm->msg_lev == GLP_MSG_DBG))
|
alpar@1
|
438 |
xerror("glp_intopt: msg_lev = %d; invalid parameter\n",
|
alpar@1
|
439 |
parm->msg_lev);
|
alpar@1
|
440 |
if (!(parm->br_tech == GLP_BR_FFV ||
|
alpar@1
|
441 |
parm->br_tech == GLP_BR_LFV ||
|
alpar@1
|
442 |
parm->br_tech == GLP_BR_MFV ||
|
alpar@1
|
443 |
parm->br_tech == GLP_BR_DTH ||
|
alpar@1
|
444 |
parm->br_tech == GLP_BR_PCH))
|
alpar@1
|
445 |
xerror("glp_intopt: br_tech = %d; invalid parameter\n",
|
alpar@1
|
446 |
parm->br_tech);
|
alpar@1
|
447 |
if (!(parm->bt_tech == GLP_BT_DFS ||
|
alpar@1
|
448 |
parm->bt_tech == GLP_BT_BFS ||
|
alpar@1
|
449 |
parm->bt_tech == GLP_BT_BLB ||
|
alpar@1
|
450 |
parm->bt_tech == GLP_BT_BPH))
|
alpar@1
|
451 |
xerror("glp_intopt: bt_tech = %d; invalid parameter\n",
|
alpar@1
|
452 |
parm->bt_tech);
|
alpar@1
|
453 |
if (!(0.0 < parm->tol_int && parm->tol_int < 1.0))
|
alpar@1
|
454 |
xerror("glp_intopt: tol_int = %g; invalid parameter\n",
|
alpar@1
|
455 |
parm->tol_int);
|
alpar@1
|
456 |
if (!(0.0 < parm->tol_obj && parm->tol_obj < 1.0))
|
alpar@1
|
457 |
xerror("glp_intopt: tol_obj = %g; invalid parameter\n",
|
alpar@1
|
458 |
parm->tol_obj);
|
alpar@1
|
459 |
if (parm->tm_lim < 0)
|
alpar@1
|
460 |
xerror("glp_intopt: tm_lim = %d; invalid parameter\n",
|
alpar@1
|
461 |
parm->tm_lim);
|
alpar@1
|
462 |
if (parm->out_frq < 0)
|
alpar@1
|
463 |
xerror("glp_intopt: out_frq = %d; invalid parameter\n",
|
alpar@1
|
464 |
parm->out_frq);
|
alpar@1
|
465 |
if (parm->out_dly < 0)
|
alpar@1
|
466 |
xerror("glp_intopt: out_dly = %d; invalid parameter\n",
|
alpar@1
|
467 |
parm->out_dly);
|
alpar@1
|
468 |
if (!(0 <= parm->cb_size && parm->cb_size <= 256))
|
alpar@1
|
469 |
xerror("glp_intopt: cb_size = %d; invalid parameter\n",
|
alpar@1
|
470 |
parm->cb_size);
|
alpar@1
|
471 |
if (!(parm->pp_tech == GLP_PP_NONE ||
|
alpar@1
|
472 |
parm->pp_tech == GLP_PP_ROOT ||
|
alpar@1
|
473 |
parm->pp_tech == GLP_PP_ALL))
|
alpar@1
|
474 |
xerror("glp_intopt: pp_tech = %d; invalid parameter\n",
|
alpar@1
|
475 |
parm->pp_tech);
|
alpar@1
|
476 |
if (parm->mip_gap < 0.0)
|
alpar@1
|
477 |
xerror("glp_intopt: mip_gap = %g; invalid parameter\n",
|
alpar@1
|
478 |
parm->mip_gap);
|
alpar@1
|
479 |
if (!(parm->mir_cuts == GLP_ON || parm->mir_cuts == GLP_OFF))
|
alpar@1
|
480 |
xerror("glp_intopt: mir_cuts = %d; invalid parameter\n",
|
alpar@1
|
481 |
parm->mir_cuts);
|
alpar@1
|
482 |
if (!(parm->gmi_cuts == GLP_ON || parm->gmi_cuts == GLP_OFF))
|
alpar@1
|
483 |
xerror("glp_intopt: gmi_cuts = %d; invalid parameter\n",
|
alpar@1
|
484 |
parm->gmi_cuts);
|
alpar@1
|
485 |
if (!(parm->cov_cuts == GLP_ON || parm->cov_cuts == GLP_OFF))
|
alpar@1
|
486 |
xerror("glp_intopt: cov_cuts = %d; invalid parameter\n",
|
alpar@1
|
487 |
parm->cov_cuts);
|
alpar@1
|
488 |
if (!(parm->clq_cuts == GLP_ON || parm->clq_cuts == GLP_OFF))
|
alpar@1
|
489 |
xerror("glp_intopt: clq_cuts = %d; invalid parameter\n",
|
alpar@1
|
490 |
parm->clq_cuts);
|
alpar@1
|
491 |
if (!(parm->presolve == GLP_ON || parm->presolve == GLP_OFF))
|
alpar@1
|
492 |
xerror("glp_intopt: presolve = %d; invalid parameter\n",
|
alpar@1
|
493 |
parm->presolve);
|
alpar@1
|
494 |
if (!(parm->binarize == GLP_ON || parm->binarize == GLP_OFF))
|
alpar@1
|
495 |
xerror("glp_intopt: binarize = %d; invalid parameter\n",
|
alpar@1
|
496 |
parm->binarize);
|
alpar@1
|
497 |
if (!(parm->fp_heur == GLP_ON || parm->fp_heur == GLP_OFF))
|
alpar@1
|
498 |
xerror("glp_intopt: fp_heur = %d; invalid parameter\n",
|
alpar@1
|
499 |
parm->fp_heur);
|
alpar@1
|
500 |
#if 1 /* 28/V-2010 */
|
alpar@1
|
501 |
if (!(parm->alien == GLP_ON || parm->alien == GLP_OFF))
|
alpar@1
|
502 |
xerror("glp_intopt: alien = %d; invalid parameter\n",
|
alpar@1
|
503 |
parm->alien);
|
alpar@1
|
504 |
#endif
|
alpar@1
|
505 |
/* integer solution is currently undefined */
|
alpar@1
|
506 |
P->mip_stat = GLP_UNDEF;
|
alpar@1
|
507 |
P->mip_obj = 0.0;
|
alpar@1
|
508 |
/* check bounds of double-bounded variables */
|
alpar@1
|
509 |
for (i = 1; i <= P->m; i++)
|
alpar@1
|
510 |
{ GLPROW *row = P->row[i];
|
alpar@1
|
511 |
if (row->type == GLP_DB && row->lb >= row->ub)
|
alpar@1
|
512 |
{ if (parm->msg_lev >= GLP_MSG_ERR)
|
alpar@1
|
513 |
xprintf("glp_intopt: row %d: lb = %g, ub = %g; incorrect"
|
alpar@1
|
514 |
" bounds\n", i, row->lb, row->ub);
|
alpar@1
|
515 |
ret = GLP_EBOUND;
|
alpar@1
|
516 |
goto done;
|
alpar@1
|
517 |
}
|
alpar@1
|
518 |
}
|
alpar@1
|
519 |
for (j = 1; j <= P->n; j++)
|
alpar@1
|
520 |
{ GLPCOL *col = P->col[j];
|
alpar@1
|
521 |
if (col->type == GLP_DB && col->lb >= col->ub)
|
alpar@1
|
522 |
{ if (parm->msg_lev >= GLP_MSG_ERR)
|
alpar@1
|
523 |
xprintf("glp_intopt: column %d: lb = %g, ub = %g; incorr"
|
alpar@1
|
524 |
"ect bounds\n", j, col->lb, col->ub);
|
alpar@1
|
525 |
ret = GLP_EBOUND;
|
alpar@1
|
526 |
goto done;
|
alpar@1
|
527 |
}
|
alpar@1
|
528 |
}
|
alpar@1
|
529 |
/* bounds of all integer variables must be integral */
|
alpar@1
|
530 |
for (j = 1; j <= P->n; j++)
|
alpar@1
|
531 |
{ GLPCOL *col = P->col[j];
|
alpar@1
|
532 |
if (col->kind != GLP_IV) continue;
|
alpar@1
|
533 |
if (col->type == GLP_LO || col->type == GLP_DB)
|
alpar@1
|
534 |
{ if (col->lb != floor(col->lb))
|
alpar@1
|
535 |
{ if (parm->msg_lev >= GLP_MSG_ERR)
|
alpar@1
|
536 |
xprintf("glp_intopt: integer column %d has non-intege"
|
alpar@1
|
537 |
"r lower bound %g\n", j, col->lb);
|
alpar@1
|
538 |
ret = GLP_EBOUND;
|
alpar@1
|
539 |
goto done;
|
alpar@1
|
540 |
}
|
alpar@1
|
541 |
}
|
alpar@1
|
542 |
if (col->type == GLP_UP || col->type == GLP_DB)
|
alpar@1
|
543 |
{ if (col->ub != floor(col->ub))
|
alpar@1
|
544 |
{ if (parm->msg_lev >= GLP_MSG_ERR)
|
alpar@1
|
545 |
xprintf("glp_intopt: integer column %d has non-intege"
|
alpar@1
|
546 |
"r upper bound %g\n", j, col->ub);
|
alpar@1
|
547 |
ret = GLP_EBOUND;
|
alpar@1
|
548 |
goto done;
|
alpar@1
|
549 |
}
|
alpar@1
|
550 |
}
|
alpar@1
|
551 |
if (col->type == GLP_FX)
|
alpar@1
|
552 |
{ if (col->lb != floor(col->lb))
|
alpar@1
|
553 |
{ if (parm->msg_lev >= GLP_MSG_ERR)
|
alpar@1
|
554 |
xprintf("glp_intopt: integer column %d has non-intege"
|
alpar@1
|
555 |
"r fixed value %g\n", j, col->lb);
|
alpar@1
|
556 |
ret = GLP_EBOUND;
|
alpar@1
|
557 |
goto done;
|
alpar@1
|
558 |
}
|
alpar@1
|
559 |
}
|
alpar@1
|
560 |
}
|
alpar@1
|
561 |
/* solve MIP problem */
|
alpar@1
|
562 |
if (parm->msg_lev >= GLP_MSG_ALL)
|
alpar@1
|
563 |
{ int ni = glp_get_num_int(P);
|
alpar@1
|
564 |
int nb = glp_get_num_bin(P);
|
alpar@1
|
565 |
char s[50];
|
alpar@1
|
566 |
xprintf("GLPK Integer Optimizer, v%s\n", glp_version());
|
alpar@1
|
567 |
xprintf("%d row%s, %d column%s, %d non-zero%s\n",
|
alpar@1
|
568 |
P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
|
alpar@1
|
569 |
P->nnz, P->nnz == 1 ? "" : "s");
|
alpar@1
|
570 |
if (nb == 0)
|
alpar@1
|
571 |
strcpy(s, "none of");
|
alpar@1
|
572 |
else if (ni == 1 && nb == 1)
|
alpar@1
|
573 |
strcpy(s, "");
|
alpar@1
|
574 |
else if (nb == 1)
|
alpar@1
|
575 |
strcpy(s, "one of");
|
alpar@1
|
576 |
else if (nb == ni)
|
alpar@1
|
577 |
strcpy(s, "all of");
|
alpar@1
|
578 |
else
|
alpar@1
|
579 |
sprintf(s, "%d of", nb);
|
alpar@1
|
580 |
xprintf("%d integer variable%s, %s which %s binary\n",
|
alpar@1
|
581 |
ni, ni == 1 ? "" : "s", s, nb == 1 ? "is" : "are");
|
alpar@1
|
582 |
}
|
alpar@1
|
583 |
#if 1 /* 28/V-2010 */
|
alpar@1
|
584 |
if (parm->alien)
|
alpar@1
|
585 |
{ /* use alien integer optimizer */
|
alpar@1
|
586 |
ret = _glp_intopt1(P, parm);
|
alpar@1
|
587 |
goto done;
|
alpar@1
|
588 |
}
|
alpar@1
|
589 |
#endif
|
alpar@1
|
590 |
if (!parm->presolve)
|
alpar@1
|
591 |
ret = solve_mip(P, parm);
|
alpar@1
|
592 |
else
|
alpar@1
|
593 |
ret = preprocess_and_solve_mip(P, parm);
|
alpar@1
|
594 |
done: /* return to the application program */
|
alpar@1
|
595 |
return ret;
|
alpar@1
|
596 |
}
|
alpar@1
|
597 |
|
alpar@1
|
598 |
/***********************************************************************
|
alpar@1
|
599 |
* NAME
|
alpar@1
|
600 |
*
|
alpar@1
|
601 |
* glp_init_iocp - initialize integer optimizer control parameters
|
alpar@1
|
602 |
*
|
alpar@1
|
603 |
* SYNOPSIS
|
alpar@1
|
604 |
*
|
alpar@1
|
605 |
* void glp_init_iocp(glp_iocp *parm);
|
alpar@1
|
606 |
*
|
alpar@1
|
607 |
* DESCRIPTION
|
alpar@1
|
608 |
*
|
alpar@1
|
609 |
* The routine glp_init_iocp initializes control parameters, which are
|
alpar@1
|
610 |
* used by the integer optimizer, with default values.
|
alpar@1
|
611 |
*
|
alpar@1
|
612 |
* Default values of the control parameters are stored in a glp_iocp
|
alpar@1
|
613 |
* structure, which the parameter parm points to. */
|
alpar@1
|
614 |
|
alpar@1
|
615 |
void glp_init_iocp(glp_iocp *parm)
|
alpar@1
|
616 |
{ parm->msg_lev = GLP_MSG_ALL;
|
alpar@1
|
617 |
parm->br_tech = GLP_BR_DTH;
|
alpar@1
|
618 |
parm->bt_tech = GLP_BT_BLB;
|
alpar@1
|
619 |
parm->tol_int = 1e-5;
|
alpar@1
|
620 |
parm->tol_obj = 1e-7;
|
alpar@1
|
621 |
parm->tm_lim = INT_MAX;
|
alpar@1
|
622 |
parm->out_frq = 5000;
|
alpar@1
|
623 |
parm->out_dly = 10000;
|
alpar@1
|
624 |
parm->cb_func = NULL;
|
alpar@1
|
625 |
parm->cb_info = NULL;
|
alpar@1
|
626 |
parm->cb_size = 0;
|
alpar@1
|
627 |
parm->pp_tech = GLP_PP_ALL;
|
alpar@1
|
628 |
parm->mip_gap = 0.0;
|
alpar@1
|
629 |
parm->mir_cuts = GLP_OFF;
|
alpar@1
|
630 |
parm->gmi_cuts = GLP_OFF;
|
alpar@1
|
631 |
parm->cov_cuts = GLP_OFF;
|
alpar@1
|
632 |
parm->clq_cuts = GLP_OFF;
|
alpar@1
|
633 |
parm->presolve = GLP_OFF;
|
alpar@1
|
634 |
parm->binarize = GLP_OFF;
|
alpar@1
|
635 |
parm->fp_heur = GLP_OFF;
|
alpar@1
|
636 |
#if 1 /* 28/V-2010 */
|
alpar@1
|
637 |
parm->alien = GLP_OFF;
|
alpar@1
|
638 |
#endif
|
alpar@1
|
639 |
return;
|
alpar@1
|
640 |
}
|
alpar@1
|
641 |
|
alpar@1
|
642 |
/***********************************************************************
|
alpar@1
|
643 |
* NAME
|
alpar@1
|
644 |
*
|
alpar@1
|
645 |
* glp_mip_status - retrieve status of MIP solution
|
alpar@1
|
646 |
*
|
alpar@1
|
647 |
* SYNOPSIS
|
alpar@1
|
648 |
*
|
alpar@1
|
649 |
* int glp_mip_status(glp_prob *mip);
|
alpar@1
|
650 |
*
|
alpar@1
|
651 |
* RETURNS
|
alpar@1
|
652 |
*
|
alpar@1
|
653 |
* The routine lpx_mip_status reports the status of MIP solution found
|
alpar@1
|
654 |
* by the branch-and-bound solver as follows:
|
alpar@1
|
655 |
*
|
alpar@1
|
656 |
* GLP_UNDEF - MIP solution is undefined;
|
alpar@1
|
657 |
* GLP_OPT - MIP solution is integer optimal;
|
alpar@1
|
658 |
* GLP_FEAS - MIP solution is integer feasible but its optimality
|
alpar@1
|
659 |
* (or non-optimality) has not been proven, perhaps due to
|
alpar@1
|
660 |
* premature termination of the search;
|
alpar@1
|
661 |
* GLP_NOFEAS - problem has no integer feasible solution (proven by the
|
alpar@1
|
662 |
* solver). */
|
alpar@1
|
663 |
|
alpar@1
|
664 |
int glp_mip_status(glp_prob *mip)
|
alpar@1
|
665 |
{ int mip_stat = mip->mip_stat;
|
alpar@1
|
666 |
return mip_stat;
|
alpar@1
|
667 |
}
|
alpar@1
|
668 |
|
alpar@1
|
669 |
/***********************************************************************
|
alpar@1
|
670 |
* NAME
|
alpar@1
|
671 |
*
|
alpar@1
|
672 |
* glp_mip_obj_val - retrieve objective value (MIP solution)
|
alpar@1
|
673 |
*
|
alpar@1
|
674 |
* SYNOPSIS
|
alpar@1
|
675 |
*
|
alpar@1
|
676 |
* double glp_mip_obj_val(glp_prob *mip);
|
alpar@1
|
677 |
*
|
alpar@1
|
678 |
* RETURNS
|
alpar@1
|
679 |
*
|
alpar@1
|
680 |
* The routine glp_mip_obj_val returns value of the objective function
|
alpar@1
|
681 |
* for MIP solution. */
|
alpar@1
|
682 |
|
alpar@1
|
683 |
double glp_mip_obj_val(glp_prob *mip)
|
alpar@1
|
684 |
{ /*struct LPXCPS *cps = mip->cps;*/
|
alpar@1
|
685 |
double z;
|
alpar@1
|
686 |
z = mip->mip_obj;
|
alpar@1
|
687 |
/*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/
|
alpar@1
|
688 |
return z;
|
alpar@1
|
689 |
}
|
alpar@1
|
690 |
|
alpar@1
|
691 |
/***********************************************************************
|
alpar@1
|
692 |
* NAME
|
alpar@1
|
693 |
*
|
alpar@1
|
694 |
* glp_mip_row_val - retrieve row value (MIP solution)
|
alpar@1
|
695 |
*
|
alpar@1
|
696 |
* SYNOPSIS
|
alpar@1
|
697 |
*
|
alpar@1
|
698 |
* double glp_mip_row_val(glp_prob *mip, int i);
|
alpar@1
|
699 |
*
|
alpar@1
|
700 |
* RETURNS
|
alpar@1
|
701 |
*
|
alpar@1
|
702 |
* The routine glp_mip_row_val returns value of the auxiliary variable
|
alpar@1
|
703 |
* associated with i-th row. */
|
alpar@1
|
704 |
|
alpar@1
|
705 |
double glp_mip_row_val(glp_prob *mip, int i)
|
alpar@1
|
706 |
{ /*struct LPXCPS *cps = mip->cps;*/
|
alpar@1
|
707 |
double mipx;
|
alpar@1
|
708 |
if (!(1 <= i && i <= mip->m))
|
alpar@1
|
709 |
xerror("glp_mip_row_val: i = %d; row number out of range\n", i)
|
alpar@1
|
710 |
;
|
alpar@1
|
711 |
mipx = mip->row[i]->mipx;
|
alpar@1
|
712 |
/*if (cps->round && fabs(mipx) < 1e-9) mipx = 0.0;*/
|
alpar@1
|
713 |
return mipx;
|
alpar@1
|
714 |
}
|
alpar@1
|
715 |
|
alpar@1
|
716 |
/***********************************************************************
|
alpar@1
|
717 |
* NAME
|
alpar@1
|
718 |
*
|
alpar@1
|
719 |
* glp_mip_col_val - retrieve column value (MIP solution)
|
alpar@1
|
720 |
*
|
alpar@1
|
721 |
* SYNOPSIS
|
alpar@1
|
722 |
*
|
alpar@1
|
723 |
* double glp_mip_col_val(glp_prob *mip, int j);
|
alpar@1
|
724 |
*
|
alpar@1
|
725 |
* RETURNS
|
alpar@1
|
726 |
*
|
alpar@1
|
727 |
* The routine glp_mip_col_val returns value of the structural variable
|
alpar@1
|
728 |
* associated with j-th column. */
|
alpar@1
|
729 |
|
alpar@1
|
730 |
double glp_mip_col_val(glp_prob *mip, int j)
|
alpar@1
|
731 |
{ /*struct LPXCPS *cps = mip->cps;*/
|
alpar@1
|
732 |
double mipx;
|
alpar@1
|
733 |
if (!(1 <= j && j <= mip->n))
|
alpar@1
|
734 |
xerror("glp_mip_col_val: j = %d; column number out of range\n",
|
alpar@1
|
735 |
j);
|
alpar@1
|
736 |
mipx = mip->col[j]->mipx;
|
alpar@1
|
737 |
/*if (cps->round && fabs(mipx) < 1e-9) mipx = 0.0;*/
|
alpar@1
|
738 |
return mipx;
|
alpar@1
|
739 |
}
|
alpar@1
|
740 |
|
alpar@1
|
741 |
/* eof */
|