rev |
line source |
alpar@9
|
1 /* glpnpp03.c */
|
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 "glpnpp.h"
|
alpar@9
|
26
|
alpar@9
|
27 /***********************************************************************
|
alpar@9
|
28 * NAME
|
alpar@9
|
29 *
|
alpar@9
|
30 * npp_empty_row - process empty row
|
alpar@9
|
31 *
|
alpar@9
|
32 * SYNOPSIS
|
alpar@9
|
33 *
|
alpar@9
|
34 * #include "glpnpp.h"
|
alpar@9
|
35 * int npp_empty_row(NPP *npp, NPPROW *p);
|
alpar@9
|
36 *
|
alpar@9
|
37 * DESCRIPTION
|
alpar@9
|
38 *
|
alpar@9
|
39 * The routine npp_empty_row processes row p, which is empty, i.e.
|
alpar@9
|
40 * coefficients at all columns in this row are zero:
|
alpar@9
|
41 *
|
alpar@9
|
42 * L[p] <= sum 0 x[j] <= U[p], (1)
|
alpar@9
|
43 *
|
alpar@9
|
44 * where L[p] <= U[p].
|
alpar@9
|
45 *
|
alpar@9
|
46 * RETURNS
|
alpar@9
|
47 *
|
alpar@9
|
48 * 0 - success;
|
alpar@9
|
49 *
|
alpar@9
|
50 * 1 - problem has no primal feasible solution.
|
alpar@9
|
51 *
|
alpar@9
|
52 * PROBLEM TRANSFORMATION
|
alpar@9
|
53 *
|
alpar@9
|
54 * If the following conditions hold:
|
alpar@9
|
55 *
|
alpar@9
|
56 * L[p] <= +eps, U[p] >= -eps, (2)
|
alpar@9
|
57 *
|
alpar@9
|
58 * where eps is an absolute tolerance for row value, the row p is
|
alpar@9
|
59 * redundant. In this case it can be replaced by equivalent redundant
|
alpar@9
|
60 * row, which is free (unbounded), and then removed from the problem.
|
alpar@9
|
61 * Otherwise, the row p is infeasible and, thus, the problem has no
|
alpar@9
|
62 * primal feasible solution.
|
alpar@9
|
63 *
|
alpar@9
|
64 * RECOVERING BASIC SOLUTION
|
alpar@9
|
65 *
|
alpar@9
|
66 * See the routine npp_free_row.
|
alpar@9
|
67 *
|
alpar@9
|
68 * RECOVERING INTERIOR-POINT SOLUTION
|
alpar@9
|
69 *
|
alpar@9
|
70 * See the routine npp_free_row.
|
alpar@9
|
71 *
|
alpar@9
|
72 * RECOVERING MIP SOLUTION
|
alpar@9
|
73 *
|
alpar@9
|
74 * None needed. */
|
alpar@9
|
75
|
alpar@9
|
76 int npp_empty_row(NPP *npp, NPPROW *p)
|
alpar@9
|
77 { /* process empty row */
|
alpar@9
|
78 double eps = 1e-3;
|
alpar@9
|
79 /* the row must be empty */
|
alpar@9
|
80 xassert(p->ptr == NULL);
|
alpar@9
|
81 /* check primal feasibility */
|
alpar@9
|
82 if (p->lb > +eps || p->ub < -eps)
|
alpar@9
|
83 return 1;
|
alpar@9
|
84 /* replace the row by equivalent free (unbounded) row */
|
alpar@9
|
85 p->lb = -DBL_MAX, p->ub = +DBL_MAX;
|
alpar@9
|
86 /* and process it */
|
alpar@9
|
87 npp_free_row(npp, p);
|
alpar@9
|
88 return 0;
|
alpar@9
|
89 }
|
alpar@9
|
90
|
alpar@9
|
91 /***********************************************************************
|
alpar@9
|
92 * NAME
|
alpar@9
|
93 *
|
alpar@9
|
94 * npp_empty_col - process empty column
|
alpar@9
|
95 *
|
alpar@9
|
96 * SYNOPSIS
|
alpar@9
|
97 *
|
alpar@9
|
98 * #include "glpnpp.h"
|
alpar@9
|
99 * int npp_empty_col(NPP *npp, NPPCOL *q);
|
alpar@9
|
100 *
|
alpar@9
|
101 * DESCRIPTION
|
alpar@9
|
102 *
|
alpar@9
|
103 * The routine npp_empty_col processes column q:
|
alpar@9
|
104 *
|
alpar@9
|
105 * l[q] <= x[q] <= u[q], (1)
|
alpar@9
|
106 *
|
alpar@9
|
107 * where l[q] <= u[q], which is empty, i.e. has zero coefficients in
|
alpar@9
|
108 * all constraint rows.
|
alpar@9
|
109 *
|
alpar@9
|
110 * RETURNS
|
alpar@9
|
111 *
|
alpar@9
|
112 * 0 - success;
|
alpar@9
|
113 *
|
alpar@9
|
114 * 1 - problem has no dual feasible solution.
|
alpar@9
|
115 *
|
alpar@9
|
116 * PROBLEM TRANSFORMATION
|
alpar@9
|
117 *
|
alpar@9
|
118 * The row of the dual system corresponding to the empty column is the
|
alpar@9
|
119 * following:
|
alpar@9
|
120 *
|
alpar@9
|
121 * sum 0 pi[i] + lambda[q] = c[q], (2)
|
alpar@9
|
122 * i
|
alpar@9
|
123 *
|
alpar@9
|
124 * from which it follows that:
|
alpar@9
|
125 *
|
alpar@9
|
126 * lambda[q] = c[q]. (3)
|
alpar@9
|
127 *
|
alpar@9
|
128 * If the following condition holds:
|
alpar@9
|
129 *
|
alpar@9
|
130 * c[q] < - eps, (4)
|
alpar@9
|
131 *
|
alpar@9
|
132 * where eps is an absolute tolerance for column multiplier, the lower
|
alpar@9
|
133 * column bound l[q] must be active to provide dual feasibility (note
|
alpar@9
|
134 * that being preprocessed the problem is always minimization). In this
|
alpar@9
|
135 * case the column can be fixed on its lower bound and removed from the
|
alpar@9
|
136 * problem (if the column is integral, its bounds are also assumed to
|
alpar@9
|
137 * be integral). And if the column has no lower bound (l[q] = -oo), the
|
alpar@9
|
138 * problem has no dual feasible solution.
|
alpar@9
|
139 *
|
alpar@9
|
140 * If the following condition holds:
|
alpar@9
|
141 *
|
alpar@9
|
142 * c[q] > + eps, (5)
|
alpar@9
|
143 *
|
alpar@9
|
144 * the upper column bound u[q] must be active to provide dual
|
alpar@9
|
145 * feasibility. In this case the column can be fixed on its upper bound
|
alpar@9
|
146 * and removed from the problem. And if the column has no upper bound
|
alpar@9
|
147 * (u[q] = +oo), the problem has no dual feasible solution.
|
alpar@9
|
148 *
|
alpar@9
|
149 * Finally, if the following condition holds:
|
alpar@9
|
150 *
|
alpar@9
|
151 * - eps <= c[q] <= +eps, (6)
|
alpar@9
|
152 *
|
alpar@9
|
153 * dual feasibility does not depend on a particular value of column q.
|
alpar@9
|
154 * In this case the column can be fixed either on its lower bound (if
|
alpar@9
|
155 * l[q] > -oo) or on its upper bound (if u[q] < +oo) or at zero (if the
|
alpar@9
|
156 * column is unbounded) and then removed from the problem.
|
alpar@9
|
157 *
|
alpar@9
|
158 * RECOVERING BASIC SOLUTION
|
alpar@9
|
159 *
|
alpar@9
|
160 * See the routine npp_fixed_col. Having been recovered the column
|
alpar@9
|
161 * is assigned status GLP_NS. However, if actually it is not fixed
|
alpar@9
|
162 * (l[q] < u[q]), its status should be changed to GLP_NL, GLP_NU, or
|
alpar@9
|
163 * GLP_NF depending on which bound it was fixed on transformation stage.
|
alpar@9
|
164 *
|
alpar@9
|
165 * RECOVERING INTERIOR-POINT SOLUTION
|
alpar@9
|
166 *
|
alpar@9
|
167 * See the routine npp_fixed_col.
|
alpar@9
|
168 *
|
alpar@9
|
169 * RECOVERING MIP SOLUTION
|
alpar@9
|
170 *
|
alpar@9
|
171 * See the routine npp_fixed_col. */
|
alpar@9
|
172
|
alpar@9
|
173 struct empty_col
|
alpar@9
|
174 { /* empty column */
|
alpar@9
|
175 int q;
|
alpar@9
|
176 /* column reference number */
|
alpar@9
|
177 char stat;
|
alpar@9
|
178 /* status in basic solution */
|
alpar@9
|
179 };
|
alpar@9
|
180
|
alpar@9
|
181 static int rcv_empty_col(NPP *npp, void *info);
|
alpar@9
|
182
|
alpar@9
|
183 int npp_empty_col(NPP *npp, NPPCOL *q)
|
alpar@9
|
184 { /* process empty column */
|
alpar@9
|
185 struct empty_col *info;
|
alpar@9
|
186 double eps = 1e-3;
|
alpar@9
|
187 /* the column must be empty */
|
alpar@9
|
188 xassert(q->ptr == NULL);
|
alpar@9
|
189 /* check dual feasibility */
|
alpar@9
|
190 if (q->coef > +eps && q->lb == -DBL_MAX)
|
alpar@9
|
191 return 1;
|
alpar@9
|
192 if (q->coef < -eps && q->ub == +DBL_MAX)
|
alpar@9
|
193 return 1;
|
alpar@9
|
194 /* create transformation stack entry */
|
alpar@9
|
195 info = npp_push_tse(npp,
|
alpar@9
|
196 rcv_empty_col, sizeof(struct empty_col));
|
alpar@9
|
197 info->q = q->j;
|
alpar@9
|
198 /* fix the column */
|
alpar@9
|
199 if (q->lb == -DBL_MAX && q->ub == +DBL_MAX)
|
alpar@9
|
200 { /* free column */
|
alpar@9
|
201 info->stat = GLP_NF;
|
alpar@9
|
202 q->lb = q->ub = 0.0;
|
alpar@9
|
203 }
|
alpar@9
|
204 else if (q->ub == +DBL_MAX)
|
alpar@9
|
205 lo: { /* column with lower bound */
|
alpar@9
|
206 info->stat = GLP_NL;
|
alpar@9
|
207 q->ub = q->lb;
|
alpar@9
|
208 }
|
alpar@9
|
209 else if (q->lb == -DBL_MAX)
|
alpar@9
|
210 up: { /* column with upper bound */
|
alpar@9
|
211 info->stat = GLP_NU;
|
alpar@9
|
212 q->lb = q->ub;
|
alpar@9
|
213 }
|
alpar@9
|
214 else if (q->lb != q->ub)
|
alpar@9
|
215 { /* double-bounded column */
|
alpar@9
|
216 if (q->coef >= +DBL_EPSILON) goto lo;
|
alpar@9
|
217 if (q->coef <= -DBL_EPSILON) goto up;
|
alpar@9
|
218 if (fabs(q->lb) <= fabs(q->ub)) goto lo; else goto up;
|
alpar@9
|
219 }
|
alpar@9
|
220 else
|
alpar@9
|
221 { /* fixed column */
|
alpar@9
|
222 info->stat = GLP_NS;
|
alpar@9
|
223 }
|
alpar@9
|
224 /* process fixed column */
|
alpar@9
|
225 npp_fixed_col(npp, q);
|
alpar@9
|
226 return 0;
|
alpar@9
|
227 }
|
alpar@9
|
228
|
alpar@9
|
229 static int rcv_empty_col(NPP *npp, void *_info)
|
alpar@9
|
230 { /* recover empty column */
|
alpar@9
|
231 struct empty_col *info = _info;
|
alpar@9
|
232 if (npp->sol == GLP_SOL)
|
alpar@9
|
233 npp->c_stat[info->q] = info->stat;
|
alpar@9
|
234 return 0;
|
alpar@9
|
235 }
|
alpar@9
|
236
|
alpar@9
|
237 /***********************************************************************
|
alpar@9
|
238 * NAME
|
alpar@9
|
239 *
|
alpar@9
|
240 * npp_implied_value - process implied column value
|
alpar@9
|
241 *
|
alpar@9
|
242 * SYNOPSIS
|
alpar@9
|
243 *
|
alpar@9
|
244 * #include "glpnpp.h"
|
alpar@9
|
245 * int npp_implied_value(NPP *npp, NPPCOL *q, double s);
|
alpar@9
|
246 *
|
alpar@9
|
247 * DESCRIPTION
|
alpar@9
|
248 *
|
alpar@9
|
249 * For column q:
|
alpar@9
|
250 *
|
alpar@9
|
251 * l[q] <= x[q] <= u[q], (1)
|
alpar@9
|
252 *
|
alpar@9
|
253 * where l[q] < u[q], the routine npp_implied_value processes its
|
alpar@9
|
254 * implied value s[q]. If this implied value satisfies to the current
|
alpar@9
|
255 * column bounds and integrality condition, the routine fixes column q
|
alpar@9
|
256 * at the given point. Note that the column is kept in the problem in
|
alpar@9
|
257 * any case.
|
alpar@9
|
258 *
|
alpar@9
|
259 * RETURNS
|
alpar@9
|
260 *
|
alpar@9
|
261 * 0 - column has been fixed;
|
alpar@9
|
262 *
|
alpar@9
|
263 * 1 - implied value violates to current column bounds;
|
alpar@9
|
264 *
|
alpar@9
|
265 * 2 - implied value violates integrality condition.
|
alpar@9
|
266 *
|
alpar@9
|
267 * ALGORITHM
|
alpar@9
|
268 *
|
alpar@9
|
269 * Implied column value s[q] satisfies to the current column bounds if
|
alpar@9
|
270 * the following condition holds:
|
alpar@9
|
271 *
|
alpar@9
|
272 * l[q] - eps <= s[q] <= u[q] + eps, (2)
|
alpar@9
|
273 *
|
alpar@9
|
274 * where eps is an absolute tolerance for column value. If the column
|
alpar@9
|
275 * is integral, the following condition also must hold:
|
alpar@9
|
276 *
|
alpar@9
|
277 * |s[q] - floor(s[q]+0.5)| <= eps, (3)
|
alpar@9
|
278 *
|
alpar@9
|
279 * where floor(s[q]+0.5) is the nearest integer to s[q].
|
alpar@9
|
280 *
|
alpar@9
|
281 * If both condition (2) and (3) are satisfied, the column can be fixed
|
alpar@9
|
282 * at the value s[q], or, if it is integral, at floor(s[q]+0.5).
|
alpar@9
|
283 * Otherwise, if s[q] violates (2) or (3), the problem has no feasible
|
alpar@9
|
284 * solution.
|
alpar@9
|
285 *
|
alpar@9
|
286 * Note: If s[q] is close to l[q] or u[q], it seems to be reasonable to
|
alpar@9
|
287 * fix the column at its lower or upper bound, resp. rather than at the
|
alpar@9
|
288 * implied value. */
|
alpar@9
|
289
|
alpar@9
|
290 int npp_implied_value(NPP *npp, NPPCOL *q, double s)
|
alpar@9
|
291 { /* process implied column value */
|
alpar@9
|
292 double eps, nint;
|
alpar@9
|
293 xassert(npp == npp);
|
alpar@9
|
294 /* column must not be fixed */
|
alpar@9
|
295 xassert(q->lb < q->ub);
|
alpar@9
|
296 /* check integrality */
|
alpar@9
|
297 if (q->is_int)
|
alpar@9
|
298 { nint = floor(s + 0.5);
|
alpar@9
|
299 if (fabs(s - nint) <= 1e-5)
|
alpar@9
|
300 s = nint;
|
alpar@9
|
301 else
|
alpar@9
|
302 return 2;
|
alpar@9
|
303 }
|
alpar@9
|
304 /* check current column lower bound */
|
alpar@9
|
305 if (q->lb != -DBL_MAX)
|
alpar@9
|
306 { eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->lb));
|
alpar@9
|
307 if (s < q->lb - eps) return 1;
|
alpar@9
|
308 /* if s[q] is close to l[q], fix column at its lower bound
|
alpar@9
|
309 rather than at the implied value */
|
alpar@9
|
310 if (s < q->lb + 1e-3 * eps)
|
alpar@9
|
311 { q->ub = q->lb;
|
alpar@9
|
312 return 0;
|
alpar@9
|
313 }
|
alpar@9
|
314 }
|
alpar@9
|
315 /* check current column upper bound */
|
alpar@9
|
316 if (q->ub != +DBL_MAX)
|
alpar@9
|
317 { eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->ub));
|
alpar@9
|
318 if (s > q->ub + eps) return 1;
|
alpar@9
|
319 /* if s[q] is close to u[q], fix column at its upper bound
|
alpar@9
|
320 rather than at the implied value */
|
alpar@9
|
321 if (s > q->ub - 1e-3 * eps)
|
alpar@9
|
322 { q->lb = q->ub;
|
alpar@9
|
323 return 0;
|
alpar@9
|
324 }
|
alpar@9
|
325 }
|
alpar@9
|
326 /* fix column at the implied value */
|
alpar@9
|
327 q->lb = q->ub = s;
|
alpar@9
|
328 return 0;
|
alpar@9
|
329 }
|
alpar@9
|
330
|
alpar@9
|
331 /***********************************************************************
|
alpar@9
|
332 * NAME
|
alpar@9
|
333 *
|
alpar@9
|
334 * npp_eq_singlet - process row singleton (equality constraint)
|
alpar@9
|
335 *
|
alpar@9
|
336 * SYNOPSIS
|
alpar@9
|
337 *
|
alpar@9
|
338 * #include "glpnpp.h"
|
alpar@9
|
339 * int npp_eq_singlet(NPP *npp, NPPROW *p);
|
alpar@9
|
340 *
|
alpar@9
|
341 * DESCRIPTION
|
alpar@9
|
342 *
|
alpar@9
|
343 * The routine npp_eq_singlet processes row p, which is equiality
|
alpar@9
|
344 * constraint having the only non-zero coefficient:
|
alpar@9
|
345 *
|
alpar@9
|
346 * a[p,q] x[q] = b. (1)
|
alpar@9
|
347 *
|
alpar@9
|
348 * RETURNS
|
alpar@9
|
349 *
|
alpar@9
|
350 * 0 - success;
|
alpar@9
|
351 *
|
alpar@9
|
352 * 1 - problem has no primal feasible solution;
|
alpar@9
|
353 *
|
alpar@9
|
354 * 2 - problem has no integer feasible solution.
|
alpar@9
|
355 *
|
alpar@9
|
356 * PROBLEM TRANSFORMATION
|
alpar@9
|
357 *
|
alpar@9
|
358 * The equality constraint defines implied value of column q:
|
alpar@9
|
359 *
|
alpar@9
|
360 * x[q] = s[q] = b / a[p,q]. (2)
|
alpar@9
|
361 *
|
alpar@9
|
362 * If the implied value s[q] satisfies to the column bounds (see the
|
alpar@9
|
363 * routine npp_implied_value), the column can be fixed at s[q] and
|
alpar@9
|
364 * removed from the problem. In this case row p becomes redundant, so
|
alpar@9
|
365 * it can be replaced by equivalent free row and also removed from the
|
alpar@9
|
366 * problem.
|
alpar@9
|
367 *
|
alpar@9
|
368 * Note that the routine removes from the problem only row p. Column q
|
alpar@9
|
369 * becomes fixed, however, it is kept in the problem.
|
alpar@9
|
370 *
|
alpar@9
|
371 * RECOVERING BASIC SOLUTION
|
alpar@9
|
372 *
|
alpar@9
|
373 * In solution to the original problem row p is assigned status GLP_NS
|
alpar@9
|
374 * (active equality constraint), and column q is assigned status GLP_BS
|
alpar@9
|
375 * (basic column).
|
alpar@9
|
376 *
|
alpar@9
|
377 * Multiplier for row p can be computed as follows. In the dual system
|
alpar@9
|
378 * of the original problem column q corresponds to the following row:
|
alpar@9
|
379 *
|
alpar@9
|
380 * sum a[i,q] pi[i] + lambda[q] = c[q] ==>
|
alpar@9
|
381 * i
|
alpar@9
|
382 *
|
alpar@9
|
383 * sum a[i,q] pi[i] + a[p,q] pi[p] + lambda[q] = c[q].
|
alpar@9
|
384 * i!=p
|
alpar@9
|
385 *
|
alpar@9
|
386 * Therefore:
|
alpar@9
|
387 *
|
alpar@9
|
388 * 1
|
alpar@9
|
389 * pi[p] = ------ (c[q] - lambda[q] - sum a[i,q] pi[i]), (3)
|
alpar@9
|
390 * a[p,q] i!=q
|
alpar@9
|
391 *
|
alpar@9
|
392 * where lambda[q] = 0 (since column[q] is basic), and pi[i] for all
|
alpar@9
|
393 * i != p are known in solution to the transformed problem.
|
alpar@9
|
394 *
|
alpar@9
|
395 * Value of column q in solution to the original problem is assigned
|
alpar@9
|
396 * its implied value s[q].
|
alpar@9
|
397 *
|
alpar@9
|
398 * RECOVERING INTERIOR-POINT SOLUTION
|
alpar@9
|
399 *
|
alpar@9
|
400 * Multiplier for row p is computed with formula (3). Value of column
|
alpar@9
|
401 * q is assigned its implied value s[q].
|
alpar@9
|
402 *
|
alpar@9
|
403 * RECOVERING MIP SOLUTION
|
alpar@9
|
404 *
|
alpar@9
|
405 * Value of column q is assigned its implied value s[q]. */
|
alpar@9
|
406
|
alpar@9
|
407 struct eq_singlet
|
alpar@9
|
408 { /* row singleton (equality constraint) */
|
alpar@9
|
409 int p;
|
alpar@9
|
410 /* row reference number */
|
alpar@9
|
411 int q;
|
alpar@9
|
412 /* column reference number */
|
alpar@9
|
413 double apq;
|
alpar@9
|
414 /* constraint coefficient a[p,q] */
|
alpar@9
|
415 double c;
|
alpar@9
|
416 /* objective coefficient at x[q] */
|
alpar@9
|
417 NPPLFE *ptr;
|
alpar@9
|
418 /* list of non-zero coefficients a[i,q], i != p */
|
alpar@9
|
419 };
|
alpar@9
|
420
|
alpar@9
|
421 static int rcv_eq_singlet(NPP *npp, void *info);
|
alpar@9
|
422
|
alpar@9
|
423 int npp_eq_singlet(NPP *npp, NPPROW *p)
|
alpar@9
|
424 { /* process row singleton (equality constraint) */
|
alpar@9
|
425 struct eq_singlet *info;
|
alpar@9
|
426 NPPCOL *q;
|
alpar@9
|
427 NPPAIJ *aij;
|
alpar@9
|
428 NPPLFE *lfe;
|
alpar@9
|
429 int ret;
|
alpar@9
|
430 double s;
|
alpar@9
|
431 /* the row must be singleton equality constraint */
|
alpar@9
|
432 xassert(p->lb == p->ub);
|
alpar@9
|
433 xassert(p->ptr != NULL && p->ptr->r_next == NULL);
|
alpar@9
|
434 /* compute and process implied column value */
|
alpar@9
|
435 aij = p->ptr;
|
alpar@9
|
436 q = aij->col;
|
alpar@9
|
437 s = p->lb / aij->val;
|
alpar@9
|
438 ret = npp_implied_value(npp, q, s);
|
alpar@9
|
439 xassert(0 <= ret && ret <= 2);
|
alpar@9
|
440 if (ret != 0) return ret;
|
alpar@9
|
441 /* create transformation stack entry */
|
alpar@9
|
442 info = npp_push_tse(npp,
|
alpar@9
|
443 rcv_eq_singlet, sizeof(struct eq_singlet));
|
alpar@9
|
444 info->p = p->i;
|
alpar@9
|
445 info->q = q->j;
|
alpar@9
|
446 info->apq = aij->val;
|
alpar@9
|
447 info->c = q->coef;
|
alpar@9
|
448 info->ptr = NULL;
|
alpar@9
|
449 /* save column coefficients a[i,q], i != p (not needed for MIP
|
alpar@9
|
450 solution) */
|
alpar@9
|
451 if (npp->sol != GLP_MIP)
|
alpar@9
|
452 { for (aij = q->ptr; aij != NULL; aij = aij->c_next)
|
alpar@9
|
453 { if (aij->row == p) continue; /* skip a[p,q] */
|
alpar@9
|
454 lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
|
alpar@9
|
455 lfe->ref = aij->row->i;
|
alpar@9
|
456 lfe->val = aij->val;
|
alpar@9
|
457 lfe->next = info->ptr;
|
alpar@9
|
458 info->ptr = lfe;
|
alpar@9
|
459 }
|
alpar@9
|
460 }
|
alpar@9
|
461 /* remove the row from the problem */
|
alpar@9
|
462 npp_del_row(npp, p);
|
alpar@9
|
463 return 0;
|
alpar@9
|
464 }
|
alpar@9
|
465
|
alpar@9
|
466 static int rcv_eq_singlet(NPP *npp, void *_info)
|
alpar@9
|
467 { /* recover row singleton (equality constraint) */
|
alpar@9
|
468 struct eq_singlet *info = _info;
|
alpar@9
|
469 NPPLFE *lfe;
|
alpar@9
|
470 double temp;
|
alpar@9
|
471 if (npp->sol == GLP_SOL)
|
alpar@9
|
472 { /* column q must be already recovered as GLP_NS */
|
alpar@9
|
473 if (npp->c_stat[info->q] != GLP_NS)
|
alpar@9
|
474 { npp_error();
|
alpar@9
|
475 return 1;
|
alpar@9
|
476 }
|
alpar@9
|
477 npp->r_stat[info->p] = GLP_NS;
|
alpar@9
|
478 npp->c_stat[info->q] = GLP_BS;
|
alpar@9
|
479 }
|
alpar@9
|
480 if (npp->sol != GLP_MIP)
|
alpar@9
|
481 { /* compute multiplier for row p with formula (3) */
|
alpar@9
|
482 temp = info->c;
|
alpar@9
|
483 for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
|
alpar@9
|
484 temp -= lfe->val * npp->r_pi[lfe->ref];
|
alpar@9
|
485 npp->r_pi[info->p] = temp / info->apq;
|
alpar@9
|
486 }
|
alpar@9
|
487 return 0;
|
alpar@9
|
488 }
|
alpar@9
|
489
|
alpar@9
|
490 /***********************************************************************
|
alpar@9
|
491 * NAME
|
alpar@9
|
492 *
|
alpar@9
|
493 * npp_implied_lower - process implied column lower bound
|
alpar@9
|
494 *
|
alpar@9
|
495 * SYNOPSIS
|
alpar@9
|
496 *
|
alpar@9
|
497 * #include "glpnpp.h"
|
alpar@9
|
498 * int npp_implied_lower(NPP *npp, NPPCOL *q, double l);
|
alpar@9
|
499 *
|
alpar@9
|
500 * DESCRIPTION
|
alpar@9
|
501 *
|
alpar@9
|
502 * For column q:
|
alpar@9
|
503 *
|
alpar@9
|
504 * l[q] <= x[q] <= u[q], (1)
|
alpar@9
|
505 *
|
alpar@9
|
506 * where l[q] < u[q], the routine npp_implied_lower processes its
|
alpar@9
|
507 * implied lower bound l'[q]. As the result the current column lower
|
alpar@9
|
508 * bound may increase. Note that the column is kept in the problem in
|
alpar@9
|
509 * any case.
|
alpar@9
|
510 *
|
alpar@9
|
511 * RETURNS
|
alpar@9
|
512 *
|
alpar@9
|
513 * 0 - current column lower bound has not changed;
|
alpar@9
|
514 *
|
alpar@9
|
515 * 1 - current column lower bound has changed, but not significantly;
|
alpar@9
|
516 *
|
alpar@9
|
517 * 2 - current column lower bound has significantly changed;
|
alpar@9
|
518 *
|
alpar@9
|
519 * 3 - column has been fixed on its upper bound;
|
alpar@9
|
520 *
|
alpar@9
|
521 * 4 - implied lower bound violates current column upper bound.
|
alpar@9
|
522 *
|
alpar@9
|
523 * ALGORITHM
|
alpar@9
|
524 *
|
alpar@9
|
525 * If column q is integral, before processing its implied lower bound
|
alpar@9
|
526 * should be rounded up:
|
alpar@9
|
527 *
|
alpar@9
|
528 * ( floor(l'[q]+0.5), if |l'[q] - floor(l'[q]+0.5)| <= eps
|
alpar@9
|
529 * l'[q] := < (2)
|
alpar@9
|
530 * ( ceil(l'[q]), otherwise
|
alpar@9
|
531 *
|
alpar@9
|
532 * where floor(l'[q]+0.5) is the nearest integer to l'[q], ceil(l'[q])
|
alpar@9
|
533 * is smallest integer not less than l'[q], and eps is an absolute
|
alpar@9
|
534 * tolerance for column value.
|
alpar@9
|
535 *
|
alpar@9
|
536 * Processing implied column lower bound l'[q] includes the following
|
alpar@9
|
537 * cases:
|
alpar@9
|
538 *
|
alpar@9
|
539 * 1) if l'[q] < l[q] + eps, implied lower bound is redundant;
|
alpar@9
|
540 *
|
alpar@9
|
541 * 2) if l[q] + eps <= l[q] <= u[q] + eps, current column lower bound
|
alpar@9
|
542 * l[q] can be strengthened by replacing it with l'[q]. If in this
|
alpar@9
|
543 * case new column lower bound becomes close to current column upper
|
alpar@9
|
544 * bound u[q], the column can be fixed on its upper bound;
|
alpar@9
|
545 *
|
alpar@9
|
546 * 3) if l'[q] > u[q] + eps, implied lower bound violates current
|
alpar@9
|
547 * column upper bound u[q], in which case the problem has no primal
|
alpar@9
|
548 * feasible solution. */
|
alpar@9
|
549
|
alpar@9
|
550 int npp_implied_lower(NPP *npp, NPPCOL *q, double l)
|
alpar@9
|
551 { /* process implied column lower bound */
|
alpar@9
|
552 int ret;
|
alpar@9
|
553 double eps, nint;
|
alpar@9
|
554 xassert(npp == npp);
|
alpar@9
|
555 /* column must not be fixed */
|
alpar@9
|
556 xassert(q->lb < q->ub);
|
alpar@9
|
557 /* implied lower bound must be finite */
|
alpar@9
|
558 xassert(l != -DBL_MAX);
|
alpar@9
|
559 /* if column is integral, round up l'[q] */
|
alpar@9
|
560 if (q->is_int)
|
alpar@9
|
561 { nint = floor(l + 0.5);
|
alpar@9
|
562 if (fabs(l - nint) <= 1e-5)
|
alpar@9
|
563 l = nint;
|
alpar@9
|
564 else
|
alpar@9
|
565 l = ceil(l);
|
alpar@9
|
566 }
|
alpar@9
|
567 /* check current column lower bound */
|
alpar@9
|
568 if (q->lb != -DBL_MAX)
|
alpar@9
|
569 { eps = (q->is_int ? 1e-3 : 1e-3 + 1e-6 * fabs(q->lb));
|
alpar@9
|
570 if (l < q->lb + eps)
|
alpar@9
|
571 { ret = 0; /* redundant */
|
alpar@9
|
572 goto done;
|
alpar@9
|
573 }
|
alpar@9
|
574 }
|
alpar@9
|
575 /* check current column upper bound */
|
alpar@9
|
576 if (q->ub != +DBL_MAX)
|
alpar@9
|
577 { eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->ub));
|
alpar@9
|
578 if (l > q->ub + eps)
|
alpar@9
|
579 { ret = 4; /* infeasible */
|
alpar@9
|
580 goto done;
|
alpar@9
|
581 }
|
alpar@9
|
582 /* if l'[q] is close to u[q], fix column at its upper bound */
|
alpar@9
|
583 if (l > q->ub - 1e-3 * eps)
|
alpar@9
|
584 { q->lb = q->ub;
|
alpar@9
|
585 ret = 3; /* fixed */
|
alpar@9
|
586 goto done;
|
alpar@9
|
587 }
|
alpar@9
|
588 }
|
alpar@9
|
589 /* check if column lower bound changes significantly */
|
alpar@9
|
590 if (q->lb == -DBL_MAX)
|
alpar@9
|
591 ret = 2; /* significantly */
|
alpar@9
|
592 else if (q->is_int && l > q->lb + 0.5)
|
alpar@9
|
593 ret = 2; /* significantly */
|
alpar@9
|
594 else if (l > q->lb + 0.30 * (1.0 + fabs(q->lb)))
|
alpar@9
|
595 ret = 2; /* significantly */
|
alpar@9
|
596 else
|
alpar@9
|
597 ret = 1; /* not significantly */
|
alpar@9
|
598 /* set new column lower bound */
|
alpar@9
|
599 q->lb = l;
|
alpar@9
|
600 done: return ret;
|
alpar@9
|
601 }
|
alpar@9
|
602
|
alpar@9
|
603 /***********************************************************************
|
alpar@9
|
604 * NAME
|
alpar@9
|
605 *
|
alpar@9
|
606 * npp_implied_upper - process implied column upper bound
|
alpar@9
|
607 *
|
alpar@9
|
608 * SYNOPSIS
|
alpar@9
|
609 *
|
alpar@9
|
610 * #include "glpnpp.h"
|
alpar@9
|
611 * int npp_implied_upper(NPP *npp, NPPCOL *q, double u);
|
alpar@9
|
612 *
|
alpar@9
|
613 * DESCRIPTION
|
alpar@9
|
614 *
|
alpar@9
|
615 * For column q:
|
alpar@9
|
616 *
|
alpar@9
|
617 * l[q] <= x[q] <= u[q], (1)
|
alpar@9
|
618 *
|
alpar@9
|
619 * where l[q] < u[q], the routine npp_implied_upper processes its
|
alpar@9
|
620 * implied upper bound u'[q]. As the result the current column upper
|
alpar@9
|
621 * bound may decrease. Note that the column is kept in the problem in
|
alpar@9
|
622 * any case.
|
alpar@9
|
623 *
|
alpar@9
|
624 * RETURNS
|
alpar@9
|
625 *
|
alpar@9
|
626 * 0 - current column upper bound has not changed;
|
alpar@9
|
627 *
|
alpar@9
|
628 * 1 - current column upper bound has changed, but not significantly;
|
alpar@9
|
629 *
|
alpar@9
|
630 * 2 - current column upper bound has significantly changed;
|
alpar@9
|
631 *
|
alpar@9
|
632 * 3 - column has been fixed on its lower bound;
|
alpar@9
|
633 *
|
alpar@9
|
634 * 4 - implied upper bound violates current column lower bound.
|
alpar@9
|
635 *
|
alpar@9
|
636 * ALGORITHM
|
alpar@9
|
637 *
|
alpar@9
|
638 * If column q is integral, before processing its implied upper bound
|
alpar@9
|
639 * should be rounded down:
|
alpar@9
|
640 *
|
alpar@9
|
641 * ( floor(u'[q]+0.5), if |u'[q] - floor(l'[q]+0.5)| <= eps
|
alpar@9
|
642 * u'[q] := < (2)
|
alpar@9
|
643 * ( floor(l'[q]), otherwise
|
alpar@9
|
644 *
|
alpar@9
|
645 * where floor(u'[q]+0.5) is the nearest integer to u'[q],
|
alpar@9
|
646 * floor(u'[q]) is largest integer not greater than u'[q], and eps is
|
alpar@9
|
647 * an absolute tolerance for column value.
|
alpar@9
|
648 *
|
alpar@9
|
649 * Processing implied column upper bound u'[q] includes the following
|
alpar@9
|
650 * cases:
|
alpar@9
|
651 *
|
alpar@9
|
652 * 1) if u'[q] > u[q] - eps, implied upper bound is redundant;
|
alpar@9
|
653 *
|
alpar@9
|
654 * 2) if l[q] - eps <= u[q] <= u[q] - eps, current column upper bound
|
alpar@9
|
655 * u[q] can be strengthened by replacing it with u'[q]. If in this
|
alpar@9
|
656 * case new column upper bound becomes close to current column lower
|
alpar@9
|
657 * bound, the column can be fixed on its lower bound;
|
alpar@9
|
658 *
|
alpar@9
|
659 * 3) if u'[q] < l[q] - eps, implied upper bound violates current
|
alpar@9
|
660 * column lower bound l[q], in which case the problem has no primal
|
alpar@9
|
661 * feasible solution. */
|
alpar@9
|
662
|
alpar@9
|
663 int npp_implied_upper(NPP *npp, NPPCOL *q, double u)
|
alpar@9
|
664 { int ret;
|
alpar@9
|
665 double eps, nint;
|
alpar@9
|
666 xassert(npp == npp);
|
alpar@9
|
667 /* column must not be fixed */
|
alpar@9
|
668 xassert(q->lb < q->ub);
|
alpar@9
|
669 /* implied upper bound must be finite */
|
alpar@9
|
670 xassert(u != +DBL_MAX);
|
alpar@9
|
671 /* if column is integral, round down u'[q] */
|
alpar@9
|
672 if (q->is_int)
|
alpar@9
|
673 { nint = floor(u + 0.5);
|
alpar@9
|
674 if (fabs(u - nint) <= 1e-5)
|
alpar@9
|
675 u = nint;
|
alpar@9
|
676 else
|
alpar@9
|
677 u = floor(u);
|
alpar@9
|
678 }
|
alpar@9
|
679 /* check current column upper bound */
|
alpar@9
|
680 if (q->ub != +DBL_MAX)
|
alpar@9
|
681 { eps = (q->is_int ? 1e-3 : 1e-3 + 1e-6 * fabs(q->ub));
|
alpar@9
|
682 if (u > q->ub - eps)
|
alpar@9
|
683 { ret = 0; /* redundant */
|
alpar@9
|
684 goto done;
|
alpar@9
|
685 }
|
alpar@9
|
686 }
|
alpar@9
|
687 /* check current column lower bound */
|
alpar@9
|
688 if (q->lb != -DBL_MAX)
|
alpar@9
|
689 { eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->lb));
|
alpar@9
|
690 if (u < q->lb - eps)
|
alpar@9
|
691 { ret = 4; /* infeasible */
|
alpar@9
|
692 goto done;
|
alpar@9
|
693 }
|
alpar@9
|
694 /* if u'[q] is close to l[q], fix column at its lower bound */
|
alpar@9
|
695 if (u < q->lb + 1e-3 * eps)
|
alpar@9
|
696 { q->ub = q->lb;
|
alpar@9
|
697 ret = 3; /* fixed */
|
alpar@9
|
698 goto done;
|
alpar@9
|
699 }
|
alpar@9
|
700 }
|
alpar@9
|
701 /* check if column upper bound changes significantly */
|
alpar@9
|
702 if (q->ub == +DBL_MAX)
|
alpar@9
|
703 ret = 2; /* significantly */
|
alpar@9
|
704 else if (q->is_int && u < q->ub - 0.5)
|
alpar@9
|
705 ret = 2; /* significantly */
|
alpar@9
|
706 else if (u < q->ub - 0.30 * (1.0 + fabs(q->ub)))
|
alpar@9
|
707 ret = 2; /* significantly */
|
alpar@9
|
708 else
|
alpar@9
|
709 ret = 1; /* not significantly */
|
alpar@9
|
710 /* set new column upper bound */
|
alpar@9
|
711 q->ub = u;
|
alpar@9
|
712 done: return ret;
|
alpar@9
|
713 }
|
alpar@9
|
714
|
alpar@9
|
715 /***********************************************************************
|
alpar@9
|
716 * NAME
|
alpar@9
|
717 *
|
alpar@9
|
718 * npp_ineq_singlet - process row singleton (inequality constraint)
|
alpar@9
|
719 *
|
alpar@9
|
720 * SYNOPSIS
|
alpar@9
|
721 *
|
alpar@9
|
722 * #include "glpnpp.h"
|
alpar@9
|
723 * int npp_ineq_singlet(NPP *npp, NPPROW *p);
|
alpar@9
|
724 *
|
alpar@9
|
725 * DESCRIPTION
|
alpar@9
|
726 *
|
alpar@9
|
727 * The routine npp_ineq_singlet processes row p, which is inequality
|
alpar@9
|
728 * constraint having the only non-zero coefficient:
|
alpar@9
|
729 *
|
alpar@9
|
730 * L[p] <= a[p,q] * x[q] <= U[p], (1)
|
alpar@9
|
731 *
|
alpar@9
|
732 * where L[p] < U[p], L[p] > -oo and/or U[p] < +oo.
|
alpar@9
|
733 *
|
alpar@9
|
734 * RETURNS
|
alpar@9
|
735 *
|
alpar@9
|
736 * 0 - current column bounds have not changed;
|
alpar@9
|
737 *
|
alpar@9
|
738 * 1 - current column bounds have changed, but not significantly;
|
alpar@9
|
739 *
|
alpar@9
|
740 * 2 - current column bounds have significantly changed;
|
alpar@9
|
741 *
|
alpar@9
|
742 * 3 - column has been fixed on its lower or upper bound;
|
alpar@9
|
743 *
|
alpar@9
|
744 * 4 - problem has no primal feasible solution.
|
alpar@9
|
745 *
|
alpar@9
|
746 * PROBLEM TRANSFORMATION
|
alpar@9
|
747 *
|
alpar@9
|
748 * Inequality constraint (1) defines implied bounds of column q:
|
alpar@9
|
749 *
|
alpar@9
|
750 * ( L[p] / a[p,q], if a[p,q] > 0
|
alpar@9
|
751 * l'[q] = < (2)
|
alpar@9
|
752 * ( U[p] / a[p,q], if a[p,q] < 0
|
alpar@9
|
753 *
|
alpar@9
|
754 * ( U[p] / a[p,q], if a[p,q] > 0
|
alpar@9
|
755 * u'[q] = < (3)
|
alpar@9
|
756 * ( L[p] / a[p,q], if a[p,q] < 0
|
alpar@9
|
757 *
|
alpar@9
|
758 * If these implied bounds do not violate current bounds of column q:
|
alpar@9
|
759 *
|
alpar@9
|
760 * l[q] <= x[q] <= u[q], (4)
|
alpar@9
|
761 *
|
alpar@9
|
762 * they can be used to strengthen the current column bounds:
|
alpar@9
|
763 *
|
alpar@9
|
764 * l[q] := max(l[q], l'[q]), (5)
|
alpar@9
|
765 *
|
alpar@9
|
766 * u[q] := min(u[q], u'[q]). (6)
|
alpar@9
|
767 *
|
alpar@9
|
768 * (See the routines npp_implied_lower and npp_implied_upper.)
|
alpar@9
|
769 *
|
alpar@9
|
770 * Once bounds of row p (1) have been carried over column q, the row
|
alpar@9
|
771 * becomes redundant, so it can be replaced by equivalent free row and
|
alpar@9
|
772 * removed from the problem.
|
alpar@9
|
773 *
|
alpar@9
|
774 * Note that the routine removes from the problem only row p. Column q,
|
alpar@9
|
775 * even it has been fixed, is kept in the problem.
|
alpar@9
|
776 *
|
alpar@9
|
777 * RECOVERING BASIC SOLUTION
|
alpar@9
|
778 *
|
alpar@9
|
779 * Note that the row in the dual system corresponding to column q is
|
alpar@9
|
780 * the following:
|
alpar@9
|
781 *
|
alpar@9
|
782 * sum a[i,q] pi[i] + lambda[q] = c[q] ==>
|
alpar@9
|
783 * i
|
alpar@9
|
784 * (7)
|
alpar@9
|
785 * sum a[i,q] pi[i] + a[p,q] pi[p] + lambda[q] = c[q],
|
alpar@9
|
786 * i!=p
|
alpar@9
|
787 *
|
alpar@9
|
788 * where pi[i] for all i != p are known in solution to the transformed
|
alpar@9
|
789 * problem. Row p does not exist in the transformed problem, so it has
|
alpar@9
|
790 * zero multiplier there. This allows computing multiplier for column q
|
alpar@9
|
791 * in solution to the transformed problem:
|
alpar@9
|
792 *
|
alpar@9
|
793 * lambda~[q] = c[q] - sum a[i,q] pi[i]. (8)
|
alpar@9
|
794 * i!=p
|
alpar@9
|
795 *
|
alpar@9
|
796 * Let in solution to the transformed problem column q be non-basic
|
alpar@9
|
797 * with lower bound active (GLP_NL, lambda~[q] >= 0), and this lower
|
alpar@9
|
798 * bound be implied one l'[q]. From the original problem's standpoint
|
alpar@9
|
799 * this then means that actually the original column lower bound l[q]
|
alpar@9
|
800 * is inactive, and active is that row bound L[p] or U[p] that defines
|
alpar@9
|
801 * the implied bound l'[q] (2). In this case in solution to the
|
alpar@9
|
802 * original problem column q is assigned status GLP_BS while row p is
|
alpar@9
|
803 * assigned status GLP_NL (if a[p,q] > 0) or GLP_NU (if a[p,q] < 0).
|
alpar@9
|
804 * Since now column q is basic, its multiplier lambda[q] is zero. This
|
alpar@9
|
805 * allows using (7) and (8) to find multiplier for row p in solution to
|
alpar@9
|
806 * the original problem:
|
alpar@9
|
807 *
|
alpar@9
|
808 * 1
|
alpar@9
|
809 * pi[p] = ------ (c[q] - sum a[i,q] pi[i]) = lambda~[q] / a[p,q] (9)
|
alpar@9
|
810 * a[p,q] i!=p
|
alpar@9
|
811 *
|
alpar@9
|
812 * Now let in solution to the transformed problem column q be non-basic
|
alpar@9
|
813 * with upper bound active (GLP_NU, lambda~[q] <= 0), and this upper
|
alpar@9
|
814 * bound be implied one u'[q]. As in the previous case this then means
|
alpar@9
|
815 * that from the original problem's standpoint actually the original
|
alpar@9
|
816 * column upper bound u[q] is inactive, and active is that row bound
|
alpar@9
|
817 * L[p] or U[p] that defines the implied bound u'[q] (3). In this case
|
alpar@9
|
818 * in solution to the original problem column q is assigned status
|
alpar@9
|
819 * GLP_BS, row p is assigned status GLP_NU (if a[p,q] > 0) or GLP_NL
|
alpar@9
|
820 * (if a[p,q] < 0), and its multiplier is computed with formula (9).
|
alpar@9
|
821 *
|
alpar@9
|
822 * Strengthening bounds of column q according to (5) and (6) may make
|
alpar@9
|
823 * it fixed. Thus, if in solution to the transformed problem column q is
|
alpar@9
|
824 * non-basic and fixed (GLP_NS), we can suppose that if lambda~[q] > 0,
|
alpar@9
|
825 * column q has active lower bound (GLP_NL), and if lambda~[q] < 0,
|
alpar@9
|
826 * column q has active upper bound (GLP_NU), reducing this case to two
|
alpar@9
|
827 * previous ones. If, however, lambda~[q] is close to zero or
|
alpar@9
|
828 * corresponding bound of row p does not exist (this may happen if
|
alpar@9
|
829 * lambda~[q] has wrong sign due to round-off errors, in which case it
|
alpar@9
|
830 * is expected to be close to zero, since solution is assumed to be dual
|
alpar@9
|
831 * feasible), column q can be assigned status GLP_BS (basic), and row p
|
alpar@9
|
832 * can be made active on its existing bound. In the latter case row
|
alpar@9
|
833 * multiplier pi[p] computed with formula (9) will be also close to
|
alpar@9
|
834 * zero, and dual feasibility will be kept.
|
alpar@9
|
835 *
|
alpar@9
|
836 * In all other cases, namely, if in solution to the transformed
|
alpar@9
|
837 * problem column q is basic (GLP_BS), or non-basic with original lower
|
alpar@9
|
838 * bound l[q] active (GLP_NL), or non-basic with original upper bound
|
alpar@9
|
839 * u[q] active (GLP_NU), constraint (1) is inactive. So in solution to
|
alpar@9
|
840 * the original problem status of column q remains unchanged, row p is
|
alpar@9
|
841 * assigned status GLP_BS, and its multiplier pi[p] is assigned zero
|
alpar@9
|
842 * value.
|
alpar@9
|
843 *
|
alpar@9
|
844 * RECOVERING INTERIOR-POINT SOLUTION
|
alpar@9
|
845 *
|
alpar@9
|
846 * First, value of multiplier for column q in solution to the original
|
alpar@9
|
847 * problem is computed with formula (8). If lambda~[q] > 0 and column q
|
alpar@9
|
848 * has implied lower bound, or if lambda~[q] < 0 and column q has
|
alpar@9
|
849 * implied upper bound, this means that from the original problem's
|
alpar@9
|
850 * standpoint actually row p has corresponding active bound, in which
|
alpar@9
|
851 * case its multiplier pi[p] is computed with formula (9). In other
|
alpar@9
|
852 * cases, when the sign of lambda~[q] corresponds to original bound of
|
alpar@9
|
853 * column q, or when lambda~[q] =~ 0, value of row multiplier pi[p] is
|
alpar@9
|
854 * assigned zero value.
|
alpar@9
|
855 *
|
alpar@9
|
856 * RECOVERING MIP SOLUTION
|
alpar@9
|
857 *
|
alpar@9
|
858 * None needed. */
|
alpar@9
|
859
|
alpar@9
|
860 struct ineq_singlet
|
alpar@9
|
861 { /* row singleton (inequality constraint) */
|
alpar@9
|
862 int p;
|
alpar@9
|
863 /* row reference number */
|
alpar@9
|
864 int q;
|
alpar@9
|
865 /* column reference number */
|
alpar@9
|
866 double apq;
|
alpar@9
|
867 /* constraint coefficient a[p,q] */
|
alpar@9
|
868 double c;
|
alpar@9
|
869 /* objective coefficient at x[q] */
|
alpar@9
|
870 double lb;
|
alpar@9
|
871 /* row lower bound */
|
alpar@9
|
872 double ub;
|
alpar@9
|
873 /* row upper bound */
|
alpar@9
|
874 char lb_changed;
|
alpar@9
|
875 /* this flag is set if column lower bound was changed */
|
alpar@9
|
876 char ub_changed;
|
alpar@9
|
877 /* this flag is set if column upper bound was changed */
|
alpar@9
|
878 NPPLFE *ptr;
|
alpar@9
|
879 /* list of non-zero coefficients a[i,q], i != p */
|
alpar@9
|
880 };
|
alpar@9
|
881
|
alpar@9
|
882 static int rcv_ineq_singlet(NPP *npp, void *info);
|
alpar@9
|
883
|
alpar@9
|
884 int npp_ineq_singlet(NPP *npp, NPPROW *p)
|
alpar@9
|
885 { /* process row singleton (inequality constraint) */
|
alpar@9
|
886 struct ineq_singlet *info;
|
alpar@9
|
887 NPPCOL *q;
|
alpar@9
|
888 NPPAIJ *apq, *aij;
|
alpar@9
|
889 NPPLFE *lfe;
|
alpar@9
|
890 int lb_changed, ub_changed;
|
alpar@9
|
891 double ll, uu;
|
alpar@9
|
892 /* the row must be singleton inequality constraint */
|
alpar@9
|
893 xassert(p->lb != -DBL_MAX || p->ub != +DBL_MAX);
|
alpar@9
|
894 xassert(p->lb < p->ub);
|
alpar@9
|
895 xassert(p->ptr != NULL && p->ptr->r_next == NULL);
|
alpar@9
|
896 /* compute implied column bounds */
|
alpar@9
|
897 apq = p->ptr;
|
alpar@9
|
898 q = apq->col;
|
alpar@9
|
899 xassert(q->lb < q->ub);
|
alpar@9
|
900 if (apq->val > 0.0)
|
alpar@9
|
901 { ll = (p->lb == -DBL_MAX ? -DBL_MAX : p->lb / apq->val);
|
alpar@9
|
902 uu = (p->ub == +DBL_MAX ? +DBL_MAX : p->ub / apq->val);
|
alpar@9
|
903 }
|
alpar@9
|
904 else
|
alpar@9
|
905 { ll = (p->ub == +DBL_MAX ? -DBL_MAX : p->ub / apq->val);
|
alpar@9
|
906 uu = (p->lb == -DBL_MAX ? +DBL_MAX : p->lb / apq->val);
|
alpar@9
|
907 }
|
alpar@9
|
908 /* process implied column lower bound */
|
alpar@9
|
909 if (ll == -DBL_MAX)
|
alpar@9
|
910 lb_changed = 0;
|
alpar@9
|
911 else
|
alpar@9
|
912 { lb_changed = npp_implied_lower(npp, q, ll);
|
alpar@9
|
913 xassert(0 <= lb_changed && lb_changed <= 4);
|
alpar@9
|
914 if (lb_changed == 4) return 4; /* infeasible */
|
alpar@9
|
915 }
|
alpar@9
|
916 /* process implied column upper bound */
|
alpar@9
|
917 if (uu == +DBL_MAX)
|
alpar@9
|
918 ub_changed = 0;
|
alpar@9
|
919 else if (lb_changed == 3)
|
alpar@9
|
920 { /* column was fixed on its upper bound due to l'[q] = u[q] */
|
alpar@9
|
921 /* note that L[p] < U[p], so l'[q] = u[q] < u'[q] */
|
alpar@9
|
922 ub_changed = 0;
|
alpar@9
|
923 }
|
alpar@9
|
924 else
|
alpar@9
|
925 { ub_changed = npp_implied_upper(npp, q, uu);
|
alpar@9
|
926 xassert(0 <= ub_changed && ub_changed <= 4);
|
alpar@9
|
927 if (ub_changed == 4) return 4; /* infeasible */
|
alpar@9
|
928 }
|
alpar@9
|
929 /* if neither lower nor upper column bound was changed, the row
|
alpar@9
|
930 is originally redundant and can be replaced by free row */
|
alpar@9
|
931 if (!lb_changed && !ub_changed)
|
alpar@9
|
932 { p->lb = -DBL_MAX, p->ub = +DBL_MAX;
|
alpar@9
|
933 npp_free_row(npp, p);
|
alpar@9
|
934 return 0;
|
alpar@9
|
935 }
|
alpar@9
|
936 /* create transformation stack entry */
|
alpar@9
|
937 info = npp_push_tse(npp,
|
alpar@9
|
938 rcv_ineq_singlet, sizeof(struct ineq_singlet));
|
alpar@9
|
939 info->p = p->i;
|
alpar@9
|
940 info->q = q->j;
|
alpar@9
|
941 info->apq = apq->val;
|
alpar@9
|
942 info->c = q->coef;
|
alpar@9
|
943 info->lb = p->lb;
|
alpar@9
|
944 info->ub = p->ub;
|
alpar@9
|
945 info->lb_changed = (char)lb_changed;
|
alpar@9
|
946 info->ub_changed = (char)ub_changed;
|
alpar@9
|
947 info->ptr = NULL;
|
alpar@9
|
948 /* save column coefficients a[i,q], i != p (not needed for MIP
|
alpar@9
|
949 solution) */
|
alpar@9
|
950 if (npp->sol != GLP_MIP)
|
alpar@9
|
951 { for (aij = q->ptr; aij != NULL; aij = aij->c_next)
|
alpar@9
|
952 { if (aij == apq) continue; /* skip a[p,q] */
|
alpar@9
|
953 lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
|
alpar@9
|
954 lfe->ref = aij->row->i;
|
alpar@9
|
955 lfe->val = aij->val;
|
alpar@9
|
956 lfe->next = info->ptr;
|
alpar@9
|
957 info->ptr = lfe;
|
alpar@9
|
958 }
|
alpar@9
|
959 }
|
alpar@9
|
960 /* remove the row from the problem */
|
alpar@9
|
961 npp_del_row(npp, p);
|
alpar@9
|
962 return lb_changed >= ub_changed ? lb_changed : ub_changed;
|
alpar@9
|
963 }
|
alpar@9
|
964
|
alpar@9
|
965 static int rcv_ineq_singlet(NPP *npp, void *_info)
|
alpar@9
|
966 { /* recover row singleton (inequality constraint) */
|
alpar@9
|
967 struct ineq_singlet *info = _info;
|
alpar@9
|
968 NPPLFE *lfe;
|
alpar@9
|
969 double lambda;
|
alpar@9
|
970 if (npp->sol == GLP_MIP) goto done;
|
alpar@9
|
971 /* compute lambda~[q] in solution to the transformed problem
|
alpar@9
|
972 with formula (8) */
|
alpar@9
|
973 lambda = info->c;
|
alpar@9
|
974 for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
|
alpar@9
|
975 lambda -= lfe->val * npp->r_pi[lfe->ref];
|
alpar@9
|
976 if (npp->sol == GLP_SOL)
|
alpar@9
|
977 { /* recover basic solution */
|
alpar@9
|
978 if (npp->c_stat[info->q] == GLP_BS)
|
alpar@9
|
979 { /* column q is basic, so row p is inactive */
|
alpar@9
|
980 npp->r_stat[info->p] = GLP_BS;
|
alpar@9
|
981 npp->r_pi[info->p] = 0.0;
|
alpar@9
|
982 }
|
alpar@9
|
983 else if (npp->c_stat[info->q] == GLP_NL)
|
alpar@9
|
984 nl: { /* column q is non-basic with lower bound active */
|
alpar@9
|
985 if (info->lb_changed)
|
alpar@9
|
986 { /* it is implied bound, so actually row p is active
|
alpar@9
|
987 while column q is basic */
|
alpar@9
|
988 npp->r_stat[info->p] =
|
alpar@9
|
989 (char)(info->apq > 0.0 ? GLP_NL : GLP_NU);
|
alpar@9
|
990 npp->c_stat[info->q] = GLP_BS;
|
alpar@9
|
991 npp->r_pi[info->p] = lambda / info->apq;
|
alpar@9
|
992 }
|
alpar@9
|
993 else
|
alpar@9
|
994 { /* it is original bound, so row p is inactive */
|
alpar@9
|
995 npp->r_stat[info->p] = GLP_BS;
|
alpar@9
|
996 npp->r_pi[info->p] = 0.0;
|
alpar@9
|
997 }
|
alpar@9
|
998 }
|
alpar@9
|
999 else if (npp->c_stat[info->q] == GLP_NU)
|
alpar@9
|
1000 nu: { /* column q is non-basic with upper bound active */
|
alpar@9
|
1001 if (info->ub_changed)
|
alpar@9
|
1002 { /* it is implied bound, so actually row p is active
|
alpar@9
|
1003 while column q is basic */
|
alpar@9
|
1004 npp->r_stat[info->p] =
|
alpar@9
|
1005 (char)(info->apq > 0.0 ? GLP_NU : GLP_NL);
|
alpar@9
|
1006 npp->c_stat[info->q] = GLP_BS;
|
alpar@9
|
1007 npp->r_pi[info->p] = lambda / info->apq;
|
alpar@9
|
1008 }
|
alpar@9
|
1009 else
|
alpar@9
|
1010 { /* it is original bound, so row p is inactive */
|
alpar@9
|
1011 npp->r_stat[info->p] = GLP_BS;
|
alpar@9
|
1012 npp->r_pi[info->p] = 0.0;
|
alpar@9
|
1013 }
|
alpar@9
|
1014 }
|
alpar@9
|
1015 else if (npp->c_stat[info->q] == GLP_NS)
|
alpar@9
|
1016 { /* column q is non-basic and fixed; note, however, that in
|
alpar@9
|
1017 in the original problem it is non-fixed */
|
alpar@9
|
1018 if (lambda > +1e-7)
|
alpar@9
|
1019 { if (info->apq > 0.0 && info->lb != -DBL_MAX ||
|
alpar@9
|
1020 info->apq < 0.0 && info->ub != +DBL_MAX ||
|
alpar@9
|
1021 !info->lb_changed)
|
alpar@9
|
1022 { /* either corresponding bound of row p exists or
|
alpar@9
|
1023 column q remains non-basic with its original lower
|
alpar@9
|
1024 bound active */
|
alpar@9
|
1025 npp->c_stat[info->q] = GLP_NL;
|
alpar@9
|
1026 goto nl;
|
alpar@9
|
1027 }
|
alpar@9
|
1028 }
|
alpar@9
|
1029 if (lambda < -1e-7)
|
alpar@9
|
1030 { if (info->apq > 0.0 && info->ub != +DBL_MAX ||
|
alpar@9
|
1031 info->apq < 0.0 && info->lb != -DBL_MAX ||
|
alpar@9
|
1032 !info->ub_changed)
|
alpar@9
|
1033 { /* either corresponding bound of row p exists or
|
alpar@9
|
1034 column q remains non-basic with its original upper
|
alpar@9
|
1035 bound active */
|
alpar@9
|
1036 npp->c_stat[info->q] = GLP_NU;
|
alpar@9
|
1037 goto nu;
|
alpar@9
|
1038 }
|
alpar@9
|
1039 }
|
alpar@9
|
1040 /* either lambda~[q] is close to zero, or corresponding
|
alpar@9
|
1041 bound of row p does not exist, because lambda~[q] has
|
alpar@9
|
1042 wrong sign due to round-off errors; in the latter case
|
alpar@9
|
1043 lambda~[q] is also assumed to be close to zero; so, we
|
alpar@9
|
1044 can make row p active on its existing bound and column q
|
alpar@9
|
1045 basic; pi[p] will have wrong sign, but it also will be
|
alpar@9
|
1046 close to zero (rarus casus of dual degeneracy) */
|
alpar@9
|
1047 if (info->lb != -DBL_MAX && info->ub == +DBL_MAX)
|
alpar@9
|
1048 { /* row lower bound exists, but upper bound doesn't */
|
alpar@9
|
1049 npp->r_stat[info->p] = GLP_NL;
|
alpar@9
|
1050 }
|
alpar@9
|
1051 else if (info->lb == -DBL_MAX && info->ub != +DBL_MAX)
|
alpar@9
|
1052 { /* row upper bound exists, but lower bound doesn't */
|
alpar@9
|
1053 npp->r_stat[info->p] = GLP_NU;
|
alpar@9
|
1054 }
|
alpar@9
|
1055 else if (info->lb != -DBL_MAX && info->ub != +DBL_MAX)
|
alpar@9
|
1056 { /* both row lower and upper bounds exist */
|
alpar@9
|
1057 /* to choose proper active row bound we should not use
|
alpar@9
|
1058 lambda~[q], because its value being close to zero is
|
alpar@9
|
1059 unreliable; so we choose that bound which provides
|
alpar@9
|
1060 primal feasibility for original constraint (1) */
|
alpar@9
|
1061 if (info->apq * npp->c_value[info->q] <=
|
alpar@9
|
1062 0.5 * (info->lb + info->ub))
|
alpar@9
|
1063 npp->r_stat[info->p] = GLP_NL;
|
alpar@9
|
1064 else
|
alpar@9
|
1065 npp->r_stat[info->p] = GLP_NU;
|
alpar@9
|
1066 }
|
alpar@9
|
1067 else
|
alpar@9
|
1068 { npp_error();
|
alpar@9
|
1069 return 1;
|
alpar@9
|
1070 }
|
alpar@9
|
1071 npp->c_stat[info->q] = GLP_BS;
|
alpar@9
|
1072 npp->r_pi[info->p] = lambda / info->apq;
|
alpar@9
|
1073 }
|
alpar@9
|
1074 else
|
alpar@9
|
1075 { npp_error();
|
alpar@9
|
1076 return 1;
|
alpar@9
|
1077 }
|
alpar@9
|
1078 }
|
alpar@9
|
1079 if (npp->sol == GLP_IPT)
|
alpar@9
|
1080 { /* recover interior-point solution */
|
alpar@9
|
1081 if (lambda > +DBL_EPSILON && info->lb_changed ||
|
alpar@9
|
1082 lambda < -DBL_EPSILON && info->ub_changed)
|
alpar@9
|
1083 { /* actually row p has corresponding active bound */
|
alpar@9
|
1084 npp->r_pi[info->p] = lambda / info->apq;
|
alpar@9
|
1085 }
|
alpar@9
|
1086 else
|
alpar@9
|
1087 { /* either bounds of column q are both inactive or its
|
alpar@9
|
1088 original bound is active */
|
alpar@9
|
1089 npp->r_pi[info->p] = 0.0;
|
alpar@9
|
1090 }
|
alpar@9
|
1091 }
|
alpar@9
|
1092 done: return 0;
|
alpar@9
|
1093 }
|
alpar@9
|
1094
|
alpar@9
|
1095 /***********************************************************************
|
alpar@9
|
1096 * NAME
|
alpar@9
|
1097 *
|
alpar@9
|
1098 * npp_implied_slack - process column singleton (implied slack variable)
|
alpar@9
|
1099 *
|
alpar@9
|
1100 * SYNOPSIS
|
alpar@9
|
1101 *
|
alpar@9
|
1102 * #include "glpnpp.h"
|
alpar@9
|
1103 * void npp_implied_slack(NPP *npp, NPPCOL *q);
|
alpar@9
|
1104 *
|
alpar@9
|
1105 * DESCRIPTION
|
alpar@9
|
1106 *
|
alpar@9
|
1107 * The routine npp_implied_slack processes column q:
|
alpar@9
|
1108 *
|
alpar@9
|
1109 * l[q] <= x[q] <= u[q], (1)
|
alpar@9
|
1110 *
|
alpar@9
|
1111 * where l[q] < u[q], having the only non-zero coefficient in row p,
|
alpar@9
|
1112 * which is equality constraint:
|
alpar@9
|
1113 *
|
alpar@9
|
1114 * sum a[p,j] x[j] + a[p,q] x[q] = b. (2)
|
alpar@9
|
1115 * j!=q
|
alpar@9
|
1116 *
|
alpar@9
|
1117 * PROBLEM TRANSFORMATION
|
alpar@9
|
1118 *
|
alpar@9
|
1119 * (If x[q] is integral, this transformation must not be used.)
|
alpar@9
|
1120 *
|
alpar@9
|
1121 * The term a[p,q] x[q] in constraint (2) can be considered as a slack
|
alpar@9
|
1122 * variable that allows to carry bounds of column q over row p and then
|
alpar@9
|
1123 * remove column q from the problem.
|
alpar@9
|
1124 *
|
alpar@9
|
1125 * Constraint (2) can be written as follows:
|
alpar@9
|
1126 *
|
alpar@9
|
1127 * sum a[p,j] x[j] = b - a[p,q] x[q]. (3)
|
alpar@9
|
1128 * j!=q
|
alpar@9
|
1129 *
|
alpar@9
|
1130 * According to (1) constraint (3) is equivalent to the following
|
alpar@9
|
1131 * inequality constraint:
|
alpar@9
|
1132 *
|
alpar@9
|
1133 * L[p] <= sum a[p,j] x[j] <= U[p], (4)
|
alpar@9
|
1134 * j!=q
|
alpar@9
|
1135 *
|
alpar@9
|
1136 * where
|
alpar@9
|
1137 *
|
alpar@9
|
1138 * ( b - a[p,q] u[q], if a[p,q] > 0
|
alpar@9
|
1139 * L[p] = < (5)
|
alpar@9
|
1140 * ( b - a[p,q] l[q], if a[p,q] < 0
|
alpar@9
|
1141 *
|
alpar@9
|
1142 * ( b - a[p,q] l[q], if a[p,q] > 0
|
alpar@9
|
1143 * U[p] = < (6)
|
alpar@9
|
1144 * ( b - a[p,q] u[q], if a[p,q] < 0
|
alpar@9
|
1145 *
|
alpar@9
|
1146 * From (2) it follows that:
|
alpar@9
|
1147 *
|
alpar@9
|
1148 * 1
|
alpar@9
|
1149 * x[q] = ------ (b - sum a[p,j] x[j]). (7)
|
alpar@9
|
1150 * a[p,q] j!=q
|
alpar@9
|
1151 *
|
alpar@9
|
1152 * In order to eliminate x[q] from the objective row we substitute it
|
alpar@9
|
1153 * from (6) to that row:
|
alpar@9
|
1154 *
|
alpar@9
|
1155 * z = sum c[j] x[j] + c[q] x[q] + c[0] =
|
alpar@9
|
1156 * j!=q
|
alpar@9
|
1157 * 1
|
alpar@9
|
1158 * = sum c[j] x[j] + c[q] [------ (b - sum a[p,j] x[j])] + c0 =
|
alpar@9
|
1159 * j!=q a[p,q] j!=q
|
alpar@9
|
1160 *
|
alpar@9
|
1161 * = sum c~[j] x[j] + c~[0],
|
alpar@9
|
1162 * j!=q
|
alpar@9
|
1163 * a[p,j] b
|
alpar@9
|
1164 * c~[j] = c[j] - c[q] ------, c~0 = c0 - c[q] ------ (8)
|
alpar@9
|
1165 * a[p,q] a[p,q]
|
alpar@9
|
1166 *
|
alpar@9
|
1167 * are values of objective coefficients and constant term, resp., in
|
alpar@9
|
1168 * the transformed problem.
|
alpar@9
|
1169 *
|
alpar@9
|
1170 * Note that column q is column singleton, so in the dual system of the
|
alpar@9
|
1171 * original problem it corresponds to the following row singleton:
|
alpar@9
|
1172 *
|
alpar@9
|
1173 * a[p,q] pi[p] + lambda[q] = c[q]. (9)
|
alpar@9
|
1174 *
|
alpar@9
|
1175 * In the transformed problem row (9) would be the following:
|
alpar@9
|
1176 *
|
alpar@9
|
1177 * a[p,q] pi~[p] + lambda[q] = c~[q] = 0. (10)
|
alpar@9
|
1178 *
|
alpar@9
|
1179 * Subtracting (10) from (9) we have:
|
alpar@9
|
1180 *
|
alpar@9
|
1181 * a[p,q] (pi[p] - pi~[p]) = c[q]
|
alpar@9
|
1182 *
|
alpar@9
|
1183 * that gives the following formula to compute multiplier for row p in
|
alpar@9
|
1184 * solution to the original problem using its value in solution to the
|
alpar@9
|
1185 * transformed problem:
|
alpar@9
|
1186 *
|
alpar@9
|
1187 * pi[p] = pi~[p] + c[q] / a[p,q]. (11)
|
alpar@9
|
1188 *
|
alpar@9
|
1189 * RECOVERING BASIC SOLUTION
|
alpar@9
|
1190 *
|
alpar@9
|
1191 * Status of column q in solution to the original problem is defined
|
alpar@9
|
1192 * by status of row p in solution to the transformed problem and the
|
alpar@9
|
1193 * sign of coefficient a[p,q] in the original inequality constraint (2)
|
alpar@9
|
1194 * as follows:
|
alpar@9
|
1195 *
|
alpar@9
|
1196 * +-----------------------+---------+--------------------+
|
alpar@9
|
1197 * | Status of row p | Sign of | Status of column q |
|
alpar@9
|
1198 * | (transformed problem) | a[p,q] | (original problem) |
|
alpar@9
|
1199 * +-----------------------+---------+--------------------+
|
alpar@9
|
1200 * | GLP_BS | + / - | GLP_BS |
|
alpar@9
|
1201 * | GLP_NL | + | GLP_NU |
|
alpar@9
|
1202 * | GLP_NL | - | GLP_NL |
|
alpar@9
|
1203 * | GLP_NU | + | GLP_NL |
|
alpar@9
|
1204 * | GLP_NU | - | GLP_NU |
|
alpar@9
|
1205 * | GLP_NF | + / - | GLP_NF |
|
alpar@9
|
1206 * +-----------------------+---------+--------------------+
|
alpar@9
|
1207 *
|
alpar@9
|
1208 * Value of column q is computed with formula (7). Since originally row
|
alpar@9
|
1209 * p is equality constraint, its status is assigned GLP_NS, and value of
|
alpar@9
|
1210 * its multiplier pi[p] is computed with formula (11).
|
alpar@9
|
1211 *
|
alpar@9
|
1212 * RECOVERING INTERIOR-POINT SOLUTION
|
alpar@9
|
1213 *
|
alpar@9
|
1214 * Value of column q is computed with formula (7). Row multiplier value
|
alpar@9
|
1215 * pi[p] is computed with formula (11).
|
alpar@9
|
1216 *
|
alpar@9
|
1217 * RECOVERING MIP SOLUTION
|
alpar@9
|
1218 *
|
alpar@9
|
1219 * Value of column q is computed with formula (7). */
|
alpar@9
|
1220
|
alpar@9
|
1221 struct implied_slack
|
alpar@9
|
1222 { /* column singleton (implied slack variable) */
|
alpar@9
|
1223 int p;
|
alpar@9
|
1224 /* row reference number */
|
alpar@9
|
1225 int q;
|
alpar@9
|
1226 /* column reference number */
|
alpar@9
|
1227 double apq;
|
alpar@9
|
1228 /* constraint coefficient a[p,q] */
|
alpar@9
|
1229 double b;
|
alpar@9
|
1230 /* right-hand side of original equality constraint */
|
alpar@9
|
1231 double c;
|
alpar@9
|
1232 /* original objective coefficient at x[q] */
|
alpar@9
|
1233 NPPLFE *ptr;
|
alpar@9
|
1234 /* list of non-zero coefficients a[p,j], j != q */
|
alpar@9
|
1235 };
|
alpar@9
|
1236
|
alpar@9
|
1237 static int rcv_implied_slack(NPP *npp, void *info);
|
alpar@9
|
1238
|
alpar@9
|
1239 void npp_implied_slack(NPP *npp, NPPCOL *q)
|
alpar@9
|
1240 { /* process column singleton (implied slack variable) */
|
alpar@9
|
1241 struct implied_slack *info;
|
alpar@9
|
1242 NPPROW *p;
|
alpar@9
|
1243 NPPAIJ *aij;
|
alpar@9
|
1244 NPPLFE *lfe;
|
alpar@9
|
1245 /* the column must be non-integral non-fixed singleton */
|
alpar@9
|
1246 xassert(!q->is_int);
|
alpar@9
|
1247 xassert(q->lb < q->ub);
|
alpar@9
|
1248 xassert(q->ptr != NULL && q->ptr->c_next == NULL);
|
alpar@9
|
1249 /* corresponding row must be equality constraint */
|
alpar@9
|
1250 aij = q->ptr;
|
alpar@9
|
1251 p = aij->row;
|
alpar@9
|
1252 xassert(p->lb == p->ub);
|
alpar@9
|
1253 /* create transformation stack entry */
|
alpar@9
|
1254 info = npp_push_tse(npp,
|
alpar@9
|
1255 rcv_implied_slack, sizeof(struct implied_slack));
|
alpar@9
|
1256 info->p = p->i;
|
alpar@9
|
1257 info->q = q->j;
|
alpar@9
|
1258 info->apq = aij->val;
|
alpar@9
|
1259 info->b = p->lb;
|
alpar@9
|
1260 info->c = q->coef;
|
alpar@9
|
1261 info->ptr = NULL;
|
alpar@9
|
1262 /* save row coefficients a[p,j], j != q, and substitute x[q]
|
alpar@9
|
1263 into the objective row */
|
alpar@9
|
1264 for (aij = p->ptr; aij != NULL; aij = aij->r_next)
|
alpar@9
|
1265 { if (aij->col == q) continue; /* skip a[p,q] */
|
alpar@9
|
1266 lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
|
alpar@9
|
1267 lfe->ref = aij->col->j;
|
alpar@9
|
1268 lfe->val = aij->val;
|
alpar@9
|
1269 lfe->next = info->ptr;
|
alpar@9
|
1270 info->ptr = lfe;
|
alpar@9
|
1271 aij->col->coef -= info->c * (aij->val / info->apq);
|
alpar@9
|
1272 }
|
alpar@9
|
1273 npp->c0 += info->c * (info->b / info->apq);
|
alpar@9
|
1274 /* compute new row bounds */
|
alpar@9
|
1275 if (info->apq > 0.0)
|
alpar@9
|
1276 { p->lb = (q->ub == +DBL_MAX ?
|
alpar@9
|
1277 -DBL_MAX : info->b - info->apq * q->ub);
|
alpar@9
|
1278 p->ub = (q->lb == -DBL_MAX ?
|
alpar@9
|
1279 +DBL_MAX : info->b - info->apq * q->lb);
|
alpar@9
|
1280 }
|
alpar@9
|
1281 else
|
alpar@9
|
1282 { p->lb = (q->lb == -DBL_MAX ?
|
alpar@9
|
1283 -DBL_MAX : info->b - info->apq * q->lb);
|
alpar@9
|
1284 p->ub = (q->ub == +DBL_MAX ?
|
alpar@9
|
1285 +DBL_MAX : info->b - info->apq * q->ub);
|
alpar@9
|
1286 }
|
alpar@9
|
1287 /* remove the column from the problem */
|
alpar@9
|
1288 npp_del_col(npp, q);
|
alpar@9
|
1289 return;
|
alpar@9
|
1290 }
|
alpar@9
|
1291
|
alpar@9
|
1292 static int rcv_implied_slack(NPP *npp, void *_info)
|
alpar@9
|
1293 { /* recover column singleton (implied slack variable) */
|
alpar@9
|
1294 struct implied_slack *info = _info;
|
alpar@9
|
1295 NPPLFE *lfe;
|
alpar@9
|
1296 double temp;
|
alpar@9
|
1297 if (npp->sol == GLP_SOL)
|
alpar@9
|
1298 { /* assign statuses to row p and column q */
|
alpar@9
|
1299 if (npp->r_stat[info->p] == GLP_BS ||
|
alpar@9
|
1300 npp->r_stat[info->p] == GLP_NF)
|
alpar@9
|
1301 npp->c_stat[info->q] = npp->r_stat[info->p];
|
alpar@9
|
1302 else if (npp->r_stat[info->p] == GLP_NL)
|
alpar@9
|
1303 npp->c_stat[info->q] =
|
alpar@9
|
1304 (char)(info->apq > 0.0 ? GLP_NU : GLP_NL);
|
alpar@9
|
1305 else if (npp->r_stat[info->p] == GLP_NU)
|
alpar@9
|
1306 npp->c_stat[info->q] =
|
alpar@9
|
1307 (char)(info->apq > 0.0 ? GLP_NL : GLP_NU);
|
alpar@9
|
1308 else
|
alpar@9
|
1309 { npp_error();
|
alpar@9
|
1310 return 1;
|
alpar@9
|
1311 }
|
alpar@9
|
1312 npp->r_stat[info->p] = GLP_NS;
|
alpar@9
|
1313 }
|
alpar@9
|
1314 if (npp->sol != GLP_MIP)
|
alpar@9
|
1315 { /* compute multiplier for row p */
|
alpar@9
|
1316 npp->r_pi[info->p] += info->c / info->apq;
|
alpar@9
|
1317 }
|
alpar@9
|
1318 /* compute value of column q */
|
alpar@9
|
1319 temp = info->b;
|
alpar@9
|
1320 for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
|
alpar@9
|
1321 temp -= lfe->val * npp->c_value[lfe->ref];
|
alpar@9
|
1322 npp->c_value[info->q] = temp / info->apq;
|
alpar@9
|
1323 return 0;
|
alpar@9
|
1324 }
|
alpar@9
|
1325
|
alpar@9
|
1326 /***********************************************************************
|
alpar@9
|
1327 * NAME
|
alpar@9
|
1328 *
|
alpar@9
|
1329 * npp_implied_free - process column singleton (implied free variable)
|
alpar@9
|
1330 *
|
alpar@9
|
1331 * SYNOPSIS
|
alpar@9
|
1332 *
|
alpar@9
|
1333 * #include "glpnpp.h"
|
alpar@9
|
1334 * int npp_implied_free(NPP *npp, NPPCOL *q);
|
alpar@9
|
1335 *
|
alpar@9
|
1336 * DESCRIPTION
|
alpar@9
|
1337 *
|
alpar@9
|
1338 * The routine npp_implied_free processes column q:
|
alpar@9
|
1339 *
|
alpar@9
|
1340 * l[q] <= x[q] <= u[q], (1)
|
alpar@9
|
1341 *
|
alpar@9
|
1342 * having non-zero coefficient in the only row p, which is inequality
|
alpar@9
|
1343 * constraint:
|
alpar@9
|
1344 *
|
alpar@9
|
1345 * L[p] <= sum a[p,j] x[j] + a[p,q] x[q] <= U[p], (2)
|
alpar@9
|
1346 * j!=q
|
alpar@9
|
1347 *
|
alpar@9
|
1348 * where l[q] < u[q], L[p] < U[p], L[p] > -oo and/or U[p] < +oo.
|
alpar@9
|
1349 *
|
alpar@9
|
1350 * RETURNS
|
alpar@9
|
1351 *
|
alpar@9
|
1352 * 0 - success;
|
alpar@9
|
1353 *
|
alpar@9
|
1354 * 1 - column lower and/or upper bound(s) can be active;
|
alpar@9
|
1355 *
|
alpar@9
|
1356 * 2 - problem has no dual feasible solution.
|
alpar@9
|
1357 *
|
alpar@9
|
1358 * PROBLEM TRANSFORMATION
|
alpar@9
|
1359 *
|
alpar@9
|
1360 * Constraint (2) can be written as follows:
|
alpar@9
|
1361 *
|
alpar@9
|
1362 * L[p] - sum a[p,j] x[j] <= a[p,q] x[q] <= U[p] - sum a[p,j] x[j],
|
alpar@9
|
1363 * j!=q j!=q
|
alpar@9
|
1364 *
|
alpar@9
|
1365 * from which it follows that:
|
alpar@9
|
1366 *
|
alpar@9
|
1367 * alfa <= a[p,q] x[q] <= beta, (3)
|
alpar@9
|
1368 *
|
alpar@9
|
1369 * where
|
alpar@9
|
1370 *
|
alpar@9
|
1371 * alfa = inf(L[p] - sum a[p,j] x[j]) =
|
alpar@9
|
1372 * j!=q
|
alpar@9
|
1373 *
|
alpar@9
|
1374 * = L[p] - sup sum a[p,j] x[j] = (4)
|
alpar@9
|
1375 * j!=q
|
alpar@9
|
1376 *
|
alpar@9
|
1377 * = L[p] - sum a[p,j] u[j] - sum a[p,j] l[j],
|
alpar@9
|
1378 * j in Jp j in Jn
|
alpar@9
|
1379 *
|
alpar@9
|
1380 * beta = sup(L[p] - sum a[p,j] x[j]) =
|
alpar@9
|
1381 * j!=q
|
alpar@9
|
1382 *
|
alpar@9
|
1383 * = L[p] - inf sum a[p,j] x[j] = (5)
|
alpar@9
|
1384 * j!=q
|
alpar@9
|
1385 *
|
alpar@9
|
1386 * = L[p] - sum a[p,j] l[j] - sum a[p,j] u[j],
|
alpar@9
|
1387 * j in Jp j in Jn
|
alpar@9
|
1388 *
|
alpar@9
|
1389 * Jp = {j != q: a[p,j] > 0}, Jn = {j != q: a[p,j] < 0}. (6)
|
alpar@9
|
1390 *
|
alpar@9
|
1391 * Inequality (3) defines implied bounds of variable x[q]:
|
alpar@9
|
1392 *
|
alpar@9
|
1393 * l'[q] <= x[q] <= u'[q], (7)
|
alpar@9
|
1394 *
|
alpar@9
|
1395 * where
|
alpar@9
|
1396 *
|
alpar@9
|
1397 * ( alfa / a[p,q], if a[p,q] > 0
|
alpar@9
|
1398 * l'[q] = < (8a)
|
alpar@9
|
1399 * ( beta / a[p,q], if a[p,q] < 0
|
alpar@9
|
1400 *
|
alpar@9
|
1401 * ( beta / a[p,q], if a[p,q] > 0
|
alpar@9
|
1402 * u'[q] = < (8b)
|
alpar@9
|
1403 * ( alfa / a[p,q], if a[p,q] < 0
|
alpar@9
|
1404 *
|
alpar@9
|
1405 * Thus, if l'[q] > l[q] - eps and u'[q] < u[q] + eps, where eps is
|
alpar@9
|
1406 * an absolute tolerance for column value, column bounds (1) cannot be
|
alpar@9
|
1407 * active, in which case column q can be replaced by equivalent free
|
alpar@9
|
1408 * (unbounded) column.
|
alpar@9
|
1409 *
|
alpar@9
|
1410 * Note that column q is column singleton, so in the dual system of the
|
alpar@9
|
1411 * original problem it corresponds to the following row singleton:
|
alpar@9
|
1412 *
|
alpar@9
|
1413 * a[p,q] pi[p] + lambda[q] = c[q], (9)
|
alpar@9
|
1414 *
|
alpar@9
|
1415 * from which it follows that:
|
alpar@9
|
1416 *
|
alpar@9
|
1417 * pi[p] = (c[q] - lambda[q]) / a[p,q]. (10)
|
alpar@9
|
1418 *
|
alpar@9
|
1419 * Let x[q] be implied free (unbounded) variable. Then column q can be
|
alpar@9
|
1420 * only basic, so its multiplier lambda[q] is equal to zero, and from
|
alpar@9
|
1421 * (10) we have:
|
alpar@9
|
1422 *
|
alpar@9
|
1423 * pi[p] = c[q] / a[p,q]. (11)
|
alpar@9
|
1424 *
|
alpar@9
|
1425 * There are possible three cases:
|
alpar@9
|
1426 *
|
alpar@9
|
1427 * 1) pi[p] < -eps, where eps is an absolute tolerance for row
|
alpar@9
|
1428 * multiplier. In this case, to provide dual feasibility of the
|
alpar@9
|
1429 * original problem, row p must be active on its lower bound, and
|
alpar@9
|
1430 * if its lower bound does not exist (L[p] = -oo), the problem has
|
alpar@9
|
1431 * no dual feasible solution;
|
alpar@9
|
1432 *
|
alpar@9
|
1433 * 2) pi[p] > +eps. In this case row p must be active on its upper
|
alpar@9
|
1434 * bound, and if its upper bound does not exist (U[p] = +oo), the
|
alpar@9
|
1435 * problem has no dual feasible solution;
|
alpar@9
|
1436 *
|
alpar@9
|
1437 * 3) -eps <= pi[p] <= +eps. In this case any (either lower or upper)
|
alpar@9
|
1438 * bound of row p can be active, because this does not affect dual
|
alpar@9
|
1439 * feasibility.
|
alpar@9
|
1440 *
|
alpar@9
|
1441 * Thus, in all three cases original inequality constraint (2) can be
|
alpar@9
|
1442 * replaced by equality constraint, where the right-hand side is either
|
alpar@9
|
1443 * lower or upper bound of row p, and bounds of column q can be removed
|
alpar@9
|
1444 * that makes it free (unbounded). (May note that this transformation
|
alpar@9
|
1445 * can be followed by transformation "Column singleton (implied slack
|
alpar@9
|
1446 * variable)" performed by the routine npp_implied_slack.)
|
alpar@9
|
1447 *
|
alpar@9
|
1448 * RECOVERING BASIC SOLUTION
|
alpar@9
|
1449 *
|
alpar@9
|
1450 * Status of row p in solution to the original problem is determined
|
alpar@9
|
1451 * by its status in solution to the transformed problem and its bound,
|
alpar@9
|
1452 * which was choosen to be active:
|
alpar@9
|
1453 *
|
alpar@9
|
1454 * +-----------------------+--------+--------------------+
|
alpar@9
|
1455 * | Status of row p | Active | Status of row p |
|
alpar@9
|
1456 * | (transformed problem) | bound | (original problem) |
|
alpar@9
|
1457 * +-----------------------+--------+--------------------+
|
alpar@9
|
1458 * | GLP_BS | L[p] | GLP_BS |
|
alpar@9
|
1459 * | GLP_BS | U[p] | GLP_BS |
|
alpar@9
|
1460 * | GLP_NS | L[p] | GLP_NL |
|
alpar@9
|
1461 * | GLP_NS | U[p] | GLP_NU |
|
alpar@9
|
1462 * +-----------------------+--------+--------------------+
|
alpar@9
|
1463 *
|
alpar@9
|
1464 * Value of row multiplier pi[p] (as well as value of column q) in
|
alpar@9
|
1465 * solution to the original problem is the same as in solution to the
|
alpar@9
|
1466 * transformed problem.
|
alpar@9
|
1467 *
|
alpar@9
|
1468 * RECOVERING INTERIOR-POINT SOLUTION
|
alpar@9
|
1469 *
|
alpar@9
|
1470 * Value of row multiplier pi[p] in solution to the original problem is
|
alpar@9
|
1471 * the same as in solution to the transformed problem.
|
alpar@9
|
1472 *
|
alpar@9
|
1473 * RECOVERING MIP SOLUTION
|
alpar@9
|
1474 *
|
alpar@9
|
1475 * None needed. */
|
alpar@9
|
1476
|
alpar@9
|
1477 struct implied_free
|
alpar@9
|
1478 { /* column singleton (implied free variable) */
|
alpar@9
|
1479 int p;
|
alpar@9
|
1480 /* row reference number */
|
alpar@9
|
1481 char stat;
|
alpar@9
|
1482 /* row status:
|
alpar@9
|
1483 GLP_NL - active constraint on lower bound
|
alpar@9
|
1484 GLP_NU - active constraint on upper bound */
|
alpar@9
|
1485 };
|
alpar@9
|
1486
|
alpar@9
|
1487 static int rcv_implied_free(NPP *npp, void *info);
|
alpar@9
|
1488
|
alpar@9
|
1489 int npp_implied_free(NPP *npp, NPPCOL *q)
|
alpar@9
|
1490 { /* process column singleton (implied free variable) */
|
alpar@9
|
1491 struct implied_free *info;
|
alpar@9
|
1492 NPPROW *p;
|
alpar@9
|
1493 NPPAIJ *apq, *aij;
|
alpar@9
|
1494 double alfa, beta, l, u, pi, eps;
|
alpar@9
|
1495 /* the column must be non-fixed singleton */
|
alpar@9
|
1496 xassert(q->lb < q->ub);
|
alpar@9
|
1497 xassert(q->ptr != NULL && q->ptr->c_next == NULL);
|
alpar@9
|
1498 /* corresponding row must be inequality constraint */
|
alpar@9
|
1499 apq = q->ptr;
|
alpar@9
|
1500 p = apq->row;
|
alpar@9
|
1501 xassert(p->lb != -DBL_MAX || p->ub != +DBL_MAX);
|
alpar@9
|
1502 xassert(p->lb < p->ub);
|
alpar@9
|
1503 /* compute alfa */
|
alpar@9
|
1504 alfa = p->lb;
|
alpar@9
|
1505 if (alfa != -DBL_MAX)
|
alpar@9
|
1506 { for (aij = p->ptr; aij != NULL; aij = aij->r_next)
|
alpar@9
|
1507 { if (aij == apq) continue; /* skip a[p,q] */
|
alpar@9
|
1508 if (aij->val > 0.0)
|
alpar@9
|
1509 { if (aij->col->ub == +DBL_MAX)
|
alpar@9
|
1510 { alfa = -DBL_MAX;
|
alpar@9
|
1511 break;
|
alpar@9
|
1512 }
|
alpar@9
|
1513 alfa -= aij->val * aij->col->ub;
|
alpar@9
|
1514 }
|
alpar@9
|
1515 else /* < 0.0 */
|
alpar@9
|
1516 { if (aij->col->lb == -DBL_MAX)
|
alpar@9
|
1517 { alfa = -DBL_MAX;
|
alpar@9
|
1518 break;
|
alpar@9
|
1519 }
|
alpar@9
|
1520 alfa -= aij->val * aij->col->lb;
|
alpar@9
|
1521 }
|
alpar@9
|
1522 }
|
alpar@9
|
1523 }
|
alpar@9
|
1524 /* compute beta */
|
alpar@9
|
1525 beta = p->ub;
|
alpar@9
|
1526 if (beta != +DBL_MAX)
|
alpar@9
|
1527 { for (aij = p->ptr; aij != NULL; aij = aij->r_next)
|
alpar@9
|
1528 { if (aij == apq) continue; /* skip a[p,q] */
|
alpar@9
|
1529 if (aij->val > 0.0)
|
alpar@9
|
1530 { if (aij->col->lb == -DBL_MAX)
|
alpar@9
|
1531 { beta = +DBL_MAX;
|
alpar@9
|
1532 break;
|
alpar@9
|
1533 }
|
alpar@9
|
1534 beta -= aij->val * aij->col->lb;
|
alpar@9
|
1535 }
|
alpar@9
|
1536 else /* < 0.0 */
|
alpar@9
|
1537 { if (aij->col->ub == +DBL_MAX)
|
alpar@9
|
1538 { beta = +DBL_MAX;
|
alpar@9
|
1539 break;
|
alpar@9
|
1540 }
|
alpar@9
|
1541 beta -= aij->val * aij->col->ub;
|
alpar@9
|
1542 }
|
alpar@9
|
1543 }
|
alpar@9
|
1544 }
|
alpar@9
|
1545 /* compute implied column lower bound l'[q] */
|
alpar@9
|
1546 if (apq->val > 0.0)
|
alpar@9
|
1547 l = (alfa == -DBL_MAX ? -DBL_MAX : alfa / apq->val);
|
alpar@9
|
1548 else /* < 0.0 */
|
alpar@9
|
1549 l = (beta == +DBL_MAX ? -DBL_MAX : beta / apq->val);
|
alpar@9
|
1550 /* compute implied column upper bound u'[q] */
|
alpar@9
|
1551 if (apq->val > 0.0)
|
alpar@9
|
1552 u = (beta == +DBL_MAX ? +DBL_MAX : beta / apq->val);
|
alpar@9
|
1553 else
|
alpar@9
|
1554 u = (alfa == -DBL_MAX ? +DBL_MAX : alfa / apq->val);
|
alpar@9
|
1555 /* check if column lower bound l[q] can be active */
|
alpar@9
|
1556 if (q->lb != -DBL_MAX)
|
alpar@9
|
1557 { eps = 1e-9 + 1e-12 * fabs(q->lb);
|
alpar@9
|
1558 if (l < q->lb - eps) return 1; /* yes, it can */
|
alpar@9
|
1559 }
|
alpar@9
|
1560 /* check if column upper bound u[q] can be active */
|
alpar@9
|
1561 if (q->ub != +DBL_MAX)
|
alpar@9
|
1562 { eps = 1e-9 + 1e-12 * fabs(q->ub);
|
alpar@9
|
1563 if (u > q->ub + eps) return 1; /* yes, it can */
|
alpar@9
|
1564 }
|
alpar@9
|
1565 /* okay; make column q free (unbounded) */
|
alpar@9
|
1566 q->lb = -DBL_MAX, q->ub = +DBL_MAX;
|
alpar@9
|
1567 /* create transformation stack entry */
|
alpar@9
|
1568 info = npp_push_tse(npp,
|
alpar@9
|
1569 rcv_implied_free, sizeof(struct implied_free));
|
alpar@9
|
1570 info->p = p->i;
|
alpar@9
|
1571 info->stat = -1;
|
alpar@9
|
1572 /* compute row multiplier pi[p] */
|
alpar@9
|
1573 pi = q->coef / apq->val;
|
alpar@9
|
1574 /* check dual feasibility for row p */
|
alpar@9
|
1575 if (pi > +DBL_EPSILON)
|
alpar@9
|
1576 { /* lower bound L[p] must be active */
|
alpar@9
|
1577 if (p->lb != -DBL_MAX)
|
alpar@9
|
1578 nl: { info->stat = GLP_NL;
|
alpar@9
|
1579 p->ub = p->lb;
|
alpar@9
|
1580 }
|
alpar@9
|
1581 else
|
alpar@9
|
1582 { if (pi > +1e-5) return 2; /* dual infeasibility */
|
alpar@9
|
1583 /* take a chance on U[p] */
|
alpar@9
|
1584 xassert(p->ub != +DBL_MAX);
|
alpar@9
|
1585 goto nu;
|
alpar@9
|
1586 }
|
alpar@9
|
1587 }
|
alpar@9
|
1588 else if (pi < -DBL_EPSILON)
|
alpar@9
|
1589 { /* upper bound U[p] must be active */
|
alpar@9
|
1590 if (p->ub != +DBL_MAX)
|
alpar@9
|
1591 nu: { info->stat = GLP_NU;
|
alpar@9
|
1592 p->lb = p->ub;
|
alpar@9
|
1593 }
|
alpar@9
|
1594 else
|
alpar@9
|
1595 { if (pi < -1e-5) return 2; /* dual infeasibility */
|
alpar@9
|
1596 /* take a chance on L[p] */
|
alpar@9
|
1597 xassert(p->lb != -DBL_MAX);
|
alpar@9
|
1598 goto nl;
|
alpar@9
|
1599 }
|
alpar@9
|
1600 }
|
alpar@9
|
1601 else
|
alpar@9
|
1602 { /* any bound (either L[p] or U[p]) can be made active */
|
alpar@9
|
1603 if (p->ub == +DBL_MAX)
|
alpar@9
|
1604 { xassert(p->lb != -DBL_MAX);
|
alpar@9
|
1605 goto nl;
|
alpar@9
|
1606 }
|
alpar@9
|
1607 if (p->lb == -DBL_MAX)
|
alpar@9
|
1608 { xassert(p->ub != +DBL_MAX);
|
alpar@9
|
1609 goto nu;
|
alpar@9
|
1610 }
|
alpar@9
|
1611 if (fabs(p->lb) <= fabs(p->ub)) goto nl; else goto nu;
|
alpar@9
|
1612 }
|
alpar@9
|
1613 return 0;
|
alpar@9
|
1614 }
|
alpar@9
|
1615
|
alpar@9
|
1616 static int rcv_implied_free(NPP *npp, void *_info)
|
alpar@9
|
1617 { /* recover column singleton (implied free variable) */
|
alpar@9
|
1618 struct implied_free *info = _info;
|
alpar@9
|
1619 if (npp->sol == GLP_SOL)
|
alpar@9
|
1620 { if (npp->r_stat[info->p] == GLP_BS)
|
alpar@9
|
1621 npp->r_stat[info->p] = GLP_BS;
|
alpar@9
|
1622 else if (npp->r_stat[info->p] == GLP_NS)
|
alpar@9
|
1623 { xassert(info->stat == GLP_NL || info->stat == GLP_NU);
|
alpar@9
|
1624 npp->r_stat[info->p] = info->stat;
|
alpar@9
|
1625 }
|
alpar@9
|
1626 else
|
alpar@9
|
1627 { npp_error();
|
alpar@9
|
1628 return 1;
|
alpar@9
|
1629 }
|
alpar@9
|
1630 }
|
alpar@9
|
1631 return 0;
|
alpar@9
|
1632 }
|
alpar@9
|
1633
|
alpar@9
|
1634 /***********************************************************************
|
alpar@9
|
1635 * NAME
|
alpar@9
|
1636 *
|
alpar@9
|
1637 * npp_eq_doublet - process row doubleton (equality constraint)
|
alpar@9
|
1638 *
|
alpar@9
|
1639 * SYNOPSIS
|
alpar@9
|
1640 *
|
alpar@9
|
1641 * #include "glpnpp.h"
|
alpar@9
|
1642 * NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p);
|
alpar@9
|
1643 *
|
alpar@9
|
1644 * DESCRIPTION
|
alpar@9
|
1645 *
|
alpar@9
|
1646 * The routine npp_eq_doublet processes row p, which is equality
|
alpar@9
|
1647 * constraint having exactly two non-zero coefficients:
|
alpar@9
|
1648 *
|
alpar@9
|
1649 * a[p,q] x[q] + a[p,r] x[r] = b. (1)
|
alpar@9
|
1650 *
|
alpar@9
|
1651 * As the result of processing one of columns q or r is eliminated from
|
alpar@9
|
1652 * all other rows and, thus, becomes column singleton of type "implied
|
alpar@9
|
1653 * slack variable". Row p is not changed and along with column q and r
|
alpar@9
|
1654 * remains in the problem.
|
alpar@9
|
1655 *
|
alpar@9
|
1656 * RETURNS
|
alpar@9
|
1657 *
|
alpar@9
|
1658 * The routine npp_eq_doublet returns pointer to the descriptor of that
|
alpar@9
|
1659 * column q or r which has been eliminated. If, due to some reason, the
|
alpar@9
|
1660 * elimination was not performed, the routine returns NULL.
|
alpar@9
|
1661 *
|
alpar@9
|
1662 * PROBLEM TRANSFORMATION
|
alpar@9
|
1663 *
|
alpar@9
|
1664 * First, we decide which column q or r will be eliminated. Let it be
|
alpar@9
|
1665 * column q. Consider i-th constraint row, where column q has non-zero
|
alpar@9
|
1666 * coefficient a[i,q] != 0:
|
alpar@9
|
1667 *
|
alpar@9
|
1668 * L[i] <= sum a[i,j] x[j] <= U[i]. (2)
|
alpar@9
|
1669 * j
|
alpar@9
|
1670 *
|
alpar@9
|
1671 * In order to eliminate column q from row (2) we subtract from it row
|
alpar@9
|
1672 * (1) multiplied by gamma[i] = a[i,q] / a[p,q], i.e. we replace in the
|
alpar@9
|
1673 * transformed problem row (2) by its linear combination with row (1).
|
alpar@9
|
1674 * This transformation changes only coefficients in columns q and r,
|
alpar@9
|
1675 * and bounds of row i as follows:
|
alpar@9
|
1676 *
|
alpar@9
|
1677 * a~[i,q] = a[i,q] - gamma[i] a[p,q] = 0, (3)
|
alpar@9
|
1678 *
|
alpar@9
|
1679 * a~[i,r] = a[i,r] - gamma[i] a[p,r], (4)
|
alpar@9
|
1680 *
|
alpar@9
|
1681 * L~[i] = L[i] - gamma[i] b, (5)
|
alpar@9
|
1682 *
|
alpar@9
|
1683 * U~[i] = U[i] - gamma[i] b. (6)
|
alpar@9
|
1684 *
|
alpar@9
|
1685 * RECOVERING BASIC SOLUTION
|
alpar@9
|
1686 *
|
alpar@9
|
1687 * The transformation of the primal system of the original problem:
|
alpar@9
|
1688 *
|
alpar@9
|
1689 * L <= A x <= U (7)
|
alpar@9
|
1690 *
|
alpar@9
|
1691 * is equivalent to multiplying from the left a transformation matrix F
|
alpar@9
|
1692 * by components of this primal system, which in the transformed problem
|
alpar@9
|
1693 * becomes the following:
|
alpar@9
|
1694 *
|
alpar@9
|
1695 * F L <= F A x <= F U ==> L~ <= A~x <= U~. (8)
|
alpar@9
|
1696 *
|
alpar@9
|
1697 * The matrix F has the following structure:
|
alpar@9
|
1698 *
|
alpar@9
|
1699 * ( 1 -gamma[1] )
|
alpar@9
|
1700 * ( )
|
alpar@9
|
1701 * ( 1 -gamma[2] )
|
alpar@9
|
1702 * ( )
|
alpar@9
|
1703 * ( ... ... )
|
alpar@9
|
1704 * ( )
|
alpar@9
|
1705 * F = ( 1 -gamma[p-1] ) (9)
|
alpar@9
|
1706 * ( )
|
alpar@9
|
1707 * ( 1 )
|
alpar@9
|
1708 * ( )
|
alpar@9
|
1709 * ( -gamma[p+1] 1 )
|
alpar@9
|
1710 * ( )
|
alpar@9
|
1711 * ( ... ... )
|
alpar@9
|
1712 *
|
alpar@9
|
1713 * where its column containing elements -gamma[i] corresponds to row p
|
alpar@9
|
1714 * of the primal system.
|
alpar@9
|
1715 *
|
alpar@9
|
1716 * From (8) it follows that the dual system of the original problem:
|
alpar@9
|
1717 *
|
alpar@9
|
1718 * A'pi + lambda = c, (10)
|
alpar@9
|
1719 *
|
alpar@9
|
1720 * in the transformed problem becomes the following:
|
alpar@9
|
1721 *
|
alpar@9
|
1722 * A'F'inv(F')pi + lambda = c ==> (A~)'pi~ + lambda = c, (11)
|
alpar@9
|
1723 *
|
alpar@9
|
1724 * where:
|
alpar@9
|
1725 *
|
alpar@9
|
1726 * pi~ = inv(F')pi (12)
|
alpar@9
|
1727 *
|
alpar@9
|
1728 * is the vector of row multipliers in the transformed problem. Thus:
|
alpar@9
|
1729 *
|
alpar@9
|
1730 * pi = F'pi~. (13)
|
alpar@9
|
1731 *
|
alpar@9
|
1732 * Therefore, as it follows from (13), value of multiplier for row p in
|
alpar@9
|
1733 * solution to the original problem can be computed as follows:
|
alpar@9
|
1734 *
|
alpar@9
|
1735 * pi[p] = pi~[p] - sum gamma[i] pi~[i], (14)
|
alpar@9
|
1736 * i
|
alpar@9
|
1737 *
|
alpar@9
|
1738 * where pi~[i] = pi[i] is multiplier for row i (i != p).
|
alpar@9
|
1739 *
|
alpar@9
|
1740 * Note that the statuses of all rows and columns are not changed.
|
alpar@9
|
1741 *
|
alpar@9
|
1742 * RECOVERING INTERIOR-POINT SOLUTION
|
alpar@9
|
1743 *
|
alpar@9
|
1744 * Multiplier for row p in solution to the original problem is computed
|
alpar@9
|
1745 * with formula (14).
|
alpar@9
|
1746 *
|
alpar@9
|
1747 * RECOVERING MIP SOLUTION
|
alpar@9
|
1748 *
|
alpar@9
|
1749 * None needed. */
|
alpar@9
|
1750
|
alpar@9
|
1751 struct eq_doublet
|
alpar@9
|
1752 { /* row doubleton (equality constraint) */
|
alpar@9
|
1753 int p;
|
alpar@9
|
1754 /* row reference number */
|
alpar@9
|
1755 double apq;
|
alpar@9
|
1756 /* constraint coefficient a[p,q] */
|
alpar@9
|
1757 NPPLFE *ptr;
|
alpar@9
|
1758 /* list of non-zero coefficients a[i,q], i != p */
|
alpar@9
|
1759 };
|
alpar@9
|
1760
|
alpar@9
|
1761 static int rcv_eq_doublet(NPP *npp, void *info);
|
alpar@9
|
1762
|
alpar@9
|
1763 NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p)
|
alpar@9
|
1764 { /* process row doubleton (equality constraint) */
|
alpar@9
|
1765 struct eq_doublet *info;
|
alpar@9
|
1766 NPPROW *i;
|
alpar@9
|
1767 NPPCOL *q, *r;
|
alpar@9
|
1768 NPPAIJ *apq, *apr, *aiq, *air, *next;
|
alpar@9
|
1769 NPPLFE *lfe;
|
alpar@9
|
1770 double gamma;
|
alpar@9
|
1771 /* the row must be doubleton equality constraint */
|
alpar@9
|
1772 xassert(p->lb == p->ub);
|
alpar@9
|
1773 xassert(p->ptr != NULL && p->ptr->r_next != NULL &&
|
alpar@9
|
1774 p->ptr->r_next->r_next == NULL);
|
alpar@9
|
1775 /* choose column to be eliminated */
|
alpar@9
|
1776 { NPPAIJ *a1, *a2;
|
alpar@9
|
1777 a1 = p->ptr, a2 = a1->r_next;
|
alpar@9
|
1778 if (fabs(a2->val) < 0.001 * fabs(a1->val))
|
alpar@9
|
1779 { /* only first column can be eliminated, because second one
|
alpar@9
|
1780 has too small constraint coefficient */
|
alpar@9
|
1781 apq = a1, apr = a2;
|
alpar@9
|
1782 }
|
alpar@9
|
1783 else if (fabs(a1->val) < 0.001 * fabs(a2->val))
|
alpar@9
|
1784 { /* only second column can be eliminated, because first one
|
alpar@9
|
1785 has too small constraint coefficient */
|
alpar@9
|
1786 apq = a2, apr = a1;
|
alpar@9
|
1787 }
|
alpar@9
|
1788 else
|
alpar@9
|
1789 { /* both columns are appropriate; choose that one which is
|
alpar@9
|
1790 shorter to minimize fill-in */
|
alpar@9
|
1791 if (npp_col_nnz(npp, a1->col) <= npp_col_nnz(npp, a2->col))
|
alpar@9
|
1792 { /* first column is shorter */
|
alpar@9
|
1793 apq = a1, apr = a2;
|
alpar@9
|
1794 }
|
alpar@9
|
1795 else
|
alpar@9
|
1796 { /* second column is shorter */
|
alpar@9
|
1797 apq = a2, apr = a1;
|
alpar@9
|
1798 }
|
alpar@9
|
1799 }
|
alpar@9
|
1800 }
|
alpar@9
|
1801 /* now columns q and r have been chosen */
|
alpar@9
|
1802 q = apq->col, r = apr->col;
|
alpar@9
|
1803 /* create transformation stack entry */
|
alpar@9
|
1804 info = npp_push_tse(npp,
|
alpar@9
|
1805 rcv_eq_doublet, sizeof(struct eq_doublet));
|
alpar@9
|
1806 info->p = p->i;
|
alpar@9
|
1807 info->apq = apq->val;
|
alpar@9
|
1808 info->ptr = NULL;
|
alpar@9
|
1809 /* transform each row i (i != p), where a[i,q] != 0, to eliminate
|
alpar@9
|
1810 column q */
|
alpar@9
|
1811 for (aiq = q->ptr; aiq != NULL; aiq = next)
|
alpar@9
|
1812 { next = aiq->c_next;
|
alpar@9
|
1813 if (aiq == apq) continue; /* skip row p */
|
alpar@9
|
1814 i = aiq->row; /* row i to be transformed */
|
alpar@9
|
1815 /* save constraint coefficient a[i,q] */
|
alpar@9
|
1816 if (npp->sol != GLP_MIP)
|
alpar@9
|
1817 { lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
|
alpar@9
|
1818 lfe->ref = i->i;
|
alpar@9
|
1819 lfe->val = aiq->val;
|
alpar@9
|
1820 lfe->next = info->ptr;
|
alpar@9
|
1821 info->ptr = lfe;
|
alpar@9
|
1822 }
|
alpar@9
|
1823 /* find coefficient a[i,r] in row i */
|
alpar@9
|
1824 for (air = i->ptr; air != NULL; air = air->r_next)
|
alpar@9
|
1825 if (air->col == r) break;
|
alpar@9
|
1826 /* if a[i,r] does not exist, create a[i,r] = 0 */
|
alpar@9
|
1827 if (air == NULL)
|
alpar@9
|
1828 air = npp_add_aij(npp, i, r, 0.0);
|
alpar@9
|
1829 /* compute gamma[i] = a[i,q] / a[p,q] */
|
alpar@9
|
1830 gamma = aiq->val / apq->val;
|
alpar@9
|
1831 /* (row i) := (row i) - gamma[i] * (row p); see (3)-(6) */
|
alpar@9
|
1832 /* new a[i,q] is exact zero due to elimnation; remove it from
|
alpar@9
|
1833 row i */
|
alpar@9
|
1834 npp_del_aij(npp, aiq);
|
alpar@9
|
1835 /* compute new a[i,r] */
|
alpar@9
|
1836 air->val -= gamma * apr->val;
|
alpar@9
|
1837 /* if new a[i,r] is close to zero due to numeric cancelation,
|
alpar@9
|
1838 remove it from row i */
|
alpar@9
|
1839 if (fabs(air->val) <= 1e-10)
|
alpar@9
|
1840 npp_del_aij(npp, air);
|
alpar@9
|
1841 /* compute new lower and upper bounds of row i */
|
alpar@9
|
1842 if (i->lb == i->ub)
|
alpar@9
|
1843 i->lb = i->ub = (i->lb - gamma * p->lb);
|
alpar@9
|
1844 else
|
alpar@9
|
1845 { if (i->lb != -DBL_MAX)
|
alpar@9
|
1846 i->lb -= gamma * p->lb;
|
alpar@9
|
1847 if (i->ub != +DBL_MAX)
|
alpar@9
|
1848 i->ub -= gamma * p->lb;
|
alpar@9
|
1849 }
|
alpar@9
|
1850 }
|
alpar@9
|
1851 return q;
|
alpar@9
|
1852 }
|
alpar@9
|
1853
|
alpar@9
|
1854 static int rcv_eq_doublet(NPP *npp, void *_info)
|
alpar@9
|
1855 { /* recover row doubleton (equality constraint) */
|
alpar@9
|
1856 struct eq_doublet *info = _info;
|
alpar@9
|
1857 NPPLFE *lfe;
|
alpar@9
|
1858 double gamma, temp;
|
alpar@9
|
1859 /* we assume that processing row p is followed by processing
|
alpar@9
|
1860 column q as singleton of type "implied slack variable", in
|
alpar@9
|
1861 which case row p must always be active equality constraint */
|
alpar@9
|
1862 if (npp->sol == GLP_SOL)
|
alpar@9
|
1863 { if (npp->r_stat[info->p] != GLP_NS)
|
alpar@9
|
1864 { npp_error();
|
alpar@9
|
1865 return 1;
|
alpar@9
|
1866 }
|
alpar@9
|
1867 }
|
alpar@9
|
1868 if (npp->sol != GLP_MIP)
|
alpar@9
|
1869 { /* compute value of multiplier for row p; see (14) */
|
alpar@9
|
1870 temp = npp->r_pi[info->p];
|
alpar@9
|
1871 for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
|
alpar@9
|
1872 { gamma = lfe->val / info->apq; /* a[i,q] / a[p,q] */
|
alpar@9
|
1873 temp -= gamma * npp->r_pi[lfe->ref];
|
alpar@9
|
1874 }
|
alpar@9
|
1875 npp->r_pi[info->p] = temp;
|
alpar@9
|
1876 }
|
alpar@9
|
1877 return 0;
|
alpar@9
|
1878 }
|
alpar@9
|
1879
|
alpar@9
|
1880 /***********************************************************************
|
alpar@9
|
1881 * NAME
|
alpar@9
|
1882 *
|
alpar@9
|
1883 * npp_forcing_row - process forcing row
|
alpar@9
|
1884 *
|
alpar@9
|
1885 * SYNOPSIS
|
alpar@9
|
1886 *
|
alpar@9
|
1887 * #include "glpnpp.h"
|
alpar@9
|
1888 * int npp_forcing_row(NPP *npp, NPPROW *p, int at);
|
alpar@9
|
1889 *
|
alpar@9
|
1890 * DESCRIPTION
|
alpar@9
|
1891 *
|
alpar@9
|
1892 * The routine npp_forcing row processes row p of general format:
|
alpar@9
|
1893 *
|
alpar@9
|
1894 * L[p] <= sum a[p,j] x[j] <= U[p], (1)
|
alpar@9
|
1895 * j
|
alpar@9
|
1896 *
|
alpar@9
|
1897 * l[j] <= x[j] <= u[j], (2)
|
alpar@9
|
1898 *
|
alpar@9
|
1899 * where L[p] <= U[p] and l[j] < u[j] for all a[p,j] != 0. It is also
|
alpar@9
|
1900 * assumed that:
|
alpar@9
|
1901 *
|
alpar@9
|
1902 * 1) if at = 0 then |L[p] - U'[p]| <= eps, where U'[p] is implied
|
alpar@9
|
1903 * row upper bound (see below), eps is an absolute tolerance for row
|
alpar@9
|
1904 * value;
|
alpar@9
|
1905 *
|
alpar@9
|
1906 * 2) if at = 1 then |U[p] - L'[p]| <= eps, where L'[p] is implied
|
alpar@9
|
1907 * row lower bound (see below).
|
alpar@9
|
1908 *
|
alpar@9
|
1909 * RETURNS
|
alpar@9
|
1910 *
|
alpar@9
|
1911 * 0 - success;
|
alpar@9
|
1912 *
|
alpar@9
|
1913 * 1 - cannot fix columns due to too small constraint coefficients.
|
alpar@9
|
1914 *
|
alpar@9
|
1915 * PROBLEM TRANSFORMATION
|
alpar@9
|
1916 *
|
alpar@9
|
1917 * Implied lower and upper bounds of row (1) are determined by bounds
|
alpar@9
|
1918 * of corresponding columns (variables) as follows:
|
alpar@9
|
1919 *
|
alpar@9
|
1920 * L'[p] = inf sum a[p,j] x[j] =
|
alpar@9
|
1921 * j
|
alpar@9
|
1922 * (3)
|
alpar@9
|
1923 * = sum a[p,j] l[j] + sum a[p,j] u[j],
|
alpar@9
|
1924 * j in Jp j in Jn
|
alpar@9
|
1925 *
|
alpar@9
|
1926 * U'[p] = sup sum a[p,j] x[j] =
|
alpar@9
|
1927 * (4)
|
alpar@9
|
1928 * = sum a[p,j] u[j] + sum a[p,j] l[j],
|
alpar@9
|
1929 * j in Jp j in Jn
|
alpar@9
|
1930 *
|
alpar@9
|
1931 * Jp = {j: a[p,j] > 0}, Jn = {j: a[p,j] < 0}. (5)
|
alpar@9
|
1932 *
|
alpar@9
|
1933 * If L[p] =~ U'[p] (at = 0), solution can be primal feasible only when
|
alpar@9
|
1934 * all variables take their boundary values as defined by (4):
|
alpar@9
|
1935 *
|
alpar@9
|
1936 * ( u[j], if j in Jp
|
alpar@9
|
1937 * x[j] = < (6)
|
alpar@9
|
1938 * ( l[j], if j in Jn
|
alpar@9
|
1939 *
|
alpar@9
|
1940 * Similarly, if U[p] =~ L'[p] (at = 1), solution can be primal feasible
|
alpar@9
|
1941 * only when all variables take their boundary values as defined by (3):
|
alpar@9
|
1942 *
|
alpar@9
|
1943 * ( l[j], if j in Jp
|
alpar@9
|
1944 * x[j] = < (7)
|
alpar@9
|
1945 * ( u[j], if j in Jn
|
alpar@9
|
1946 *
|
alpar@9
|
1947 * Condition (6) or (7) allows fixing all columns (variables x[j])
|
alpar@9
|
1948 * in row (1) on their bounds and then removing them from the problem
|
alpar@9
|
1949 * (see the routine npp_fixed_col). Due to this row p becomes redundant,
|
alpar@9
|
1950 * so it can be replaced by equivalent free (unbounded) row and also
|
alpar@9
|
1951 * removed from the problem (see the routine npp_free_row).
|
alpar@9
|
1952 *
|
alpar@9
|
1953 * 1. To apply this transformation row (1) should not have coefficients
|
alpar@9
|
1954 * whose magnitude is too small, i.e. all a[p,j] should satisfy to
|
alpar@9
|
1955 * the following condition:
|
alpar@9
|
1956 *
|
alpar@9
|
1957 * |a[p,j]| >= eps * max(1, |a[p,k]|), (8)
|
alpar@9
|
1958 * k
|
alpar@9
|
1959 * where eps is a relative tolerance for constraint coefficients.
|
alpar@9
|
1960 * Otherwise, fixing columns may be numerically unreliable and may
|
alpar@9
|
1961 * lead to wrong solution.
|
alpar@9
|
1962 *
|
alpar@9
|
1963 * 2. The routine fixes columns and remove bounds of row p, however,
|
alpar@9
|
1964 * it does not remove the row and columns from the problem.
|
alpar@9
|
1965 *
|
alpar@9
|
1966 * RECOVERING BASIC SOLUTION
|
alpar@9
|
1967 *
|
alpar@9
|
1968 * In the transformed problem row p being inactive constraint is
|
alpar@9
|
1969 * assigned status GLP_BS (as the result of transformation of free
|
alpar@9
|
1970 * row), and all columns in this row are assigned status GLP_NS (as the
|
alpar@9
|
1971 * result of transformation of fixed columns).
|
alpar@9
|
1972 *
|
alpar@9
|
1973 * Note that in the dual system of the transformed (as well as original)
|
alpar@9
|
1974 * problem every column j in row p corresponds to the following row:
|
alpar@9
|
1975 *
|
alpar@9
|
1976 * sum a[i,j] pi[i] + a[p,j] pi[p] + lambda[j] = c[j], (9)
|
alpar@9
|
1977 * i!=p
|
alpar@9
|
1978 *
|
alpar@9
|
1979 * from which it follows that:
|
alpar@9
|
1980 *
|
alpar@9
|
1981 * lambda[j] = c[j] - sum a[i,j] pi[i] - a[p,j] pi[p]. (10)
|
alpar@9
|
1982 * i!=p
|
alpar@9
|
1983 *
|
alpar@9
|
1984 * In the transformed problem values of all multipliers pi[i] are known
|
alpar@9
|
1985 * (including pi[i], whose value is zero, since row p is inactive).
|
alpar@9
|
1986 * Thus, using formula (10) it is possible to compute values of
|
alpar@9
|
1987 * multipliers lambda[j] for all columns in row p.
|
alpar@9
|
1988 *
|
alpar@9
|
1989 * Note also that in the original problem all columns in row p are
|
alpar@9
|
1990 * bounded, not fixed. So status GLP_NS assigned to every such column
|
alpar@9
|
1991 * must be changed to GLP_NL or GLP_NU depending on which bound the
|
alpar@9
|
1992 * corresponding column has been fixed. This status change may lead to
|
alpar@9
|
1993 * dual feasibility violation for solution of the original problem,
|
alpar@9
|
1994 * because now column multipliers must satisfy to the following
|
alpar@9
|
1995 * condition:
|
alpar@9
|
1996 *
|
alpar@9
|
1997 * ( >= 0, if status of column j is GLP_NL,
|
alpar@9
|
1998 * lambda[j] < (11)
|
alpar@9
|
1999 * ( <= 0, if status of column j is GLP_NU.
|
alpar@9
|
2000 *
|
alpar@9
|
2001 * If this condition holds, solution to the original problem is the
|
alpar@9
|
2002 * same as to the transformed problem. Otherwise, we have to perform
|
alpar@9
|
2003 * one degenerate pivoting step of the primal simplex method to obtain
|
alpar@9
|
2004 * dual feasible (hence, optimal) solution to the original problem as
|
alpar@9
|
2005 * follows. If, on problem transformation, row p was made active on its
|
alpar@9
|
2006 * lower bound (case at = 0), we change its status to GLP_NL (or GLP_NS)
|
alpar@9
|
2007 * and start increasing its multiplier pi[p]. Otherwise, if row p was
|
alpar@9
|
2008 * made active on its upper bound (case at = 1), we change its status
|
alpar@9
|
2009 * to GLP_NU (or GLP_NS) and start decreasing pi[p]. From (10) it
|
alpar@9
|
2010 * follows that:
|
alpar@9
|
2011 *
|
alpar@9
|
2012 * delta lambda[j] = - a[p,j] * delta pi[p] = - a[p,j] pi[p]. (12)
|
alpar@9
|
2013 *
|
alpar@9
|
2014 * Simple analysis of formulae (3)-(5) shows that changing pi[p] in the
|
alpar@9
|
2015 * specified direction causes increasing lambda[j] for every column j
|
alpar@9
|
2016 * assigned status GLP_NL (delta lambda[j] > 0) and decreasing lambda[j]
|
alpar@9
|
2017 * for every column j assigned status GLP_NU (delta lambda[j] < 0). It
|
alpar@9
|
2018 * is understood that once the last lambda[q], which violates condition
|
alpar@9
|
2019 * (11), has reached zero, multipliers lambda[j] for all columns get
|
alpar@9
|
2020 * valid signs. Such column q can be determined as follows. Let d[j] be
|
alpar@9
|
2021 * initial value of lambda[j] (i.e. reduced cost of column j) in the
|
alpar@9
|
2022 * transformed problem computed with formula (10) when pi[p] = 0. Then
|
alpar@9
|
2023 * lambda[j] = d[j] + delta lambda[j], and from (12) it follows that
|
alpar@9
|
2024 * lambda[j] becomes zero if:
|
alpar@9
|
2025 *
|
alpar@9
|
2026 * delta lambda[j] = - a[p,j] pi[p] = - d[j] ==>
|
alpar@9
|
2027 * (13)
|
alpar@9
|
2028 * pi[p] = d[j] / a[p,j].
|
alpar@9
|
2029 *
|
alpar@9
|
2030 * Therefore, the last column q, for which lambda[q] becomes zero, can
|
alpar@9
|
2031 * be determined from the following condition:
|
alpar@9
|
2032 *
|
alpar@9
|
2033 * |d[q] / a[p,q]| = max |pi[p]| = max |d[j] / a[p,j]|, (14)
|
alpar@9
|
2034 * j in D j in D
|
alpar@9
|
2035 *
|
alpar@9
|
2036 * where D is a set of columns j whose, reduced costs d[j] have invalid
|
alpar@9
|
2037 * signs, i.e. violate condition (11). (Thus, if D is empty, solution
|
alpar@9
|
2038 * to the original problem is the same as solution to the transformed
|
alpar@9
|
2039 * problem, and no correction is needed as was noticed above.) In
|
alpar@9
|
2040 * solution to the original problem column q is assigned status GLP_BS,
|
alpar@9
|
2041 * since it replaces column of auxiliary variable of row p (becoming
|
alpar@9
|
2042 * active) in the basis, and multiplier for row p is assigned its new
|
alpar@9
|
2043 * value, which is pi[p] = d[q] / a[p,q]. Note that due to primal
|
alpar@9
|
2044 * degeneracy values of all columns having non-zero coefficients in row
|
alpar@9
|
2045 * p remain unchanged.
|
alpar@9
|
2046 *
|
alpar@9
|
2047 * RECOVERING INTERIOR-POINT SOLUTION
|
alpar@9
|
2048 *
|
alpar@9
|
2049 * Value of multiplier pi[p] in solution to the original problem is
|
alpar@9
|
2050 * corrected in the same way as for basic solution. Values of all
|
alpar@9
|
2051 * columns having non-zero coefficients in row p remain unchanged.
|
alpar@9
|
2052 *
|
alpar@9
|
2053 * RECOVERING MIP SOLUTION
|
alpar@9
|
2054 *
|
alpar@9
|
2055 * None needed. */
|
alpar@9
|
2056
|
alpar@9
|
2057 struct forcing_col
|
alpar@9
|
2058 { /* column fixed on its bound by forcing row */
|
alpar@9
|
2059 int j;
|
alpar@9
|
2060 /* column reference number */
|
alpar@9
|
2061 char stat;
|
alpar@9
|
2062 /* original column status:
|
alpar@9
|
2063 GLP_NL - fixed on lower bound
|
alpar@9
|
2064 GLP_NU - fixed on upper bound */
|
alpar@9
|
2065 double a;
|
alpar@9
|
2066 /* constraint coefficient a[p,j] */
|
alpar@9
|
2067 double c;
|
alpar@9
|
2068 /* objective coefficient c[j] */
|
alpar@9
|
2069 NPPLFE *ptr;
|
alpar@9
|
2070 /* list of non-zero coefficients a[i,j], i != p */
|
alpar@9
|
2071 struct forcing_col *next;
|
alpar@9
|
2072 /* pointer to another column fixed by forcing row */
|
alpar@9
|
2073 };
|
alpar@9
|
2074
|
alpar@9
|
2075 struct forcing_row
|
alpar@9
|
2076 { /* forcing row */
|
alpar@9
|
2077 int p;
|
alpar@9
|
2078 /* row reference number */
|
alpar@9
|
2079 char stat;
|
alpar@9
|
2080 /* status assigned to the row if it becomes active:
|
alpar@9
|
2081 GLP_NS - active equality constraint
|
alpar@9
|
2082 GLP_NL - inequality constraint with lower bound active
|
alpar@9
|
2083 GLP_NU - inequality constraint with upper bound active */
|
alpar@9
|
2084 struct forcing_col *ptr;
|
alpar@9
|
2085 /* list of all columns having non-zero constraint coefficient
|
alpar@9
|
2086 a[p,j] in the forcing row */
|
alpar@9
|
2087 };
|
alpar@9
|
2088
|
alpar@9
|
2089 static int rcv_forcing_row(NPP *npp, void *info);
|
alpar@9
|
2090
|
alpar@9
|
2091 int npp_forcing_row(NPP *npp, NPPROW *p, int at)
|
alpar@9
|
2092 { /* process forcing row */
|
alpar@9
|
2093 struct forcing_row *info;
|
alpar@9
|
2094 struct forcing_col *col = NULL;
|
alpar@9
|
2095 NPPCOL *j;
|
alpar@9
|
2096 NPPAIJ *apj, *aij;
|
alpar@9
|
2097 NPPLFE *lfe;
|
alpar@9
|
2098 double big;
|
alpar@9
|
2099 xassert(at == 0 || at == 1);
|
alpar@9
|
2100 /* determine maximal magnitude of the row coefficients */
|
alpar@9
|
2101 big = 1.0;
|
alpar@9
|
2102 for (apj = p->ptr; apj != NULL; apj = apj->r_next)
|
alpar@9
|
2103 if (big < fabs(apj->val)) big = fabs(apj->val);
|
alpar@9
|
2104 /* if there are too small coefficients in the row, transformation
|
alpar@9
|
2105 should not be applied */
|
alpar@9
|
2106 for (apj = p->ptr; apj != NULL; apj = apj->r_next)
|
alpar@9
|
2107 if (fabs(apj->val) < 1e-7 * big) return 1;
|
alpar@9
|
2108 /* create transformation stack entry */
|
alpar@9
|
2109 info = npp_push_tse(npp,
|
alpar@9
|
2110 rcv_forcing_row, sizeof(struct forcing_row));
|
alpar@9
|
2111 info->p = p->i;
|
alpar@9
|
2112 if (p->lb == p->ub)
|
alpar@9
|
2113 { /* equality constraint */
|
alpar@9
|
2114 info->stat = GLP_NS;
|
alpar@9
|
2115 }
|
alpar@9
|
2116 else if (at == 0)
|
alpar@9
|
2117 { /* inequality constraint; case L[p] = U'[p] */
|
alpar@9
|
2118 info->stat = GLP_NL;
|
alpar@9
|
2119 xassert(p->lb != -DBL_MAX);
|
alpar@9
|
2120 }
|
alpar@9
|
2121 else /* at == 1 */
|
alpar@9
|
2122 { /* inequality constraint; case U[p] = L'[p] */
|
alpar@9
|
2123 info->stat = GLP_NU;
|
alpar@9
|
2124 xassert(p->ub != +DBL_MAX);
|
alpar@9
|
2125 }
|
alpar@9
|
2126 info->ptr = NULL;
|
alpar@9
|
2127 /* scan the forcing row, fix columns at corresponding bounds, and
|
alpar@9
|
2128 save column information (the latter is not needed for MIP) */
|
alpar@9
|
2129 for (apj = p->ptr; apj != NULL; apj = apj->r_next)
|
alpar@9
|
2130 { /* column j has non-zero coefficient in the forcing row */
|
alpar@9
|
2131 j = apj->col;
|
alpar@9
|
2132 /* it must be non-fixed */
|
alpar@9
|
2133 xassert(j->lb < j->ub);
|
alpar@9
|
2134 /* allocate stack entry to save column information */
|
alpar@9
|
2135 if (npp->sol != GLP_MIP)
|
alpar@9
|
2136 { col = dmp_get_atom(npp->stack, sizeof(struct forcing_col));
|
alpar@9
|
2137 col->j = j->j;
|
alpar@9
|
2138 col->stat = -1; /* will be set below */
|
alpar@9
|
2139 col->a = apj->val;
|
alpar@9
|
2140 col->c = j->coef;
|
alpar@9
|
2141 col->ptr = NULL;
|
alpar@9
|
2142 col->next = info->ptr;
|
alpar@9
|
2143 info->ptr = col;
|
alpar@9
|
2144 }
|
alpar@9
|
2145 /* fix column j */
|
alpar@9
|
2146 if (at == 0 && apj->val < 0.0 || at != 0 && apj->val > 0.0)
|
alpar@9
|
2147 { /* at its lower bound */
|
alpar@9
|
2148 if (npp->sol != GLP_MIP)
|
alpar@9
|
2149 col->stat = GLP_NL;
|
alpar@9
|
2150 xassert(j->lb != -DBL_MAX);
|
alpar@9
|
2151 j->ub = j->lb;
|
alpar@9
|
2152 }
|
alpar@9
|
2153 else
|
alpar@9
|
2154 { /* at its upper bound */
|
alpar@9
|
2155 if (npp->sol != GLP_MIP)
|
alpar@9
|
2156 col->stat = GLP_NU;
|
alpar@9
|
2157 xassert(j->ub != +DBL_MAX);
|
alpar@9
|
2158 j->lb = j->ub;
|
alpar@9
|
2159 }
|
alpar@9
|
2160 /* save column coefficients a[i,j], i != p */
|
alpar@9
|
2161 if (npp->sol != GLP_MIP)
|
alpar@9
|
2162 { for (aij = j->ptr; aij != NULL; aij = aij->c_next)
|
alpar@9
|
2163 { if (aij == apj) continue; /* skip a[p,j] */
|
alpar@9
|
2164 lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
|
alpar@9
|
2165 lfe->ref = aij->row->i;
|
alpar@9
|
2166 lfe->val = aij->val;
|
alpar@9
|
2167 lfe->next = col->ptr;
|
alpar@9
|
2168 col->ptr = lfe;
|
alpar@9
|
2169 }
|
alpar@9
|
2170 }
|
alpar@9
|
2171 }
|
alpar@9
|
2172 /* make the row free (unbounded) */
|
alpar@9
|
2173 p->lb = -DBL_MAX, p->ub = +DBL_MAX;
|
alpar@9
|
2174 return 0;
|
alpar@9
|
2175 }
|
alpar@9
|
2176
|
alpar@9
|
2177 static int rcv_forcing_row(NPP *npp, void *_info)
|
alpar@9
|
2178 { /* recover forcing row */
|
alpar@9
|
2179 struct forcing_row *info = _info;
|
alpar@9
|
2180 struct forcing_col *col, *piv;
|
alpar@9
|
2181 NPPLFE *lfe;
|
alpar@9
|
2182 double d, big, temp;
|
alpar@9
|
2183 if (npp->sol == GLP_MIP) goto done;
|
alpar@9
|
2184 /* initially solution to the original problem is the same as
|
alpar@9
|
2185 to the transformed problem, where row p is inactive constraint
|
alpar@9
|
2186 with pi[p] = 0, and all columns are non-basic */
|
alpar@9
|
2187 if (npp->sol == GLP_SOL)
|
alpar@9
|
2188 { if (npp->r_stat[info->p] != GLP_BS)
|
alpar@9
|
2189 { npp_error();
|
alpar@9
|
2190 return 1;
|
alpar@9
|
2191 }
|
alpar@9
|
2192 for (col = info->ptr; col != NULL; col = col->next)
|
alpar@9
|
2193 { if (npp->c_stat[col->j] != GLP_NS)
|
alpar@9
|
2194 { npp_error();
|
alpar@9
|
2195 return 1;
|
alpar@9
|
2196 }
|
alpar@9
|
2197 npp->c_stat[col->j] = col->stat; /* original status */
|
alpar@9
|
2198 }
|
alpar@9
|
2199 }
|
alpar@9
|
2200 /* compute reduced costs d[j] for all columns with formula (10)
|
alpar@9
|
2201 and store them in col.c instead objective coefficients */
|
alpar@9
|
2202 for (col = info->ptr; col != NULL; col = col->next)
|
alpar@9
|
2203 { d = col->c;
|
alpar@9
|
2204 for (lfe = col->ptr; lfe != NULL; lfe = lfe->next)
|
alpar@9
|
2205 d -= lfe->val * npp->r_pi[lfe->ref];
|
alpar@9
|
2206 col->c = d;
|
alpar@9
|
2207 }
|
alpar@9
|
2208 /* consider columns j, whose multipliers lambda[j] has wrong
|
alpar@9
|
2209 sign in solution to the transformed problem (where lambda[j] =
|
alpar@9
|
2210 d[j]), and choose column q, whose multipler lambda[q] reaches
|
alpar@9
|
2211 zero last on changing row multiplier pi[p]; see (14) */
|
alpar@9
|
2212 piv = NULL, big = 0.0;
|
alpar@9
|
2213 for (col = info->ptr; col != NULL; col = col->next)
|
alpar@9
|
2214 { d = col->c; /* d[j] */
|
alpar@9
|
2215 temp = fabs(d / col->a);
|
alpar@9
|
2216 if (col->stat == GLP_NL)
|
alpar@9
|
2217 { /* column j has active lower bound */
|
alpar@9
|
2218 if (d < 0.0 && big < temp)
|
alpar@9
|
2219 piv = col, big = temp;
|
alpar@9
|
2220 }
|
alpar@9
|
2221 else if (col->stat == GLP_NU)
|
alpar@9
|
2222 { /* column j has active upper bound */
|
alpar@9
|
2223 if (d > 0.0 && big < temp)
|
alpar@9
|
2224 piv = col, big = temp;
|
alpar@9
|
2225 }
|
alpar@9
|
2226 else
|
alpar@9
|
2227 { npp_error();
|
alpar@9
|
2228 return 1;
|
alpar@9
|
2229 }
|
alpar@9
|
2230 }
|
alpar@9
|
2231 /* if column q does not exist, no correction is needed */
|
alpar@9
|
2232 if (piv != NULL)
|
alpar@9
|
2233 { /* correct solution; row p becomes active constraint while
|
alpar@9
|
2234 column q becomes basic */
|
alpar@9
|
2235 if (npp->sol == GLP_SOL)
|
alpar@9
|
2236 { npp->r_stat[info->p] = info->stat;
|
alpar@9
|
2237 npp->c_stat[piv->j] = GLP_BS;
|
alpar@9
|
2238 }
|
alpar@9
|
2239 /* assign new value to row multiplier pi[p] = d[p] / a[p,q] */
|
alpar@9
|
2240 npp->r_pi[info->p] = piv->c / piv->a;
|
alpar@9
|
2241 }
|
alpar@9
|
2242 done: return 0;
|
alpar@9
|
2243 }
|
alpar@9
|
2244
|
alpar@9
|
2245 /***********************************************************************
|
alpar@9
|
2246 * NAME
|
alpar@9
|
2247 *
|
alpar@9
|
2248 * npp_analyze_row - perform general row analysis
|
alpar@9
|
2249 *
|
alpar@9
|
2250 * SYNOPSIS
|
alpar@9
|
2251 *
|
alpar@9
|
2252 * #include "glpnpp.h"
|
alpar@9
|
2253 * int npp_analyze_row(NPP *npp, NPPROW *p);
|
alpar@9
|
2254 *
|
alpar@9
|
2255 * DESCRIPTION
|
alpar@9
|
2256 *
|
alpar@9
|
2257 * The routine npp_analyze_row performs analysis of row p of general
|
alpar@9
|
2258 * format:
|
alpar@9
|
2259 *
|
alpar@9
|
2260 * L[p] <= sum a[p,j] x[j] <= U[p], (1)
|
alpar@9
|
2261 * j
|
alpar@9
|
2262 *
|
alpar@9
|
2263 * l[j] <= x[j] <= u[j], (2)
|
alpar@9
|
2264 *
|
alpar@9
|
2265 * where L[p] <= U[p] and l[j] <= u[j] for all a[p,j] != 0.
|
alpar@9
|
2266 *
|
alpar@9
|
2267 * RETURNS
|
alpar@9
|
2268 *
|
alpar@9
|
2269 * 0x?0 - row lower bound does not exist or is redundant;
|
alpar@9
|
2270 *
|
alpar@9
|
2271 * 0x?1 - row lower bound can be active;
|
alpar@9
|
2272 *
|
alpar@9
|
2273 * 0x?2 - row lower bound is a forcing bound;
|
alpar@9
|
2274 *
|
alpar@9
|
2275 * 0x0? - row upper bound does not exist or is redundant;
|
alpar@9
|
2276 *
|
alpar@9
|
2277 * 0x1? - row upper bound can be active;
|
alpar@9
|
2278 *
|
alpar@9
|
2279 * 0x2? - row upper bound is a forcing bound;
|
alpar@9
|
2280 *
|
alpar@9
|
2281 * 0x33 - row bounds are inconsistent with column bounds.
|
alpar@9
|
2282 *
|
alpar@9
|
2283 * ALGORITHM
|
alpar@9
|
2284 *
|
alpar@9
|
2285 * Analysis of row (1) is based on analysis of its implied lower and
|
alpar@9
|
2286 * upper bounds, which are determined by bounds of corresponding columns
|
alpar@9
|
2287 * (variables) as follows:
|
alpar@9
|
2288 *
|
alpar@9
|
2289 * L'[p] = inf sum a[p,j] x[j] =
|
alpar@9
|
2290 * j
|
alpar@9
|
2291 * (3)
|
alpar@9
|
2292 * = sum a[p,j] l[j] + sum a[p,j] u[j],
|
alpar@9
|
2293 * j in Jp j in Jn
|
alpar@9
|
2294 *
|
alpar@9
|
2295 * U'[p] = sup sum a[p,j] x[j] =
|
alpar@9
|
2296 * (4)
|
alpar@9
|
2297 * = sum a[p,j] u[j] + sum a[p,j] l[j],
|
alpar@9
|
2298 * j in Jp j in Jn
|
alpar@9
|
2299 *
|
alpar@9
|
2300 * Jp = {j: a[p,j] > 0}, Jn = {j: a[p,j] < 0}. (5)
|
alpar@9
|
2301 *
|
alpar@9
|
2302 * (Note that bounds of all columns in row p are assumed to be correct,
|
alpar@9
|
2303 * so L'[p] <= U'[p].)
|
alpar@9
|
2304 *
|
alpar@9
|
2305 * Analysis of row lower bound L[p] includes the following cases:
|
alpar@9
|
2306 *
|
alpar@9
|
2307 * 1) if L[p] > U'[p] + eps, where eps is an absolute tolerance for row
|
alpar@9
|
2308 * value, row lower bound L[p] and implied row upper bound U'[p] are
|
alpar@9
|
2309 * inconsistent, ergo, the problem has no primal feasible solution;
|
alpar@9
|
2310 *
|
alpar@9
|
2311 * 2) if U'[p] - eps <= L[p] <= U'[p] + eps, i.e. if L[p] =~ U'[p],
|
alpar@9
|
2312 * the row is a forcing row on its lower bound (see description of
|
alpar@9
|
2313 * the routine npp_forcing_row);
|
alpar@9
|
2314 *
|
alpar@9
|
2315 * 3) if L[p] > L'[p] + eps, row lower bound L[p] can be active (this
|
alpar@9
|
2316 * conclusion does not account other rows in the problem);
|
alpar@9
|
2317 *
|
alpar@9
|
2318 * 4) if L[p] <= L'[p] + eps, row lower bound L[p] cannot be active, so
|
alpar@9
|
2319 * it is redundant and can be removed (replaced by -oo).
|
alpar@9
|
2320 *
|
alpar@9
|
2321 * Analysis of row upper bound U[p] is performed in a similar way and
|
alpar@9
|
2322 * includes the following cases:
|
alpar@9
|
2323 *
|
alpar@9
|
2324 * 1) if U[p] < L'[p] - eps, row upper bound U[p] and implied row lower
|
alpar@9
|
2325 * bound L'[p] are inconsistent, ergo the problem has no primal
|
alpar@9
|
2326 * feasible solution;
|
alpar@9
|
2327 *
|
alpar@9
|
2328 * 2) if L'[p] - eps <= U[p] <= L'[p] + eps, i.e. if U[p] =~ L'[p],
|
alpar@9
|
2329 * the row is a forcing row on its upper bound (see description of
|
alpar@9
|
2330 * the routine npp_forcing_row);
|
alpar@9
|
2331 *
|
alpar@9
|
2332 * 3) if U[p] < U'[p] - eps, row upper bound U[p] can be active (this
|
alpar@9
|
2333 * conclusion does not account other rows in the problem);
|
alpar@9
|
2334 *
|
alpar@9
|
2335 * 4) if U[p] >= U'[p] - eps, row upper bound U[p] cannot be active, so
|
alpar@9
|
2336 * it is redundant and can be removed (replaced by +oo). */
|
alpar@9
|
2337
|
alpar@9
|
2338 int npp_analyze_row(NPP *npp, NPPROW *p)
|
alpar@9
|
2339 { /* perform general row analysis */
|
alpar@9
|
2340 NPPAIJ *aij;
|
alpar@9
|
2341 int ret = 0x00;
|
alpar@9
|
2342 double l, u, eps;
|
alpar@9
|
2343 xassert(npp == npp);
|
alpar@9
|
2344 /* compute implied lower bound L'[p]; see (3) */
|
alpar@9
|
2345 l = 0.0;
|
alpar@9
|
2346 for (aij = p->ptr; aij != NULL; aij = aij->r_next)
|
alpar@9
|
2347 { if (aij->val > 0.0)
|
alpar@9
|
2348 { if (aij->col->lb == -DBL_MAX)
|
alpar@9
|
2349 { l = -DBL_MAX;
|
alpar@9
|
2350 break;
|
alpar@9
|
2351 }
|
alpar@9
|
2352 l += aij->val * aij->col->lb;
|
alpar@9
|
2353 }
|
alpar@9
|
2354 else /* aij->val < 0.0 */
|
alpar@9
|
2355 { if (aij->col->ub == +DBL_MAX)
|
alpar@9
|
2356 { l = -DBL_MAX;
|
alpar@9
|
2357 break;
|
alpar@9
|
2358 }
|
alpar@9
|
2359 l += aij->val * aij->col->ub;
|
alpar@9
|
2360 }
|
alpar@9
|
2361 }
|
alpar@9
|
2362 /* compute implied upper bound U'[p]; see (4) */
|
alpar@9
|
2363 u = 0.0;
|
alpar@9
|
2364 for (aij = p->ptr; aij != NULL; aij = aij->r_next)
|
alpar@9
|
2365 { if (aij->val > 0.0)
|
alpar@9
|
2366 { if (aij->col->ub == +DBL_MAX)
|
alpar@9
|
2367 { u = +DBL_MAX;
|
alpar@9
|
2368 break;
|
alpar@9
|
2369 }
|
alpar@9
|
2370 u += aij->val * aij->col->ub;
|
alpar@9
|
2371 }
|
alpar@9
|
2372 else /* aij->val < 0.0 */
|
alpar@9
|
2373 { if (aij->col->lb == -DBL_MAX)
|
alpar@9
|
2374 { u = +DBL_MAX;
|
alpar@9
|
2375 break;
|
alpar@9
|
2376 }
|
alpar@9
|
2377 u += aij->val * aij->col->lb;
|
alpar@9
|
2378 }
|
alpar@9
|
2379 }
|
alpar@9
|
2380 /* column bounds are assumed correct, so L'[p] <= U'[p] */
|
alpar@9
|
2381 /* check if row lower bound is consistent */
|
alpar@9
|
2382 if (p->lb != -DBL_MAX)
|
alpar@9
|
2383 { eps = 1e-3 + 1e-6 * fabs(p->lb);
|
alpar@9
|
2384 if (p->lb - eps > u)
|
alpar@9
|
2385 { ret = 0x33;
|
alpar@9
|
2386 goto done;
|
alpar@9
|
2387 }
|
alpar@9
|
2388 }
|
alpar@9
|
2389 /* check if row upper bound is consistent */
|
alpar@9
|
2390 if (p->ub != +DBL_MAX)
|
alpar@9
|
2391 { eps = 1e-3 + 1e-6 * fabs(p->ub);
|
alpar@9
|
2392 if (p->ub + eps < l)
|
alpar@9
|
2393 { ret = 0x33;
|
alpar@9
|
2394 goto done;
|
alpar@9
|
2395 }
|
alpar@9
|
2396 }
|
alpar@9
|
2397 /* check if row lower bound can be active/forcing */
|
alpar@9
|
2398 if (p->lb != -DBL_MAX)
|
alpar@9
|
2399 { eps = 1e-9 + 1e-12 * fabs(p->lb);
|
alpar@9
|
2400 if (p->lb - eps > l)
|
alpar@9
|
2401 { if (p->lb + eps <= u)
|
alpar@9
|
2402 ret |= 0x01;
|
alpar@9
|
2403 else
|
alpar@9
|
2404 ret |= 0x02;
|
alpar@9
|
2405 }
|
alpar@9
|
2406 }
|
alpar@9
|
2407 /* check if row upper bound can be active/forcing */
|
alpar@9
|
2408 if (p->ub != +DBL_MAX)
|
alpar@9
|
2409 { eps = 1e-9 + 1e-12 * fabs(p->ub);
|
alpar@9
|
2410 if (p->ub + eps < u)
|
alpar@9
|
2411 { /* check if the upper bound is forcing */
|
alpar@9
|
2412 if (p->ub - eps >= l)
|
alpar@9
|
2413 ret |= 0x10;
|
alpar@9
|
2414 else
|
alpar@9
|
2415 ret |= 0x20;
|
alpar@9
|
2416 }
|
alpar@9
|
2417 }
|
alpar@9
|
2418 done: return ret;
|
alpar@9
|
2419 }
|
alpar@9
|
2420
|
alpar@9
|
2421 /***********************************************************************
|
alpar@9
|
2422 * NAME
|
alpar@9
|
2423 *
|
alpar@9
|
2424 * npp_inactive_bound - remove row lower/upper inactive bound
|
alpar@9
|
2425 *
|
alpar@9
|
2426 * SYNOPSIS
|
alpar@9
|
2427 *
|
alpar@9
|
2428 * #include "glpnpp.h"
|
alpar@9
|
2429 * void npp_inactive_bound(NPP *npp, NPPROW *p, int which);
|
alpar@9
|
2430 *
|
alpar@9
|
2431 * DESCRIPTION
|
alpar@9
|
2432 *
|
alpar@9
|
2433 * The routine npp_inactive_bound removes lower (if which = 0) or upper
|
alpar@9
|
2434 * (if which = 1) bound of row p:
|
alpar@9
|
2435 *
|
alpar@9
|
2436 * L[p] <= sum a[p,j] x[j] <= U[p],
|
alpar@9
|
2437 *
|
alpar@9
|
2438 * which (bound) is assumed to be redundant.
|
alpar@9
|
2439 *
|
alpar@9
|
2440 * PROBLEM TRANSFORMATION
|
alpar@9
|
2441 *
|
alpar@9
|
2442 * If which = 0, current lower bound L[p] of row p is assigned -oo.
|
alpar@9
|
2443 * If which = 1, current upper bound U[p] of row p is assigned +oo.
|
alpar@9
|
2444 *
|
alpar@9
|
2445 * RECOVERING BASIC SOLUTION
|
alpar@9
|
2446 *
|
alpar@9
|
2447 * If in solution to the transformed problem row p is inactive
|
alpar@9
|
2448 * constraint (GLP_BS), its status is not changed in solution to the
|
alpar@9
|
2449 * original problem. Otherwise, status of row p in solution to the
|
alpar@9
|
2450 * original problem is defined by its type before transformation and
|
alpar@9
|
2451 * its status in solution to the transformed problem as follows:
|
alpar@9
|
2452 *
|
alpar@9
|
2453 * +---------------------+-------+---------------+---------------+
|
alpar@9
|
2454 * | Row | Flag | Row status in | Row status in |
|
alpar@9
|
2455 * | type | which | transfmd soln | original soln |
|
alpar@9
|
2456 * +---------------------+-------+---------------+---------------+
|
alpar@9
|
2457 * | sum >= L[p] | 0 | GLP_NF | GLP_NL |
|
alpar@9
|
2458 * | sum <= U[p] | 1 | GLP_NF | GLP_NU |
|
alpar@9
|
2459 * | L[p] <= sum <= U[p] | 0 | GLP_NU | GLP_NU |
|
alpar@9
|
2460 * | L[p] <= sum <= U[p] | 1 | GLP_NL | GLP_NL |
|
alpar@9
|
2461 * | sum = L[p] = U[p] | 0 | GLP_NU | GLP_NS |
|
alpar@9
|
2462 * | sum = L[p] = U[p] | 1 | GLP_NL | GLP_NS |
|
alpar@9
|
2463 * +---------------------+-------+---------------+---------------+
|
alpar@9
|
2464 *
|
alpar@9
|
2465 * RECOVERING INTERIOR-POINT SOLUTION
|
alpar@9
|
2466 *
|
alpar@9
|
2467 * None needed.
|
alpar@9
|
2468 *
|
alpar@9
|
2469 * RECOVERING MIP SOLUTION
|
alpar@9
|
2470 *
|
alpar@9
|
2471 * None needed. */
|
alpar@9
|
2472
|
alpar@9
|
2473 struct inactive_bound
|
alpar@9
|
2474 { /* row inactive bound */
|
alpar@9
|
2475 int p;
|
alpar@9
|
2476 /* row reference number */
|
alpar@9
|
2477 char stat;
|
alpar@9
|
2478 /* row status (if active constraint) */
|
alpar@9
|
2479 };
|
alpar@9
|
2480
|
alpar@9
|
2481 static int rcv_inactive_bound(NPP *npp, void *info);
|
alpar@9
|
2482
|
alpar@9
|
2483 void npp_inactive_bound(NPP *npp, NPPROW *p, int which)
|
alpar@9
|
2484 { /* remove row lower/upper inactive bound */
|
alpar@9
|
2485 struct inactive_bound *info;
|
alpar@9
|
2486 if (npp->sol == GLP_SOL)
|
alpar@9
|
2487 { /* create transformation stack entry */
|
alpar@9
|
2488 info = npp_push_tse(npp,
|
alpar@9
|
2489 rcv_inactive_bound, sizeof(struct inactive_bound));
|
alpar@9
|
2490 info->p = p->i;
|
alpar@9
|
2491 if (p->ub == +DBL_MAX)
|
alpar@9
|
2492 info->stat = GLP_NL;
|
alpar@9
|
2493 else if (p->lb == -DBL_MAX)
|
alpar@9
|
2494 info->stat = GLP_NU;
|
alpar@9
|
2495 else if (p->lb != p->ub)
|
alpar@9
|
2496 info->stat = (char)(which == 0 ? GLP_NU : GLP_NL);
|
alpar@9
|
2497 else
|
alpar@9
|
2498 info->stat = GLP_NS;
|
alpar@9
|
2499 }
|
alpar@9
|
2500 /* remove row inactive bound */
|
alpar@9
|
2501 if (which == 0)
|
alpar@9
|
2502 { xassert(p->lb != -DBL_MAX);
|
alpar@9
|
2503 p->lb = -DBL_MAX;
|
alpar@9
|
2504 }
|
alpar@9
|
2505 else if (which == 1)
|
alpar@9
|
2506 { xassert(p->ub != +DBL_MAX);
|
alpar@9
|
2507 p->ub = +DBL_MAX;
|
alpar@9
|
2508 }
|
alpar@9
|
2509 else
|
alpar@9
|
2510 xassert(which != which);
|
alpar@9
|
2511 return;
|
alpar@9
|
2512 }
|
alpar@9
|
2513
|
alpar@9
|
2514 static int rcv_inactive_bound(NPP *npp, void *_info)
|
alpar@9
|
2515 { /* recover row status */
|
alpar@9
|
2516 struct inactive_bound *info = _info;
|
alpar@9
|
2517 if (npp->sol != GLP_SOL)
|
alpar@9
|
2518 { npp_error();
|
alpar@9
|
2519 return 1;
|
alpar@9
|
2520 }
|
alpar@9
|
2521 if (npp->r_stat[info->p] == GLP_BS)
|
alpar@9
|
2522 npp->r_stat[info->p] = GLP_BS;
|
alpar@9
|
2523 else
|
alpar@9
|
2524 npp->r_stat[info->p] = info->stat;
|
alpar@9
|
2525 return 0;
|
alpar@9
|
2526 }
|
alpar@9
|
2527
|
alpar@9
|
2528 /***********************************************************************
|
alpar@9
|
2529 * NAME
|
alpar@9
|
2530 *
|
alpar@9
|
2531 * npp_implied_bounds - determine implied column bounds
|
alpar@9
|
2532 *
|
alpar@9
|
2533 * SYNOPSIS
|
alpar@9
|
2534 *
|
alpar@9
|
2535 * #include "glpnpp.h"
|
alpar@9
|
2536 * void npp_implied_bounds(NPP *npp, NPPROW *p);
|
alpar@9
|
2537 *
|
alpar@9
|
2538 * DESCRIPTION
|
alpar@9
|
2539 *
|
alpar@9
|
2540 * The routine npp_implied_bounds inspects general row (constraint) p:
|
alpar@9
|
2541 *
|
alpar@9
|
2542 * L[p] <= sum a[p,j] x[j] <= U[p], (1)
|
alpar@9
|
2543 *
|
alpar@9
|
2544 * l[j] <= x[j] <= u[j], (2)
|
alpar@9
|
2545 *
|
alpar@9
|
2546 * where L[p] <= U[p] and l[j] <= u[j] for all a[p,j] != 0, to compute
|
alpar@9
|
2547 * implied bounds of columns (variables x[j]) in this row.
|
alpar@9
|
2548 *
|
alpar@9
|
2549 * The routine stores implied column bounds l'[j] and u'[j] in column
|
alpar@9
|
2550 * descriptors (NPPCOL); it does not change current column bounds l[j]
|
alpar@9
|
2551 * and u[j]. (Implied column bounds can be then used to strengthen the
|
alpar@9
|
2552 * current column bounds; see the routines npp_implied_lower and
|
alpar@9
|
2553 * npp_implied_upper).
|
alpar@9
|
2554 *
|
alpar@9
|
2555 * ALGORITHM
|
alpar@9
|
2556 *
|
alpar@9
|
2557 * Current column bounds (2) define implied lower and upper bounds of
|
alpar@9
|
2558 * row (1) as follows:
|
alpar@9
|
2559 *
|
alpar@9
|
2560 * L'[p] = inf sum a[p,j] x[j] =
|
alpar@9
|
2561 * j
|
alpar@9
|
2562 * (3)
|
alpar@9
|
2563 * = sum a[p,j] l[j] + sum a[p,j] u[j],
|
alpar@9
|
2564 * j in Jp j in Jn
|
alpar@9
|
2565 *
|
alpar@9
|
2566 * U'[p] = sup sum a[p,j] x[j] =
|
alpar@9
|
2567 * (4)
|
alpar@9
|
2568 * = sum a[p,j] u[j] + sum a[p,j] l[j],
|
alpar@9
|
2569 * j in Jp j in Jn
|
alpar@9
|
2570 *
|
alpar@9
|
2571 * Jp = {j: a[p,j] > 0}, Jn = {j: a[p,j] < 0}. (5)
|
alpar@9
|
2572 *
|
alpar@9
|
2573 * (Note that bounds of all columns in row p are assumed to be correct,
|
alpar@9
|
2574 * so L'[p] <= U'[p].)
|
alpar@9
|
2575 *
|
alpar@9
|
2576 * If L[p] > L'[p] and/or U[p] < U'[p], the lower and/or upper bound of
|
alpar@9
|
2577 * row (1) can be active, in which case such row defines implied bounds
|
alpar@9
|
2578 * of its variables.
|
alpar@9
|
2579 *
|
alpar@9
|
2580 * Let x[k] be some variable having in row (1) coefficient a[p,k] != 0.
|
alpar@9
|
2581 * Consider a case when row lower bound can be active (L[p] > L'[p]):
|
alpar@9
|
2582 *
|
alpar@9
|
2583 * sum a[p,j] x[j] >= L[p] ==>
|
alpar@9
|
2584 * j
|
alpar@9
|
2585 *
|
alpar@9
|
2586 * sum a[p,j] x[j] + a[p,k] x[k] >= L[p] ==>
|
alpar@9
|
2587 * j!=k
|
alpar@9
|
2588 * (6)
|
alpar@9
|
2589 * a[p,k] x[k] >= L[p] - sum a[p,j] x[j] ==>
|
alpar@9
|
2590 * j!=k
|
alpar@9
|
2591 *
|
alpar@9
|
2592 * a[p,k] x[k] >= L[p,k],
|
alpar@9
|
2593 *
|
alpar@9
|
2594 * where
|
alpar@9
|
2595 *
|
alpar@9
|
2596 * L[p,k] = inf(L[p] - sum a[p,j] x[j]) =
|
alpar@9
|
2597 * j!=k
|
alpar@9
|
2598 *
|
alpar@9
|
2599 * = L[p] - sup sum a[p,j] x[j] = (7)
|
alpar@9
|
2600 * j!=k
|
alpar@9
|
2601 *
|
alpar@9
|
2602 * = L[p] - sum a[p,j] u[j] - sum a[p,j] l[j].
|
alpar@9
|
2603 * j in Jp\{k} j in Jn\{k}
|
alpar@9
|
2604 *
|
alpar@9
|
2605 * Thus:
|
alpar@9
|
2606 *
|
alpar@9
|
2607 * x[k] >= l'[k] = L[p,k] / a[p,k], if a[p,k] > 0, (8)
|
alpar@9
|
2608 *
|
alpar@9
|
2609 * x[k] <= u'[k] = L[p,k] / a[p,k], if a[p,k] < 0. (9)
|
alpar@9
|
2610 *
|
alpar@9
|
2611 * where l'[k] and u'[k] are implied lower and upper bounds of variable
|
alpar@9
|
2612 * x[k], resp.
|
alpar@9
|
2613 *
|
alpar@9
|
2614 * Now consider a similar case when row upper bound can be active
|
alpar@9
|
2615 * (U[p] < U'[p]):
|
alpar@9
|
2616 *
|
alpar@9
|
2617 * sum a[p,j] x[j] <= U[p] ==>
|
alpar@9
|
2618 * j
|
alpar@9
|
2619 *
|
alpar@9
|
2620 * sum a[p,j] x[j] + a[p,k] x[k] <= U[p] ==>
|
alpar@9
|
2621 * j!=k
|
alpar@9
|
2622 * (10)
|
alpar@9
|
2623 * a[p,k] x[k] <= U[p] - sum a[p,j] x[j] ==>
|
alpar@9
|
2624 * j!=k
|
alpar@9
|
2625 *
|
alpar@9
|
2626 * a[p,k] x[k] <= U[p,k],
|
alpar@9
|
2627 *
|
alpar@9
|
2628 * where:
|
alpar@9
|
2629 *
|
alpar@9
|
2630 * U[p,k] = sup(U[p] - sum a[p,j] x[j]) =
|
alpar@9
|
2631 * j!=k
|
alpar@9
|
2632 *
|
alpar@9
|
2633 * = U[p] - inf sum a[p,j] x[j] = (11)
|
alpar@9
|
2634 * j!=k
|
alpar@9
|
2635 *
|
alpar@9
|
2636 * = U[p] - sum a[p,j] l[j] - sum a[p,j] u[j].
|
alpar@9
|
2637 * j in Jp\{k} j in Jn\{k}
|
alpar@9
|
2638 *
|
alpar@9
|
2639 * Thus:
|
alpar@9
|
2640 *
|
alpar@9
|
2641 * x[k] <= u'[k] = U[p,k] / a[p,k], if a[p,k] > 0, (12)
|
alpar@9
|
2642 *
|
alpar@9
|
2643 * x[k] >= l'[k] = U[p,k] / a[p,k], if a[p,k] < 0. (13)
|
alpar@9
|
2644 *
|
alpar@9
|
2645 * Note that in formulae (8), (9), (12), and (13) coefficient a[p,k]
|
alpar@9
|
2646 * must not be too small in magnitude relatively to other non-zero
|
alpar@9
|
2647 * coefficients in row (1), i.e. the following condition must hold:
|
alpar@9
|
2648 *
|
alpar@9
|
2649 * |a[p,k]| >= eps * max(1, |a[p,j]|), (14)
|
alpar@9
|
2650 * j
|
alpar@9
|
2651 *
|
alpar@9
|
2652 * where eps is a relative tolerance for constraint coefficients.
|
alpar@9
|
2653 * Otherwise the implied column bounds can be numerical inreliable. For
|
alpar@9
|
2654 * example, using formula (8) for the following inequality constraint:
|
alpar@9
|
2655 *
|
alpar@9
|
2656 * 1e-12 x1 - x2 - x3 >= 0,
|
alpar@9
|
2657 *
|
alpar@9
|
2658 * where x1 >= -1, x2, x3, >= 0, may lead to numerically unreliable
|
alpar@9
|
2659 * conclusion that x1 >= 0.
|
alpar@9
|
2660 *
|
alpar@9
|
2661 * Using formulae (8), (9), (12), and (13) to compute implied bounds
|
alpar@9
|
2662 * for one variable requires |J| operations, where J = {j: a[p,j] != 0},
|
alpar@9
|
2663 * because this needs computing L[p,k] and U[p,k]. Thus, computing
|
alpar@9
|
2664 * implied bounds for all variables in row (1) would require |J|^2
|
alpar@9
|
2665 * operations, that is not a good technique. However, the total number
|
alpar@9
|
2666 * of operations can be reduced to |J| as follows.
|
alpar@9
|
2667 *
|
alpar@9
|
2668 * Let a[p,k] > 0. Then from (7) and (11) we have:
|
alpar@9
|
2669 *
|
alpar@9
|
2670 * L[p,k] = L[p] - (U'[p] - a[p,k] u[k]) =
|
alpar@9
|
2671 *
|
alpar@9
|
2672 * = L[p] - U'[p] + a[p,k] u[k],
|
alpar@9
|
2673 *
|
alpar@9
|
2674 * U[p,k] = U[p] - (L'[p] - a[p,k] l[k]) =
|
alpar@9
|
2675 *
|
alpar@9
|
2676 * = U[p] - L'[p] + a[p,k] l[k],
|
alpar@9
|
2677 *
|
alpar@9
|
2678 * where L'[p] and U'[p] are implied row lower and upper bounds defined
|
alpar@9
|
2679 * by formulae (3) and (4). Substituting these expressions into (8) and
|
alpar@9
|
2680 * (12) gives:
|
alpar@9
|
2681 *
|
alpar@9
|
2682 * l'[k] = L[p,k] / a[p,k] = u[k] + (L[p] - U'[p]) / a[p,k], (15)
|
alpar@9
|
2683 *
|
alpar@9
|
2684 * u'[k] = U[p,k] / a[p,k] = l[k] + (U[p] - L'[p]) / a[p,k]. (16)
|
alpar@9
|
2685 *
|
alpar@9
|
2686 * Similarly, if a[p,k] < 0, according to (7) and (11) we have:
|
alpar@9
|
2687 *
|
alpar@9
|
2688 * L[p,k] = L[p] - (U'[p] - a[p,k] l[k]) =
|
alpar@9
|
2689 *
|
alpar@9
|
2690 * = L[p] - U'[p] + a[p,k] l[k],
|
alpar@9
|
2691 *
|
alpar@9
|
2692 * U[p,k] = U[p] - (L'[p] - a[p,k] u[k]) =
|
alpar@9
|
2693 *
|
alpar@9
|
2694 * = U[p] - L'[p] + a[p,k] u[k],
|
alpar@9
|
2695 *
|
alpar@9
|
2696 * and substituting these expressions into (8) and (12) gives:
|
alpar@9
|
2697 *
|
alpar@9
|
2698 * l'[k] = U[p,k] / a[p,k] = u[k] + (U[p] - L'[p]) / a[p,k], (17)
|
alpar@9
|
2699 *
|
alpar@9
|
2700 * u'[k] = L[p,k] / a[p,k] = l[k] + (L[p] - U'[p]) / a[p,k]. (18)
|
alpar@9
|
2701 *
|
alpar@9
|
2702 * Note that formulae (15)-(18) can be used only if L'[p] and U'[p]
|
alpar@9
|
2703 * exist. However, if for some variable x[j] it happens that l[j] = -oo
|
alpar@9
|
2704 * and/or u[j] = +oo, values of L'[p] (if a[p,j] > 0) and/or U'[p] (if
|
alpar@9
|
2705 * a[p,j] < 0) are undefined. Consider, therefore, the most general
|
alpar@9
|
2706 * situation, when some column bounds (2) may not exist.
|
alpar@9
|
2707 *
|
alpar@9
|
2708 * Let:
|
alpar@9
|
2709 *
|
alpar@9
|
2710 * J' = {j : (a[p,j] > 0 and l[j] = -oo) or
|
alpar@9
|
2711 * (19)
|
alpar@9
|
2712 * (a[p,j] < 0 and u[j] = +oo)}.
|
alpar@9
|
2713 *
|
alpar@9
|
2714 * Then (assuming that row upper bound U[p] can be active) the following
|
alpar@9
|
2715 * three cases are possible:
|
alpar@9
|
2716 *
|
alpar@9
|
2717 * 1) |J'| = 0. In this case L'[p] exists, thus, for all variables x[j]
|
alpar@9
|
2718 * in row (1) we can use formulae (16) and (17);
|
alpar@9
|
2719 *
|
alpar@9
|
2720 * 2) J' = {k}. In this case L'[p] = -oo, however, U[p,k] (11) exists,
|
alpar@9
|
2721 * so for variable x[k] we can use formulae (12) and (13). Note that
|
alpar@9
|
2722 * for all other variables x[j] (j != k) l'[j] = -oo (if a[p,j] < 0)
|
alpar@9
|
2723 * or u'[j] = +oo (if a[p,j] > 0);
|
alpar@9
|
2724 *
|
alpar@9
|
2725 * 3) |J'| > 1. In this case for all variables x[j] in row [1] we have
|
alpar@9
|
2726 * l'[j] = -oo (if a[p,j] < 0) or u'[j] = +oo (if a[p,j] > 0).
|
alpar@9
|
2727 *
|
alpar@9
|
2728 * Similarly, let:
|
alpar@9
|
2729 *
|
alpar@9
|
2730 * J'' = {j : (a[p,j] > 0 and u[j] = +oo) or
|
alpar@9
|
2731 * (20)
|
alpar@9
|
2732 * (a[p,j] < 0 and l[j] = -oo)}.
|
alpar@9
|
2733 *
|
alpar@9
|
2734 * Then (assuming that row lower bound L[p] can be active) the following
|
alpar@9
|
2735 * three cases are possible:
|
alpar@9
|
2736 *
|
alpar@9
|
2737 * 1) |J''| = 0. In this case U'[p] exists, thus, for all variables x[j]
|
alpar@9
|
2738 * in row (1) we can use formulae (15) and (18);
|
alpar@9
|
2739 *
|
alpar@9
|
2740 * 2) J'' = {k}. In this case U'[p] = +oo, however, L[p,k] (7) exists,
|
alpar@9
|
2741 * so for variable x[k] we can use formulae (8) and (9). Note that
|
alpar@9
|
2742 * for all other variables x[j] (j != k) l'[j] = -oo (if a[p,j] > 0)
|
alpar@9
|
2743 * or u'[j] = +oo (if a[p,j] < 0);
|
alpar@9
|
2744 *
|
alpar@9
|
2745 * 3) |J''| > 1. In this case for all variables x[j] in row (1) we have
|
alpar@9
|
2746 * l'[j] = -oo (if a[p,j] > 0) or u'[j] = +oo (if a[p,j] < 0). */
|
alpar@9
|
2747
|
alpar@9
|
2748 void npp_implied_bounds(NPP *npp, NPPROW *p)
|
alpar@9
|
2749 { NPPAIJ *apj, *apk;
|
alpar@9
|
2750 double big, eps, temp;
|
alpar@9
|
2751 xassert(npp == npp);
|
alpar@9
|
2752 /* initialize implied bounds for all variables and determine
|
alpar@9
|
2753 maximal magnitude of row coefficients a[p,j] */
|
alpar@9
|
2754 big = 1.0;
|
alpar@9
|
2755 for (apj = p->ptr; apj != NULL; apj = apj->r_next)
|
alpar@9
|
2756 { apj->col->ll.ll = -DBL_MAX, apj->col->uu.uu = +DBL_MAX;
|
alpar@9
|
2757 if (big < fabs(apj->val)) big = fabs(apj->val);
|
alpar@9
|
2758 }
|
alpar@9
|
2759 eps = 1e-6 * big;
|
alpar@9
|
2760 /* process row lower bound (assuming that it can be active) */
|
alpar@9
|
2761 if (p->lb != -DBL_MAX)
|
alpar@9
|
2762 { apk = NULL;
|
alpar@9
|
2763 for (apj = p->ptr; apj != NULL; apj = apj->r_next)
|
alpar@9
|
2764 { if (apj->val > 0.0 && apj->col->ub == +DBL_MAX ||
|
alpar@9
|
2765 apj->val < 0.0 && apj->col->lb == -DBL_MAX)
|
alpar@9
|
2766 { if (apk == NULL)
|
alpar@9
|
2767 apk = apj;
|
alpar@9
|
2768 else
|
alpar@9
|
2769 goto skip1;
|
alpar@9
|
2770 }
|
alpar@9
|
2771 }
|
alpar@9
|
2772 /* if a[p,k] = NULL then |J'| = 0 else J' = { k } */
|
alpar@9
|
2773 temp = p->lb;
|
alpar@9
|
2774 for (apj = p->ptr; apj != NULL; apj = apj->r_next)
|
alpar@9
|
2775 { if (apj == apk)
|
alpar@9
|
2776 /* skip a[p,k] */;
|
alpar@9
|
2777 else if (apj->val > 0.0)
|
alpar@9
|
2778 temp -= apj->val * apj->col->ub;
|
alpar@9
|
2779 else /* apj->val < 0.0 */
|
alpar@9
|
2780 temp -= apj->val * apj->col->lb;
|
alpar@9
|
2781 }
|
alpar@9
|
2782 /* compute column implied bounds */
|
alpar@9
|
2783 if (apk == NULL)
|
alpar@9
|
2784 { /* temp = L[p] - U'[p] */
|
alpar@9
|
2785 for (apj = p->ptr; apj != NULL; apj = apj->r_next)
|
alpar@9
|
2786 { if (apj->val >= +eps)
|
alpar@9
|
2787 { /* l'[j] := u[j] + (L[p] - U'[p]) / a[p,j] */
|
alpar@9
|
2788 apj->col->ll.ll = apj->col->ub + temp / apj->val;
|
alpar@9
|
2789 }
|
alpar@9
|
2790 else if (apj->val <= -eps)
|
alpar@9
|
2791 { /* u'[j] := l[j] + (L[p] - U'[p]) / a[p,j] */
|
alpar@9
|
2792 apj->col->uu.uu = apj->col->lb + temp / apj->val;
|
alpar@9
|
2793 }
|
alpar@9
|
2794 }
|
alpar@9
|
2795 }
|
alpar@9
|
2796 else
|
alpar@9
|
2797 { /* temp = L[p,k] */
|
alpar@9
|
2798 if (apk->val >= +eps)
|
alpar@9
|
2799 { /* l'[k] := L[p,k] / a[p,k] */
|
alpar@9
|
2800 apk->col->ll.ll = temp / apk->val;
|
alpar@9
|
2801 }
|
alpar@9
|
2802 else if (apk->val <= -eps)
|
alpar@9
|
2803 { /* u'[k] := L[p,k] / a[p,k] */
|
alpar@9
|
2804 apk->col->uu.uu = temp / apk->val;
|
alpar@9
|
2805 }
|
alpar@9
|
2806 }
|
alpar@9
|
2807 skip1: ;
|
alpar@9
|
2808 }
|
alpar@9
|
2809 /* process row upper bound (assuming that it can be active) */
|
alpar@9
|
2810 if (p->ub != +DBL_MAX)
|
alpar@9
|
2811 { apk = NULL;
|
alpar@9
|
2812 for (apj = p->ptr; apj != NULL; apj = apj->r_next)
|
alpar@9
|
2813 { if (apj->val > 0.0 && apj->col->lb == -DBL_MAX ||
|
alpar@9
|
2814 apj->val < 0.0 && apj->col->ub == +DBL_MAX)
|
alpar@9
|
2815 { if (apk == NULL)
|
alpar@9
|
2816 apk = apj;
|
alpar@9
|
2817 else
|
alpar@9
|
2818 goto skip2;
|
alpar@9
|
2819 }
|
alpar@9
|
2820 }
|
alpar@9
|
2821 /* if a[p,k] = NULL then |J''| = 0 else J'' = { k } */
|
alpar@9
|
2822 temp = p->ub;
|
alpar@9
|
2823 for (apj = p->ptr; apj != NULL; apj = apj->r_next)
|
alpar@9
|
2824 { if (apj == apk)
|
alpar@9
|
2825 /* skip a[p,k] */;
|
alpar@9
|
2826 else if (apj->val > 0.0)
|
alpar@9
|
2827 temp -= apj->val * apj->col->lb;
|
alpar@9
|
2828 else /* apj->val < 0.0 */
|
alpar@9
|
2829 temp -= apj->val * apj->col->ub;
|
alpar@9
|
2830 }
|
alpar@9
|
2831 /* compute column implied bounds */
|
alpar@9
|
2832 if (apk == NULL)
|
alpar@9
|
2833 { /* temp = U[p] - L'[p] */
|
alpar@9
|
2834 for (apj = p->ptr; apj != NULL; apj = apj->r_next)
|
alpar@9
|
2835 { if (apj->val >= +eps)
|
alpar@9
|
2836 { /* u'[j] := l[j] + (U[p] - L'[p]) / a[p,j] */
|
alpar@9
|
2837 apj->col->uu.uu = apj->col->lb + temp / apj->val;
|
alpar@9
|
2838 }
|
alpar@9
|
2839 else if (apj->val <= -eps)
|
alpar@9
|
2840 { /* l'[j] := u[j] + (U[p] - L'[p]) / a[p,j] */
|
alpar@9
|
2841 apj->col->ll.ll = apj->col->ub + temp / apj->val;
|
alpar@9
|
2842 }
|
alpar@9
|
2843 }
|
alpar@9
|
2844 }
|
alpar@9
|
2845 else
|
alpar@9
|
2846 { /* temp = U[p,k] */
|
alpar@9
|
2847 if (apk->val >= +eps)
|
alpar@9
|
2848 { /* u'[k] := U[p,k] / a[p,k] */
|
alpar@9
|
2849 apk->col->uu.uu = temp / apk->val;
|
alpar@9
|
2850 }
|
alpar@9
|
2851 else if (apk->val <= -eps)
|
alpar@9
|
2852 { /* l'[k] := U[p,k] / a[p,k] */
|
alpar@9
|
2853 apk->col->ll.ll = temp / apk->val;
|
alpar@9
|
2854 }
|
alpar@9
|
2855 }
|
alpar@9
|
2856 skip2: ;
|
alpar@9
|
2857 }
|
alpar@9
|
2858 return;
|
alpar@9
|
2859 }
|
alpar@9
|
2860
|
alpar@9
|
2861 /* eof */
|