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