alpar@1
|
1 |
/* glpapi07.c (exact simplex solver) */
|
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 "glpapi.h"
|
alpar@1
|
26 |
#include "glpssx.h"
|
alpar@1
|
27 |
|
alpar@1
|
28 |
/***********************************************************************
|
alpar@1
|
29 |
* NAME
|
alpar@1
|
30 |
*
|
alpar@1
|
31 |
* glp_exact - solve LP problem in exact arithmetic
|
alpar@1
|
32 |
*
|
alpar@1
|
33 |
* SYNOPSIS
|
alpar@1
|
34 |
*
|
alpar@1
|
35 |
* int glp_exact(glp_prob *lp, const glp_smcp *parm);
|
alpar@1
|
36 |
*
|
alpar@1
|
37 |
* DESCRIPTION
|
alpar@1
|
38 |
*
|
alpar@1
|
39 |
* The routine glp_exact is a tentative implementation of the primal
|
alpar@1
|
40 |
* two-phase simplex method based on exact (rational) arithmetic. It is
|
alpar@1
|
41 |
* similar to the routine glp_simplex, however, for all internal
|
alpar@1
|
42 |
* computations it uses arithmetic of rational numbers, which is exact
|
alpar@1
|
43 |
* in mathematical sense, i.e. free of round-off errors unlike floating
|
alpar@1
|
44 |
* point arithmetic.
|
alpar@1
|
45 |
*
|
alpar@1
|
46 |
* Note that the routine glp_exact uses inly two control parameters
|
alpar@1
|
47 |
* passed in the structure glp_smcp, namely, it_lim and tm_lim.
|
alpar@1
|
48 |
*
|
alpar@1
|
49 |
* RETURNS
|
alpar@1
|
50 |
*
|
alpar@1
|
51 |
* 0 The LP problem instance has been successfully solved. This code
|
alpar@1
|
52 |
* does not necessarily mean that the solver has found optimal
|
alpar@1
|
53 |
* solution. It only means that the solution process was successful.
|
alpar@1
|
54 |
*
|
alpar@1
|
55 |
* GLP_EBADB
|
alpar@1
|
56 |
* Unable to start the search, because the initial basis specified
|
alpar@1
|
57 |
* in the problem object is invalid--the number of basic (auxiliary
|
alpar@1
|
58 |
* and structural) variables is not the same as the number of rows in
|
alpar@1
|
59 |
* the problem object.
|
alpar@1
|
60 |
*
|
alpar@1
|
61 |
* GLP_ESING
|
alpar@1
|
62 |
* Unable to start the search, because the basis matrix correspodning
|
alpar@1
|
63 |
* to the initial basis is exactly singular.
|
alpar@1
|
64 |
*
|
alpar@1
|
65 |
* GLP_EBOUND
|
alpar@1
|
66 |
* Unable to start the search, because some double-bounded variables
|
alpar@1
|
67 |
* have incorrect bounds.
|
alpar@1
|
68 |
*
|
alpar@1
|
69 |
* GLP_EFAIL
|
alpar@1
|
70 |
* The problem has no rows/columns.
|
alpar@1
|
71 |
*
|
alpar@1
|
72 |
* GLP_EITLIM
|
alpar@1
|
73 |
* The search was prematurely terminated, because the simplex
|
alpar@1
|
74 |
* iteration limit has been exceeded.
|
alpar@1
|
75 |
*
|
alpar@1
|
76 |
* GLP_ETMLIM
|
alpar@1
|
77 |
* The search was prematurely terminated, because the time limit has
|
alpar@1
|
78 |
* been exceeded. */
|
alpar@1
|
79 |
|
alpar@1
|
80 |
static void set_d_eps(mpq_t x, double val)
|
alpar@1
|
81 |
{ /* convert double val to rational x obtaining a more adequate
|
alpar@1
|
82 |
fraction than provided by mpq_set_d due to allowing a small
|
alpar@1
|
83 |
approximation error specified by a given relative tolerance;
|
alpar@1
|
84 |
for example, mpq_set_d would give the following
|
alpar@1
|
85 |
1/3 ~= 0.333333333333333314829616256247391... ->
|
alpar@1
|
86 |
-> 6004799503160661/18014398509481984
|
alpar@1
|
87 |
while this routine gives exactly 1/3 */
|
alpar@1
|
88 |
int s, n, j;
|
alpar@1
|
89 |
double f, p, q, eps = 1e-9;
|
alpar@1
|
90 |
mpq_t temp;
|
alpar@1
|
91 |
xassert(-DBL_MAX <= val && val <= +DBL_MAX);
|
alpar@1
|
92 |
#if 1 /* 30/VII-2008 */
|
alpar@1
|
93 |
if (val == floor(val))
|
alpar@1
|
94 |
{ /* if val is integral, do not approximate */
|
alpar@1
|
95 |
mpq_set_d(x, val);
|
alpar@1
|
96 |
goto done;
|
alpar@1
|
97 |
}
|
alpar@1
|
98 |
#endif
|
alpar@1
|
99 |
if (val > 0.0)
|
alpar@1
|
100 |
s = +1;
|
alpar@1
|
101 |
else if (val < 0.0)
|
alpar@1
|
102 |
s = -1;
|
alpar@1
|
103 |
else
|
alpar@1
|
104 |
{ mpq_set_si(x, 0, 1);
|
alpar@1
|
105 |
goto done;
|
alpar@1
|
106 |
}
|
alpar@1
|
107 |
f = frexp(fabs(val), &n);
|
alpar@1
|
108 |
/* |val| = f * 2^n, where 0.5 <= f < 1.0 */
|
alpar@1
|
109 |
fp2rat(f, 0.1 * eps, &p, &q);
|
alpar@1
|
110 |
/* f ~= p / q, where p and q are integers */
|
alpar@1
|
111 |
mpq_init(temp);
|
alpar@1
|
112 |
mpq_set_d(x, p);
|
alpar@1
|
113 |
mpq_set_d(temp, q);
|
alpar@1
|
114 |
mpq_div(x, x, temp);
|
alpar@1
|
115 |
mpq_set_si(temp, 1, 1);
|
alpar@1
|
116 |
for (j = 1; j <= abs(n); j++)
|
alpar@1
|
117 |
mpq_add(temp, temp, temp);
|
alpar@1
|
118 |
if (n > 0)
|
alpar@1
|
119 |
mpq_mul(x, x, temp);
|
alpar@1
|
120 |
else if (n < 0)
|
alpar@1
|
121 |
mpq_div(x, x, temp);
|
alpar@1
|
122 |
mpq_clear(temp);
|
alpar@1
|
123 |
if (s < 0) mpq_neg(x, x);
|
alpar@1
|
124 |
/* check that the desired tolerance has been attained */
|
alpar@1
|
125 |
xassert(fabs(val - mpq_get_d(x)) <= eps * (1.0 + fabs(val)));
|
alpar@1
|
126 |
done: return;
|
alpar@1
|
127 |
}
|
alpar@1
|
128 |
|
alpar@1
|
129 |
static void load_data(SSX *ssx, LPX *lp)
|
alpar@1
|
130 |
{ /* load LP problem data into simplex solver workspace */
|
alpar@1
|
131 |
int m = ssx->m;
|
alpar@1
|
132 |
int n = ssx->n;
|
alpar@1
|
133 |
int nnz = ssx->A_ptr[n+1]-1;
|
alpar@1
|
134 |
int j, k, type, loc, len, *ind;
|
alpar@1
|
135 |
double lb, ub, coef, *val;
|
alpar@1
|
136 |
xassert(lpx_get_num_rows(lp) == m);
|
alpar@1
|
137 |
xassert(lpx_get_num_cols(lp) == n);
|
alpar@1
|
138 |
xassert(lpx_get_num_nz(lp) == nnz);
|
alpar@1
|
139 |
/* types and bounds of rows and columns */
|
alpar@1
|
140 |
for (k = 1; k <= m+n; k++)
|
alpar@1
|
141 |
{ if (k <= m)
|
alpar@1
|
142 |
{ type = lpx_get_row_type(lp, k);
|
alpar@1
|
143 |
lb = lpx_get_row_lb(lp, k);
|
alpar@1
|
144 |
ub = lpx_get_row_ub(lp, k);
|
alpar@1
|
145 |
}
|
alpar@1
|
146 |
else
|
alpar@1
|
147 |
{ type = lpx_get_col_type(lp, k-m);
|
alpar@1
|
148 |
lb = lpx_get_col_lb(lp, k-m);
|
alpar@1
|
149 |
ub = lpx_get_col_ub(lp, k-m);
|
alpar@1
|
150 |
}
|
alpar@1
|
151 |
switch (type)
|
alpar@1
|
152 |
{ case LPX_FR: type = SSX_FR; break;
|
alpar@1
|
153 |
case LPX_LO: type = SSX_LO; break;
|
alpar@1
|
154 |
case LPX_UP: type = SSX_UP; break;
|
alpar@1
|
155 |
case LPX_DB: type = SSX_DB; break;
|
alpar@1
|
156 |
case LPX_FX: type = SSX_FX; break;
|
alpar@1
|
157 |
default: xassert(type != type);
|
alpar@1
|
158 |
}
|
alpar@1
|
159 |
ssx->type[k] = type;
|
alpar@1
|
160 |
set_d_eps(ssx->lb[k], lb);
|
alpar@1
|
161 |
set_d_eps(ssx->ub[k], ub);
|
alpar@1
|
162 |
}
|
alpar@1
|
163 |
/* optimization direction */
|
alpar@1
|
164 |
switch (lpx_get_obj_dir(lp))
|
alpar@1
|
165 |
{ case LPX_MIN: ssx->dir = SSX_MIN; break;
|
alpar@1
|
166 |
case LPX_MAX: ssx->dir = SSX_MAX; break;
|
alpar@1
|
167 |
default: xassert(lp != lp);
|
alpar@1
|
168 |
}
|
alpar@1
|
169 |
/* objective coefficients */
|
alpar@1
|
170 |
for (k = 0; k <= m+n; k++)
|
alpar@1
|
171 |
{ if (k == 0)
|
alpar@1
|
172 |
coef = lpx_get_obj_coef(lp, 0);
|
alpar@1
|
173 |
else if (k <= m)
|
alpar@1
|
174 |
coef = 0.0;
|
alpar@1
|
175 |
else
|
alpar@1
|
176 |
coef = lpx_get_obj_coef(lp, k-m);
|
alpar@1
|
177 |
set_d_eps(ssx->coef[k], coef);
|
alpar@1
|
178 |
}
|
alpar@1
|
179 |
/* constraint coefficients */
|
alpar@1
|
180 |
ind = xcalloc(1+m, sizeof(int));
|
alpar@1
|
181 |
val = xcalloc(1+m, sizeof(double));
|
alpar@1
|
182 |
loc = 0;
|
alpar@1
|
183 |
for (j = 1; j <= n; j++)
|
alpar@1
|
184 |
{ ssx->A_ptr[j] = loc+1;
|
alpar@1
|
185 |
len = lpx_get_mat_col(lp, j, ind, val);
|
alpar@1
|
186 |
for (k = 1; k <= len; k++)
|
alpar@1
|
187 |
{ loc++;
|
alpar@1
|
188 |
ssx->A_ind[loc] = ind[k];
|
alpar@1
|
189 |
set_d_eps(ssx->A_val[loc], val[k]);
|
alpar@1
|
190 |
}
|
alpar@1
|
191 |
}
|
alpar@1
|
192 |
xassert(loc == nnz);
|
alpar@1
|
193 |
xfree(ind);
|
alpar@1
|
194 |
xfree(val);
|
alpar@1
|
195 |
return;
|
alpar@1
|
196 |
}
|
alpar@1
|
197 |
|
alpar@1
|
198 |
static int load_basis(SSX *ssx, LPX *lp)
|
alpar@1
|
199 |
{ /* load current LP basis into simplex solver workspace */
|
alpar@1
|
200 |
int m = ssx->m;
|
alpar@1
|
201 |
int n = ssx->n;
|
alpar@1
|
202 |
int *type = ssx->type;
|
alpar@1
|
203 |
int *stat = ssx->stat;
|
alpar@1
|
204 |
int *Q_row = ssx->Q_row;
|
alpar@1
|
205 |
int *Q_col = ssx->Q_col;
|
alpar@1
|
206 |
int i, j, k;
|
alpar@1
|
207 |
xassert(lpx_get_num_rows(lp) == m);
|
alpar@1
|
208 |
xassert(lpx_get_num_cols(lp) == n);
|
alpar@1
|
209 |
/* statuses of rows and columns */
|
alpar@1
|
210 |
for (k = 1; k <= m+n; k++)
|
alpar@1
|
211 |
{ if (k <= m)
|
alpar@1
|
212 |
stat[k] = lpx_get_row_stat(lp, k);
|
alpar@1
|
213 |
else
|
alpar@1
|
214 |
stat[k] = lpx_get_col_stat(lp, k-m);
|
alpar@1
|
215 |
switch (stat[k])
|
alpar@1
|
216 |
{ case LPX_BS:
|
alpar@1
|
217 |
stat[k] = SSX_BS;
|
alpar@1
|
218 |
break;
|
alpar@1
|
219 |
case LPX_NL:
|
alpar@1
|
220 |
stat[k] = SSX_NL;
|
alpar@1
|
221 |
xassert(type[k] == SSX_LO || type[k] == SSX_DB);
|
alpar@1
|
222 |
break;
|
alpar@1
|
223 |
case LPX_NU:
|
alpar@1
|
224 |
stat[k] = SSX_NU;
|
alpar@1
|
225 |
xassert(type[k] == SSX_UP || type[k] == SSX_DB);
|
alpar@1
|
226 |
break;
|
alpar@1
|
227 |
case LPX_NF:
|
alpar@1
|
228 |
stat[k] = SSX_NF;
|
alpar@1
|
229 |
xassert(type[k] == SSX_FR);
|
alpar@1
|
230 |
break;
|
alpar@1
|
231 |
case LPX_NS:
|
alpar@1
|
232 |
stat[k] = SSX_NS;
|
alpar@1
|
233 |
xassert(type[k] == SSX_FX);
|
alpar@1
|
234 |
break;
|
alpar@1
|
235 |
default:
|
alpar@1
|
236 |
xassert(stat != stat);
|
alpar@1
|
237 |
}
|
alpar@1
|
238 |
}
|
alpar@1
|
239 |
/* build permutation matix Q */
|
alpar@1
|
240 |
i = j = 0;
|
alpar@1
|
241 |
for (k = 1; k <= m+n; k++)
|
alpar@1
|
242 |
{ if (stat[k] == SSX_BS)
|
alpar@1
|
243 |
{ i++;
|
alpar@1
|
244 |
if (i > m) return 1;
|
alpar@1
|
245 |
Q_row[k] = i, Q_col[i] = k;
|
alpar@1
|
246 |
}
|
alpar@1
|
247 |
else
|
alpar@1
|
248 |
{ j++;
|
alpar@1
|
249 |
if (j > n) return 1;
|
alpar@1
|
250 |
Q_row[k] = m+j, Q_col[m+j] = k;
|
alpar@1
|
251 |
}
|
alpar@1
|
252 |
}
|
alpar@1
|
253 |
xassert(i == m && j == n);
|
alpar@1
|
254 |
return 0;
|
alpar@1
|
255 |
}
|
alpar@1
|
256 |
|
alpar@1
|
257 |
int glp_exact(glp_prob *lp, const glp_smcp *parm)
|
alpar@1
|
258 |
{ glp_smcp _parm;
|
alpar@1
|
259 |
SSX *ssx;
|
alpar@1
|
260 |
int m = lpx_get_num_rows(lp);
|
alpar@1
|
261 |
int n = lpx_get_num_cols(lp);
|
alpar@1
|
262 |
int nnz = lpx_get_num_nz(lp);
|
alpar@1
|
263 |
int i, j, k, type, pst, dst, ret, *stat;
|
alpar@1
|
264 |
double lb, ub, *prim, *dual, sum;
|
alpar@1
|
265 |
if (parm == NULL)
|
alpar@1
|
266 |
parm = &_parm, glp_init_smcp((glp_smcp *)parm);
|
alpar@1
|
267 |
/* check control parameters */
|
alpar@1
|
268 |
if (parm->it_lim < 0)
|
alpar@1
|
269 |
xerror("glp_exact: it_lim = %d; invalid parameter\n",
|
alpar@1
|
270 |
parm->it_lim);
|
alpar@1
|
271 |
if (parm->tm_lim < 0)
|
alpar@1
|
272 |
xerror("glp_exact: tm_lim = %d; invalid parameter\n",
|
alpar@1
|
273 |
parm->tm_lim);
|
alpar@1
|
274 |
/* the problem must have at least one row and one column */
|
alpar@1
|
275 |
if (!(m > 0 && n > 0))
|
alpar@1
|
276 |
{ xprintf("glp_exact: problem has no rows/columns\n");
|
alpar@1
|
277 |
return GLP_EFAIL;
|
alpar@1
|
278 |
}
|
alpar@1
|
279 |
#if 1
|
alpar@1
|
280 |
/* basic solution is currently undefined */
|
alpar@1
|
281 |
lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
|
alpar@1
|
282 |
lp->obj_val = 0.0;
|
alpar@1
|
283 |
lp->some = 0;
|
alpar@1
|
284 |
#endif
|
alpar@1
|
285 |
/* check that all double-bounded variables have correct bounds */
|
alpar@1
|
286 |
for (k = 1; k <= m+n; k++)
|
alpar@1
|
287 |
{ if (k <= m)
|
alpar@1
|
288 |
{ type = lpx_get_row_type(lp, k);
|
alpar@1
|
289 |
lb = lpx_get_row_lb(lp, k);
|
alpar@1
|
290 |
ub = lpx_get_row_ub(lp, k);
|
alpar@1
|
291 |
}
|
alpar@1
|
292 |
else
|
alpar@1
|
293 |
{ type = lpx_get_col_type(lp, k-m);
|
alpar@1
|
294 |
lb = lpx_get_col_lb(lp, k-m);
|
alpar@1
|
295 |
ub = lpx_get_col_ub(lp, k-m);
|
alpar@1
|
296 |
}
|
alpar@1
|
297 |
if (type == LPX_DB && lb >= ub)
|
alpar@1
|
298 |
{ xprintf("glp_exact: %s %d has invalid bounds\n",
|
alpar@1
|
299 |
k <= m ? "row" : "column", k <= m ? k : k-m);
|
alpar@1
|
300 |
return GLP_EBOUND;
|
alpar@1
|
301 |
}
|
alpar@1
|
302 |
}
|
alpar@1
|
303 |
/* create the simplex solver workspace */
|
alpar@1
|
304 |
xprintf("glp_exact: %d rows, %d columns, %d non-zeros\n",
|
alpar@1
|
305 |
m, n, nnz);
|
alpar@1
|
306 |
#ifdef HAVE_GMP
|
alpar@1
|
307 |
xprintf("GNU MP bignum library is being used\n");
|
alpar@1
|
308 |
#else
|
alpar@1
|
309 |
xprintf("GLPK bignum module is being used\n");
|
alpar@1
|
310 |
xprintf("(Consider installing GNU MP to attain a much better perf"
|
alpar@1
|
311 |
"ormance.)\n");
|
alpar@1
|
312 |
#endif
|
alpar@1
|
313 |
ssx = ssx_create(m, n, nnz);
|
alpar@1
|
314 |
/* load LP problem data into the workspace */
|
alpar@1
|
315 |
load_data(ssx, lp);
|
alpar@1
|
316 |
/* load current LP basis into the workspace */
|
alpar@1
|
317 |
if (load_basis(ssx, lp))
|
alpar@1
|
318 |
{ xprintf("glp_exact: initial LP basis is invalid\n");
|
alpar@1
|
319 |
ret = GLP_EBADB;
|
alpar@1
|
320 |
goto done;
|
alpar@1
|
321 |
}
|
alpar@1
|
322 |
/* inherit some control parameters from the LP object */
|
alpar@1
|
323 |
#if 0
|
alpar@1
|
324 |
ssx->it_lim = lpx_get_int_parm(lp, LPX_K_ITLIM);
|
alpar@1
|
325 |
ssx->it_cnt = lpx_get_int_parm(lp, LPX_K_ITCNT);
|
alpar@1
|
326 |
ssx->tm_lim = lpx_get_real_parm(lp, LPX_K_TMLIM);
|
alpar@1
|
327 |
#else
|
alpar@1
|
328 |
ssx->it_lim = parm->it_lim;
|
alpar@1
|
329 |
ssx->it_cnt = lp->it_cnt;
|
alpar@1
|
330 |
ssx->tm_lim = (double)parm->tm_lim / 1000.0;
|
alpar@1
|
331 |
#endif
|
alpar@1
|
332 |
ssx->out_frq = 5.0;
|
alpar@1
|
333 |
ssx->tm_beg = xtime();
|
alpar@1
|
334 |
ssx->tm_lag = xlset(0);
|
alpar@1
|
335 |
/* solve LP */
|
alpar@1
|
336 |
ret = ssx_driver(ssx);
|
alpar@1
|
337 |
/* copy back some statistics to the LP object */
|
alpar@1
|
338 |
#if 0
|
alpar@1
|
339 |
lpx_set_int_parm(lp, LPX_K_ITLIM, ssx->it_lim);
|
alpar@1
|
340 |
lpx_set_int_parm(lp, LPX_K_ITCNT, ssx->it_cnt);
|
alpar@1
|
341 |
lpx_set_real_parm(lp, LPX_K_TMLIM, ssx->tm_lim);
|
alpar@1
|
342 |
#else
|
alpar@1
|
343 |
lp->it_cnt = ssx->it_cnt;
|
alpar@1
|
344 |
#endif
|
alpar@1
|
345 |
/* analyze the return code */
|
alpar@1
|
346 |
switch (ret)
|
alpar@1
|
347 |
{ case 0:
|
alpar@1
|
348 |
/* optimal solution found */
|
alpar@1
|
349 |
ret = 0;
|
alpar@1
|
350 |
pst = LPX_P_FEAS, dst = LPX_D_FEAS;
|
alpar@1
|
351 |
break;
|
alpar@1
|
352 |
case 1:
|
alpar@1
|
353 |
/* problem has no feasible solution */
|
alpar@1
|
354 |
ret = 0;
|
alpar@1
|
355 |
pst = LPX_P_NOFEAS, dst = LPX_D_INFEAS;
|
alpar@1
|
356 |
break;
|
alpar@1
|
357 |
case 2:
|
alpar@1
|
358 |
/* problem has unbounded solution */
|
alpar@1
|
359 |
ret = 0;
|
alpar@1
|
360 |
pst = LPX_P_FEAS, dst = LPX_D_NOFEAS;
|
alpar@1
|
361 |
#if 1
|
alpar@1
|
362 |
xassert(1 <= ssx->q && ssx->q <= n);
|
alpar@1
|
363 |
lp->some = ssx->Q_col[m + ssx->q];
|
alpar@1
|
364 |
xassert(1 <= lp->some && lp->some <= m+n);
|
alpar@1
|
365 |
#endif
|
alpar@1
|
366 |
break;
|
alpar@1
|
367 |
case 3:
|
alpar@1
|
368 |
/* iteration limit exceeded (phase I) */
|
alpar@1
|
369 |
ret = GLP_EITLIM;
|
alpar@1
|
370 |
pst = LPX_P_INFEAS, dst = LPX_D_INFEAS;
|
alpar@1
|
371 |
break;
|
alpar@1
|
372 |
case 4:
|
alpar@1
|
373 |
/* iteration limit exceeded (phase II) */
|
alpar@1
|
374 |
ret = GLP_EITLIM;
|
alpar@1
|
375 |
pst = LPX_P_FEAS, dst = LPX_D_INFEAS;
|
alpar@1
|
376 |
break;
|
alpar@1
|
377 |
case 5:
|
alpar@1
|
378 |
/* time limit exceeded (phase I) */
|
alpar@1
|
379 |
ret = GLP_ETMLIM;
|
alpar@1
|
380 |
pst = LPX_P_INFEAS, dst = LPX_D_INFEAS;
|
alpar@1
|
381 |
break;
|
alpar@1
|
382 |
case 6:
|
alpar@1
|
383 |
/* time limit exceeded (phase II) */
|
alpar@1
|
384 |
ret = GLP_ETMLIM;
|
alpar@1
|
385 |
pst = LPX_P_FEAS, dst = LPX_D_INFEAS;
|
alpar@1
|
386 |
break;
|
alpar@1
|
387 |
case 7:
|
alpar@1
|
388 |
/* initial basis matrix is singular */
|
alpar@1
|
389 |
ret = GLP_ESING;
|
alpar@1
|
390 |
goto done;
|
alpar@1
|
391 |
default:
|
alpar@1
|
392 |
xassert(ret != ret);
|
alpar@1
|
393 |
}
|
alpar@1
|
394 |
/* obtain final basic solution components */
|
alpar@1
|
395 |
stat = xcalloc(1+m+n, sizeof(int));
|
alpar@1
|
396 |
prim = xcalloc(1+m+n, sizeof(double));
|
alpar@1
|
397 |
dual = xcalloc(1+m+n, sizeof(double));
|
alpar@1
|
398 |
for (k = 1; k <= m+n; k++)
|
alpar@1
|
399 |
{ if (ssx->stat[k] == SSX_BS)
|
alpar@1
|
400 |
{ i = ssx->Q_row[k]; /* x[k] = xB[i] */
|
alpar@1
|
401 |
xassert(1 <= i && i <= m);
|
alpar@1
|
402 |
stat[k] = LPX_BS;
|
alpar@1
|
403 |
prim[k] = mpq_get_d(ssx->bbar[i]);
|
alpar@1
|
404 |
dual[k] = 0.0;
|
alpar@1
|
405 |
}
|
alpar@1
|
406 |
else
|
alpar@1
|
407 |
{ j = ssx->Q_row[k] - m; /* x[k] = xN[j] */
|
alpar@1
|
408 |
xassert(1 <= j && j <= n);
|
alpar@1
|
409 |
switch (ssx->stat[k])
|
alpar@1
|
410 |
{ case SSX_NF:
|
alpar@1
|
411 |
stat[k] = LPX_NF;
|
alpar@1
|
412 |
prim[k] = 0.0;
|
alpar@1
|
413 |
break;
|
alpar@1
|
414 |
case SSX_NL:
|
alpar@1
|
415 |
stat[k] = LPX_NL;
|
alpar@1
|
416 |
prim[k] = mpq_get_d(ssx->lb[k]);
|
alpar@1
|
417 |
break;
|
alpar@1
|
418 |
case SSX_NU:
|
alpar@1
|
419 |
stat[k] = LPX_NU;
|
alpar@1
|
420 |
prim[k] = mpq_get_d(ssx->ub[k]);
|
alpar@1
|
421 |
break;
|
alpar@1
|
422 |
case SSX_NS:
|
alpar@1
|
423 |
stat[k] = LPX_NS;
|
alpar@1
|
424 |
prim[k] = mpq_get_d(ssx->lb[k]);
|
alpar@1
|
425 |
break;
|
alpar@1
|
426 |
default:
|
alpar@1
|
427 |
xassert(ssx != ssx);
|
alpar@1
|
428 |
}
|
alpar@1
|
429 |
dual[k] = mpq_get_d(ssx->cbar[j]);
|
alpar@1
|
430 |
}
|
alpar@1
|
431 |
}
|
alpar@1
|
432 |
/* and store them into the LP object */
|
alpar@1
|
433 |
pst = pst - LPX_P_UNDEF + GLP_UNDEF;
|
alpar@1
|
434 |
dst = dst - LPX_D_UNDEF + GLP_UNDEF;
|
alpar@1
|
435 |
for (k = 1; k <= m+n; k++)
|
alpar@1
|
436 |
stat[k] = stat[k] - LPX_BS + GLP_BS;
|
alpar@1
|
437 |
sum = lpx_get_obj_coef(lp, 0);
|
alpar@1
|
438 |
for (j = 1; j <= n; j++)
|
alpar@1
|
439 |
sum += lpx_get_obj_coef(lp, j) * prim[m+j];
|
alpar@1
|
440 |
lpx_put_solution(lp, 1, &pst, &dst, &sum,
|
alpar@1
|
441 |
&stat[0], &prim[0], &dual[0], &stat[m], &prim[m], &dual[m]);
|
alpar@1
|
442 |
xfree(stat);
|
alpar@1
|
443 |
xfree(prim);
|
alpar@1
|
444 |
xfree(dual);
|
alpar@1
|
445 |
done: /* delete the simplex solver workspace */
|
alpar@1
|
446 |
ssx_delete(ssx);
|
alpar@1
|
447 |
/* return to the application program */
|
alpar@1
|
448 |
return ret;
|
alpar@1
|
449 |
}
|
alpar@1
|
450 |
|
alpar@1
|
451 |
/* eof */
|