alpar@1
|
1 |
/* glpnpp02.c */
|
alpar@1
|
2 |
|
alpar@1
|
3 |
/***********************************************************************
|
alpar@1
|
4 |
* This code is part of GLPK (GNU Linear Programming Kit).
|
alpar@1
|
5 |
*
|
alpar@1
|
6 |
* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
|
alpar@1
|
7 |
* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
|
alpar@1
|
8 |
* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
|
alpar@1
|
9 |
* E-mail: <mao@gnu.org>.
|
alpar@1
|
10 |
*
|
alpar@1
|
11 |
* GLPK is free software: you can redistribute it and/or modify it
|
alpar@1
|
12 |
* under the terms of the GNU General Public License as published by
|
alpar@1
|
13 |
* the Free Software Foundation, either version 3 of the License, or
|
alpar@1
|
14 |
* (at your option) any later version.
|
alpar@1
|
15 |
*
|
alpar@1
|
16 |
* GLPK is distributed in the hope that it will be useful, but WITHOUT
|
alpar@1
|
17 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
alpar@1
|
18 |
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
alpar@1
|
19 |
* License for more details.
|
alpar@1
|
20 |
*
|
alpar@1
|
21 |
* You should have received a copy of the GNU General Public License
|
alpar@1
|
22 |
* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
|
alpar@1
|
23 |
***********************************************************************/
|
alpar@1
|
24 |
|
alpar@1
|
25 |
#include "glpnpp.h"
|
alpar@1
|
26 |
|
alpar@1
|
27 |
/***********************************************************************
|
alpar@1
|
28 |
* NAME
|
alpar@1
|
29 |
*
|
alpar@1
|
30 |
* npp_free_row - process free (unbounded) row
|
alpar@1
|
31 |
*
|
alpar@1
|
32 |
* SYNOPSIS
|
alpar@1
|
33 |
*
|
alpar@1
|
34 |
* #include "glpnpp.h"
|
alpar@1
|
35 |
* void npp_free_row(NPP *npp, NPPROW *p);
|
alpar@1
|
36 |
*
|
alpar@1
|
37 |
* DESCRIPTION
|
alpar@1
|
38 |
*
|
alpar@1
|
39 |
* The routine npp_free_row processes row p, which is free (i.e. has
|
alpar@1
|
40 |
* no finite bounds):
|
alpar@1
|
41 |
*
|
alpar@1
|
42 |
* -inf < sum a[p,j] x[j] < +inf. (1)
|
alpar@1
|
43 |
* j
|
alpar@1
|
44 |
*
|
alpar@1
|
45 |
* PROBLEM TRANSFORMATION
|
alpar@1
|
46 |
*
|
alpar@1
|
47 |
* Constraint (1) cannot be active, so it is redundant and can be
|
alpar@1
|
48 |
* removed from the original problem.
|
alpar@1
|
49 |
*
|
alpar@1
|
50 |
* Removing row p leads to removing a column of multiplier pi[p] for
|
alpar@1
|
51 |
* this row in the dual system. Since row p has no bounds, pi[p] = 0,
|
alpar@1
|
52 |
* so removing the column does not affect the dual solution.
|
alpar@1
|
53 |
*
|
alpar@1
|
54 |
* RECOVERING BASIC SOLUTION
|
alpar@1
|
55 |
*
|
alpar@1
|
56 |
* In solution to the original problem row p is inactive constraint,
|
alpar@1
|
57 |
* so it is assigned status GLP_BS, and multiplier pi[p] is assigned
|
alpar@1
|
58 |
* zero value.
|
alpar@1
|
59 |
*
|
alpar@1
|
60 |
* RECOVERING INTERIOR-POINT SOLUTION
|
alpar@1
|
61 |
*
|
alpar@1
|
62 |
* In solution to the original problem row p is inactive constraint,
|
alpar@1
|
63 |
* so its multiplier pi[p] is assigned zero value.
|
alpar@1
|
64 |
*
|
alpar@1
|
65 |
* RECOVERING MIP SOLUTION
|
alpar@1
|
66 |
*
|
alpar@1
|
67 |
* None needed. */
|
alpar@1
|
68 |
|
alpar@1
|
69 |
struct free_row
|
alpar@1
|
70 |
{ /* free (unbounded) row */
|
alpar@1
|
71 |
int p;
|
alpar@1
|
72 |
/* row reference number */
|
alpar@1
|
73 |
};
|
alpar@1
|
74 |
|
alpar@1
|
75 |
static int rcv_free_row(NPP *npp, void *info);
|
alpar@1
|
76 |
|
alpar@1
|
77 |
void npp_free_row(NPP *npp, NPPROW *p)
|
alpar@1
|
78 |
{ /* process free (unbounded) row */
|
alpar@1
|
79 |
struct free_row *info;
|
alpar@1
|
80 |
/* the row must be free */
|
alpar@1
|
81 |
xassert(p->lb == -DBL_MAX && p->ub == +DBL_MAX);
|
alpar@1
|
82 |
/* create transformation stack entry */
|
alpar@1
|
83 |
info = npp_push_tse(npp,
|
alpar@1
|
84 |
rcv_free_row, sizeof(struct free_row));
|
alpar@1
|
85 |
info->p = p->i;
|
alpar@1
|
86 |
/* remove the row from the problem */
|
alpar@1
|
87 |
npp_del_row(npp, p);
|
alpar@1
|
88 |
return;
|
alpar@1
|
89 |
}
|
alpar@1
|
90 |
|
alpar@1
|
91 |
static int rcv_free_row(NPP *npp, void *_info)
|
alpar@1
|
92 |
{ /* recover free (unbounded) row */
|
alpar@1
|
93 |
struct free_row *info = _info;
|
alpar@1
|
94 |
if (npp->sol == GLP_SOL)
|
alpar@1
|
95 |
npp->r_stat[info->p] = GLP_BS;
|
alpar@1
|
96 |
if (npp->sol != GLP_MIP)
|
alpar@1
|
97 |
npp->r_pi[info->p] = 0.0;
|
alpar@1
|
98 |
return 0;
|
alpar@1
|
99 |
}
|
alpar@1
|
100 |
|
alpar@1
|
101 |
/***********************************************************************
|
alpar@1
|
102 |
* NAME
|
alpar@1
|
103 |
*
|
alpar@1
|
104 |
* npp_geq_row - process row of 'not less than' type
|
alpar@1
|
105 |
*
|
alpar@1
|
106 |
* SYNOPSIS
|
alpar@1
|
107 |
*
|
alpar@1
|
108 |
* #include "glpnpp.h"
|
alpar@1
|
109 |
* void npp_geq_row(NPP *npp, NPPROW *p);
|
alpar@1
|
110 |
*
|
alpar@1
|
111 |
* DESCRIPTION
|
alpar@1
|
112 |
*
|
alpar@1
|
113 |
* The routine npp_geq_row processes row p, which is 'not less than'
|
alpar@1
|
114 |
* inequality constraint:
|
alpar@1
|
115 |
*
|
alpar@1
|
116 |
* L[p] <= sum a[p,j] x[j] (<= U[p]), (1)
|
alpar@1
|
117 |
* j
|
alpar@1
|
118 |
*
|
alpar@1
|
119 |
* where L[p] < U[p], and upper bound may not exist (U[p] = +oo).
|
alpar@1
|
120 |
*
|
alpar@1
|
121 |
* PROBLEM TRANSFORMATION
|
alpar@1
|
122 |
*
|
alpar@1
|
123 |
* Constraint (1) can be replaced by equality constraint:
|
alpar@1
|
124 |
*
|
alpar@1
|
125 |
* sum a[p,j] x[j] - s = L[p], (2)
|
alpar@1
|
126 |
* j
|
alpar@1
|
127 |
*
|
alpar@1
|
128 |
* where
|
alpar@1
|
129 |
*
|
alpar@1
|
130 |
* 0 <= s (<= U[p] - L[p]) (3)
|
alpar@1
|
131 |
*
|
alpar@1
|
132 |
* is a non-negative surplus variable.
|
alpar@1
|
133 |
*
|
alpar@1
|
134 |
* Since in the primal system there appears column s having the only
|
alpar@1
|
135 |
* non-zero coefficient in row p, in the dual system there appears a
|
alpar@1
|
136 |
* new row:
|
alpar@1
|
137 |
*
|
alpar@1
|
138 |
* (-1) pi[p] + lambda = 0, (4)
|
alpar@1
|
139 |
*
|
alpar@1
|
140 |
* where (-1) is coefficient of column s in row p, pi[p] is multiplier
|
alpar@1
|
141 |
* of row p, lambda is multiplier of column q, 0 is coefficient of
|
alpar@1
|
142 |
* column s in the objective row.
|
alpar@1
|
143 |
*
|
alpar@1
|
144 |
* RECOVERING BASIC SOLUTION
|
alpar@1
|
145 |
*
|
alpar@1
|
146 |
* Status of row p in solution to the original problem is determined
|
alpar@1
|
147 |
* by its status and status of column q in solution to the transformed
|
alpar@1
|
148 |
* problem as follows:
|
alpar@1
|
149 |
*
|
alpar@1
|
150 |
* +--------------------------------------+------------------+
|
alpar@1
|
151 |
* | Transformed problem | Original problem |
|
alpar@1
|
152 |
* +-----------------+--------------------+------------------+
|
alpar@1
|
153 |
* | Status of row p | Status of column s | Status of row p |
|
alpar@1
|
154 |
* +-----------------+--------------------+------------------+
|
alpar@1
|
155 |
* | GLP_BS | GLP_BS | N/A |
|
alpar@1
|
156 |
* | GLP_BS | GLP_NL | GLP_BS |
|
alpar@1
|
157 |
* | GLP_BS | GLP_NU | GLP_BS |
|
alpar@1
|
158 |
* | GLP_NS | GLP_BS | GLP_BS |
|
alpar@1
|
159 |
* | GLP_NS | GLP_NL | GLP_NL |
|
alpar@1
|
160 |
* | GLP_NS | GLP_NU | GLP_NU |
|
alpar@1
|
161 |
* +-----------------+--------------------+------------------+
|
alpar@1
|
162 |
*
|
alpar@1
|
163 |
* Value of row multiplier pi[p] in solution to the original problem
|
alpar@1
|
164 |
* is the same as in solution to the transformed problem.
|
alpar@1
|
165 |
*
|
alpar@1
|
166 |
* 1. In solution to the transformed problem row p and column q cannot
|
alpar@1
|
167 |
* be basic at the same time; otherwise the basis matrix would have
|
alpar@1
|
168 |
* two linear dependent columns: unity column of auxiliary variable
|
alpar@1
|
169 |
* of row p and unity column of variable s.
|
alpar@1
|
170 |
*
|
alpar@1
|
171 |
* 2. Though in the transformed problem row p is equality constraint,
|
alpar@1
|
172 |
* it may be basic due to primal degenerate solution.
|
alpar@1
|
173 |
*
|
alpar@1
|
174 |
* RECOVERING INTERIOR-POINT SOLUTION
|
alpar@1
|
175 |
*
|
alpar@1
|
176 |
* Value of row multiplier pi[p] in solution to the original problem
|
alpar@1
|
177 |
* is the same as in solution to the transformed problem.
|
alpar@1
|
178 |
*
|
alpar@1
|
179 |
* RECOVERING MIP SOLUTION
|
alpar@1
|
180 |
*
|
alpar@1
|
181 |
* None needed. */
|
alpar@1
|
182 |
|
alpar@1
|
183 |
struct ineq_row
|
alpar@1
|
184 |
{ /* inequality constraint row */
|
alpar@1
|
185 |
int p;
|
alpar@1
|
186 |
/* row reference number */
|
alpar@1
|
187 |
int s;
|
alpar@1
|
188 |
/* column reference number for slack/surplus variable */
|
alpar@1
|
189 |
};
|
alpar@1
|
190 |
|
alpar@1
|
191 |
static int rcv_geq_row(NPP *npp, void *info);
|
alpar@1
|
192 |
|
alpar@1
|
193 |
void npp_geq_row(NPP *npp, NPPROW *p)
|
alpar@1
|
194 |
{ /* process row of 'not less than' type */
|
alpar@1
|
195 |
struct ineq_row *info;
|
alpar@1
|
196 |
NPPCOL *s;
|
alpar@1
|
197 |
/* the row must have lower bound */
|
alpar@1
|
198 |
xassert(p->lb != -DBL_MAX);
|
alpar@1
|
199 |
xassert(p->lb < p->ub);
|
alpar@1
|
200 |
/* create column for surplus variable */
|
alpar@1
|
201 |
s = npp_add_col(npp);
|
alpar@1
|
202 |
s->lb = 0.0;
|
alpar@1
|
203 |
s->ub = (p->ub == +DBL_MAX ? +DBL_MAX : p->ub - p->lb);
|
alpar@1
|
204 |
/* and add it to the transformed problem */
|
alpar@1
|
205 |
npp_add_aij(npp, p, s, -1.0);
|
alpar@1
|
206 |
/* create transformation stack entry */
|
alpar@1
|
207 |
info = npp_push_tse(npp,
|
alpar@1
|
208 |
rcv_geq_row, sizeof(struct ineq_row));
|
alpar@1
|
209 |
info->p = p->i;
|
alpar@1
|
210 |
info->s = s->j;
|
alpar@1
|
211 |
/* replace the row by equality constraint */
|
alpar@1
|
212 |
p->ub = p->lb;
|
alpar@1
|
213 |
return;
|
alpar@1
|
214 |
}
|
alpar@1
|
215 |
|
alpar@1
|
216 |
static int rcv_geq_row(NPP *npp, void *_info)
|
alpar@1
|
217 |
{ /* recover row of 'not less than' type */
|
alpar@1
|
218 |
struct ineq_row *info = _info;
|
alpar@1
|
219 |
if (npp->sol == GLP_SOL)
|
alpar@1
|
220 |
{ if (npp->r_stat[info->p] == GLP_BS)
|
alpar@1
|
221 |
{ if (npp->c_stat[info->s] == GLP_BS)
|
alpar@1
|
222 |
{ npp_error();
|
alpar@1
|
223 |
return 1;
|
alpar@1
|
224 |
}
|
alpar@1
|
225 |
else if (npp->c_stat[info->s] == GLP_NL ||
|
alpar@1
|
226 |
npp->c_stat[info->s] == GLP_NU)
|
alpar@1
|
227 |
npp->r_stat[info->p] = GLP_BS;
|
alpar@1
|
228 |
else
|
alpar@1
|
229 |
{ npp_error();
|
alpar@1
|
230 |
return 1;
|
alpar@1
|
231 |
}
|
alpar@1
|
232 |
}
|
alpar@1
|
233 |
else if (npp->r_stat[info->p] == GLP_NS)
|
alpar@1
|
234 |
{ if (npp->c_stat[info->s] == GLP_BS)
|
alpar@1
|
235 |
npp->r_stat[info->p] = GLP_BS;
|
alpar@1
|
236 |
else if (npp->c_stat[info->s] == GLP_NL)
|
alpar@1
|
237 |
npp->r_stat[info->p] = GLP_NL;
|
alpar@1
|
238 |
else if (npp->c_stat[info->s] == GLP_NU)
|
alpar@1
|
239 |
npp->r_stat[info->p] = GLP_NU;
|
alpar@1
|
240 |
else
|
alpar@1
|
241 |
{ npp_error();
|
alpar@1
|
242 |
return 1;
|
alpar@1
|
243 |
}
|
alpar@1
|
244 |
}
|
alpar@1
|
245 |
else
|
alpar@1
|
246 |
{ npp_error();
|
alpar@1
|
247 |
return 1;
|
alpar@1
|
248 |
}
|
alpar@1
|
249 |
}
|
alpar@1
|
250 |
return 0;
|
alpar@1
|
251 |
}
|
alpar@1
|
252 |
|
alpar@1
|
253 |
/***********************************************************************
|
alpar@1
|
254 |
* NAME
|
alpar@1
|
255 |
*
|
alpar@1
|
256 |
* npp_leq_row - process row of 'not greater than' type
|
alpar@1
|
257 |
*
|
alpar@1
|
258 |
* SYNOPSIS
|
alpar@1
|
259 |
*
|
alpar@1
|
260 |
* #include "glpnpp.h"
|
alpar@1
|
261 |
* void npp_leq_row(NPP *npp, NPPROW *p);
|
alpar@1
|
262 |
*
|
alpar@1
|
263 |
* DESCRIPTION
|
alpar@1
|
264 |
*
|
alpar@1
|
265 |
* The routine npp_leq_row processes row p, which is 'not greater than'
|
alpar@1
|
266 |
* inequality constraint:
|
alpar@1
|
267 |
*
|
alpar@1
|
268 |
* (L[p] <=) sum a[p,j] x[j] <= U[p], (1)
|
alpar@1
|
269 |
* j
|
alpar@1
|
270 |
*
|
alpar@1
|
271 |
* where L[p] < U[p], and lower bound may not exist (L[p] = +oo).
|
alpar@1
|
272 |
*
|
alpar@1
|
273 |
* PROBLEM TRANSFORMATION
|
alpar@1
|
274 |
*
|
alpar@1
|
275 |
* Constraint (1) can be replaced by equality constraint:
|
alpar@1
|
276 |
*
|
alpar@1
|
277 |
* sum a[p,j] x[j] + s = L[p], (2)
|
alpar@1
|
278 |
* j
|
alpar@1
|
279 |
*
|
alpar@1
|
280 |
* where
|
alpar@1
|
281 |
*
|
alpar@1
|
282 |
* 0 <= s (<= U[p] - L[p]) (3)
|
alpar@1
|
283 |
*
|
alpar@1
|
284 |
* is a non-negative slack variable.
|
alpar@1
|
285 |
*
|
alpar@1
|
286 |
* Since in the primal system there appears column s having the only
|
alpar@1
|
287 |
* non-zero coefficient in row p, in the dual system there appears a
|
alpar@1
|
288 |
* new row:
|
alpar@1
|
289 |
*
|
alpar@1
|
290 |
* (+1) pi[p] + lambda = 0, (4)
|
alpar@1
|
291 |
*
|
alpar@1
|
292 |
* where (+1) is coefficient of column s in row p, pi[p] is multiplier
|
alpar@1
|
293 |
* of row p, lambda is multiplier of column q, 0 is coefficient of
|
alpar@1
|
294 |
* column s in the objective row.
|
alpar@1
|
295 |
*
|
alpar@1
|
296 |
* RECOVERING BASIC SOLUTION
|
alpar@1
|
297 |
*
|
alpar@1
|
298 |
* Status of row p in solution to the original problem is determined
|
alpar@1
|
299 |
* by its status and status of column q in solution to the transformed
|
alpar@1
|
300 |
* problem as follows:
|
alpar@1
|
301 |
*
|
alpar@1
|
302 |
* +--------------------------------------+------------------+
|
alpar@1
|
303 |
* | Transformed problem | Original problem |
|
alpar@1
|
304 |
* +-----------------+--------------------+------------------+
|
alpar@1
|
305 |
* | Status of row p | Status of column s | Status of row p |
|
alpar@1
|
306 |
* +-----------------+--------------------+------------------+
|
alpar@1
|
307 |
* | GLP_BS | GLP_BS | N/A |
|
alpar@1
|
308 |
* | GLP_BS | GLP_NL | GLP_BS |
|
alpar@1
|
309 |
* | GLP_BS | GLP_NU | GLP_BS |
|
alpar@1
|
310 |
* | GLP_NS | GLP_BS | GLP_BS |
|
alpar@1
|
311 |
* | GLP_NS | GLP_NL | GLP_NU |
|
alpar@1
|
312 |
* | GLP_NS | GLP_NU | GLP_NL |
|
alpar@1
|
313 |
* +-----------------+--------------------+------------------+
|
alpar@1
|
314 |
*
|
alpar@1
|
315 |
* Value of row multiplier pi[p] in solution to the original problem
|
alpar@1
|
316 |
* is the same as in solution to the transformed problem.
|
alpar@1
|
317 |
*
|
alpar@1
|
318 |
* 1. In solution to the transformed problem row p and column q cannot
|
alpar@1
|
319 |
* be basic at the same time; otherwise the basis matrix would have
|
alpar@1
|
320 |
* two linear dependent columns: unity column of auxiliary variable
|
alpar@1
|
321 |
* of row p and unity column of variable s.
|
alpar@1
|
322 |
*
|
alpar@1
|
323 |
* 2. Though in the transformed problem row p is equality constraint,
|
alpar@1
|
324 |
* it may be basic due to primal degeneracy.
|
alpar@1
|
325 |
*
|
alpar@1
|
326 |
* RECOVERING INTERIOR-POINT SOLUTION
|
alpar@1
|
327 |
*
|
alpar@1
|
328 |
* Value of row multiplier pi[p] in solution to the original problem
|
alpar@1
|
329 |
* is the same as in solution to the transformed problem.
|
alpar@1
|
330 |
*
|
alpar@1
|
331 |
* RECOVERING MIP SOLUTION
|
alpar@1
|
332 |
*
|
alpar@1
|
333 |
* None needed. */
|
alpar@1
|
334 |
|
alpar@1
|
335 |
static int rcv_leq_row(NPP *npp, void *info);
|
alpar@1
|
336 |
|
alpar@1
|
337 |
void npp_leq_row(NPP *npp, NPPROW *p)
|
alpar@1
|
338 |
{ /* process row of 'not greater than' type */
|
alpar@1
|
339 |
struct ineq_row *info;
|
alpar@1
|
340 |
NPPCOL *s;
|
alpar@1
|
341 |
/* the row must have upper bound */
|
alpar@1
|
342 |
xassert(p->ub != +DBL_MAX);
|
alpar@1
|
343 |
xassert(p->lb < p->ub);
|
alpar@1
|
344 |
/* create column for slack variable */
|
alpar@1
|
345 |
s = npp_add_col(npp);
|
alpar@1
|
346 |
s->lb = 0.0;
|
alpar@1
|
347 |
s->ub = (p->lb == -DBL_MAX ? +DBL_MAX : p->ub - p->lb);
|
alpar@1
|
348 |
/* and add it to the transformed problem */
|
alpar@1
|
349 |
npp_add_aij(npp, p, s, +1.0);
|
alpar@1
|
350 |
/* create transformation stack entry */
|
alpar@1
|
351 |
info = npp_push_tse(npp,
|
alpar@1
|
352 |
rcv_leq_row, sizeof(struct ineq_row));
|
alpar@1
|
353 |
info->p = p->i;
|
alpar@1
|
354 |
info->s = s->j;
|
alpar@1
|
355 |
/* replace the row by equality constraint */
|
alpar@1
|
356 |
p->lb = p->ub;
|
alpar@1
|
357 |
return;
|
alpar@1
|
358 |
}
|
alpar@1
|
359 |
|
alpar@1
|
360 |
static int rcv_leq_row(NPP *npp, void *_info)
|
alpar@1
|
361 |
{ /* recover row of 'not greater than' type */
|
alpar@1
|
362 |
struct ineq_row *info = _info;
|
alpar@1
|
363 |
if (npp->sol == GLP_SOL)
|
alpar@1
|
364 |
{ if (npp->r_stat[info->p] == GLP_BS)
|
alpar@1
|
365 |
{ if (npp->c_stat[info->s] == GLP_BS)
|
alpar@1
|
366 |
{ npp_error();
|
alpar@1
|
367 |
return 1;
|
alpar@1
|
368 |
}
|
alpar@1
|
369 |
else if (npp->c_stat[info->s] == GLP_NL ||
|
alpar@1
|
370 |
npp->c_stat[info->s] == GLP_NU)
|
alpar@1
|
371 |
npp->r_stat[info->p] = GLP_BS;
|
alpar@1
|
372 |
else
|
alpar@1
|
373 |
{ npp_error();
|
alpar@1
|
374 |
return 1;
|
alpar@1
|
375 |
}
|
alpar@1
|
376 |
}
|
alpar@1
|
377 |
else if (npp->r_stat[info->p] == GLP_NS)
|
alpar@1
|
378 |
{ if (npp->c_stat[info->s] == GLP_BS)
|
alpar@1
|
379 |
npp->r_stat[info->p] = GLP_BS;
|
alpar@1
|
380 |
else if (npp->c_stat[info->s] == GLP_NL)
|
alpar@1
|
381 |
npp->r_stat[info->p] = GLP_NU;
|
alpar@1
|
382 |
else if (npp->c_stat[info->s] == GLP_NU)
|
alpar@1
|
383 |
npp->r_stat[info->p] = GLP_NL;
|
alpar@1
|
384 |
else
|
alpar@1
|
385 |
{ npp_error();
|
alpar@1
|
386 |
return 1;
|
alpar@1
|
387 |
}
|
alpar@1
|
388 |
}
|
alpar@1
|
389 |
else
|
alpar@1
|
390 |
{ npp_error();
|
alpar@1
|
391 |
return 1;
|
alpar@1
|
392 |
}
|
alpar@1
|
393 |
}
|
alpar@1
|
394 |
return 0;
|
alpar@1
|
395 |
}
|
alpar@1
|
396 |
|
alpar@1
|
397 |
/***********************************************************************
|
alpar@1
|
398 |
* NAME
|
alpar@1
|
399 |
*
|
alpar@1
|
400 |
* npp_free_col - process free (unbounded) column
|
alpar@1
|
401 |
*
|
alpar@1
|
402 |
* SYNOPSIS
|
alpar@1
|
403 |
*
|
alpar@1
|
404 |
* #include "glpnpp.h"
|
alpar@1
|
405 |
* void npp_free_col(NPP *npp, NPPCOL *q);
|
alpar@1
|
406 |
*
|
alpar@1
|
407 |
* DESCRIPTION
|
alpar@1
|
408 |
*
|
alpar@1
|
409 |
* The routine npp_free_col processes column q, which is free (i.e. has
|
alpar@1
|
410 |
* no finite bounds):
|
alpar@1
|
411 |
*
|
alpar@1
|
412 |
* -oo < x[q] < +oo. (1)
|
alpar@1
|
413 |
*
|
alpar@1
|
414 |
* PROBLEM TRANSFORMATION
|
alpar@1
|
415 |
*
|
alpar@1
|
416 |
* Free (unbounded) variable can be replaced by the difference of two
|
alpar@1
|
417 |
* non-negative variables:
|
alpar@1
|
418 |
*
|
alpar@1
|
419 |
* x[q] = s' - s'', s', s'' >= 0. (2)
|
alpar@1
|
420 |
*
|
alpar@1
|
421 |
* Assuming that in the transformed problem x[q] becomes s',
|
alpar@1
|
422 |
* transformation (2) causes new column s'' to appear, which differs
|
alpar@1
|
423 |
* from column s' only in the sign of coefficients in constraint and
|
alpar@1
|
424 |
* objective rows. Thus, if in the dual system the following row
|
alpar@1
|
425 |
* corresponds to column s':
|
alpar@1
|
426 |
*
|
alpar@1
|
427 |
* sum a[i,q] pi[i] + lambda' = c[q], (3)
|
alpar@1
|
428 |
* i
|
alpar@1
|
429 |
*
|
alpar@1
|
430 |
* the row which corresponds to column s'' is the following:
|
alpar@1
|
431 |
*
|
alpar@1
|
432 |
* sum (-a[i,q]) pi[i] + lambda'' = -c[q]. (4)
|
alpar@1
|
433 |
* i
|
alpar@1
|
434 |
*
|
alpar@1
|
435 |
* Then from (3) and (4) it follows that:
|
alpar@1
|
436 |
*
|
alpar@1
|
437 |
* lambda' + lambda'' = 0 => lambda' = lmabda'' = 0, (5)
|
alpar@1
|
438 |
*
|
alpar@1
|
439 |
* where lambda' and lambda'' are multipliers for columns s' and s'',
|
alpar@1
|
440 |
* resp.
|
alpar@1
|
441 |
*
|
alpar@1
|
442 |
* RECOVERING BASIC SOLUTION
|
alpar@1
|
443 |
*
|
alpar@1
|
444 |
* With respect to (5) status of column q in solution to the original
|
alpar@1
|
445 |
* problem is determined by statuses of columns s' and s'' in solution
|
alpar@1
|
446 |
* to the transformed problem as follows:
|
alpar@1
|
447 |
*
|
alpar@1
|
448 |
* +--------------------------------------+------------------+
|
alpar@1
|
449 |
* | Transformed problem | Original problem |
|
alpar@1
|
450 |
* +------------------+-------------------+------------------+
|
alpar@1
|
451 |
* | Status of col s' | Status of col s'' | Status of col q |
|
alpar@1
|
452 |
* +------------------+-------------------+------------------+
|
alpar@1
|
453 |
* | GLP_BS | GLP_BS | N/A |
|
alpar@1
|
454 |
* | GLP_BS | GLP_NL | GLP_BS |
|
alpar@1
|
455 |
* | GLP_NL | GLP_BS | GLP_BS |
|
alpar@1
|
456 |
* | GLP_NL | GLP_NL | GLP_NF |
|
alpar@1
|
457 |
* +------------------+-------------------+------------------+
|
alpar@1
|
458 |
*
|
alpar@1
|
459 |
* Value of column q is computed with formula (2).
|
alpar@1
|
460 |
*
|
alpar@1
|
461 |
* 1. In solution to the transformed problem columns s' and s'' cannot
|
alpar@1
|
462 |
* be basic at the same time, because they differ only in the sign,
|
alpar@1
|
463 |
* hence, are linear dependent.
|
alpar@1
|
464 |
*
|
alpar@1
|
465 |
* 2. Though column q is free, it can be non-basic due to dual
|
alpar@1
|
466 |
* degeneracy.
|
alpar@1
|
467 |
*
|
alpar@1
|
468 |
* 3. If column q is integral, columns s' and s'' are also integral.
|
alpar@1
|
469 |
*
|
alpar@1
|
470 |
* RECOVERING INTERIOR-POINT SOLUTION
|
alpar@1
|
471 |
*
|
alpar@1
|
472 |
* Value of column q is computed with formula (2).
|
alpar@1
|
473 |
*
|
alpar@1
|
474 |
* RECOVERING MIP SOLUTION
|
alpar@1
|
475 |
*
|
alpar@1
|
476 |
* Value of column q is computed with formula (2). */
|
alpar@1
|
477 |
|
alpar@1
|
478 |
struct free_col
|
alpar@1
|
479 |
{ /* free (unbounded) column */
|
alpar@1
|
480 |
int q;
|
alpar@1
|
481 |
/* column reference number for variables x[q] and s' */
|
alpar@1
|
482 |
int s;
|
alpar@1
|
483 |
/* column reference number for variable s'' */
|
alpar@1
|
484 |
};
|
alpar@1
|
485 |
|
alpar@1
|
486 |
static int rcv_free_col(NPP *npp, void *info);
|
alpar@1
|
487 |
|
alpar@1
|
488 |
void npp_free_col(NPP *npp, NPPCOL *q)
|
alpar@1
|
489 |
{ /* process free (unbounded) column */
|
alpar@1
|
490 |
struct free_col *info;
|
alpar@1
|
491 |
NPPCOL *s;
|
alpar@1
|
492 |
NPPAIJ *aij;
|
alpar@1
|
493 |
/* the column must be free */
|
alpar@1
|
494 |
xassert(q->lb == -DBL_MAX && q->ub == +DBL_MAX);
|
alpar@1
|
495 |
/* variable x[q] becomes s' */
|
alpar@1
|
496 |
q->lb = 0.0, q->ub = +DBL_MAX;
|
alpar@1
|
497 |
/* create variable s'' */
|
alpar@1
|
498 |
s = npp_add_col(npp);
|
alpar@1
|
499 |
s->is_int = q->is_int;
|
alpar@1
|
500 |
s->lb = 0.0, s->ub = +DBL_MAX;
|
alpar@1
|
501 |
/* duplicate objective coefficient */
|
alpar@1
|
502 |
s->coef = -q->coef;
|
alpar@1
|
503 |
/* duplicate column of the constraint matrix */
|
alpar@1
|
504 |
for (aij = q->ptr; aij != NULL; aij = aij->c_next)
|
alpar@1
|
505 |
npp_add_aij(npp, aij->row, s, -aij->val);
|
alpar@1
|
506 |
/* create transformation stack entry */
|
alpar@1
|
507 |
info = npp_push_tse(npp,
|
alpar@1
|
508 |
rcv_free_col, sizeof(struct free_col));
|
alpar@1
|
509 |
info->q = q->j;
|
alpar@1
|
510 |
info->s = s->j;
|
alpar@1
|
511 |
return;
|
alpar@1
|
512 |
}
|
alpar@1
|
513 |
|
alpar@1
|
514 |
static int rcv_free_col(NPP *npp, void *_info)
|
alpar@1
|
515 |
{ /* recover free (unbounded) column */
|
alpar@1
|
516 |
struct free_col *info = _info;
|
alpar@1
|
517 |
if (npp->sol == GLP_SOL)
|
alpar@1
|
518 |
{ if (npp->c_stat[info->q] == GLP_BS)
|
alpar@1
|
519 |
{ if (npp->c_stat[info->s] == GLP_BS)
|
alpar@1
|
520 |
{ npp_error();
|
alpar@1
|
521 |
return 1;
|
alpar@1
|
522 |
}
|
alpar@1
|
523 |
else if (npp->c_stat[info->s] == GLP_NL)
|
alpar@1
|
524 |
npp->c_stat[info->q] = GLP_BS;
|
alpar@1
|
525 |
else
|
alpar@1
|
526 |
{ npp_error();
|
alpar@1
|
527 |
return -1;
|
alpar@1
|
528 |
}
|
alpar@1
|
529 |
}
|
alpar@1
|
530 |
else if (npp->c_stat[info->q] == GLP_NL)
|
alpar@1
|
531 |
{ if (npp->c_stat[info->s] == GLP_BS)
|
alpar@1
|
532 |
npp->c_stat[info->q] = GLP_BS;
|
alpar@1
|
533 |
else if (npp->c_stat[info->s] == GLP_NL)
|
alpar@1
|
534 |
npp->c_stat[info->q] = GLP_NF;
|
alpar@1
|
535 |
else
|
alpar@1
|
536 |
{ npp_error();
|
alpar@1
|
537 |
return -1;
|
alpar@1
|
538 |
}
|
alpar@1
|
539 |
}
|
alpar@1
|
540 |
else
|
alpar@1
|
541 |
{ npp_error();
|
alpar@1
|
542 |
return -1;
|
alpar@1
|
543 |
}
|
alpar@1
|
544 |
}
|
alpar@1
|
545 |
/* compute value of x[q] with formula (2) */
|
alpar@1
|
546 |
npp->c_value[info->q] -= npp->c_value[info->s];
|
alpar@1
|
547 |
return 0;
|
alpar@1
|
548 |
}
|
alpar@1
|
549 |
|
alpar@1
|
550 |
/***********************************************************************
|
alpar@1
|
551 |
* NAME
|
alpar@1
|
552 |
*
|
alpar@1
|
553 |
* npp_lbnd_col - process column with (non-zero) lower bound
|
alpar@1
|
554 |
*
|
alpar@1
|
555 |
* SYNOPSIS
|
alpar@1
|
556 |
*
|
alpar@1
|
557 |
* #include "glpnpp.h"
|
alpar@1
|
558 |
* void npp_lbnd_col(NPP *npp, NPPCOL *q);
|
alpar@1
|
559 |
*
|
alpar@1
|
560 |
* DESCRIPTION
|
alpar@1
|
561 |
*
|
alpar@1
|
562 |
* The routine npp_lbnd_col processes column q, which has (non-zero)
|
alpar@1
|
563 |
* lower bound:
|
alpar@1
|
564 |
*
|
alpar@1
|
565 |
* l[q] <= x[q] (<= u[q]), (1)
|
alpar@1
|
566 |
*
|
alpar@1
|
567 |
* where l[q] < u[q], and upper bound may not exist (u[q] = +oo).
|
alpar@1
|
568 |
*
|
alpar@1
|
569 |
* PROBLEM TRANSFORMATION
|
alpar@1
|
570 |
*
|
alpar@1
|
571 |
* Column q can be replaced as follows:
|
alpar@1
|
572 |
*
|
alpar@1
|
573 |
* x[q] = l[q] + s, (2)
|
alpar@1
|
574 |
*
|
alpar@1
|
575 |
* where
|
alpar@1
|
576 |
*
|
alpar@1
|
577 |
* 0 <= s (<= u[q] - l[q]) (3)
|
alpar@1
|
578 |
*
|
alpar@1
|
579 |
* is a non-negative variable.
|
alpar@1
|
580 |
*
|
alpar@1
|
581 |
* Substituting x[q] from (2) into the objective row, we have:
|
alpar@1
|
582 |
*
|
alpar@1
|
583 |
* z = sum c[j] x[j] + c0 =
|
alpar@1
|
584 |
* j
|
alpar@1
|
585 |
*
|
alpar@1
|
586 |
* = sum c[j] x[j] + c[q] x[q] + c0 =
|
alpar@1
|
587 |
* j!=q
|
alpar@1
|
588 |
*
|
alpar@1
|
589 |
* = sum c[j] x[j] + c[q] (l[q] + s) + c0 =
|
alpar@1
|
590 |
* j!=q
|
alpar@1
|
591 |
*
|
alpar@1
|
592 |
* = sum c[j] x[j] + c[q] s + c~0,
|
alpar@1
|
593 |
*
|
alpar@1
|
594 |
* where
|
alpar@1
|
595 |
*
|
alpar@1
|
596 |
* c~0 = c0 + c[q] l[q] (4)
|
alpar@1
|
597 |
*
|
alpar@1
|
598 |
* is the constant term of the objective in the transformed problem.
|
alpar@1
|
599 |
* Similarly, substituting x[q] into constraint row i, we have:
|
alpar@1
|
600 |
*
|
alpar@1
|
601 |
* L[i] <= sum a[i,j] x[j] <= U[i] ==>
|
alpar@1
|
602 |
* j
|
alpar@1
|
603 |
*
|
alpar@1
|
604 |
* L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
|
alpar@1
|
605 |
* j!=q
|
alpar@1
|
606 |
*
|
alpar@1
|
607 |
* L[i] <= sum a[i,j] x[j] + a[i,q] (l[q] + s) <= U[i] ==>
|
alpar@1
|
608 |
* j!=q
|
alpar@1
|
609 |
*
|
alpar@1
|
610 |
* L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
|
alpar@1
|
611 |
* j!=q
|
alpar@1
|
612 |
*
|
alpar@1
|
613 |
* where
|
alpar@1
|
614 |
*
|
alpar@1
|
615 |
* L~[i] = L[i] - a[i,q] l[q], U~[i] = U[i] - a[i,q] l[q] (5)
|
alpar@1
|
616 |
*
|
alpar@1
|
617 |
* are lower and upper bounds of row i in the transformed problem,
|
alpar@1
|
618 |
* resp.
|
alpar@1
|
619 |
*
|
alpar@1
|
620 |
* Transformation (2) does not affect the dual system.
|
alpar@1
|
621 |
*
|
alpar@1
|
622 |
* RECOVERING BASIC SOLUTION
|
alpar@1
|
623 |
*
|
alpar@1
|
624 |
* Status of column q in solution to the original problem is the same
|
alpar@1
|
625 |
* as in solution to the transformed problem (GLP_BS, GLP_NL or GLP_NU).
|
alpar@1
|
626 |
* Value of column q is computed with formula (2).
|
alpar@1
|
627 |
*
|
alpar@1
|
628 |
* RECOVERING INTERIOR-POINT SOLUTION
|
alpar@1
|
629 |
*
|
alpar@1
|
630 |
* Value of column q is computed with formula (2).
|
alpar@1
|
631 |
*
|
alpar@1
|
632 |
* RECOVERING MIP SOLUTION
|
alpar@1
|
633 |
*
|
alpar@1
|
634 |
* Value of column q is computed with formula (2). */
|
alpar@1
|
635 |
|
alpar@1
|
636 |
struct bnd_col
|
alpar@1
|
637 |
{ /* bounded column */
|
alpar@1
|
638 |
int q;
|
alpar@1
|
639 |
/* column reference number for variables x[q] and s */
|
alpar@1
|
640 |
double bnd;
|
alpar@1
|
641 |
/* lower/upper bound l[q] or u[q] */
|
alpar@1
|
642 |
};
|
alpar@1
|
643 |
|
alpar@1
|
644 |
static int rcv_lbnd_col(NPP *npp, void *info);
|
alpar@1
|
645 |
|
alpar@1
|
646 |
void npp_lbnd_col(NPP *npp, NPPCOL *q)
|
alpar@1
|
647 |
{ /* process column with (non-zero) lower bound */
|
alpar@1
|
648 |
struct bnd_col *info;
|
alpar@1
|
649 |
NPPROW *i;
|
alpar@1
|
650 |
NPPAIJ *aij;
|
alpar@1
|
651 |
/* the column must have non-zero lower bound */
|
alpar@1
|
652 |
xassert(q->lb != 0.0);
|
alpar@1
|
653 |
xassert(q->lb != -DBL_MAX);
|
alpar@1
|
654 |
xassert(q->lb < q->ub);
|
alpar@1
|
655 |
/* create transformation stack entry */
|
alpar@1
|
656 |
info = npp_push_tse(npp,
|
alpar@1
|
657 |
rcv_lbnd_col, sizeof(struct bnd_col));
|
alpar@1
|
658 |
info->q = q->j;
|
alpar@1
|
659 |
info->bnd = q->lb;
|
alpar@1
|
660 |
/* substitute x[q] into objective row */
|
alpar@1
|
661 |
npp->c0 += q->coef * q->lb;
|
alpar@1
|
662 |
/* substitute x[q] into constraint rows */
|
alpar@1
|
663 |
for (aij = q->ptr; aij != NULL; aij = aij->c_next)
|
alpar@1
|
664 |
{ i = aij->row;
|
alpar@1
|
665 |
if (i->lb == i->ub)
|
alpar@1
|
666 |
i->ub = (i->lb -= aij->val * q->lb);
|
alpar@1
|
667 |
else
|
alpar@1
|
668 |
{ if (i->lb != -DBL_MAX)
|
alpar@1
|
669 |
i->lb -= aij->val * q->lb;
|
alpar@1
|
670 |
if (i->ub != +DBL_MAX)
|
alpar@1
|
671 |
i->ub -= aij->val * q->lb;
|
alpar@1
|
672 |
}
|
alpar@1
|
673 |
}
|
alpar@1
|
674 |
/* column x[q] becomes column s */
|
alpar@1
|
675 |
if (q->ub != +DBL_MAX)
|
alpar@1
|
676 |
q->ub -= q->lb;
|
alpar@1
|
677 |
q->lb = 0.0;
|
alpar@1
|
678 |
return;
|
alpar@1
|
679 |
}
|
alpar@1
|
680 |
|
alpar@1
|
681 |
static int rcv_lbnd_col(NPP *npp, void *_info)
|
alpar@1
|
682 |
{ /* recover column with (non-zero) lower bound */
|
alpar@1
|
683 |
struct bnd_col *info = _info;
|
alpar@1
|
684 |
if (npp->sol == GLP_SOL)
|
alpar@1
|
685 |
{ if (npp->c_stat[info->q] == GLP_BS ||
|
alpar@1
|
686 |
npp->c_stat[info->q] == GLP_NL ||
|
alpar@1
|
687 |
npp->c_stat[info->q] == GLP_NU)
|
alpar@1
|
688 |
npp->c_stat[info->q] = npp->c_stat[info->q];
|
alpar@1
|
689 |
else
|
alpar@1
|
690 |
{ npp_error();
|
alpar@1
|
691 |
return 1;
|
alpar@1
|
692 |
}
|
alpar@1
|
693 |
}
|
alpar@1
|
694 |
/* compute value of x[q] with formula (2) */
|
alpar@1
|
695 |
npp->c_value[info->q] = info->bnd + npp->c_value[info->q];
|
alpar@1
|
696 |
return 0;
|
alpar@1
|
697 |
}
|
alpar@1
|
698 |
|
alpar@1
|
699 |
/***********************************************************************
|
alpar@1
|
700 |
* NAME
|
alpar@1
|
701 |
*
|
alpar@1
|
702 |
* npp_ubnd_col - process column with upper bound
|
alpar@1
|
703 |
*
|
alpar@1
|
704 |
* SYNOPSIS
|
alpar@1
|
705 |
*
|
alpar@1
|
706 |
* #include "glpnpp.h"
|
alpar@1
|
707 |
* void npp_ubnd_col(NPP *npp, NPPCOL *q);
|
alpar@1
|
708 |
*
|
alpar@1
|
709 |
* DESCRIPTION
|
alpar@1
|
710 |
*
|
alpar@1
|
711 |
* The routine npp_ubnd_col processes column q, which has upper bound:
|
alpar@1
|
712 |
*
|
alpar@1
|
713 |
* (l[q] <=) x[q] <= u[q], (1)
|
alpar@1
|
714 |
*
|
alpar@1
|
715 |
* where l[q] < u[q], and lower bound may not exist (l[q] = -oo).
|
alpar@1
|
716 |
*
|
alpar@1
|
717 |
* PROBLEM TRANSFORMATION
|
alpar@1
|
718 |
*
|
alpar@1
|
719 |
* Column q can be replaced as follows:
|
alpar@1
|
720 |
*
|
alpar@1
|
721 |
* x[q] = u[q] - s, (2)
|
alpar@1
|
722 |
*
|
alpar@1
|
723 |
* where
|
alpar@1
|
724 |
*
|
alpar@1
|
725 |
* 0 <= s (<= u[q] - l[q]) (3)
|
alpar@1
|
726 |
*
|
alpar@1
|
727 |
* is a non-negative variable.
|
alpar@1
|
728 |
*
|
alpar@1
|
729 |
* Substituting x[q] from (2) into the objective row, we have:
|
alpar@1
|
730 |
*
|
alpar@1
|
731 |
* z = sum c[j] x[j] + c0 =
|
alpar@1
|
732 |
* j
|
alpar@1
|
733 |
*
|
alpar@1
|
734 |
* = sum c[j] x[j] + c[q] x[q] + c0 =
|
alpar@1
|
735 |
* j!=q
|
alpar@1
|
736 |
*
|
alpar@1
|
737 |
* = sum c[j] x[j] + c[q] (u[q] - s) + c0 =
|
alpar@1
|
738 |
* j!=q
|
alpar@1
|
739 |
*
|
alpar@1
|
740 |
* = sum c[j] x[j] - c[q] s + c~0,
|
alpar@1
|
741 |
*
|
alpar@1
|
742 |
* where
|
alpar@1
|
743 |
*
|
alpar@1
|
744 |
* c~0 = c0 + c[q] u[q] (4)
|
alpar@1
|
745 |
*
|
alpar@1
|
746 |
* is the constant term of the objective in the transformed problem.
|
alpar@1
|
747 |
* Similarly, substituting x[q] into constraint row i, we have:
|
alpar@1
|
748 |
*
|
alpar@1
|
749 |
* L[i] <= sum a[i,j] x[j] <= U[i] ==>
|
alpar@1
|
750 |
* j
|
alpar@1
|
751 |
*
|
alpar@1
|
752 |
* L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
|
alpar@1
|
753 |
* j!=q
|
alpar@1
|
754 |
*
|
alpar@1
|
755 |
* L[i] <= sum a[i,j] x[j] + a[i,q] (u[q] - s) <= U[i] ==>
|
alpar@1
|
756 |
* j!=q
|
alpar@1
|
757 |
*
|
alpar@1
|
758 |
* L~[i] <= sum a[i,j] x[j] - a[i,q] s <= U~[i],
|
alpar@1
|
759 |
* j!=q
|
alpar@1
|
760 |
*
|
alpar@1
|
761 |
* where
|
alpar@1
|
762 |
*
|
alpar@1
|
763 |
* L~[i] = L[i] - a[i,q] u[q], U~[i] = U[i] - a[i,q] u[q] (5)
|
alpar@1
|
764 |
*
|
alpar@1
|
765 |
* are lower and upper bounds of row i in the transformed problem,
|
alpar@1
|
766 |
* resp.
|
alpar@1
|
767 |
*
|
alpar@1
|
768 |
* Note that in the transformed problem coefficients c[q] and a[i,q]
|
alpar@1
|
769 |
* change their sign. Thus, the row of the dual system corresponding to
|
alpar@1
|
770 |
* column q:
|
alpar@1
|
771 |
*
|
alpar@1
|
772 |
* sum a[i,q] pi[i] + lambda[q] = c[q] (6)
|
alpar@1
|
773 |
* i
|
alpar@1
|
774 |
*
|
alpar@1
|
775 |
* in the transformed problem becomes the following:
|
alpar@1
|
776 |
*
|
alpar@1
|
777 |
* sum (-a[i,q]) pi[i] + lambda[s] = -c[q]. (7)
|
alpar@1
|
778 |
* i
|
alpar@1
|
779 |
*
|
alpar@1
|
780 |
* Therefore:
|
alpar@1
|
781 |
*
|
alpar@1
|
782 |
* lambda[q] = - lambda[s], (8)
|
alpar@1
|
783 |
*
|
alpar@1
|
784 |
* where lambda[q] is multiplier for column q, lambda[s] is multiplier
|
alpar@1
|
785 |
* for column s.
|
alpar@1
|
786 |
*
|
alpar@1
|
787 |
* RECOVERING BASIC SOLUTION
|
alpar@1
|
788 |
*
|
alpar@1
|
789 |
* With respect to (8) status of column q in solution to the original
|
alpar@1
|
790 |
* problem is determined by status of column s in solution to the
|
alpar@1
|
791 |
* transformed problem as follows:
|
alpar@1
|
792 |
*
|
alpar@1
|
793 |
* +-----------------------+--------------------+
|
alpar@1
|
794 |
* | Status of column s | Status of column q |
|
alpar@1
|
795 |
* | (transformed problem) | (original problem) |
|
alpar@1
|
796 |
* +-----------------------+--------------------+
|
alpar@1
|
797 |
* | GLP_BS | GLP_BS |
|
alpar@1
|
798 |
* | GLP_NL | GLP_NU |
|
alpar@1
|
799 |
* | GLP_NU | GLP_NL |
|
alpar@1
|
800 |
* +-----------------------+--------------------+
|
alpar@1
|
801 |
*
|
alpar@1
|
802 |
* Value of column q is computed with formula (2).
|
alpar@1
|
803 |
*
|
alpar@1
|
804 |
* RECOVERING INTERIOR-POINT SOLUTION
|
alpar@1
|
805 |
*
|
alpar@1
|
806 |
* Value of column q is computed with formula (2).
|
alpar@1
|
807 |
*
|
alpar@1
|
808 |
* RECOVERING MIP SOLUTION
|
alpar@1
|
809 |
*
|
alpar@1
|
810 |
* Value of column q is computed with formula (2). */
|
alpar@1
|
811 |
|
alpar@1
|
812 |
static int rcv_ubnd_col(NPP *npp, void *info);
|
alpar@1
|
813 |
|
alpar@1
|
814 |
void npp_ubnd_col(NPP *npp, NPPCOL *q)
|
alpar@1
|
815 |
{ /* process column with upper bound */
|
alpar@1
|
816 |
struct bnd_col *info;
|
alpar@1
|
817 |
NPPROW *i;
|
alpar@1
|
818 |
NPPAIJ *aij;
|
alpar@1
|
819 |
/* the column must have upper bound */
|
alpar@1
|
820 |
xassert(q->ub != +DBL_MAX);
|
alpar@1
|
821 |
xassert(q->lb < q->ub);
|
alpar@1
|
822 |
/* create transformation stack entry */
|
alpar@1
|
823 |
info = npp_push_tse(npp,
|
alpar@1
|
824 |
rcv_ubnd_col, sizeof(struct bnd_col));
|
alpar@1
|
825 |
info->q = q->j;
|
alpar@1
|
826 |
info->bnd = q->ub;
|
alpar@1
|
827 |
/* substitute x[q] into objective row */
|
alpar@1
|
828 |
npp->c0 += q->coef * q->ub;
|
alpar@1
|
829 |
q->coef = -q->coef;
|
alpar@1
|
830 |
/* substitute x[q] into constraint rows */
|
alpar@1
|
831 |
for (aij = q->ptr; aij != NULL; aij = aij->c_next)
|
alpar@1
|
832 |
{ i = aij->row;
|
alpar@1
|
833 |
if (i->lb == i->ub)
|
alpar@1
|
834 |
i->ub = (i->lb -= aij->val * q->ub);
|
alpar@1
|
835 |
else
|
alpar@1
|
836 |
{ if (i->lb != -DBL_MAX)
|
alpar@1
|
837 |
i->lb -= aij->val * q->ub;
|
alpar@1
|
838 |
if (i->ub != +DBL_MAX)
|
alpar@1
|
839 |
i->ub -= aij->val * q->ub;
|
alpar@1
|
840 |
}
|
alpar@1
|
841 |
aij->val = -aij->val;
|
alpar@1
|
842 |
}
|
alpar@1
|
843 |
/* column x[q] becomes column s */
|
alpar@1
|
844 |
if (q->lb != -DBL_MAX)
|
alpar@1
|
845 |
q->ub -= q->lb;
|
alpar@1
|
846 |
else
|
alpar@1
|
847 |
q->ub = +DBL_MAX;
|
alpar@1
|
848 |
q->lb = 0.0;
|
alpar@1
|
849 |
return;
|
alpar@1
|
850 |
}
|
alpar@1
|
851 |
|
alpar@1
|
852 |
static int rcv_ubnd_col(NPP *npp, void *_info)
|
alpar@1
|
853 |
{ /* recover column with upper bound */
|
alpar@1
|
854 |
struct bnd_col *info = _info;
|
alpar@1
|
855 |
if (npp->sol == GLP_BS)
|
alpar@1
|
856 |
{ if (npp->c_stat[info->q] == GLP_BS)
|
alpar@1
|
857 |
npp->c_stat[info->q] = GLP_BS;
|
alpar@1
|
858 |
else if (npp->c_stat[info->q] == GLP_NL)
|
alpar@1
|
859 |
npp->c_stat[info->q] = GLP_NU;
|
alpar@1
|
860 |
else if (npp->c_stat[info->q] == GLP_NU)
|
alpar@1
|
861 |
npp->c_stat[info->q] = GLP_NL;
|
alpar@1
|
862 |
else
|
alpar@1
|
863 |
{ npp_error();
|
alpar@1
|
864 |
return 1;
|
alpar@1
|
865 |
}
|
alpar@1
|
866 |
}
|
alpar@1
|
867 |
/* compute value of x[q] with formula (2) */
|
alpar@1
|
868 |
npp->c_value[info->q] = info->bnd - npp->c_value[info->q];
|
alpar@1
|
869 |
return 0;
|
alpar@1
|
870 |
}
|
alpar@1
|
871 |
|
alpar@1
|
872 |
/***********************************************************************
|
alpar@1
|
873 |
* NAME
|
alpar@1
|
874 |
*
|
alpar@1
|
875 |
* npp_dbnd_col - process non-negative column with upper bound
|
alpar@1
|
876 |
*
|
alpar@1
|
877 |
* SYNOPSIS
|
alpar@1
|
878 |
*
|
alpar@1
|
879 |
* #include "glpnpp.h"
|
alpar@1
|
880 |
* void npp_dbnd_col(NPP *npp, NPPCOL *q);
|
alpar@1
|
881 |
*
|
alpar@1
|
882 |
* DESCRIPTION
|
alpar@1
|
883 |
*
|
alpar@1
|
884 |
* The routine npp_dbnd_col processes column q, which is non-negative
|
alpar@1
|
885 |
* and has upper bound:
|
alpar@1
|
886 |
*
|
alpar@1
|
887 |
* 0 <= x[q] <= u[q], (1)
|
alpar@1
|
888 |
*
|
alpar@1
|
889 |
* where u[q] > 0.
|
alpar@1
|
890 |
*
|
alpar@1
|
891 |
* PROBLEM TRANSFORMATION
|
alpar@1
|
892 |
*
|
alpar@1
|
893 |
* Upper bound of column q can be replaced by the following equality
|
alpar@1
|
894 |
* constraint:
|
alpar@1
|
895 |
*
|
alpar@1
|
896 |
* x[q] + s = u[q], (2)
|
alpar@1
|
897 |
*
|
alpar@1
|
898 |
* where s >= 0 is a non-negative complement variable.
|
alpar@1
|
899 |
*
|
alpar@1
|
900 |
* Since in the primal system along with new row (2) there appears a
|
alpar@1
|
901 |
* new column s having the only non-zero coefficient in this row, in
|
alpar@1
|
902 |
* the dual system there appears a new row:
|
alpar@1
|
903 |
*
|
alpar@1
|
904 |
* (+1)pi + lambda[s] = 0, (3)
|
alpar@1
|
905 |
*
|
alpar@1
|
906 |
* where (+1) is coefficient at column s in row (2), pi is multiplier
|
alpar@1
|
907 |
* for row (2), lambda[s] is multiplier for column s, 0 is coefficient
|
alpar@1
|
908 |
* at column s in the objective row.
|
alpar@1
|
909 |
*
|
alpar@1
|
910 |
* RECOVERING BASIC SOLUTION
|
alpar@1
|
911 |
*
|
alpar@1
|
912 |
* Status of column q in solution to the original problem is determined
|
alpar@1
|
913 |
* by its status and status of column s in solution to the transformed
|
alpar@1
|
914 |
* problem as follows:
|
alpar@1
|
915 |
*
|
alpar@1
|
916 |
* +-----------------------------------+------------------+
|
alpar@1
|
917 |
* | Transformed problem | Original problem |
|
alpar@1
|
918 |
* +-----------------+-----------------+------------------+
|
alpar@1
|
919 |
* | Status of col q | Status of col s | Status of col q |
|
alpar@1
|
920 |
* +-----------------+-----------------+------------------+
|
alpar@1
|
921 |
* | GLP_BS | GLP_BS | GLP_BS |
|
alpar@1
|
922 |
* | GLP_BS | GLP_NL | GLP_NU |
|
alpar@1
|
923 |
* | GLP_NL | GLP_BS | GLP_NL |
|
alpar@1
|
924 |
* | GLP_NL | GLP_NL | GLP_NL (*) |
|
alpar@1
|
925 |
* +-----------------+-----------------+------------------+
|
alpar@1
|
926 |
*
|
alpar@1
|
927 |
* Value of column q in solution to the original problem is the same as
|
alpar@1
|
928 |
* in solution to the transformed problem.
|
alpar@1
|
929 |
*
|
alpar@1
|
930 |
* 1. Formally, in solution to the transformed problem columns q and s
|
alpar@1
|
931 |
* cannot be non-basic at the same time, since the constraint (2)
|
alpar@1
|
932 |
* would be violated. However, if u[q] is close to zero, violation
|
alpar@1
|
933 |
* may be less than a working precision even if both columns q and s
|
alpar@1
|
934 |
* are non-basic. In this degenerate case row (2) can be only basic,
|
alpar@1
|
935 |
* i.e. non-active constraint (otherwise corresponding row of the
|
alpar@1
|
936 |
* basis matrix would be zero). This allows to pivot out auxiliary
|
alpar@1
|
937 |
* variable and pivot in column s, in which case the row becomes
|
alpar@1
|
938 |
* active while column s becomes basic.
|
alpar@1
|
939 |
*
|
alpar@1
|
940 |
* 2. If column q is integral, column s is also integral.
|
alpar@1
|
941 |
*
|
alpar@1
|
942 |
* RECOVERING INTERIOR-POINT SOLUTION
|
alpar@1
|
943 |
*
|
alpar@1
|
944 |
* Value of column q in solution to the original problem is the same as
|
alpar@1
|
945 |
* in solution to the transformed problem.
|
alpar@1
|
946 |
*
|
alpar@1
|
947 |
* RECOVERING MIP SOLUTION
|
alpar@1
|
948 |
*
|
alpar@1
|
949 |
* Value of column q in solution to the original problem is the same as
|
alpar@1
|
950 |
* in solution to the transformed problem. */
|
alpar@1
|
951 |
|
alpar@1
|
952 |
struct dbnd_col
|
alpar@1
|
953 |
{ /* double-bounded column */
|
alpar@1
|
954 |
int q;
|
alpar@1
|
955 |
/* column reference number for variable x[q] */
|
alpar@1
|
956 |
int s;
|
alpar@1
|
957 |
/* column reference number for complement variable s */
|
alpar@1
|
958 |
};
|
alpar@1
|
959 |
|
alpar@1
|
960 |
static int rcv_dbnd_col(NPP *npp, void *info);
|
alpar@1
|
961 |
|
alpar@1
|
962 |
void npp_dbnd_col(NPP *npp, NPPCOL *q)
|
alpar@1
|
963 |
{ /* process non-negative column with upper bound */
|
alpar@1
|
964 |
struct dbnd_col *info;
|
alpar@1
|
965 |
NPPROW *p;
|
alpar@1
|
966 |
NPPCOL *s;
|
alpar@1
|
967 |
/* the column must be non-negative with upper bound */
|
alpar@1
|
968 |
xassert(q->lb == 0.0);
|
alpar@1
|
969 |
xassert(q->ub > 0.0);
|
alpar@1
|
970 |
xassert(q->ub != +DBL_MAX);
|
alpar@1
|
971 |
/* create variable s */
|
alpar@1
|
972 |
s = npp_add_col(npp);
|
alpar@1
|
973 |
s->is_int = q->is_int;
|
alpar@1
|
974 |
s->lb = 0.0, s->ub = +DBL_MAX;
|
alpar@1
|
975 |
/* create equality constraint (2) */
|
alpar@1
|
976 |
p = npp_add_row(npp);
|
alpar@1
|
977 |
p->lb = p->ub = q->ub;
|
alpar@1
|
978 |
npp_add_aij(npp, p, q, +1.0);
|
alpar@1
|
979 |
npp_add_aij(npp, p, s, +1.0);
|
alpar@1
|
980 |
/* create transformation stack entry */
|
alpar@1
|
981 |
info = npp_push_tse(npp,
|
alpar@1
|
982 |
rcv_dbnd_col, sizeof(struct dbnd_col));
|
alpar@1
|
983 |
info->q = q->j;
|
alpar@1
|
984 |
info->s = s->j;
|
alpar@1
|
985 |
/* remove upper bound of x[q] */
|
alpar@1
|
986 |
q->ub = +DBL_MAX;
|
alpar@1
|
987 |
return;
|
alpar@1
|
988 |
}
|
alpar@1
|
989 |
|
alpar@1
|
990 |
static int rcv_dbnd_col(NPP *npp, void *_info)
|
alpar@1
|
991 |
{ /* recover non-negative column with upper bound */
|
alpar@1
|
992 |
struct dbnd_col *info = _info;
|
alpar@1
|
993 |
if (npp->sol == GLP_BS)
|
alpar@1
|
994 |
{ if (npp->c_stat[info->q] == GLP_BS)
|
alpar@1
|
995 |
{ if (npp->c_stat[info->s] == GLP_BS)
|
alpar@1
|
996 |
npp->c_stat[info->q] = GLP_BS;
|
alpar@1
|
997 |
else if (npp->c_stat[info->s] == GLP_NL)
|
alpar@1
|
998 |
npp->c_stat[info->q] = GLP_NU;
|
alpar@1
|
999 |
else
|
alpar@1
|
1000 |
{ npp_error();
|
alpar@1
|
1001 |
return 1;
|
alpar@1
|
1002 |
}
|
alpar@1
|
1003 |
}
|
alpar@1
|
1004 |
else if (npp->c_stat[info->q] == GLP_NL)
|
alpar@1
|
1005 |
{ if (npp->c_stat[info->s] == GLP_BS ||
|
alpar@1
|
1006 |
npp->c_stat[info->s] == GLP_NL)
|
alpar@1
|
1007 |
npp->c_stat[info->q] = GLP_NL;
|
alpar@1
|
1008 |
else
|
alpar@1
|
1009 |
{ npp_error();
|
alpar@1
|
1010 |
return 1;
|
alpar@1
|
1011 |
}
|
alpar@1
|
1012 |
}
|
alpar@1
|
1013 |
else
|
alpar@1
|
1014 |
{ npp_error();
|
alpar@1
|
1015 |
return 1;
|
alpar@1
|
1016 |
}
|
alpar@1
|
1017 |
}
|
alpar@1
|
1018 |
return 0;
|
alpar@1
|
1019 |
}
|
alpar@1
|
1020 |
|
alpar@1
|
1021 |
/***********************************************************************
|
alpar@1
|
1022 |
* NAME
|
alpar@1
|
1023 |
*
|
alpar@1
|
1024 |
* npp_fixed_col - process fixed column
|
alpar@1
|
1025 |
*
|
alpar@1
|
1026 |
* SYNOPSIS
|
alpar@1
|
1027 |
*
|
alpar@1
|
1028 |
* #include "glpnpp.h"
|
alpar@1
|
1029 |
* void npp_fixed_col(NPP *npp, NPPCOL *q);
|
alpar@1
|
1030 |
*
|
alpar@1
|
1031 |
* DESCRIPTION
|
alpar@1
|
1032 |
*
|
alpar@1
|
1033 |
* The routine npp_fixed_col processes column q, which is fixed:
|
alpar@1
|
1034 |
*
|
alpar@1
|
1035 |
* x[q] = s[q], (1)
|
alpar@1
|
1036 |
*
|
alpar@1
|
1037 |
* where s[q] is a fixed column value.
|
alpar@1
|
1038 |
*
|
alpar@1
|
1039 |
* PROBLEM TRANSFORMATION
|
alpar@1
|
1040 |
*
|
alpar@1
|
1041 |
* The value of a fixed column can be substituted into the objective
|
alpar@1
|
1042 |
* and constraint rows that allows removing the column from the problem.
|
alpar@1
|
1043 |
*
|
alpar@1
|
1044 |
* Substituting x[q] = s[q] into the objective row, we have:
|
alpar@1
|
1045 |
*
|
alpar@1
|
1046 |
* z = sum c[j] x[j] + c0 =
|
alpar@1
|
1047 |
* j
|
alpar@1
|
1048 |
*
|
alpar@1
|
1049 |
* = sum c[j] x[j] + c[q] x[q] + c0 =
|
alpar@1
|
1050 |
* j!=q
|
alpar@1
|
1051 |
*
|
alpar@1
|
1052 |
* = sum c[j] x[j] + c[q] s[q] + c0 =
|
alpar@1
|
1053 |
* j!=q
|
alpar@1
|
1054 |
*
|
alpar@1
|
1055 |
* = sum c[j] x[j] + c~0,
|
alpar@1
|
1056 |
* j!=q
|
alpar@1
|
1057 |
*
|
alpar@1
|
1058 |
* where
|
alpar@1
|
1059 |
*
|
alpar@1
|
1060 |
* c~0 = c0 + c[q] s[q] (2)
|
alpar@1
|
1061 |
*
|
alpar@1
|
1062 |
* is the constant term of the objective in the transformed problem.
|
alpar@1
|
1063 |
* Similarly, substituting x[q] = s[q] into constraint row i, we have:
|
alpar@1
|
1064 |
*
|
alpar@1
|
1065 |
* L[i] <= sum a[i,j] x[j] <= U[i] ==>
|
alpar@1
|
1066 |
* j
|
alpar@1
|
1067 |
*
|
alpar@1
|
1068 |
* L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
|
alpar@1
|
1069 |
* j!=q
|
alpar@1
|
1070 |
*
|
alpar@1
|
1071 |
* L[i] <= sum a[i,j] x[j] + a[i,q] s[q] <= U[i] ==>
|
alpar@1
|
1072 |
* j!=q
|
alpar@1
|
1073 |
*
|
alpar@1
|
1074 |
* L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
|
alpar@1
|
1075 |
* j!=q
|
alpar@1
|
1076 |
*
|
alpar@1
|
1077 |
* where
|
alpar@1
|
1078 |
*
|
alpar@1
|
1079 |
* L~[i] = L[i] - a[i,q] s[q], U~[i] = U[i] - a[i,q] s[q] (3)
|
alpar@1
|
1080 |
*
|
alpar@1
|
1081 |
* are lower and upper bounds of row i in the transformed problem,
|
alpar@1
|
1082 |
* resp.
|
alpar@1
|
1083 |
*
|
alpar@1
|
1084 |
* RECOVERING BASIC SOLUTION
|
alpar@1
|
1085 |
*
|
alpar@1
|
1086 |
* Column q is assigned status GLP_NS and its value is assigned s[q].
|
alpar@1
|
1087 |
*
|
alpar@1
|
1088 |
* RECOVERING INTERIOR-POINT SOLUTION
|
alpar@1
|
1089 |
*
|
alpar@1
|
1090 |
* Value of column q is assigned s[q].
|
alpar@1
|
1091 |
*
|
alpar@1
|
1092 |
* RECOVERING MIP SOLUTION
|
alpar@1
|
1093 |
*
|
alpar@1
|
1094 |
* Value of column q is assigned s[q]. */
|
alpar@1
|
1095 |
|
alpar@1
|
1096 |
struct fixed_col
|
alpar@1
|
1097 |
{ /* fixed column */
|
alpar@1
|
1098 |
int q;
|
alpar@1
|
1099 |
/* column reference number for variable x[q] */
|
alpar@1
|
1100 |
double s;
|
alpar@1
|
1101 |
/* value, at which x[q] is fixed */
|
alpar@1
|
1102 |
};
|
alpar@1
|
1103 |
|
alpar@1
|
1104 |
static int rcv_fixed_col(NPP *npp, void *info);
|
alpar@1
|
1105 |
|
alpar@1
|
1106 |
void npp_fixed_col(NPP *npp, NPPCOL *q)
|
alpar@1
|
1107 |
{ /* process fixed column */
|
alpar@1
|
1108 |
struct fixed_col *info;
|
alpar@1
|
1109 |
NPPROW *i;
|
alpar@1
|
1110 |
NPPAIJ *aij;
|
alpar@1
|
1111 |
/* the column must be fixed */
|
alpar@1
|
1112 |
xassert(q->lb == q->ub);
|
alpar@1
|
1113 |
/* create transformation stack entry */
|
alpar@1
|
1114 |
info = npp_push_tse(npp,
|
alpar@1
|
1115 |
rcv_fixed_col, sizeof(struct fixed_col));
|
alpar@1
|
1116 |
info->q = q->j;
|
alpar@1
|
1117 |
info->s = q->lb;
|
alpar@1
|
1118 |
/* substitute x[q] = s[q] into objective row */
|
alpar@1
|
1119 |
npp->c0 += q->coef * q->lb;
|
alpar@1
|
1120 |
/* substitute x[q] = s[q] into constraint rows */
|
alpar@1
|
1121 |
for (aij = q->ptr; aij != NULL; aij = aij->c_next)
|
alpar@1
|
1122 |
{ i = aij->row;
|
alpar@1
|
1123 |
if (i->lb == i->ub)
|
alpar@1
|
1124 |
i->ub = (i->lb -= aij->val * q->lb);
|
alpar@1
|
1125 |
else
|
alpar@1
|
1126 |
{ if (i->lb != -DBL_MAX)
|
alpar@1
|
1127 |
i->lb -= aij->val * q->lb;
|
alpar@1
|
1128 |
if (i->ub != +DBL_MAX)
|
alpar@1
|
1129 |
i->ub -= aij->val * q->lb;
|
alpar@1
|
1130 |
}
|
alpar@1
|
1131 |
}
|
alpar@1
|
1132 |
/* remove the column from the problem */
|
alpar@1
|
1133 |
npp_del_col(npp, q);
|
alpar@1
|
1134 |
return;
|
alpar@1
|
1135 |
}
|
alpar@1
|
1136 |
|
alpar@1
|
1137 |
static int rcv_fixed_col(NPP *npp, void *_info)
|
alpar@1
|
1138 |
{ /* recover fixed column */
|
alpar@1
|
1139 |
struct fixed_col *info = _info;
|
alpar@1
|
1140 |
if (npp->sol == GLP_SOL)
|
alpar@1
|
1141 |
npp->c_stat[info->q] = GLP_NS;
|
alpar@1
|
1142 |
npp->c_value[info->q] = info->s;
|
alpar@1
|
1143 |
return 0;
|
alpar@1
|
1144 |
}
|
alpar@1
|
1145 |
|
alpar@1
|
1146 |
/***********************************************************************
|
alpar@1
|
1147 |
* NAME
|
alpar@1
|
1148 |
*
|
alpar@1
|
1149 |
* npp_make_equality - process row with almost identical bounds
|
alpar@1
|
1150 |
*
|
alpar@1
|
1151 |
* SYNOPSIS
|
alpar@1
|
1152 |
*
|
alpar@1
|
1153 |
* #include "glpnpp.h"
|
alpar@1
|
1154 |
* int npp_make_equality(NPP *npp, NPPROW *p);
|
alpar@1
|
1155 |
*
|
alpar@1
|
1156 |
* DESCRIPTION
|
alpar@1
|
1157 |
*
|
alpar@1
|
1158 |
* The routine npp_make_equality processes row p:
|
alpar@1
|
1159 |
*
|
alpar@1
|
1160 |
* L[p] <= sum a[p,j] x[j] <= U[p], (1)
|
alpar@1
|
1161 |
* j
|
alpar@1
|
1162 |
*
|
alpar@1
|
1163 |
* where -oo < L[p] < U[p] < +oo, i.e. which is double-sided inequality
|
alpar@1
|
1164 |
* constraint.
|
alpar@1
|
1165 |
*
|
alpar@1
|
1166 |
* RETURNS
|
alpar@1
|
1167 |
*
|
alpar@1
|
1168 |
* 0 - row bounds have not been changed;
|
alpar@1
|
1169 |
*
|
alpar@1
|
1170 |
* 1 - row has been replaced by equality constraint.
|
alpar@1
|
1171 |
*
|
alpar@1
|
1172 |
* PROBLEM TRANSFORMATION
|
alpar@1
|
1173 |
*
|
alpar@1
|
1174 |
* If bounds of row (1) are very close to each other:
|
alpar@1
|
1175 |
*
|
alpar@1
|
1176 |
* U[p] - L[p] <= eps, (2)
|
alpar@1
|
1177 |
*
|
alpar@1
|
1178 |
* where eps is an absolute tolerance for row value, the row can be
|
alpar@1
|
1179 |
* replaced by the following almost equivalent equiality constraint:
|
alpar@1
|
1180 |
*
|
alpar@1
|
1181 |
* sum a[p,j] x[j] = b, (3)
|
alpar@1
|
1182 |
* j
|
alpar@1
|
1183 |
*
|
alpar@1
|
1184 |
* where b = (L[p] + U[p]) / 2. If the right-hand side in (3) happens
|
alpar@1
|
1185 |
* to be very close to its nearest integer:
|
alpar@1
|
1186 |
*
|
alpar@1
|
1187 |
* |b - floor(b + 0.5)| <= eps, (4)
|
alpar@1
|
1188 |
*
|
alpar@1
|
1189 |
* it is reasonable to use this nearest integer as the right-hand side.
|
alpar@1
|
1190 |
*
|
alpar@1
|
1191 |
* RECOVERING BASIC SOLUTION
|
alpar@1
|
1192 |
*
|
alpar@1
|
1193 |
* Status of row p in solution to the original problem is determined
|
alpar@1
|
1194 |
* by its status and the sign of its multiplier pi[p] in solution to
|
alpar@1
|
1195 |
* the transformed problem as follows:
|
alpar@1
|
1196 |
*
|
alpar@1
|
1197 |
* +-----------------------+---------+--------------------+
|
alpar@1
|
1198 |
* | Status of row p | Sign of | Status of row p |
|
alpar@1
|
1199 |
* | (transformed problem) | pi[p] | (original problem) |
|
alpar@1
|
1200 |
* +-----------------------+---------+--------------------+
|
alpar@1
|
1201 |
* | GLP_BS | + / - | GLP_BS |
|
alpar@1
|
1202 |
* | GLP_NS | + | GLP_NL |
|
alpar@1
|
1203 |
* | GLP_NS | - | GLP_NU |
|
alpar@1
|
1204 |
* +-----------------------+---------+--------------------+
|
alpar@1
|
1205 |
*
|
alpar@1
|
1206 |
* Value of row multiplier pi[p] in solution to the original problem is
|
alpar@1
|
1207 |
* the same as in solution to the transformed problem.
|
alpar@1
|
1208 |
*
|
alpar@1
|
1209 |
* RECOVERING INTERIOR POINT SOLUTION
|
alpar@1
|
1210 |
*
|
alpar@1
|
1211 |
* Value of row multiplier pi[p] in solution to the original problem is
|
alpar@1
|
1212 |
* the same as in solution to the transformed problem.
|
alpar@1
|
1213 |
*
|
alpar@1
|
1214 |
* RECOVERING MIP SOLUTION
|
alpar@1
|
1215 |
*
|
alpar@1
|
1216 |
* None needed. */
|
alpar@1
|
1217 |
|
alpar@1
|
1218 |
struct make_equality
|
alpar@1
|
1219 |
{ /* row with almost identical bounds */
|
alpar@1
|
1220 |
int p;
|
alpar@1
|
1221 |
/* row reference number */
|
alpar@1
|
1222 |
};
|
alpar@1
|
1223 |
|
alpar@1
|
1224 |
static int rcv_make_equality(NPP *npp, void *info);
|
alpar@1
|
1225 |
|
alpar@1
|
1226 |
int npp_make_equality(NPP *npp, NPPROW *p)
|
alpar@1
|
1227 |
{ /* process row with almost identical bounds */
|
alpar@1
|
1228 |
struct make_equality *info;
|
alpar@1
|
1229 |
double b, eps, nint;
|
alpar@1
|
1230 |
/* the row must be double-sided inequality */
|
alpar@1
|
1231 |
xassert(p->lb != -DBL_MAX);
|
alpar@1
|
1232 |
xassert(p->ub != +DBL_MAX);
|
alpar@1
|
1233 |
xassert(p->lb < p->ub);
|
alpar@1
|
1234 |
/* check row bounds */
|
alpar@1
|
1235 |
eps = 1e-9 + 1e-12 * fabs(p->lb);
|
alpar@1
|
1236 |
if (p->ub - p->lb > eps) return 0;
|
alpar@1
|
1237 |
/* row bounds are very close to each other */
|
alpar@1
|
1238 |
/* create transformation stack entry */
|
alpar@1
|
1239 |
info = npp_push_tse(npp,
|
alpar@1
|
1240 |
rcv_make_equality, sizeof(struct make_equality));
|
alpar@1
|
1241 |
info->p = p->i;
|
alpar@1
|
1242 |
/* compute right-hand side */
|
alpar@1
|
1243 |
b = 0.5 * (p->ub + p->lb);
|
alpar@1
|
1244 |
nint = floor(b + 0.5);
|
alpar@1
|
1245 |
if (fabs(b - nint) <= eps) b = nint;
|
alpar@1
|
1246 |
/* replace row p by almost equivalent equality constraint */
|
alpar@1
|
1247 |
p->lb = p->ub = b;
|
alpar@1
|
1248 |
return 1;
|
alpar@1
|
1249 |
}
|
alpar@1
|
1250 |
|
alpar@1
|
1251 |
int rcv_make_equality(NPP *npp, void *_info)
|
alpar@1
|
1252 |
{ /* recover row with almost identical bounds */
|
alpar@1
|
1253 |
struct make_equality *info = _info;
|
alpar@1
|
1254 |
if (npp->sol == GLP_SOL)
|
alpar@1
|
1255 |
{ if (npp->r_stat[info->p] == GLP_BS)
|
alpar@1
|
1256 |
npp->r_stat[info->p] = GLP_BS;
|
alpar@1
|
1257 |
else if (npp->r_stat[info->p] == GLP_NS)
|
alpar@1
|
1258 |
{ if (npp->r_pi[info->p] >= 0.0)
|
alpar@1
|
1259 |
npp->r_stat[info->p] = GLP_NL;
|
alpar@1
|
1260 |
else
|
alpar@1
|
1261 |
npp->r_stat[info->p] = GLP_NU;
|
alpar@1
|
1262 |
}
|
alpar@1
|
1263 |
else
|
alpar@1
|
1264 |
{ npp_error();
|
alpar@1
|
1265 |
return 1;
|
alpar@1
|
1266 |
}
|
alpar@1
|
1267 |
}
|
alpar@1
|
1268 |
return 0;
|
alpar@1
|
1269 |
}
|
alpar@1
|
1270 |
|
alpar@1
|
1271 |
/***********************************************************************
|
alpar@1
|
1272 |
* NAME
|
alpar@1
|
1273 |
*
|
alpar@1
|
1274 |
* npp_make_fixed - process column with almost identical bounds
|
alpar@1
|
1275 |
*
|
alpar@1
|
1276 |
* SYNOPSIS
|
alpar@1
|
1277 |
*
|
alpar@1
|
1278 |
* #include "glpnpp.h"
|
alpar@1
|
1279 |
* int npp_make_fixed(NPP *npp, NPPCOL *q);
|
alpar@1
|
1280 |
*
|
alpar@1
|
1281 |
* DESCRIPTION
|
alpar@1
|
1282 |
*
|
alpar@1
|
1283 |
* The routine npp_make_fixed processes column q:
|
alpar@1
|
1284 |
*
|
alpar@1
|
1285 |
* l[q] <= x[q] <= u[q], (1)
|
alpar@1
|
1286 |
*
|
alpar@1
|
1287 |
* where -oo < l[q] < u[q] < +oo, i.e. which has both lower and upper
|
alpar@1
|
1288 |
* bounds.
|
alpar@1
|
1289 |
*
|
alpar@1
|
1290 |
* RETURNS
|
alpar@1
|
1291 |
*
|
alpar@1
|
1292 |
* 0 - column bounds have not been changed;
|
alpar@1
|
1293 |
*
|
alpar@1
|
1294 |
* 1 - column has been fixed.
|
alpar@1
|
1295 |
*
|
alpar@1
|
1296 |
* PROBLEM TRANSFORMATION
|
alpar@1
|
1297 |
*
|
alpar@1
|
1298 |
* If bounds of column (1) are very close to each other:
|
alpar@1
|
1299 |
*
|
alpar@1
|
1300 |
* u[q] - l[q] <= eps, (2)
|
alpar@1
|
1301 |
*
|
alpar@1
|
1302 |
* where eps is an absolute tolerance for column value, the column can
|
alpar@1
|
1303 |
* be fixed:
|
alpar@1
|
1304 |
*
|
alpar@1
|
1305 |
* x[q] = s[q], (3)
|
alpar@1
|
1306 |
*
|
alpar@1
|
1307 |
* where s[q] = (l[q] + u[q]) / 2. And if the fixed column value s[q]
|
alpar@1
|
1308 |
* happens to be very close to its nearest integer:
|
alpar@1
|
1309 |
*
|
alpar@1
|
1310 |
* |s[q] - floor(s[q] + 0.5)| <= eps, (4)
|
alpar@1
|
1311 |
*
|
alpar@1
|
1312 |
* it is reasonable to use this nearest integer as the fixed value.
|
alpar@1
|
1313 |
*
|
alpar@1
|
1314 |
* RECOVERING BASIC SOLUTION
|
alpar@1
|
1315 |
*
|
alpar@1
|
1316 |
* In the dual system of the original (as well as transformed) problem
|
alpar@1
|
1317 |
* column q corresponds to the following row:
|
alpar@1
|
1318 |
*
|
alpar@1
|
1319 |
* sum a[i,q] pi[i] + lambda[q] = c[q]. (5)
|
alpar@1
|
1320 |
* i
|
alpar@1
|
1321 |
*
|
alpar@1
|
1322 |
* Since multipliers pi[i] are known for all rows from solution to the
|
alpar@1
|
1323 |
* transformed problem, formula (5) allows computing value of multiplier
|
alpar@1
|
1324 |
* (reduced cost) for column q:
|
alpar@1
|
1325 |
*
|
alpar@1
|
1326 |
* lambda[q] = c[q] - sum a[i,q] pi[i]. (6)
|
alpar@1
|
1327 |
* i
|
alpar@1
|
1328 |
*
|
alpar@1
|
1329 |
* Status of column q in solution to the original problem is determined
|
alpar@1
|
1330 |
* by its status and the sign of its multiplier lambda[q] in solution to
|
alpar@1
|
1331 |
* the transformed problem as follows:
|
alpar@1
|
1332 |
*
|
alpar@1
|
1333 |
* +-----------------------+-----------+--------------------+
|
alpar@1
|
1334 |
* | Status of column q | Sign of | Status of column q |
|
alpar@1
|
1335 |
* | (transformed problem) | lambda[q] | (original problem) |
|
alpar@1
|
1336 |
* +-----------------------+-----------+--------------------+
|
alpar@1
|
1337 |
* | GLP_BS | + / - | GLP_BS |
|
alpar@1
|
1338 |
* | GLP_NS | + | GLP_NL |
|
alpar@1
|
1339 |
* | GLP_NS | - | GLP_NU |
|
alpar@1
|
1340 |
* +-----------------------+-----------+--------------------+
|
alpar@1
|
1341 |
*
|
alpar@1
|
1342 |
* Value of column q in solution to the original problem is the same as
|
alpar@1
|
1343 |
* in solution to the transformed problem.
|
alpar@1
|
1344 |
*
|
alpar@1
|
1345 |
* RECOVERING INTERIOR POINT SOLUTION
|
alpar@1
|
1346 |
*
|
alpar@1
|
1347 |
* Value of column q in solution to the original problem is the same as
|
alpar@1
|
1348 |
* in solution to the transformed problem.
|
alpar@1
|
1349 |
*
|
alpar@1
|
1350 |
* RECOVERING MIP SOLUTION
|
alpar@1
|
1351 |
*
|
alpar@1
|
1352 |
* None needed. */
|
alpar@1
|
1353 |
|
alpar@1
|
1354 |
struct make_fixed
|
alpar@1
|
1355 |
{ /* column with almost identical bounds */
|
alpar@1
|
1356 |
int q;
|
alpar@1
|
1357 |
/* column reference number */
|
alpar@1
|
1358 |
double c;
|
alpar@1
|
1359 |
/* objective coefficient at x[q] */
|
alpar@1
|
1360 |
NPPLFE *ptr;
|
alpar@1
|
1361 |
/* list of non-zero coefficients a[i,q] */
|
alpar@1
|
1362 |
};
|
alpar@1
|
1363 |
|
alpar@1
|
1364 |
static int rcv_make_fixed(NPP *npp, void *info);
|
alpar@1
|
1365 |
|
alpar@1
|
1366 |
int npp_make_fixed(NPP *npp, NPPCOL *q)
|
alpar@1
|
1367 |
{ /* process column with almost identical bounds */
|
alpar@1
|
1368 |
struct make_fixed *info;
|
alpar@1
|
1369 |
NPPAIJ *aij;
|
alpar@1
|
1370 |
NPPLFE *lfe;
|
alpar@1
|
1371 |
double s, eps, nint;
|
alpar@1
|
1372 |
/* the column must be double-bounded */
|
alpar@1
|
1373 |
xassert(q->lb != -DBL_MAX);
|
alpar@1
|
1374 |
xassert(q->ub != +DBL_MAX);
|
alpar@1
|
1375 |
xassert(q->lb < q->ub);
|
alpar@1
|
1376 |
/* check column bounds */
|
alpar@1
|
1377 |
eps = 1e-9 + 1e-12 * fabs(q->lb);
|
alpar@1
|
1378 |
if (q->ub - q->lb > eps) return 0;
|
alpar@1
|
1379 |
/* column bounds are very close to each other */
|
alpar@1
|
1380 |
/* create transformation stack entry */
|
alpar@1
|
1381 |
info = npp_push_tse(npp,
|
alpar@1
|
1382 |
rcv_make_fixed, sizeof(struct make_fixed));
|
alpar@1
|
1383 |
info->q = q->j;
|
alpar@1
|
1384 |
info->c = q->coef;
|
alpar@1
|
1385 |
info->ptr = NULL;
|
alpar@1
|
1386 |
/* save column coefficients a[i,q] (needed for basic solution
|
alpar@1
|
1387 |
only) */
|
alpar@1
|
1388 |
if (npp->sol == GLP_SOL)
|
alpar@1
|
1389 |
{ for (aij = q->ptr; aij != NULL; aij = aij->c_next)
|
alpar@1
|
1390 |
{ lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
|
alpar@1
|
1391 |
lfe->ref = aij->row->i;
|
alpar@1
|
1392 |
lfe->val = aij->val;
|
alpar@1
|
1393 |
lfe->next = info->ptr;
|
alpar@1
|
1394 |
info->ptr = lfe;
|
alpar@1
|
1395 |
}
|
alpar@1
|
1396 |
}
|
alpar@1
|
1397 |
/* compute column fixed value */
|
alpar@1
|
1398 |
s = 0.5 * (q->ub + q->lb);
|
alpar@1
|
1399 |
nint = floor(s + 0.5);
|
alpar@1
|
1400 |
if (fabs(s - nint) <= eps) s = nint;
|
alpar@1
|
1401 |
/* make column q fixed */
|
alpar@1
|
1402 |
q->lb = q->ub = s;
|
alpar@1
|
1403 |
return 1;
|
alpar@1
|
1404 |
}
|
alpar@1
|
1405 |
|
alpar@1
|
1406 |
static int rcv_make_fixed(NPP *npp, void *_info)
|
alpar@1
|
1407 |
{ /* recover column with almost identical bounds */
|
alpar@1
|
1408 |
struct make_fixed *info = _info;
|
alpar@1
|
1409 |
NPPLFE *lfe;
|
alpar@1
|
1410 |
double lambda;
|
alpar@1
|
1411 |
if (npp->sol == GLP_SOL)
|
alpar@1
|
1412 |
{ if (npp->c_stat[info->q] == GLP_BS)
|
alpar@1
|
1413 |
npp->c_stat[info->q] = GLP_BS;
|
alpar@1
|
1414 |
else if (npp->c_stat[info->q] == GLP_NS)
|
alpar@1
|
1415 |
{ /* compute multiplier for column q with formula (6) */
|
alpar@1
|
1416 |
lambda = info->c;
|
alpar@1
|
1417 |
for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
|
alpar@1
|
1418 |
lambda -= lfe->val * npp->r_pi[lfe->ref];
|
alpar@1
|
1419 |
/* assign status to non-basic column */
|
alpar@1
|
1420 |
if (lambda >= 0.0)
|
alpar@1
|
1421 |
npp->c_stat[info->q] = GLP_NL;
|
alpar@1
|
1422 |
else
|
alpar@1
|
1423 |
npp->c_stat[info->q] = GLP_NU;
|
alpar@1
|
1424 |
}
|
alpar@1
|
1425 |
else
|
alpar@1
|
1426 |
{ npp_error();
|
alpar@1
|
1427 |
return 1;
|
alpar@1
|
1428 |
}
|
alpar@1
|
1429 |
}
|
alpar@1
|
1430 |
return 0;
|
alpar@1
|
1431 |
}
|
alpar@1
|
1432 |
|
alpar@1
|
1433 |
/* eof */
|