rev |
line source |
alpar@9
|
1 /* glpapi06.c (simplex method routines) */
|
alpar@9
|
2
|
alpar@9
|
3 /***********************************************************************
|
alpar@9
|
4 * This code is part of GLPK (GNU Linear Programming Kit).
|
alpar@9
|
5 *
|
alpar@9
|
6 * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
|
alpar@9
|
7 * 2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
|
alpar@9
|
8 * Moscow Aviation Institute, Moscow, Russia. All rights reserved.
|
alpar@9
|
9 * E-mail: <mao@gnu.org>.
|
alpar@9
|
10 *
|
alpar@9
|
11 * GLPK is free software: you can redistribute it and/or modify it
|
alpar@9
|
12 * under the terms of the GNU General Public License as published by
|
alpar@9
|
13 * the Free Software Foundation, either version 3 of the License, or
|
alpar@9
|
14 * (at your option) any later version.
|
alpar@9
|
15 *
|
alpar@9
|
16 * GLPK is distributed in the hope that it will be useful, but WITHOUT
|
alpar@9
|
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
alpar@9
|
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
alpar@9
|
19 * License for more details.
|
alpar@9
|
20 *
|
alpar@9
|
21 * You should have received a copy of the GNU General Public License
|
alpar@9
|
22 * along with GLPK. If not, see <http://www.gnu.org/licenses/>.
|
alpar@9
|
23 ***********************************************************************/
|
alpar@9
|
24
|
alpar@9
|
25 #include "glpios.h"
|
alpar@9
|
26 #include "glpnpp.h"
|
alpar@9
|
27 #include "glpspx.h"
|
alpar@9
|
28
|
alpar@9
|
29 /***********************************************************************
|
alpar@9
|
30 * NAME
|
alpar@9
|
31 *
|
alpar@9
|
32 * glp_simplex - solve LP problem with the simplex method
|
alpar@9
|
33 *
|
alpar@9
|
34 * SYNOPSIS
|
alpar@9
|
35 *
|
alpar@9
|
36 * int glp_simplex(glp_prob *P, const glp_smcp *parm);
|
alpar@9
|
37 *
|
alpar@9
|
38 * DESCRIPTION
|
alpar@9
|
39 *
|
alpar@9
|
40 * The routine glp_simplex is a driver to the LP solver based on the
|
alpar@9
|
41 * simplex method. This routine retrieves problem data from the
|
alpar@9
|
42 * specified problem object, calls the solver to solve the problem
|
alpar@9
|
43 * instance, and stores results of computations back into the problem
|
alpar@9
|
44 * object.
|
alpar@9
|
45 *
|
alpar@9
|
46 * The simplex solver has a set of control parameters. Values of the
|
alpar@9
|
47 * control parameters can be passed in a structure glp_smcp, which the
|
alpar@9
|
48 * parameter parm points to.
|
alpar@9
|
49 *
|
alpar@9
|
50 * The parameter parm can be specified as NULL, in which case the LP
|
alpar@9
|
51 * solver uses default settings.
|
alpar@9
|
52 *
|
alpar@9
|
53 * RETURNS
|
alpar@9
|
54 *
|
alpar@9
|
55 * 0 The LP problem instance has been successfully solved. This code
|
alpar@9
|
56 * does not necessarily mean that the solver has found optimal
|
alpar@9
|
57 * solution. It only means that the solution process was successful.
|
alpar@9
|
58 *
|
alpar@9
|
59 * GLP_EBADB
|
alpar@9
|
60 * Unable to start the search, because the initial basis specified
|
alpar@9
|
61 * in the problem object is invalid--the number of basic (auxiliary
|
alpar@9
|
62 * and structural) variables is not the same as the number of rows in
|
alpar@9
|
63 * the problem object.
|
alpar@9
|
64 *
|
alpar@9
|
65 * GLP_ESING
|
alpar@9
|
66 * Unable to start the search, because the basis matrix correspodning
|
alpar@9
|
67 * to the initial basis is singular within the working precision.
|
alpar@9
|
68 *
|
alpar@9
|
69 * GLP_ECOND
|
alpar@9
|
70 * Unable to start the search, because the basis matrix correspodning
|
alpar@9
|
71 * to the initial basis is ill-conditioned, i.e. its condition number
|
alpar@9
|
72 * is too large.
|
alpar@9
|
73 *
|
alpar@9
|
74 * GLP_EBOUND
|
alpar@9
|
75 * Unable to start the search, because some double-bounded variables
|
alpar@9
|
76 * have incorrect bounds.
|
alpar@9
|
77 *
|
alpar@9
|
78 * GLP_EFAIL
|
alpar@9
|
79 * The search was prematurely terminated due to the solver failure.
|
alpar@9
|
80 *
|
alpar@9
|
81 * GLP_EOBJLL
|
alpar@9
|
82 * The search was prematurely terminated, because the objective
|
alpar@9
|
83 * function being maximized has reached its lower limit and continues
|
alpar@9
|
84 * decreasing (dual simplex only).
|
alpar@9
|
85 *
|
alpar@9
|
86 * GLP_EOBJUL
|
alpar@9
|
87 * The search was prematurely terminated, because the objective
|
alpar@9
|
88 * function being minimized has reached its upper limit and continues
|
alpar@9
|
89 * increasing (dual simplex only).
|
alpar@9
|
90 *
|
alpar@9
|
91 * GLP_EITLIM
|
alpar@9
|
92 * The search was prematurely terminated, because the simplex
|
alpar@9
|
93 * iteration limit has been exceeded.
|
alpar@9
|
94 *
|
alpar@9
|
95 * GLP_ETMLIM
|
alpar@9
|
96 * The search was prematurely terminated, because the time limit has
|
alpar@9
|
97 * been exceeded.
|
alpar@9
|
98 *
|
alpar@9
|
99 * GLP_ENOPFS
|
alpar@9
|
100 * The LP problem instance has no primal feasible solution (only if
|
alpar@9
|
101 * the LP presolver is used).
|
alpar@9
|
102 *
|
alpar@9
|
103 * GLP_ENODFS
|
alpar@9
|
104 * The LP problem instance has no dual feasible solution (only if the
|
alpar@9
|
105 * LP presolver is used). */
|
alpar@9
|
106
|
alpar@9
|
107 static void trivial_lp(glp_prob *P, const glp_smcp *parm)
|
alpar@9
|
108 { /* solve trivial LP which has empty constraint matrix */
|
alpar@9
|
109 GLPROW *row;
|
alpar@9
|
110 GLPCOL *col;
|
alpar@9
|
111 int i, j;
|
alpar@9
|
112 double p_infeas, d_infeas, zeta;
|
alpar@9
|
113 P->valid = 0;
|
alpar@9
|
114 P->pbs_stat = P->dbs_stat = GLP_FEAS;
|
alpar@9
|
115 P->obj_val = P->c0;
|
alpar@9
|
116 P->some = 0;
|
alpar@9
|
117 p_infeas = d_infeas = 0.0;
|
alpar@9
|
118 /* make all auxiliary variables basic */
|
alpar@9
|
119 for (i = 1; i <= P->m; i++)
|
alpar@9
|
120 { row = P->row[i];
|
alpar@9
|
121 row->stat = GLP_BS;
|
alpar@9
|
122 row->prim = row->dual = 0.0;
|
alpar@9
|
123 /* check primal feasibility */
|
alpar@9
|
124 if (row->type == GLP_LO || row->type == GLP_DB ||
|
alpar@9
|
125 row->type == GLP_FX)
|
alpar@9
|
126 { /* row has lower bound */
|
alpar@9
|
127 if (row->lb > + parm->tol_bnd)
|
alpar@9
|
128 { P->pbs_stat = GLP_NOFEAS;
|
alpar@9
|
129 if (P->some == 0 && parm->meth != GLP_PRIMAL)
|
alpar@9
|
130 P->some = i;
|
alpar@9
|
131 }
|
alpar@9
|
132 if (p_infeas < + row->lb)
|
alpar@9
|
133 p_infeas = + row->lb;
|
alpar@9
|
134 }
|
alpar@9
|
135 if (row->type == GLP_UP || row->type == GLP_DB ||
|
alpar@9
|
136 row->type == GLP_FX)
|
alpar@9
|
137 { /* row has upper bound */
|
alpar@9
|
138 if (row->ub < - parm->tol_bnd)
|
alpar@9
|
139 { P->pbs_stat = GLP_NOFEAS;
|
alpar@9
|
140 if (P->some == 0 && parm->meth != GLP_PRIMAL)
|
alpar@9
|
141 P->some = i;
|
alpar@9
|
142 }
|
alpar@9
|
143 if (p_infeas < - row->ub)
|
alpar@9
|
144 p_infeas = - row->ub;
|
alpar@9
|
145 }
|
alpar@9
|
146 }
|
alpar@9
|
147 /* determine scale factor for the objective row */
|
alpar@9
|
148 zeta = 1.0;
|
alpar@9
|
149 for (j = 1; j <= P->n; j++)
|
alpar@9
|
150 { col = P->col[j];
|
alpar@9
|
151 if (zeta < fabs(col->coef)) zeta = fabs(col->coef);
|
alpar@9
|
152 }
|
alpar@9
|
153 zeta = (P->dir == GLP_MIN ? +1.0 : -1.0) / zeta;
|
alpar@9
|
154 /* make all structural variables non-basic */
|
alpar@9
|
155 for (j = 1; j <= P->n; j++)
|
alpar@9
|
156 { col = P->col[j];
|
alpar@9
|
157 if (col->type == GLP_FR)
|
alpar@9
|
158 col->stat = GLP_NF, col->prim = 0.0;
|
alpar@9
|
159 else if (col->type == GLP_LO)
|
alpar@9
|
160 lo: col->stat = GLP_NL, col->prim = col->lb;
|
alpar@9
|
161 else if (col->type == GLP_UP)
|
alpar@9
|
162 up: col->stat = GLP_NU, col->prim = col->ub;
|
alpar@9
|
163 else if (col->type == GLP_DB)
|
alpar@9
|
164 { if (zeta * col->coef > 0.0)
|
alpar@9
|
165 goto lo;
|
alpar@9
|
166 else if (zeta * col->coef < 0.0)
|
alpar@9
|
167 goto up;
|
alpar@9
|
168 else if (fabs(col->lb) <= fabs(col->ub))
|
alpar@9
|
169 goto lo;
|
alpar@9
|
170 else
|
alpar@9
|
171 goto up;
|
alpar@9
|
172 }
|
alpar@9
|
173 else if (col->type == GLP_FX)
|
alpar@9
|
174 col->stat = GLP_NS, col->prim = col->lb;
|
alpar@9
|
175 col->dual = col->coef;
|
alpar@9
|
176 P->obj_val += col->coef * col->prim;
|
alpar@9
|
177 /* check dual feasibility */
|
alpar@9
|
178 if (col->type == GLP_FR || col->type == GLP_LO)
|
alpar@9
|
179 { /* column has no upper bound */
|
alpar@9
|
180 if (zeta * col->dual < - parm->tol_dj)
|
alpar@9
|
181 { P->dbs_stat = GLP_NOFEAS;
|
alpar@9
|
182 if (P->some == 0 && parm->meth == GLP_PRIMAL)
|
alpar@9
|
183 P->some = P->m + j;
|
alpar@9
|
184 }
|
alpar@9
|
185 if (d_infeas < - zeta * col->dual)
|
alpar@9
|
186 d_infeas = - zeta * col->dual;
|
alpar@9
|
187 }
|
alpar@9
|
188 if (col->type == GLP_FR || col->type == GLP_UP)
|
alpar@9
|
189 { /* column has no lower bound */
|
alpar@9
|
190 if (zeta * col->dual > + parm->tol_dj)
|
alpar@9
|
191 { P->dbs_stat = GLP_NOFEAS;
|
alpar@9
|
192 if (P->some == 0 && parm->meth == GLP_PRIMAL)
|
alpar@9
|
193 P->some = P->m + j;
|
alpar@9
|
194 }
|
alpar@9
|
195 if (d_infeas < + zeta * col->dual)
|
alpar@9
|
196 d_infeas = + zeta * col->dual;
|
alpar@9
|
197 }
|
alpar@9
|
198 }
|
alpar@9
|
199 /* simulate the simplex solver output */
|
alpar@9
|
200 if (parm->msg_lev >= GLP_MSG_ON && parm->out_dly == 0)
|
alpar@9
|
201 { xprintf("~%6d: obj = %17.9e infeas = %10.3e\n", P->it_cnt,
|
alpar@9
|
202 P->obj_val, parm->meth == GLP_PRIMAL ? p_infeas : d_infeas);
|
alpar@9
|
203 }
|
alpar@9
|
204 if (parm->msg_lev >= GLP_MSG_ALL && parm->out_dly == 0)
|
alpar@9
|
205 { if (P->pbs_stat == GLP_FEAS && P->dbs_stat == GLP_FEAS)
|
alpar@9
|
206 xprintf("OPTIMAL SOLUTION FOUND\n");
|
alpar@9
|
207 else if (P->pbs_stat == GLP_NOFEAS)
|
alpar@9
|
208 xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n");
|
alpar@9
|
209 else if (parm->meth == GLP_PRIMAL)
|
alpar@9
|
210 xprintf("PROBLEM HAS UNBOUNDED SOLUTION\n");
|
alpar@9
|
211 else
|
alpar@9
|
212 xprintf("PROBLEM HAS NO DUAL FEASIBLE SOLUTION\n");
|
alpar@9
|
213 }
|
alpar@9
|
214 return;
|
alpar@9
|
215 }
|
alpar@9
|
216
|
alpar@9
|
217 static int solve_lp(glp_prob *P, const glp_smcp *parm)
|
alpar@9
|
218 { /* solve LP directly without using the preprocessor */
|
alpar@9
|
219 int ret;
|
alpar@9
|
220 if (!glp_bf_exists(P))
|
alpar@9
|
221 { ret = glp_factorize(P);
|
alpar@9
|
222 if (ret == 0)
|
alpar@9
|
223 ;
|
alpar@9
|
224 else if (ret == GLP_EBADB)
|
alpar@9
|
225 { if (parm->msg_lev >= GLP_MSG_ERR)
|
alpar@9
|
226 xprintf("glp_simplex: initial basis is invalid\n");
|
alpar@9
|
227 }
|
alpar@9
|
228 else if (ret == GLP_ESING)
|
alpar@9
|
229 { if (parm->msg_lev >= GLP_MSG_ERR)
|
alpar@9
|
230 xprintf("glp_simplex: initial basis is singular\n");
|
alpar@9
|
231 }
|
alpar@9
|
232 else if (ret == GLP_ECOND)
|
alpar@9
|
233 { if (parm->msg_lev >= GLP_MSG_ERR)
|
alpar@9
|
234 xprintf(
|
alpar@9
|
235 "glp_simplex: initial basis is ill-conditioned\n");
|
alpar@9
|
236 }
|
alpar@9
|
237 else
|
alpar@9
|
238 xassert(ret != ret);
|
alpar@9
|
239 if (ret != 0) goto done;
|
alpar@9
|
240 }
|
alpar@9
|
241 if (parm->meth == GLP_PRIMAL)
|
alpar@9
|
242 ret = spx_primal(P, parm);
|
alpar@9
|
243 else if (parm->meth == GLP_DUALP)
|
alpar@9
|
244 { ret = spx_dual(P, parm);
|
alpar@9
|
245 if (ret == GLP_EFAIL && P->valid)
|
alpar@9
|
246 ret = spx_primal(P, parm);
|
alpar@9
|
247 }
|
alpar@9
|
248 else if (parm->meth == GLP_DUAL)
|
alpar@9
|
249 ret = spx_dual(P, parm);
|
alpar@9
|
250 else
|
alpar@9
|
251 xassert(parm != parm);
|
alpar@9
|
252 done: return ret;
|
alpar@9
|
253 }
|
alpar@9
|
254
|
alpar@9
|
255 static int preprocess_and_solve_lp(glp_prob *P, const glp_smcp *parm)
|
alpar@9
|
256 { /* solve LP using the preprocessor */
|
alpar@9
|
257 NPP *npp;
|
alpar@9
|
258 glp_prob *lp = NULL;
|
alpar@9
|
259 glp_bfcp bfcp;
|
alpar@9
|
260 int ret;
|
alpar@9
|
261 if (parm->msg_lev >= GLP_MSG_ALL)
|
alpar@9
|
262 xprintf("Preprocessing...\n");
|
alpar@9
|
263 /* create preprocessor workspace */
|
alpar@9
|
264 npp = npp_create_wksp();
|
alpar@9
|
265 /* load original problem into the preprocessor workspace */
|
alpar@9
|
266 npp_load_prob(npp, P, GLP_OFF, GLP_SOL, GLP_OFF);
|
alpar@9
|
267 /* process LP prior to applying primal/dual simplex method */
|
alpar@9
|
268 ret = npp_simplex(npp, parm);
|
alpar@9
|
269 if (ret == 0)
|
alpar@9
|
270 ;
|
alpar@9
|
271 else if (ret == GLP_ENOPFS)
|
alpar@9
|
272 { if (parm->msg_lev >= GLP_MSG_ALL)
|
alpar@9
|
273 xprintf("PROBLEM HAS NO PRIMAL FEASIBLE SOLUTION\n");
|
alpar@9
|
274 }
|
alpar@9
|
275 else if (ret == GLP_ENODFS)
|
alpar@9
|
276 { if (parm->msg_lev >= GLP_MSG_ALL)
|
alpar@9
|
277 xprintf("PROBLEM HAS NO DUAL FEASIBLE SOLUTION\n");
|
alpar@9
|
278 }
|
alpar@9
|
279 else
|
alpar@9
|
280 xassert(ret != ret);
|
alpar@9
|
281 if (ret != 0) goto done;
|
alpar@9
|
282 /* build transformed LP */
|
alpar@9
|
283 lp = glp_create_prob();
|
alpar@9
|
284 npp_build_prob(npp, lp);
|
alpar@9
|
285 /* if the transformed LP is empty, it has empty solution, which
|
alpar@9
|
286 is optimal */
|
alpar@9
|
287 if (lp->m == 0 && lp->n == 0)
|
alpar@9
|
288 { lp->pbs_stat = lp->dbs_stat = GLP_FEAS;
|
alpar@9
|
289 lp->obj_val = lp->c0;
|
alpar@9
|
290 if (parm->msg_lev >= GLP_MSG_ON && parm->out_dly == 0)
|
alpar@9
|
291 { xprintf("~%6d: obj = %17.9e infeas = %10.3e\n", P->it_cnt,
|
alpar@9
|
292 lp->obj_val, 0.0);
|
alpar@9
|
293 }
|
alpar@9
|
294 if (parm->msg_lev >= GLP_MSG_ALL)
|
alpar@9
|
295 xprintf("OPTIMAL SOLUTION FOUND BY LP PREPROCESSOR\n");
|
alpar@9
|
296 goto post;
|
alpar@9
|
297 }
|
alpar@9
|
298 if (parm->msg_lev >= GLP_MSG_ALL)
|
alpar@9
|
299 { xprintf("%d row%s, %d column%s, %d non-zero%s\n",
|
alpar@9
|
300 lp->m, lp->m == 1 ? "" : "s", lp->n, lp->n == 1 ? "" : "s",
|
alpar@9
|
301 lp->nnz, lp->nnz == 1 ? "" : "s");
|
alpar@9
|
302 }
|
alpar@9
|
303 /* inherit basis factorization control parameters */
|
alpar@9
|
304 glp_get_bfcp(P, &bfcp);
|
alpar@9
|
305 glp_set_bfcp(lp, &bfcp);
|
alpar@9
|
306 /* scale the transformed problem */
|
alpar@9
|
307 { ENV *env = get_env_ptr();
|
alpar@9
|
308 int term_out = env->term_out;
|
alpar@9
|
309 if (!term_out || parm->msg_lev < GLP_MSG_ALL)
|
alpar@9
|
310 env->term_out = GLP_OFF;
|
alpar@9
|
311 else
|
alpar@9
|
312 env->term_out = GLP_ON;
|
alpar@9
|
313 glp_scale_prob(lp, GLP_SF_AUTO);
|
alpar@9
|
314 env->term_out = term_out;
|
alpar@9
|
315 }
|
alpar@9
|
316 /* build advanced initial basis */
|
alpar@9
|
317 { ENV *env = get_env_ptr();
|
alpar@9
|
318 int term_out = env->term_out;
|
alpar@9
|
319 if (!term_out || parm->msg_lev < GLP_MSG_ALL)
|
alpar@9
|
320 env->term_out = GLP_OFF;
|
alpar@9
|
321 else
|
alpar@9
|
322 env->term_out = GLP_ON;
|
alpar@9
|
323 glp_adv_basis(lp, 0);
|
alpar@9
|
324 env->term_out = term_out;
|
alpar@9
|
325 }
|
alpar@9
|
326 /* solve the transformed LP */
|
alpar@9
|
327 lp->it_cnt = P->it_cnt;
|
alpar@9
|
328 ret = solve_lp(lp, parm);
|
alpar@9
|
329 P->it_cnt = lp->it_cnt;
|
alpar@9
|
330 /* only optimal solution can be postprocessed */
|
alpar@9
|
331 if (!(ret == 0 && lp->pbs_stat == GLP_FEAS && lp->dbs_stat ==
|
alpar@9
|
332 GLP_FEAS))
|
alpar@9
|
333 { if (parm->msg_lev >= GLP_MSG_ERR)
|
alpar@9
|
334 xprintf("glp_simplex: unable to recover undefined or non-op"
|
alpar@9
|
335 "timal solution\n");
|
alpar@9
|
336 if (ret == 0)
|
alpar@9
|
337 { if (lp->pbs_stat == GLP_NOFEAS)
|
alpar@9
|
338 ret = GLP_ENOPFS;
|
alpar@9
|
339 else if (lp->dbs_stat == GLP_NOFEAS)
|
alpar@9
|
340 ret = GLP_ENODFS;
|
alpar@9
|
341 else
|
alpar@9
|
342 xassert(lp != lp);
|
alpar@9
|
343 }
|
alpar@9
|
344 goto done;
|
alpar@9
|
345 }
|
alpar@9
|
346 post: /* postprocess solution from the transformed LP */
|
alpar@9
|
347 npp_postprocess(npp, lp);
|
alpar@9
|
348 /* the transformed LP is no longer needed */
|
alpar@9
|
349 glp_delete_prob(lp), lp = NULL;
|
alpar@9
|
350 /* store solution to the original problem */
|
alpar@9
|
351 npp_unload_sol(npp, P);
|
alpar@9
|
352 /* the original LP has been successfully solved */
|
alpar@9
|
353 ret = 0;
|
alpar@9
|
354 done: /* delete the transformed LP, if it exists */
|
alpar@9
|
355 if (lp != NULL) glp_delete_prob(lp);
|
alpar@9
|
356 /* delete preprocessor workspace */
|
alpar@9
|
357 npp_delete_wksp(npp);
|
alpar@9
|
358 return ret;
|
alpar@9
|
359 }
|
alpar@9
|
360
|
alpar@9
|
361 int glp_simplex(glp_prob *P, const glp_smcp *parm)
|
alpar@9
|
362 { /* solve LP problem with the simplex method */
|
alpar@9
|
363 glp_smcp _parm;
|
alpar@9
|
364 int i, j, ret;
|
alpar@9
|
365 /* check problem object */
|
alpar@9
|
366 if (P == NULL || P->magic != GLP_PROB_MAGIC)
|
alpar@9
|
367 xerror("glp_simplex: P = %p; invalid problem object\n", P);
|
alpar@9
|
368 if (P->tree != NULL && P->tree->reason != 0)
|
alpar@9
|
369 xerror("glp_simplex: operation not allowed\n");
|
alpar@9
|
370 /* check control parameters */
|
alpar@9
|
371 if (parm == NULL)
|
alpar@9
|
372 parm = &_parm, glp_init_smcp((glp_smcp *)parm);
|
alpar@9
|
373 if (!(parm->msg_lev == GLP_MSG_OFF ||
|
alpar@9
|
374 parm->msg_lev == GLP_MSG_ERR ||
|
alpar@9
|
375 parm->msg_lev == GLP_MSG_ON ||
|
alpar@9
|
376 parm->msg_lev == GLP_MSG_ALL ||
|
alpar@9
|
377 parm->msg_lev == GLP_MSG_DBG))
|
alpar@9
|
378 xerror("glp_simplex: msg_lev = %d; invalid parameter\n",
|
alpar@9
|
379 parm->msg_lev);
|
alpar@9
|
380 if (!(parm->meth == GLP_PRIMAL ||
|
alpar@9
|
381 parm->meth == GLP_DUALP ||
|
alpar@9
|
382 parm->meth == GLP_DUAL))
|
alpar@9
|
383 xerror("glp_simplex: meth = %d; invalid parameter\n",
|
alpar@9
|
384 parm->meth);
|
alpar@9
|
385 if (!(parm->pricing == GLP_PT_STD ||
|
alpar@9
|
386 parm->pricing == GLP_PT_PSE))
|
alpar@9
|
387 xerror("glp_simplex: pricing = %d; invalid parameter\n",
|
alpar@9
|
388 parm->pricing);
|
alpar@9
|
389 if (!(parm->r_test == GLP_RT_STD ||
|
alpar@9
|
390 parm->r_test == GLP_RT_HAR))
|
alpar@9
|
391 xerror("glp_simplex: r_test = %d; invalid parameter\n",
|
alpar@9
|
392 parm->r_test);
|
alpar@9
|
393 if (!(0.0 < parm->tol_bnd && parm->tol_bnd < 1.0))
|
alpar@9
|
394 xerror("glp_simplex: tol_bnd = %g; invalid parameter\n",
|
alpar@9
|
395 parm->tol_bnd);
|
alpar@9
|
396 if (!(0.0 < parm->tol_dj && parm->tol_dj < 1.0))
|
alpar@9
|
397 xerror("glp_simplex: tol_dj = %g; invalid parameter\n",
|
alpar@9
|
398 parm->tol_dj);
|
alpar@9
|
399 if (!(0.0 < parm->tol_piv && parm->tol_piv < 1.0))
|
alpar@9
|
400 xerror("glp_simplex: tol_piv = %g; invalid parameter\n",
|
alpar@9
|
401 parm->tol_piv);
|
alpar@9
|
402 if (parm->it_lim < 0)
|
alpar@9
|
403 xerror("glp_simplex: it_lim = %d; invalid parameter\n",
|
alpar@9
|
404 parm->it_lim);
|
alpar@9
|
405 if (parm->tm_lim < 0)
|
alpar@9
|
406 xerror("glp_simplex: tm_lim = %d; invalid parameter\n",
|
alpar@9
|
407 parm->tm_lim);
|
alpar@9
|
408 if (parm->out_frq < 1)
|
alpar@9
|
409 xerror("glp_simplex: out_frq = %d; invalid parameter\n",
|
alpar@9
|
410 parm->out_frq);
|
alpar@9
|
411 if (parm->out_dly < 0)
|
alpar@9
|
412 xerror("glp_simplex: out_dly = %d; invalid parameter\n",
|
alpar@9
|
413 parm->out_dly);
|
alpar@9
|
414 if (!(parm->presolve == GLP_ON || parm->presolve == GLP_OFF))
|
alpar@9
|
415 xerror("glp_simplex: presolve = %d; invalid parameter\n",
|
alpar@9
|
416 parm->presolve);
|
alpar@9
|
417 /* basic solution is currently undefined */
|
alpar@9
|
418 P->pbs_stat = P->dbs_stat = GLP_UNDEF;
|
alpar@9
|
419 P->obj_val = 0.0;
|
alpar@9
|
420 P->some = 0;
|
alpar@9
|
421 /* check bounds of double-bounded variables */
|
alpar@9
|
422 for (i = 1; i <= P->m; i++)
|
alpar@9
|
423 { GLPROW *row = P->row[i];
|
alpar@9
|
424 if (row->type == GLP_DB && row->lb >= row->ub)
|
alpar@9
|
425 { if (parm->msg_lev >= GLP_MSG_ERR)
|
alpar@9
|
426 xprintf("glp_simplex: row %d: lb = %g, ub = %g; incorrec"
|
alpar@9
|
427 "t bounds\n", i, row->lb, row->ub);
|
alpar@9
|
428 ret = GLP_EBOUND;
|
alpar@9
|
429 goto done;
|
alpar@9
|
430 }
|
alpar@9
|
431 }
|
alpar@9
|
432 for (j = 1; j <= P->n; j++)
|
alpar@9
|
433 { GLPCOL *col = P->col[j];
|
alpar@9
|
434 if (col->type == GLP_DB && col->lb >= col->ub)
|
alpar@9
|
435 { if (parm->msg_lev >= GLP_MSG_ERR)
|
alpar@9
|
436 xprintf("glp_simplex: column %d: lb = %g, ub = %g; incor"
|
alpar@9
|
437 "rect bounds\n", j, col->lb, col->ub);
|
alpar@9
|
438 ret = GLP_EBOUND;
|
alpar@9
|
439 goto done;
|
alpar@9
|
440 }
|
alpar@9
|
441 }
|
alpar@9
|
442 /* solve LP problem */
|
alpar@9
|
443 if (parm->msg_lev >= GLP_MSG_ALL)
|
alpar@9
|
444 { xprintf("GLPK Simplex Optimizer, v%s\n", glp_version());
|
alpar@9
|
445 xprintf("%d row%s, %d column%s, %d non-zero%s\n",
|
alpar@9
|
446 P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
|
alpar@9
|
447 P->nnz, P->nnz == 1 ? "" : "s");
|
alpar@9
|
448 }
|
alpar@9
|
449 if (P->nnz == 0)
|
alpar@9
|
450 trivial_lp(P, parm), ret = 0;
|
alpar@9
|
451 else if (!parm->presolve)
|
alpar@9
|
452 ret = solve_lp(P, parm);
|
alpar@9
|
453 else
|
alpar@9
|
454 ret = preprocess_and_solve_lp(P, parm);
|
alpar@9
|
455 done: /* return to the application program */
|
alpar@9
|
456 return ret;
|
alpar@9
|
457 }
|
alpar@9
|
458
|
alpar@9
|
459 /***********************************************************************
|
alpar@9
|
460 * NAME
|
alpar@9
|
461 *
|
alpar@9
|
462 * glp_init_smcp - initialize simplex method control parameters
|
alpar@9
|
463 *
|
alpar@9
|
464 * SYNOPSIS
|
alpar@9
|
465 *
|
alpar@9
|
466 * void glp_init_smcp(glp_smcp *parm);
|
alpar@9
|
467 *
|
alpar@9
|
468 * DESCRIPTION
|
alpar@9
|
469 *
|
alpar@9
|
470 * The routine glp_init_smcp initializes control parameters, which are
|
alpar@9
|
471 * used by the simplex solver, with default values.
|
alpar@9
|
472 *
|
alpar@9
|
473 * Default values of the control parameters are stored in a glp_smcp
|
alpar@9
|
474 * structure, which the parameter parm points to. */
|
alpar@9
|
475
|
alpar@9
|
476 void glp_init_smcp(glp_smcp *parm)
|
alpar@9
|
477 { parm->msg_lev = GLP_MSG_ALL;
|
alpar@9
|
478 parm->meth = GLP_PRIMAL;
|
alpar@9
|
479 parm->pricing = GLP_PT_PSE;
|
alpar@9
|
480 parm->r_test = GLP_RT_HAR;
|
alpar@9
|
481 parm->tol_bnd = 1e-7;
|
alpar@9
|
482 parm->tol_dj = 1e-7;
|
alpar@9
|
483 parm->tol_piv = 1e-10;
|
alpar@9
|
484 parm->obj_ll = -DBL_MAX;
|
alpar@9
|
485 parm->obj_ul = +DBL_MAX;
|
alpar@9
|
486 parm->it_lim = INT_MAX;
|
alpar@9
|
487 parm->tm_lim = INT_MAX;
|
alpar@9
|
488 parm->out_frq = 500;
|
alpar@9
|
489 parm->out_dly = 0;
|
alpar@9
|
490 parm->presolve = GLP_OFF;
|
alpar@9
|
491 return;
|
alpar@9
|
492 }
|
alpar@9
|
493
|
alpar@9
|
494 /***********************************************************************
|
alpar@9
|
495 * NAME
|
alpar@9
|
496 *
|
alpar@9
|
497 * glp_get_status - retrieve generic status of basic solution
|
alpar@9
|
498 *
|
alpar@9
|
499 * SYNOPSIS
|
alpar@9
|
500 *
|
alpar@9
|
501 * int glp_get_status(glp_prob *lp);
|
alpar@9
|
502 *
|
alpar@9
|
503 * RETURNS
|
alpar@9
|
504 *
|
alpar@9
|
505 * The routine glp_get_status reports the generic status of the basic
|
alpar@9
|
506 * solution for the specified problem object as follows:
|
alpar@9
|
507 *
|
alpar@9
|
508 * GLP_OPT - solution is optimal;
|
alpar@9
|
509 * GLP_FEAS - solution is feasible;
|
alpar@9
|
510 * GLP_INFEAS - solution is infeasible;
|
alpar@9
|
511 * GLP_NOFEAS - problem has no feasible solution;
|
alpar@9
|
512 * GLP_UNBND - problem has unbounded solution;
|
alpar@9
|
513 * GLP_UNDEF - solution is undefined. */
|
alpar@9
|
514
|
alpar@9
|
515 int glp_get_status(glp_prob *lp)
|
alpar@9
|
516 { int status;
|
alpar@9
|
517 status = glp_get_prim_stat(lp);
|
alpar@9
|
518 switch (status)
|
alpar@9
|
519 { case GLP_FEAS:
|
alpar@9
|
520 switch (glp_get_dual_stat(lp))
|
alpar@9
|
521 { case GLP_FEAS:
|
alpar@9
|
522 status = GLP_OPT;
|
alpar@9
|
523 break;
|
alpar@9
|
524 case GLP_NOFEAS:
|
alpar@9
|
525 status = GLP_UNBND;
|
alpar@9
|
526 break;
|
alpar@9
|
527 case GLP_UNDEF:
|
alpar@9
|
528 case GLP_INFEAS:
|
alpar@9
|
529 status = status;
|
alpar@9
|
530 break;
|
alpar@9
|
531 default:
|
alpar@9
|
532 xassert(lp != lp);
|
alpar@9
|
533 }
|
alpar@9
|
534 break;
|
alpar@9
|
535 case GLP_UNDEF:
|
alpar@9
|
536 case GLP_INFEAS:
|
alpar@9
|
537 case GLP_NOFEAS:
|
alpar@9
|
538 status = status;
|
alpar@9
|
539 break;
|
alpar@9
|
540 default:
|
alpar@9
|
541 xassert(lp != lp);
|
alpar@9
|
542 }
|
alpar@9
|
543 return status;
|
alpar@9
|
544 }
|
alpar@9
|
545
|
alpar@9
|
546 /***********************************************************************
|
alpar@9
|
547 * NAME
|
alpar@9
|
548 *
|
alpar@9
|
549 * glp_get_prim_stat - retrieve status of primal basic solution
|
alpar@9
|
550 *
|
alpar@9
|
551 * SYNOPSIS
|
alpar@9
|
552 *
|
alpar@9
|
553 * int glp_get_prim_stat(glp_prob *lp);
|
alpar@9
|
554 *
|
alpar@9
|
555 * RETURNS
|
alpar@9
|
556 *
|
alpar@9
|
557 * The routine glp_get_prim_stat reports the status of the primal basic
|
alpar@9
|
558 * solution for the specified problem object as follows:
|
alpar@9
|
559 *
|
alpar@9
|
560 * GLP_UNDEF - primal solution is undefined;
|
alpar@9
|
561 * GLP_FEAS - primal solution is feasible;
|
alpar@9
|
562 * GLP_INFEAS - primal solution is infeasible;
|
alpar@9
|
563 * GLP_NOFEAS - no primal feasible solution exists. */
|
alpar@9
|
564
|
alpar@9
|
565 int glp_get_prim_stat(glp_prob *lp)
|
alpar@9
|
566 { int pbs_stat = lp->pbs_stat;
|
alpar@9
|
567 return pbs_stat;
|
alpar@9
|
568 }
|
alpar@9
|
569
|
alpar@9
|
570 /***********************************************************************
|
alpar@9
|
571 * NAME
|
alpar@9
|
572 *
|
alpar@9
|
573 * glp_get_dual_stat - retrieve status of dual basic solution
|
alpar@9
|
574 *
|
alpar@9
|
575 * SYNOPSIS
|
alpar@9
|
576 *
|
alpar@9
|
577 * int glp_get_dual_stat(glp_prob *lp);
|
alpar@9
|
578 *
|
alpar@9
|
579 * RETURNS
|
alpar@9
|
580 *
|
alpar@9
|
581 * The routine glp_get_dual_stat reports the status of the dual basic
|
alpar@9
|
582 * solution for the specified problem object as follows:
|
alpar@9
|
583 *
|
alpar@9
|
584 * GLP_UNDEF - dual solution is undefined;
|
alpar@9
|
585 * GLP_FEAS - dual solution is feasible;
|
alpar@9
|
586 * GLP_INFEAS - dual solution is infeasible;
|
alpar@9
|
587 * GLP_NOFEAS - no dual feasible solution exists. */
|
alpar@9
|
588
|
alpar@9
|
589 int glp_get_dual_stat(glp_prob *lp)
|
alpar@9
|
590 { int dbs_stat = lp->dbs_stat;
|
alpar@9
|
591 return dbs_stat;
|
alpar@9
|
592 }
|
alpar@9
|
593
|
alpar@9
|
594 /***********************************************************************
|
alpar@9
|
595 * NAME
|
alpar@9
|
596 *
|
alpar@9
|
597 * glp_get_obj_val - retrieve objective value (basic solution)
|
alpar@9
|
598 *
|
alpar@9
|
599 * SYNOPSIS
|
alpar@9
|
600 *
|
alpar@9
|
601 * double glp_get_obj_val(glp_prob *lp);
|
alpar@9
|
602 *
|
alpar@9
|
603 * RETURNS
|
alpar@9
|
604 *
|
alpar@9
|
605 * The routine glp_get_obj_val returns value of the objective function
|
alpar@9
|
606 * for basic solution. */
|
alpar@9
|
607
|
alpar@9
|
608 double glp_get_obj_val(glp_prob *lp)
|
alpar@9
|
609 { /*struct LPXCPS *cps = lp->cps;*/
|
alpar@9
|
610 double z;
|
alpar@9
|
611 z = lp->obj_val;
|
alpar@9
|
612 /*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/
|
alpar@9
|
613 return z;
|
alpar@9
|
614 }
|
alpar@9
|
615
|
alpar@9
|
616 /***********************************************************************
|
alpar@9
|
617 * NAME
|
alpar@9
|
618 *
|
alpar@9
|
619 * glp_get_row_stat - retrieve row status
|
alpar@9
|
620 *
|
alpar@9
|
621 * SYNOPSIS
|
alpar@9
|
622 *
|
alpar@9
|
623 * int glp_get_row_stat(glp_prob *lp, int i);
|
alpar@9
|
624 *
|
alpar@9
|
625 * RETURNS
|
alpar@9
|
626 *
|
alpar@9
|
627 * The routine glp_get_row_stat returns current status assigned to the
|
alpar@9
|
628 * auxiliary variable associated with i-th row as follows:
|
alpar@9
|
629 *
|
alpar@9
|
630 * GLP_BS - basic variable;
|
alpar@9
|
631 * GLP_NL - non-basic variable on its lower bound;
|
alpar@9
|
632 * GLP_NU - non-basic variable on its upper bound;
|
alpar@9
|
633 * GLP_NF - non-basic free (unbounded) variable;
|
alpar@9
|
634 * GLP_NS - non-basic fixed variable. */
|
alpar@9
|
635
|
alpar@9
|
636 int glp_get_row_stat(glp_prob *lp, int i)
|
alpar@9
|
637 { if (!(1 <= i && i <= lp->m))
|
alpar@9
|
638 xerror("glp_get_row_stat: i = %d; row number out of range\n",
|
alpar@9
|
639 i);
|
alpar@9
|
640 return lp->row[i]->stat;
|
alpar@9
|
641 }
|
alpar@9
|
642
|
alpar@9
|
643 /***********************************************************************
|
alpar@9
|
644 * NAME
|
alpar@9
|
645 *
|
alpar@9
|
646 * glp_get_row_prim - retrieve row primal value (basic solution)
|
alpar@9
|
647 *
|
alpar@9
|
648 * SYNOPSIS
|
alpar@9
|
649 *
|
alpar@9
|
650 * double glp_get_row_prim(glp_prob *lp, int i);
|
alpar@9
|
651 *
|
alpar@9
|
652 * RETURNS
|
alpar@9
|
653 *
|
alpar@9
|
654 * The routine glp_get_row_prim returns primal value of the auxiliary
|
alpar@9
|
655 * variable associated with i-th row. */
|
alpar@9
|
656
|
alpar@9
|
657 double glp_get_row_prim(glp_prob *lp, int i)
|
alpar@9
|
658 { /*struct LPXCPS *cps = lp->cps;*/
|
alpar@9
|
659 double prim;
|
alpar@9
|
660 if (!(1 <= i && i <= lp->m))
|
alpar@9
|
661 xerror("glp_get_row_prim: i = %d; row number out of range\n",
|
alpar@9
|
662 i);
|
alpar@9
|
663 prim = lp->row[i]->prim;
|
alpar@9
|
664 /*if (cps->round && fabs(prim) < 1e-9) prim = 0.0;*/
|
alpar@9
|
665 return prim;
|
alpar@9
|
666 }
|
alpar@9
|
667
|
alpar@9
|
668 /***********************************************************************
|
alpar@9
|
669 * NAME
|
alpar@9
|
670 *
|
alpar@9
|
671 * glp_get_row_dual - retrieve row dual value (basic solution)
|
alpar@9
|
672 *
|
alpar@9
|
673 * SYNOPSIS
|
alpar@9
|
674 *
|
alpar@9
|
675 * double glp_get_row_dual(glp_prob *lp, int i);
|
alpar@9
|
676 *
|
alpar@9
|
677 * RETURNS
|
alpar@9
|
678 *
|
alpar@9
|
679 * The routine glp_get_row_dual returns dual value (i.e. reduced cost)
|
alpar@9
|
680 * of the auxiliary variable associated with i-th row. */
|
alpar@9
|
681
|
alpar@9
|
682 double glp_get_row_dual(glp_prob *lp, int i)
|
alpar@9
|
683 { /*struct LPXCPS *cps = lp->cps;*/
|
alpar@9
|
684 double dual;
|
alpar@9
|
685 if (!(1 <= i && i <= lp->m))
|
alpar@9
|
686 xerror("glp_get_row_dual: i = %d; row number out of range\n",
|
alpar@9
|
687 i);
|
alpar@9
|
688 dual = lp->row[i]->dual;
|
alpar@9
|
689 /*if (cps->round && fabs(dual) < 1e-9) dual = 0.0;*/
|
alpar@9
|
690 return dual;
|
alpar@9
|
691 }
|
alpar@9
|
692
|
alpar@9
|
693 /***********************************************************************
|
alpar@9
|
694 * NAME
|
alpar@9
|
695 *
|
alpar@9
|
696 * glp_get_col_stat - retrieve column status
|
alpar@9
|
697 *
|
alpar@9
|
698 * SYNOPSIS
|
alpar@9
|
699 *
|
alpar@9
|
700 * int glp_get_col_stat(glp_prob *lp, int j);
|
alpar@9
|
701 *
|
alpar@9
|
702 * RETURNS
|
alpar@9
|
703 *
|
alpar@9
|
704 * The routine glp_get_col_stat returns current status assigned to the
|
alpar@9
|
705 * structural variable associated with j-th column as follows:
|
alpar@9
|
706 *
|
alpar@9
|
707 * GLP_BS - basic variable;
|
alpar@9
|
708 * GLP_NL - non-basic variable on its lower bound;
|
alpar@9
|
709 * GLP_NU - non-basic variable on its upper bound;
|
alpar@9
|
710 * GLP_NF - non-basic free (unbounded) variable;
|
alpar@9
|
711 * GLP_NS - non-basic fixed variable. */
|
alpar@9
|
712
|
alpar@9
|
713 int glp_get_col_stat(glp_prob *lp, int j)
|
alpar@9
|
714 { if (!(1 <= j && j <= lp->n))
|
alpar@9
|
715 xerror("glp_get_col_stat: j = %d; column number out of range\n"
|
alpar@9
|
716 , j);
|
alpar@9
|
717 return lp->col[j]->stat;
|
alpar@9
|
718 }
|
alpar@9
|
719
|
alpar@9
|
720 /***********************************************************************
|
alpar@9
|
721 * NAME
|
alpar@9
|
722 *
|
alpar@9
|
723 * glp_get_col_prim - retrieve column primal value (basic solution)
|
alpar@9
|
724 *
|
alpar@9
|
725 * SYNOPSIS
|
alpar@9
|
726 *
|
alpar@9
|
727 * double glp_get_col_prim(glp_prob *lp, int j);
|
alpar@9
|
728 *
|
alpar@9
|
729 * RETURNS
|
alpar@9
|
730 *
|
alpar@9
|
731 * The routine glp_get_col_prim returns primal value of the structural
|
alpar@9
|
732 * variable associated with j-th column. */
|
alpar@9
|
733
|
alpar@9
|
734 double glp_get_col_prim(glp_prob *lp, int j)
|
alpar@9
|
735 { /*struct LPXCPS *cps = lp->cps;*/
|
alpar@9
|
736 double prim;
|
alpar@9
|
737 if (!(1 <= j && j <= lp->n))
|
alpar@9
|
738 xerror("glp_get_col_prim: j = %d; column number out of range\n"
|
alpar@9
|
739 , j);
|
alpar@9
|
740 prim = lp->col[j]->prim;
|
alpar@9
|
741 /*if (cps->round && fabs(prim) < 1e-9) prim = 0.0;*/
|
alpar@9
|
742 return prim;
|
alpar@9
|
743 }
|
alpar@9
|
744
|
alpar@9
|
745 /***********************************************************************
|
alpar@9
|
746 * NAME
|
alpar@9
|
747 *
|
alpar@9
|
748 * glp_get_col_dual - retrieve column dual value (basic solution)
|
alpar@9
|
749 *
|
alpar@9
|
750 * SYNOPSIS
|
alpar@9
|
751 *
|
alpar@9
|
752 * double glp_get_col_dual(glp_prob *lp, int j);
|
alpar@9
|
753 *
|
alpar@9
|
754 * RETURNS
|
alpar@9
|
755 *
|
alpar@9
|
756 * The routine glp_get_col_dual returns dual value (i.e. reduced cost)
|
alpar@9
|
757 * of the structural variable associated with j-th column. */
|
alpar@9
|
758
|
alpar@9
|
759 double glp_get_col_dual(glp_prob *lp, int j)
|
alpar@9
|
760 { /*struct LPXCPS *cps = lp->cps;*/
|
alpar@9
|
761 double dual;
|
alpar@9
|
762 if (!(1 <= j && j <= lp->n))
|
alpar@9
|
763 xerror("glp_get_col_dual: j = %d; column number out of range\n"
|
alpar@9
|
764 , j);
|
alpar@9
|
765 dual = lp->col[j]->dual;
|
alpar@9
|
766 /*if (cps->round && fabs(dual) < 1e-9) dual = 0.0;*/
|
alpar@9
|
767 return dual;
|
alpar@9
|
768 }
|
alpar@9
|
769
|
alpar@9
|
770 /***********************************************************************
|
alpar@9
|
771 * NAME
|
alpar@9
|
772 *
|
alpar@9
|
773 * glp_get_unbnd_ray - determine variable causing unboundedness
|
alpar@9
|
774 *
|
alpar@9
|
775 * SYNOPSIS
|
alpar@9
|
776 *
|
alpar@9
|
777 * int glp_get_unbnd_ray(glp_prob *lp);
|
alpar@9
|
778 *
|
alpar@9
|
779 * RETURNS
|
alpar@9
|
780 *
|
alpar@9
|
781 * The routine glp_get_unbnd_ray returns the number k of a variable,
|
alpar@9
|
782 * which causes primal or dual unboundedness. If 1 <= k <= m, it is
|
alpar@9
|
783 * k-th auxiliary variable, and if m+1 <= k <= m+n, it is (k-m)-th
|
alpar@9
|
784 * structural variable, where m is the number of rows, n is the number
|
alpar@9
|
785 * of columns in the problem object. If such variable is not defined,
|
alpar@9
|
786 * the routine returns 0.
|
alpar@9
|
787 *
|
alpar@9
|
788 * COMMENTS
|
alpar@9
|
789 *
|
alpar@9
|
790 * If it is not exactly known which version of the simplex solver
|
alpar@9
|
791 * detected unboundedness, i.e. whether the unboundedness is primal or
|
alpar@9
|
792 * dual, it is sufficient to check the status of the variable reported
|
alpar@9
|
793 * with the routine glp_get_row_stat or glp_get_col_stat. If the
|
alpar@9
|
794 * variable is non-basic, the unboundedness is primal, otherwise, if
|
alpar@9
|
795 * the variable is basic, the unboundedness is dual (the latter case
|
alpar@9
|
796 * means that the problem has no primal feasible dolution). */
|
alpar@9
|
797
|
alpar@9
|
798 int glp_get_unbnd_ray(glp_prob *lp)
|
alpar@9
|
799 { int k;
|
alpar@9
|
800 k = lp->some;
|
alpar@9
|
801 xassert(k >= 0);
|
alpar@9
|
802 if (k > lp->m + lp->n) k = 0;
|
alpar@9
|
803 return k;
|
alpar@9
|
804 }
|
alpar@9
|
805
|
alpar@9
|
806 /* eof */
|