1 /* glpapi08.c (interior-point method routines) */
2
3 /***********************************************************************
4 * This code is part of GLPK (GNU Linear Programming Kit).
5 * Copyright (C) 2000-2013 Free Software Foundation, Inc.
6 * Written by Andrew Makhorin <mao@gnu.org>.
7 *
8 * GLPK is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * GLPK is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 * License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with GLPK. If not, see <http://www.gnu.org/licenses/>.
20 ***********************************************************************/
21
22 #include "env.h"
23 #include "glpipm.h"
24 #include "npp.h"
25
26 /***********************************************************************
27 * NAME
28 *
29 * glp_interior - solve LP problem with the interior-point method
30 *
31 * SYNOPSIS
32 *
33 * int glp_interior(glp_prob *P, const glp_iptcp *parm);
34 *
35 * The routine glp_interior is a driver to the LP solver based on the
36 * interior-point method.
37 *
38 * The interior-point solver has a set of control parameters. Values of
39 * the control parameters can be passed in a structure glp_iptcp, which
40 * the parameter parm points to.
41 *
42 * Currently this routine implements an easy variant of the primal-dual
43 * interior-point method based on Mehrotra's technique.
44 *
45 * This routine transforms the original LP problem to an equivalent LP
46 * problem in the standard formulation (all constraints are equalities,
47 * all variables are non-negative), calls the routine ipm_main to solve
48 * the transformed problem, and then transforms an obtained solution to
49 * the solution of the original problem.
50 *
51 * RETURNS
52 *
53 * 0 The LP problem instance has been successfully solved. This code
54 * does not necessarily mean that the solver has found optimal
55 * solution. It only means that the solution process was successful.
56 *
57 * GLP_EFAIL
58 * The problem has no rows/columns.
59 *
60 * GLP_ENOCVG
61 * Very slow convergence or divergence.
62 *
63 * GLP_EITLIM
64 * Iteration limit exceeded.
65 *
66 * GLP_EINSTAB
67 * Numerical instability on solving Newtonian system. */
68
transform(NPP * npp)69 static void transform(NPP *npp)
70 { /* transform LP to the standard formulation */
71 NPPROW *row, *prev_row;
72 NPPCOL *col, *prev_col;
73 for (row = npp->r_tail; row != NULL; row = prev_row)
74 { prev_row = row->prev;
75 if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
76 npp_free_row(npp, row);
77 else if (row->lb == -DBL_MAX)
78 npp_leq_row(npp, row);
79 else if (row->ub == +DBL_MAX)
80 npp_geq_row(npp, row);
81 else if (row->lb != row->ub)
82 { if (fabs(row->lb) < fabs(row->ub))
83 npp_geq_row(npp, row);
84 else
85 npp_leq_row(npp, row);
86 }
87 }
88 for (col = npp->c_tail; col != NULL; col = prev_col)
89 { prev_col = col->prev;
90 if (col->lb == -DBL_MAX && col->ub == +DBL_MAX)
91 npp_free_col(npp, col);
92 else if (col->lb == -DBL_MAX)
93 npp_ubnd_col(npp, col);
94 else if (col->ub == +DBL_MAX)
95 { if (col->lb != 0.0)
96 npp_lbnd_col(npp, col);
97 }
98 else if (col->lb != col->ub)
99 { if (fabs(col->lb) < fabs(col->ub))
100 { if (col->lb != 0.0)
101 npp_lbnd_col(npp, col);
102 }
103 else
104 npp_ubnd_col(npp, col);
105 npp_dbnd_col(npp, col);
106 }
107 else
108 npp_fixed_col(npp, col);
109 }
110 for (row = npp->r_head; row != NULL; row = row->next)
111 xassert(row->lb == row->ub);
112 for (col = npp->c_head; col != NULL; col = col->next)
113 xassert(col->lb == 0.0 && col->ub == +DBL_MAX);
114 return;
115 }
116
glp_interior(glp_prob * P,const glp_iptcp * parm)117 int glp_interior(glp_prob *P, const glp_iptcp *parm)
118 { glp_iptcp _parm;
119 GLPROW *row;
120 GLPCOL *col;
121 NPP *npp = NULL;
122 glp_prob *prob = NULL;
123 int i, j, ret;
124 /* check control parameters */
125 if (parm == NULL)
126 glp_init_iptcp(&_parm), parm = &_parm;
127 if (!(parm->msg_lev == GLP_MSG_OFF ||
128 parm->msg_lev == GLP_MSG_ERR ||
129 parm->msg_lev == GLP_MSG_ON ||
130 parm->msg_lev == GLP_MSG_ALL))
131 xerror("glp_interior: msg_lev = %d; invalid parameter\n",
132 parm->msg_lev);
133 if (!(parm->ord_alg == GLP_ORD_NONE ||
134 parm->ord_alg == GLP_ORD_QMD ||
135 parm->ord_alg == GLP_ORD_AMD ||
136 parm->ord_alg == GLP_ORD_SYMAMD))
137 xerror("glp_interior: ord_alg = %d; invalid parameter\n",
138 parm->ord_alg);
139 /* interior-point solution is currently undefined */
140 P->ipt_stat = GLP_UNDEF;
141 P->ipt_obj = 0.0;
142 /* check bounds of double-bounded variables */
143 for (i = 1; i <= P->m; i++)
144 { row = P->row[i];
145 if (row->type == GLP_DB && row->lb >= row->ub)
146 { if (parm->msg_lev >= GLP_MSG_ERR)
147 xprintf("glp_interior: row %d: lb = %g, ub = %g; incorre"
148 "ct bounds\n", i, row->lb, row->ub);
149 ret = GLP_EBOUND;
150 goto done;
151 }
152 }
153 for (j = 1; j <= P->n; j++)
154 { col = P->col[j];
155 if (col->type == GLP_DB && col->lb >= col->ub)
156 { if (parm->msg_lev >= GLP_MSG_ERR)
157 xprintf("glp_interior: column %d: lb = %g, ub = %g; inco"
158 "rrect bounds\n", j, col->lb, col->ub);
159 ret = GLP_EBOUND;
160 goto done;
161 }
162 }
163 /* transform LP to the standard formulation */
164 if (parm->msg_lev >= GLP_MSG_ALL)
165 xprintf("Original LP has %d row(s), %d column(s), and %d non-z"
166 "ero(s)\n", P->m, P->n, P->nnz);
167 npp = npp_create_wksp();
168 npp_load_prob(npp, P, GLP_OFF, GLP_IPT, GLP_ON);
169 transform(npp);
170 prob = glp_create_prob();
171 npp_build_prob(npp, prob);
172 if (parm->msg_lev >= GLP_MSG_ALL)
173 xprintf("Working LP has %d row(s), %d column(s), and %d non-ze"
174 "ro(s)\n", prob->m, prob->n, prob->nnz);
175 #if 1
176 /* currently empty problem cannot be solved */
177 if (!(prob->m > 0 && prob->n > 0))
178 { if (parm->msg_lev >= GLP_MSG_ERR)
179 xprintf("glp_interior: unable to solve empty problem\n");
180 ret = GLP_EFAIL;
181 goto done;
182 }
183 #endif
184 /* scale the resultant LP */
185 { ENV *env = get_env_ptr();
186 int term_out = env->term_out;
187 env->term_out = GLP_OFF;
188 glp_scale_prob(prob, GLP_SF_EQ);
189 env->term_out = term_out;
190 }
191 /* warn about dense columns */
192 if (parm->msg_lev >= GLP_MSG_ON && prob->m >= 200)
193 { int len, cnt = 0;
194 for (j = 1; j <= prob->n; j++)
195 { len = glp_get_mat_col(prob, j, NULL, NULL);
196 if ((double)len >= 0.20 * (double)prob->m) cnt++;
197 }
198 if (cnt == 1)
199 xprintf("WARNING: PROBLEM HAS ONE DENSE COLUMN\n");
200 else if (cnt > 0)
201 xprintf("WARNING: PROBLEM HAS %d DENSE COLUMNS\n", cnt);
202 }
203 /* solve the transformed LP */
204 ret = ipm_solve(prob, parm);
205 /* postprocess solution from the transformed LP */
206 npp_postprocess(npp, prob);
207 /* and store solution to the original LP */
208 npp_unload_sol(npp, P);
209 done: /* free working program objects */
210 if (npp != NULL) npp_delete_wksp(npp);
211 if (prob != NULL) glp_delete_prob(prob);
212 /* return to the application program */
213 return ret;
214 }
215
216 /***********************************************************************
217 * NAME
218 *
219 * glp_init_iptcp - initialize interior-point solver control parameters
220 *
221 * SYNOPSIS
222 *
223 * void glp_init_iptcp(glp_iptcp *parm);
224 *
225 * DESCRIPTION
226 *
227 * The routine glp_init_iptcp initializes control parameters, which are
228 * used by the interior-point solver, with default values.
229 *
230 * Default values of the control parameters are stored in the glp_iptcp
231 * structure, which the parameter parm points to. */
232
glp_init_iptcp(glp_iptcp * parm)233 void glp_init_iptcp(glp_iptcp *parm)
234 { parm->msg_lev = GLP_MSG_ALL;
235 parm->ord_alg = GLP_ORD_AMD;
236 return;
237 }
238
239 /***********************************************************************
240 * NAME
241 *
242 * glp_ipt_status - retrieve status of interior-point solution
243 *
244 * SYNOPSIS
245 *
246 * int glp_ipt_status(glp_prob *lp);
247 *
248 * RETURNS
249 *
250 * The routine glp_ipt_status reports the status of solution found by
251 * the interior-point solver as follows:
252 *
253 * GLP_UNDEF - interior-point solution is undefined;
254 * GLP_OPT - interior-point solution is optimal;
255 * GLP_INFEAS - interior-point solution is infeasible;
256 * GLP_NOFEAS - no feasible solution exists. */
257
glp_ipt_status(glp_prob * lp)258 int glp_ipt_status(glp_prob *lp)
259 { int ipt_stat = lp->ipt_stat;
260 return ipt_stat;
261 }
262
263 /***********************************************************************
264 * NAME
265 *
266 * glp_ipt_obj_val - retrieve objective value (interior point)
267 *
268 * SYNOPSIS
269 *
270 * double glp_ipt_obj_val(glp_prob *lp);
271 *
272 * RETURNS
273 *
274 * The routine glp_ipt_obj_val returns value of the objective function
275 * for interior-point solution. */
276
glp_ipt_obj_val(glp_prob * lp)277 double glp_ipt_obj_val(glp_prob *lp)
278 { /*struct LPXCPS *cps = lp->cps;*/
279 double z;
280 z = lp->ipt_obj;
281 /*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/
282 return z;
283 }
284
285 /***********************************************************************
286 * NAME
287 *
288 * glp_ipt_row_prim - retrieve row primal value (interior point)
289 *
290 * SYNOPSIS
291 *
292 * double glp_ipt_row_prim(glp_prob *lp, int i);
293 *
294 * RETURNS
295 *
296 * The routine glp_ipt_row_prim returns primal value of the auxiliary
297 * variable associated with i-th row. */
298
glp_ipt_row_prim(glp_prob * lp,int i)299 double glp_ipt_row_prim(glp_prob *lp, int i)
300 { /*struct LPXCPS *cps = lp->cps;*/
301 double pval;
302 if (!(1 <= i && i <= lp->m))
303 xerror("glp_ipt_row_prim: i = %d; row number out of range\n",
304 i);
305 pval = lp->row[i]->pval;
306 /*if (cps->round && fabs(pval) < 1e-9) pval = 0.0;*/
307 return pval;
308 }
309
310 /***********************************************************************
311 * NAME
312 *
313 * glp_ipt_row_dual - retrieve row dual value (interior point)
314 *
315 * SYNOPSIS
316 *
317 * double glp_ipt_row_dual(glp_prob *lp, int i);
318 *
319 * RETURNS
320 *
321 * The routine glp_ipt_row_dual returns dual value (i.e. reduced cost)
322 * of the auxiliary variable associated with i-th row. */
323
glp_ipt_row_dual(glp_prob * lp,int i)324 double glp_ipt_row_dual(glp_prob *lp, int i)
325 { /*struct LPXCPS *cps = lp->cps;*/
326 double dval;
327 if (!(1 <= i && i <= lp->m))
328 xerror("glp_ipt_row_dual: i = %d; row number out of range\n",
329 i);
330 dval = lp->row[i]->dval;
331 /*if (cps->round && fabs(dval) < 1e-9) dval = 0.0;*/
332 return dval;
333 }
334
335 /***********************************************************************
336 * NAME
337 *
338 * glp_ipt_col_prim - retrieve column primal value (interior point)
339 *
340 * SYNOPSIS
341 *
342 * double glp_ipt_col_prim(glp_prob *lp, int j);
343 *
344 * RETURNS
345 *
346 * The routine glp_ipt_col_prim returns primal value of the structural
347 * variable associated with j-th column. */
348
glp_ipt_col_prim(glp_prob * lp,int j)349 double glp_ipt_col_prim(glp_prob *lp, int j)
350 { /*struct LPXCPS *cps = lp->cps;*/
351 double pval;
352 if (!(1 <= j && j <= lp->n))
353 xerror("glp_ipt_col_prim: j = %d; column number out of range\n"
354 , j);
355 pval = lp->col[j]->pval;
356 /*if (cps->round && fabs(pval) < 1e-9) pval = 0.0;*/
357 return pval;
358 }
359
360 /***********************************************************************
361 * NAME
362 *
363 * glp_ipt_col_dual - retrieve column dual value (interior point)
364 *
365 * SYNOPSIS
366 *
367 * double glp_ipt_col_dual(glp_prob *lp, int j);
368 *
369 * RETURNS
370 *
371 * The routine glp_ipt_col_dual returns dual value (i.e. reduced cost)
372 * of the structural variable associated with j-th column. */
373
glp_ipt_col_dual(glp_prob * lp,int j)374 double glp_ipt_col_dual(glp_prob *lp, int j)
375 { /*struct LPXCPS *cps = lp->cps;*/
376 double dval;
377 if (!(1 <= j && j <= lp->n))
378 xerror("glp_ipt_col_dual: j = %d; column number out of range\n"
379 , j);
380 dval = lp->col[j]->dval;
381 /*if (cps->round && fabs(dval) < 1e-9) dval = 0.0;*/
382 return dval;
383 }
384
385 /* eof */
386