rev |
line source |
alpar@9
|
1 /* glpnpp05.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_clean_prob - perform initial LP/MIP processing
|
alpar@9
|
31 *
|
alpar@9
|
32 * SYNOPSIS
|
alpar@9
|
33 *
|
alpar@9
|
34 * #include "glpnpp.h"
|
alpar@9
|
35 * void npp_clean_prob(NPP *npp);
|
alpar@9
|
36 *
|
alpar@9
|
37 * DESCRIPTION
|
alpar@9
|
38 *
|
alpar@9
|
39 * The routine npp_clean_prob performs initial LP/MIP processing that
|
alpar@9
|
40 * currently includes:
|
alpar@9
|
41 *
|
alpar@9
|
42 * 1) removing free rows;
|
alpar@9
|
43 *
|
alpar@9
|
44 * 2) replacing double-sided constraint rows with almost identical
|
alpar@9
|
45 * bounds, by equality constraint rows;
|
alpar@9
|
46 *
|
alpar@9
|
47 * 3) removing fixed columns;
|
alpar@9
|
48 *
|
alpar@9
|
49 * 4) replacing double-bounded columns with almost identical bounds by
|
alpar@9
|
50 * fixed columns and removing those columns;
|
alpar@9
|
51 *
|
alpar@9
|
52 * 5) initial processing constraint coefficients (not implemented);
|
alpar@9
|
53 *
|
alpar@9
|
54 * 6) initial processing objective coefficients (not implemented). */
|
alpar@9
|
55
|
alpar@9
|
56 void npp_clean_prob(NPP *npp)
|
alpar@9
|
57 { /* perform initial LP/MIP processing */
|
alpar@9
|
58 NPPROW *row, *next_row;
|
alpar@9
|
59 NPPCOL *col, *next_col;
|
alpar@9
|
60 int ret;
|
alpar@9
|
61 xassert(npp == npp);
|
alpar@9
|
62 /* process rows which originally are free */
|
alpar@9
|
63 for (row = npp->r_head; row != NULL; row = next_row)
|
alpar@9
|
64 { next_row = row->next;
|
alpar@9
|
65 if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
|
alpar@9
|
66 { /* process free row */
|
alpar@9
|
67 #ifdef GLP_DEBUG
|
alpar@9
|
68 xprintf("1");
|
alpar@9
|
69 #endif
|
alpar@9
|
70 npp_free_row(npp, row);
|
alpar@9
|
71 /* row was deleted */
|
alpar@9
|
72 }
|
alpar@9
|
73 }
|
alpar@9
|
74 /* process rows which originally are double-sided inequalities */
|
alpar@9
|
75 for (row = npp->r_head; row != NULL; row = next_row)
|
alpar@9
|
76 { next_row = row->next;
|
alpar@9
|
77 if (row->lb != -DBL_MAX && row->ub != +DBL_MAX &&
|
alpar@9
|
78 row->lb < row->ub)
|
alpar@9
|
79 { ret = npp_make_equality(npp, row);
|
alpar@9
|
80 if (ret == 0)
|
alpar@9
|
81 ;
|
alpar@9
|
82 else if (ret == 1)
|
alpar@9
|
83 { /* row was replaced by equality constraint */
|
alpar@9
|
84 #ifdef GLP_DEBUG
|
alpar@9
|
85 xprintf("2");
|
alpar@9
|
86 #endif
|
alpar@9
|
87 }
|
alpar@9
|
88 else
|
alpar@9
|
89 xassert(ret != ret);
|
alpar@9
|
90 }
|
alpar@9
|
91 }
|
alpar@9
|
92 /* process columns which are originally fixed */
|
alpar@9
|
93 for (col = npp->c_head; col != NULL; col = next_col)
|
alpar@9
|
94 { next_col = col->next;
|
alpar@9
|
95 if (col->lb == col->ub)
|
alpar@9
|
96 { /* process fixed column */
|
alpar@9
|
97 #ifdef GLP_DEBUG
|
alpar@9
|
98 xprintf("3");
|
alpar@9
|
99 #endif
|
alpar@9
|
100 npp_fixed_col(npp, col);
|
alpar@9
|
101 /* column was deleted */
|
alpar@9
|
102 }
|
alpar@9
|
103 }
|
alpar@9
|
104 /* process columns which are originally double-bounded */
|
alpar@9
|
105 for (col = npp->c_head; col != NULL; col = next_col)
|
alpar@9
|
106 { next_col = col->next;
|
alpar@9
|
107 if (col->lb != -DBL_MAX && col->ub != +DBL_MAX &&
|
alpar@9
|
108 col->lb < col->ub)
|
alpar@9
|
109 { ret = npp_make_fixed(npp, col);
|
alpar@9
|
110 if (ret == 0)
|
alpar@9
|
111 ;
|
alpar@9
|
112 else if (ret == 1)
|
alpar@9
|
113 { /* column was replaced by fixed column; process it */
|
alpar@9
|
114 #ifdef GLP_DEBUG
|
alpar@9
|
115 xprintf("4");
|
alpar@9
|
116 #endif
|
alpar@9
|
117 npp_fixed_col(npp, col);
|
alpar@9
|
118 /* column was deleted */
|
alpar@9
|
119 }
|
alpar@9
|
120 }
|
alpar@9
|
121 }
|
alpar@9
|
122 return;
|
alpar@9
|
123 }
|
alpar@9
|
124
|
alpar@9
|
125 /***********************************************************************
|
alpar@9
|
126 * NAME
|
alpar@9
|
127 *
|
alpar@9
|
128 * npp_process_row - perform basic row processing
|
alpar@9
|
129 *
|
alpar@9
|
130 * SYNOPSIS
|
alpar@9
|
131 *
|
alpar@9
|
132 * #include "glpnpp.h"
|
alpar@9
|
133 * int npp_process_row(NPP *npp, NPPROW *row, int hard);
|
alpar@9
|
134 *
|
alpar@9
|
135 * DESCRIPTION
|
alpar@9
|
136 *
|
alpar@9
|
137 * The routine npp_process_row performs basic row processing that
|
alpar@9
|
138 * currently includes:
|
alpar@9
|
139 *
|
alpar@9
|
140 * 1) removing empty row;
|
alpar@9
|
141 *
|
alpar@9
|
142 * 2) removing equality constraint row singleton and corresponding
|
alpar@9
|
143 * column;
|
alpar@9
|
144 *
|
alpar@9
|
145 * 3) removing inequality constraint row singleton and corresponding
|
alpar@9
|
146 * column if it was fixed;
|
alpar@9
|
147 *
|
alpar@9
|
148 * 4) performing general row analysis;
|
alpar@9
|
149 *
|
alpar@9
|
150 * 5) removing redundant row bounds;
|
alpar@9
|
151 *
|
alpar@9
|
152 * 6) removing forcing row and corresponding columns;
|
alpar@9
|
153 *
|
alpar@9
|
154 * 7) removing row which becomes free due to redundant bounds;
|
alpar@9
|
155 *
|
alpar@9
|
156 * 8) computing implied bounds for all columns in the row and using
|
alpar@9
|
157 * them to strengthen current column bounds (MIP only, optional,
|
alpar@9
|
158 * performed if the flag hard is on).
|
alpar@9
|
159 *
|
alpar@9
|
160 * Additionally the routine may activate affected rows and/or columns
|
alpar@9
|
161 * for further processing.
|
alpar@9
|
162 *
|
alpar@9
|
163 * RETURNS
|
alpar@9
|
164 *
|
alpar@9
|
165 * 0 success;
|
alpar@9
|
166 *
|
alpar@9
|
167 * GLP_ENOPFS primal/integer infeasibility detected;
|
alpar@9
|
168 *
|
alpar@9
|
169 * GLP_ENODFS dual infeasibility detected. */
|
alpar@9
|
170
|
alpar@9
|
171 int npp_process_row(NPP *npp, NPPROW *row, int hard)
|
alpar@9
|
172 { /* perform basic row processing */
|
alpar@9
|
173 NPPCOL *col;
|
alpar@9
|
174 NPPAIJ *aij, *next_aij, *aaa;
|
alpar@9
|
175 int ret;
|
alpar@9
|
176 /* row must not be free */
|
alpar@9
|
177 xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
|
alpar@9
|
178 /* start processing row */
|
alpar@9
|
179 if (row->ptr == NULL)
|
alpar@9
|
180 { /* empty row */
|
alpar@9
|
181 ret = npp_empty_row(npp, row);
|
alpar@9
|
182 if (ret == 0)
|
alpar@9
|
183 { /* row was deleted */
|
alpar@9
|
184 #ifdef GLP_DEBUG
|
alpar@9
|
185 xprintf("A");
|
alpar@9
|
186 #endif
|
alpar@9
|
187 return 0;
|
alpar@9
|
188 }
|
alpar@9
|
189 else if (ret == 1)
|
alpar@9
|
190 { /* primal infeasibility */
|
alpar@9
|
191 return GLP_ENOPFS;
|
alpar@9
|
192 }
|
alpar@9
|
193 else
|
alpar@9
|
194 xassert(ret != ret);
|
alpar@9
|
195 }
|
alpar@9
|
196 if (row->ptr->r_next == NULL)
|
alpar@9
|
197 { /* row singleton */
|
alpar@9
|
198 col = row->ptr->col;
|
alpar@9
|
199 if (row->lb == row->ub)
|
alpar@9
|
200 { /* equality constraint */
|
alpar@9
|
201 ret = npp_eq_singlet(npp, row);
|
alpar@9
|
202 if (ret == 0)
|
alpar@9
|
203 { /* column was fixed, row was deleted */
|
alpar@9
|
204 #ifdef GLP_DEBUG
|
alpar@9
|
205 xprintf("B");
|
alpar@9
|
206 #endif
|
alpar@9
|
207 /* activate rows affected by column */
|
alpar@9
|
208 for (aij = col->ptr; aij != NULL; aij = aij->c_next)
|
alpar@9
|
209 npp_activate_row(npp, aij->row);
|
alpar@9
|
210 /* process fixed column */
|
alpar@9
|
211 npp_fixed_col(npp, col);
|
alpar@9
|
212 /* column was deleted */
|
alpar@9
|
213 return 0;
|
alpar@9
|
214 }
|
alpar@9
|
215 else if (ret == 1 || ret == 2)
|
alpar@9
|
216 { /* primal/integer infeasibility */
|
alpar@9
|
217 return GLP_ENOPFS;
|
alpar@9
|
218 }
|
alpar@9
|
219 else
|
alpar@9
|
220 xassert(ret != ret);
|
alpar@9
|
221 }
|
alpar@9
|
222 else
|
alpar@9
|
223 { /* inequality constraint */
|
alpar@9
|
224 ret = npp_ineq_singlet(npp, row);
|
alpar@9
|
225 if (0 <= ret && ret <= 3)
|
alpar@9
|
226 { /* row was deleted */
|
alpar@9
|
227 #ifdef GLP_DEBUG
|
alpar@9
|
228 xprintf("C");
|
alpar@9
|
229 #endif
|
alpar@9
|
230 /* activate column, since its length was changed due to
|
alpar@9
|
231 row deletion */
|
alpar@9
|
232 npp_activate_col(npp, col);
|
alpar@9
|
233 if (ret >= 2)
|
alpar@9
|
234 { /* column bounds changed significantly or column was
|
alpar@9
|
235 fixed */
|
alpar@9
|
236 /* activate rows affected by column */
|
alpar@9
|
237 for (aij = col->ptr; aij != NULL; aij = aij->c_next)
|
alpar@9
|
238 npp_activate_row(npp, aij->row);
|
alpar@9
|
239 }
|
alpar@9
|
240 if (ret == 3)
|
alpar@9
|
241 { /* column was fixed; process it */
|
alpar@9
|
242 #ifdef GLP_DEBUG
|
alpar@9
|
243 xprintf("D");
|
alpar@9
|
244 #endif
|
alpar@9
|
245 npp_fixed_col(npp, col);
|
alpar@9
|
246 /* column was deleted */
|
alpar@9
|
247 }
|
alpar@9
|
248 return 0;
|
alpar@9
|
249 }
|
alpar@9
|
250 else if (ret == 4)
|
alpar@9
|
251 { /* primal infeasibility */
|
alpar@9
|
252 return GLP_ENOPFS;
|
alpar@9
|
253 }
|
alpar@9
|
254 else
|
alpar@9
|
255 xassert(ret != ret);
|
alpar@9
|
256 }
|
alpar@9
|
257 }
|
alpar@9
|
258 #if 0
|
alpar@9
|
259 /* sometimes this causes too large round-off errors; probably
|
alpar@9
|
260 pivot coefficient should be chosen more carefully */
|
alpar@9
|
261 if (row->ptr->r_next->r_next == NULL)
|
alpar@9
|
262 { /* row doubleton */
|
alpar@9
|
263 if (row->lb == row->ub)
|
alpar@9
|
264 { /* equality constraint */
|
alpar@9
|
265 if (!(row->ptr->col->is_int ||
|
alpar@9
|
266 row->ptr->r_next->col->is_int))
|
alpar@9
|
267 { /* both columns are continuous */
|
alpar@9
|
268 NPPCOL *q;
|
alpar@9
|
269 q = npp_eq_doublet(npp, row);
|
alpar@9
|
270 if (q != NULL)
|
alpar@9
|
271 { /* column q was eliminated */
|
alpar@9
|
272 #ifdef GLP_DEBUG
|
alpar@9
|
273 xprintf("E");
|
alpar@9
|
274 #endif
|
alpar@9
|
275 /* now column q is singleton of type "implied slack
|
alpar@9
|
276 variable"; we process it here to make sure that on
|
alpar@9
|
277 recovering basic solution the row is always active
|
alpar@9
|
278 equality constraint (as required by the routine
|
alpar@9
|
279 rcv_eq_doublet) */
|
alpar@9
|
280 xassert(npp_process_col(npp, q) == 0);
|
alpar@9
|
281 /* column q was deleted; note that row p also may be
|
alpar@9
|
282 deleted */
|
alpar@9
|
283 return 0;
|
alpar@9
|
284 }
|
alpar@9
|
285 }
|
alpar@9
|
286 }
|
alpar@9
|
287 }
|
alpar@9
|
288 #endif
|
alpar@9
|
289 /* general row analysis */
|
alpar@9
|
290 ret = npp_analyze_row(npp, row);
|
alpar@9
|
291 xassert(0x00 <= ret && ret <= 0xFF);
|
alpar@9
|
292 if (ret == 0x33)
|
alpar@9
|
293 { /* row bounds are inconsistent with column bounds */
|
alpar@9
|
294 return GLP_ENOPFS;
|
alpar@9
|
295 }
|
alpar@9
|
296 if ((ret & 0x0F) == 0x00)
|
alpar@9
|
297 { /* row lower bound does not exist or redundant */
|
alpar@9
|
298 if (row->lb != -DBL_MAX)
|
alpar@9
|
299 { /* remove redundant row lower bound */
|
alpar@9
|
300 #ifdef GLP_DEBUG
|
alpar@9
|
301 xprintf("F");
|
alpar@9
|
302 #endif
|
alpar@9
|
303 npp_inactive_bound(npp, row, 0);
|
alpar@9
|
304 }
|
alpar@9
|
305 }
|
alpar@9
|
306 else if ((ret & 0x0F) == 0x01)
|
alpar@9
|
307 { /* row lower bound can be active */
|
alpar@9
|
308 /* see below */
|
alpar@9
|
309 }
|
alpar@9
|
310 else if ((ret & 0x0F) == 0x02)
|
alpar@9
|
311 { /* row lower bound is a forcing bound */
|
alpar@9
|
312 #ifdef GLP_DEBUG
|
alpar@9
|
313 xprintf("G");
|
alpar@9
|
314 #endif
|
alpar@9
|
315 /* process forcing row */
|
alpar@9
|
316 if (npp_forcing_row(npp, row, 0) == 0)
|
alpar@9
|
317 fixup: { /* columns were fixed, row was made free */
|
alpar@9
|
318 for (aij = row->ptr; aij != NULL; aij = next_aij)
|
alpar@9
|
319 { /* process column fixed by forcing row */
|
alpar@9
|
320 #ifdef GLP_DEBUG
|
alpar@9
|
321 xprintf("H");
|
alpar@9
|
322 #endif
|
alpar@9
|
323 col = aij->col;
|
alpar@9
|
324 next_aij = aij->r_next;
|
alpar@9
|
325 /* activate rows affected by column */
|
alpar@9
|
326 for (aaa = col->ptr; aaa != NULL; aaa = aaa->c_next)
|
alpar@9
|
327 npp_activate_row(npp, aaa->row);
|
alpar@9
|
328 /* process fixed column */
|
alpar@9
|
329 npp_fixed_col(npp, col);
|
alpar@9
|
330 /* column was deleted */
|
alpar@9
|
331 }
|
alpar@9
|
332 /* process free row (which now is empty due to deletion of
|
alpar@9
|
333 all its columns) */
|
alpar@9
|
334 npp_free_row(npp, row);
|
alpar@9
|
335 /* row was deleted */
|
alpar@9
|
336 return 0;
|
alpar@9
|
337 }
|
alpar@9
|
338 }
|
alpar@9
|
339 else
|
alpar@9
|
340 xassert(ret != ret);
|
alpar@9
|
341 if ((ret & 0xF0) == 0x00)
|
alpar@9
|
342 { /* row upper bound does not exist or redundant */
|
alpar@9
|
343 if (row->ub != +DBL_MAX)
|
alpar@9
|
344 { /* remove redundant row upper bound */
|
alpar@9
|
345 #ifdef GLP_DEBUG
|
alpar@9
|
346 xprintf("I");
|
alpar@9
|
347 #endif
|
alpar@9
|
348 npp_inactive_bound(npp, row, 1);
|
alpar@9
|
349 }
|
alpar@9
|
350 }
|
alpar@9
|
351 else if ((ret & 0xF0) == 0x10)
|
alpar@9
|
352 { /* row upper bound can be active */
|
alpar@9
|
353 /* see below */
|
alpar@9
|
354 }
|
alpar@9
|
355 else if ((ret & 0xF0) == 0x20)
|
alpar@9
|
356 { /* row upper bound is a forcing bound */
|
alpar@9
|
357 #ifdef GLP_DEBUG
|
alpar@9
|
358 xprintf("J");
|
alpar@9
|
359 #endif
|
alpar@9
|
360 /* process forcing row */
|
alpar@9
|
361 if (npp_forcing_row(npp, row, 1) == 0) goto fixup;
|
alpar@9
|
362 }
|
alpar@9
|
363 else
|
alpar@9
|
364 xassert(ret != ret);
|
alpar@9
|
365 if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
|
alpar@9
|
366 { /* row became free due to redundant bounds removal */
|
alpar@9
|
367 #ifdef GLP_DEBUG
|
alpar@9
|
368 xprintf("K");
|
alpar@9
|
369 #endif
|
alpar@9
|
370 /* activate its columns, since their length will change due
|
alpar@9
|
371 to row deletion */
|
alpar@9
|
372 for (aij = row->ptr; aij != NULL; aij = aij->r_next)
|
alpar@9
|
373 npp_activate_col(npp, aij->col);
|
alpar@9
|
374 /* process free row */
|
alpar@9
|
375 npp_free_row(npp, row);
|
alpar@9
|
376 /* row was deleted */
|
alpar@9
|
377 return 0;
|
alpar@9
|
378 }
|
alpar@9
|
379 #if 1 /* 23/XII-2009 */
|
alpar@9
|
380 /* row lower and/or upper bounds can be active */
|
alpar@9
|
381 if (npp->sol == GLP_MIP && hard)
|
alpar@9
|
382 { /* improve current column bounds (optional) */
|
alpar@9
|
383 if (npp_improve_bounds(npp, row, 1) < 0)
|
alpar@9
|
384 return GLP_ENOPFS;
|
alpar@9
|
385 }
|
alpar@9
|
386 #endif
|
alpar@9
|
387 return 0;
|
alpar@9
|
388 }
|
alpar@9
|
389
|
alpar@9
|
390 /***********************************************************************
|
alpar@9
|
391 * NAME
|
alpar@9
|
392 *
|
alpar@9
|
393 * npp_improve_bounds - improve current column bounds
|
alpar@9
|
394 *
|
alpar@9
|
395 * SYNOPSIS
|
alpar@9
|
396 *
|
alpar@9
|
397 * #include "glpnpp.h"
|
alpar@9
|
398 * int npp_improve_bounds(NPP *npp, NPPROW *row, int flag);
|
alpar@9
|
399 *
|
alpar@9
|
400 * DESCRIPTION
|
alpar@9
|
401 *
|
alpar@9
|
402 * The routine npp_improve_bounds analyzes specified row (inequality
|
alpar@9
|
403 * or equality constraint) to determine implied column bounds and then
|
alpar@9
|
404 * uses these bounds to improve (strengthen) current column bounds.
|
alpar@9
|
405 *
|
alpar@9
|
406 * If the flag is on and current column bounds changed significantly
|
alpar@9
|
407 * or the column was fixed, the routine activate rows affected by the
|
alpar@9
|
408 * column for further processing. (This feature is intended to be used
|
alpar@9
|
409 * in the main loop of the routine npp_process_row.)
|
alpar@9
|
410 *
|
alpar@9
|
411 * NOTE: This operation can be used for MIP problem only.
|
alpar@9
|
412 *
|
alpar@9
|
413 * RETURNS
|
alpar@9
|
414 *
|
alpar@9
|
415 * The routine npp_improve_bounds returns the number of significantly
|
alpar@9
|
416 * changed bounds plus the number of column having been fixed due to
|
alpar@9
|
417 * bound improvements. However, if the routine detects primal/integer
|
alpar@9
|
418 * infeasibility, it returns a negative value. */
|
alpar@9
|
419
|
alpar@9
|
420 int npp_improve_bounds(NPP *npp, NPPROW *row, int flag)
|
alpar@9
|
421 { /* improve current column bounds */
|
alpar@9
|
422 NPPCOL *col;
|
alpar@9
|
423 NPPAIJ *aij, *next_aij, *aaa;
|
alpar@9
|
424 int kase, ret, count = 0;
|
alpar@9
|
425 double lb, ub;
|
alpar@9
|
426 xassert(npp->sol == GLP_MIP);
|
alpar@9
|
427 /* row must not be free */
|
alpar@9
|
428 xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
|
alpar@9
|
429 /* determine implied column bounds */
|
alpar@9
|
430 npp_implied_bounds(npp, row);
|
alpar@9
|
431 /* and use these bounds to strengthen current column bounds */
|
alpar@9
|
432 for (aij = row->ptr; aij != NULL; aij = next_aij)
|
alpar@9
|
433 { col = aij->col;
|
alpar@9
|
434 next_aij = aij->r_next;
|
alpar@9
|
435 for (kase = 0; kase <= 1; kase++)
|
alpar@9
|
436 { /* save current column bounds */
|
alpar@9
|
437 lb = col->lb, ub = col->ub;
|
alpar@9
|
438 if (kase == 0)
|
alpar@9
|
439 { /* process implied column lower bound */
|
alpar@9
|
440 if (col->ll.ll == -DBL_MAX) continue;
|
alpar@9
|
441 ret = npp_implied_lower(npp, col, col->ll.ll);
|
alpar@9
|
442 }
|
alpar@9
|
443 else
|
alpar@9
|
444 { /* process implied column upper bound */
|
alpar@9
|
445 if (col->uu.uu == +DBL_MAX) continue;
|
alpar@9
|
446 ret = npp_implied_upper(npp, col, col->uu.uu);
|
alpar@9
|
447 }
|
alpar@9
|
448 if (ret == 0 || ret == 1)
|
alpar@9
|
449 { /* current column bounds did not change or changed, but
|
alpar@9
|
450 not significantly; restore current column bounds */
|
alpar@9
|
451 col->lb = lb, col->ub = ub;
|
alpar@9
|
452 }
|
alpar@9
|
453 else if (ret == 2 || ret == 3)
|
alpar@9
|
454 { /* current column bounds changed significantly or column
|
alpar@9
|
455 was fixed */
|
alpar@9
|
456 #ifdef GLP_DEBUG
|
alpar@9
|
457 xprintf("L");
|
alpar@9
|
458 #endif
|
alpar@9
|
459 count++;
|
alpar@9
|
460 /* activate other rows affected by column, if required */
|
alpar@9
|
461 if (flag)
|
alpar@9
|
462 { for (aaa = col->ptr; aaa != NULL; aaa = aaa->c_next)
|
alpar@9
|
463 { if (aaa->row != row)
|
alpar@9
|
464 npp_activate_row(npp, aaa->row);
|
alpar@9
|
465 }
|
alpar@9
|
466 }
|
alpar@9
|
467 if (ret == 3)
|
alpar@9
|
468 { /* process fixed column */
|
alpar@9
|
469 #ifdef GLP_DEBUG
|
alpar@9
|
470 xprintf("M");
|
alpar@9
|
471 #endif
|
alpar@9
|
472 npp_fixed_col(npp, col);
|
alpar@9
|
473 /* column was deleted */
|
alpar@9
|
474 break; /* for kase */
|
alpar@9
|
475 }
|
alpar@9
|
476 }
|
alpar@9
|
477 else if (ret == 4)
|
alpar@9
|
478 { /* primal/integer infeasibility */
|
alpar@9
|
479 return -1;
|
alpar@9
|
480 }
|
alpar@9
|
481 else
|
alpar@9
|
482 xassert(ret != ret);
|
alpar@9
|
483 }
|
alpar@9
|
484 }
|
alpar@9
|
485 return count;
|
alpar@9
|
486 }
|
alpar@9
|
487
|
alpar@9
|
488 /***********************************************************************
|
alpar@9
|
489 * NAME
|
alpar@9
|
490 *
|
alpar@9
|
491 * npp_process_col - perform basic column processing
|
alpar@9
|
492 *
|
alpar@9
|
493 * SYNOPSIS
|
alpar@9
|
494 *
|
alpar@9
|
495 * #include "glpnpp.h"
|
alpar@9
|
496 * int npp_process_col(NPP *npp, NPPCOL *col);
|
alpar@9
|
497 *
|
alpar@9
|
498 * DESCRIPTION
|
alpar@9
|
499 *
|
alpar@9
|
500 * The routine npp_process_col performs basic column processing that
|
alpar@9
|
501 * currently includes:
|
alpar@9
|
502 *
|
alpar@9
|
503 * 1) fixing and removing empty column;
|
alpar@9
|
504 *
|
alpar@9
|
505 * 2) removing column singleton, which is implied slack variable, and
|
alpar@9
|
506 * corresponding row if it becomes free;
|
alpar@9
|
507 *
|
alpar@9
|
508 * 3) removing bounds of column, which is implied free variable, and
|
alpar@9
|
509 * replacing corresponding row by equality constraint.
|
alpar@9
|
510 *
|
alpar@9
|
511 * Additionally the routine may activate affected rows and/or columns
|
alpar@9
|
512 * for further processing.
|
alpar@9
|
513 *
|
alpar@9
|
514 * RETURNS
|
alpar@9
|
515 *
|
alpar@9
|
516 * 0 success;
|
alpar@9
|
517 *
|
alpar@9
|
518 * GLP_ENOPFS primal/integer infeasibility detected;
|
alpar@9
|
519 *
|
alpar@9
|
520 * GLP_ENODFS dual infeasibility detected. */
|
alpar@9
|
521
|
alpar@9
|
522 int npp_process_col(NPP *npp, NPPCOL *col)
|
alpar@9
|
523 { /* perform basic column processing */
|
alpar@9
|
524 NPPROW *row;
|
alpar@9
|
525 NPPAIJ *aij;
|
alpar@9
|
526 int ret;
|
alpar@9
|
527 /* column must not be fixed */
|
alpar@9
|
528 xassert(col->lb < col->ub);
|
alpar@9
|
529 /* start processing column */
|
alpar@9
|
530 if (col->ptr == NULL)
|
alpar@9
|
531 { /* empty column */
|
alpar@9
|
532 ret = npp_empty_col(npp, col);
|
alpar@9
|
533 if (ret == 0)
|
alpar@9
|
534 { /* column was fixed and deleted */
|
alpar@9
|
535 #ifdef GLP_DEBUG
|
alpar@9
|
536 xprintf("N");
|
alpar@9
|
537 #endif
|
alpar@9
|
538 return 0;
|
alpar@9
|
539 }
|
alpar@9
|
540 else if (ret == 1)
|
alpar@9
|
541 { /* dual infeasibility */
|
alpar@9
|
542 return GLP_ENODFS;
|
alpar@9
|
543 }
|
alpar@9
|
544 else
|
alpar@9
|
545 xassert(ret != ret);
|
alpar@9
|
546 }
|
alpar@9
|
547 if (col->ptr->c_next == NULL)
|
alpar@9
|
548 { /* column singleton */
|
alpar@9
|
549 row = col->ptr->row;
|
alpar@9
|
550 if (row->lb == row->ub)
|
alpar@9
|
551 { /* equality constraint */
|
alpar@9
|
552 if (!col->is_int)
|
alpar@9
|
553 slack: { /* implied slack variable */
|
alpar@9
|
554 #ifdef GLP_DEBUG
|
alpar@9
|
555 xprintf("O");
|
alpar@9
|
556 #endif
|
alpar@9
|
557 npp_implied_slack(npp, col);
|
alpar@9
|
558 /* column was deleted */
|
alpar@9
|
559 if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
|
alpar@9
|
560 { /* row became free due to implied slack variable */
|
alpar@9
|
561 #ifdef GLP_DEBUG
|
alpar@9
|
562 xprintf("P");
|
alpar@9
|
563 #endif
|
alpar@9
|
564 /* activate columns affected by row */
|
alpar@9
|
565 for (aij = row->ptr; aij != NULL; aij = aij->r_next)
|
alpar@9
|
566 npp_activate_col(npp, aij->col);
|
alpar@9
|
567 /* process free row */
|
alpar@9
|
568 npp_free_row(npp, row);
|
alpar@9
|
569 /* row was deleted */
|
alpar@9
|
570 }
|
alpar@9
|
571 else
|
alpar@9
|
572 { /* row became inequality constraint; activate it
|
alpar@9
|
573 since its length changed due to column deletion */
|
alpar@9
|
574 npp_activate_row(npp, row);
|
alpar@9
|
575 }
|
alpar@9
|
576 return 0;
|
alpar@9
|
577 }
|
alpar@9
|
578 }
|
alpar@9
|
579 else
|
alpar@9
|
580 { /* inequality constraint */
|
alpar@9
|
581 if (!col->is_int)
|
alpar@9
|
582 { ret = npp_implied_free(npp, col);
|
alpar@9
|
583 if (ret == 0)
|
alpar@9
|
584 { /* implied free variable */
|
alpar@9
|
585 #ifdef GLP_DEBUG
|
alpar@9
|
586 xprintf("Q");
|
alpar@9
|
587 #endif
|
alpar@9
|
588 /* column bounds were removed, row was replaced by
|
alpar@9
|
589 equality constraint */
|
alpar@9
|
590 goto slack;
|
alpar@9
|
591 }
|
alpar@9
|
592 else if (ret == 1)
|
alpar@9
|
593 { /* column is not implied free variable, because its
|
alpar@9
|
594 lower and/or upper bounds can be active */
|
alpar@9
|
595 }
|
alpar@9
|
596 else if (ret == 2)
|
alpar@9
|
597 { /* dual infeasibility */
|
alpar@9
|
598 return GLP_ENODFS;
|
alpar@9
|
599 }
|
alpar@9
|
600 }
|
alpar@9
|
601 }
|
alpar@9
|
602 }
|
alpar@9
|
603 /* column still exists */
|
alpar@9
|
604 return 0;
|
alpar@9
|
605 }
|
alpar@9
|
606
|
alpar@9
|
607 /***********************************************************************
|
alpar@9
|
608 * NAME
|
alpar@9
|
609 *
|
alpar@9
|
610 * npp_process_prob - perform basic LP/MIP processing
|
alpar@9
|
611 *
|
alpar@9
|
612 * SYNOPSIS
|
alpar@9
|
613 *
|
alpar@9
|
614 * #include "glpnpp.h"
|
alpar@9
|
615 * int npp_process_prob(NPP *npp, int hard);
|
alpar@9
|
616 *
|
alpar@9
|
617 * DESCRIPTION
|
alpar@9
|
618 *
|
alpar@9
|
619 * The routine npp_process_prob performs basic LP/MIP processing that
|
alpar@9
|
620 * currently includes:
|
alpar@9
|
621 *
|
alpar@9
|
622 * 1) initial LP/MIP processing (see the routine npp_clean_prob),
|
alpar@9
|
623 *
|
alpar@9
|
624 * 2) basic row processing (see the routine npp_process_row), and
|
alpar@9
|
625 *
|
alpar@9
|
626 * 3) basic column processing (see the routine npp_process_col).
|
alpar@9
|
627 *
|
alpar@9
|
628 * If the flag hard is on, the routine attempts to improve current
|
alpar@9
|
629 * column bounds multiple times within the main processing loop, in
|
alpar@9
|
630 * which case this feature may take a time. Otherwise, if the flag hard
|
alpar@9
|
631 * is off, improving column bounds is performed only once at the end of
|
alpar@9
|
632 * the main loop. (Note that this feature is used for MIP only.)
|
alpar@9
|
633 *
|
alpar@9
|
634 * The routine uses two sets: the set of active rows and the set of
|
alpar@9
|
635 * active columns. Rows/columns are marked by a flag (the field temp in
|
alpar@9
|
636 * NPPROW/NPPCOL). If the flag is non-zero, the row/column is active,
|
alpar@9
|
637 * in which case it is placed in the beginning of the row/column list;
|
alpar@9
|
638 * otherwise, if the flag is zero, the row/column is inactive, in which
|
alpar@9
|
639 * case it is placed in the end of the row/column list. If a row/column
|
alpar@9
|
640 * being currently processed may affect other rows/columns, the latters
|
alpar@9
|
641 * are activated for further processing.
|
alpar@9
|
642 *
|
alpar@9
|
643 * RETURNS
|
alpar@9
|
644 *
|
alpar@9
|
645 * 0 success;
|
alpar@9
|
646 *
|
alpar@9
|
647 * GLP_ENOPFS primal/integer infeasibility detected;
|
alpar@9
|
648 *
|
alpar@9
|
649 * GLP_ENODFS dual infeasibility detected. */
|
alpar@9
|
650
|
alpar@9
|
651 int npp_process_prob(NPP *npp, int hard)
|
alpar@9
|
652 { /* perform basic LP/MIP processing */
|
alpar@9
|
653 NPPROW *row;
|
alpar@9
|
654 NPPCOL *col;
|
alpar@9
|
655 int processing, ret;
|
alpar@9
|
656 /* perform initial LP/MIP processing */
|
alpar@9
|
657 npp_clean_prob(npp);
|
alpar@9
|
658 /* activate all remaining rows and columns */
|
alpar@9
|
659 for (row = npp->r_head; row != NULL; row = row->next)
|
alpar@9
|
660 row->temp = 1;
|
alpar@9
|
661 for (col = npp->c_head; col != NULL; col = col->next)
|
alpar@9
|
662 col->temp = 1;
|
alpar@9
|
663 /* main processing loop */
|
alpar@9
|
664 processing = 1;
|
alpar@9
|
665 while (processing)
|
alpar@9
|
666 { processing = 0;
|
alpar@9
|
667 /* process all active rows */
|
alpar@9
|
668 for (;;)
|
alpar@9
|
669 { row = npp->r_head;
|
alpar@9
|
670 if (row == NULL || !row->temp) break;
|
alpar@9
|
671 npp_deactivate_row(npp, row);
|
alpar@9
|
672 ret = npp_process_row(npp, row, hard);
|
alpar@9
|
673 if (ret != 0) goto done;
|
alpar@9
|
674 processing = 1;
|
alpar@9
|
675 }
|
alpar@9
|
676 /* process all active columns */
|
alpar@9
|
677 for (;;)
|
alpar@9
|
678 { col = npp->c_head;
|
alpar@9
|
679 if (col == NULL || !col->temp) break;
|
alpar@9
|
680 npp_deactivate_col(npp, col);
|
alpar@9
|
681 ret = npp_process_col(npp, col);
|
alpar@9
|
682 if (ret != 0) goto done;
|
alpar@9
|
683 processing = 1;
|
alpar@9
|
684 }
|
alpar@9
|
685 }
|
alpar@9
|
686 #if 1 /* 23/XII-2009 */
|
alpar@9
|
687 if (npp->sol == GLP_MIP && !hard)
|
alpar@9
|
688 { /* improve current column bounds (optional) */
|
alpar@9
|
689 for (row = npp->r_head; row != NULL; row = row->next)
|
alpar@9
|
690 { if (npp_improve_bounds(npp, row, 0) < 0)
|
alpar@9
|
691 { ret = GLP_ENOPFS;
|
alpar@9
|
692 goto done;
|
alpar@9
|
693 }
|
alpar@9
|
694 }
|
alpar@9
|
695 }
|
alpar@9
|
696 #endif
|
alpar@9
|
697 /* all seems ok */
|
alpar@9
|
698 ret = 0;
|
alpar@9
|
699 done: xassert(ret == 0 || ret == GLP_ENOPFS || ret == GLP_ENODFS);
|
alpar@9
|
700 #ifdef GLP_DEBUG
|
alpar@9
|
701 xprintf("\n");
|
alpar@9
|
702 #endif
|
alpar@9
|
703 return ret;
|
alpar@9
|
704 }
|
alpar@9
|
705
|
alpar@9
|
706 /**********************************************************************/
|
alpar@9
|
707
|
alpar@9
|
708 int npp_simplex(NPP *npp, const glp_smcp *parm)
|
alpar@9
|
709 { /* process LP prior to applying primal/dual simplex method */
|
alpar@9
|
710 int ret;
|
alpar@9
|
711 xassert(npp->sol == GLP_SOL);
|
alpar@9
|
712 xassert(parm == parm);
|
alpar@9
|
713 ret = npp_process_prob(npp, 0);
|
alpar@9
|
714 return ret;
|
alpar@9
|
715 }
|
alpar@9
|
716
|
alpar@9
|
717 /**********************************************************************/
|
alpar@9
|
718
|
alpar@9
|
719 int npp_integer(NPP *npp, const glp_iocp *parm)
|
alpar@9
|
720 { /* process MIP prior to applying branch-and-bound method */
|
alpar@9
|
721 NPPROW *row, *prev_row;
|
alpar@9
|
722 NPPCOL *col;
|
alpar@9
|
723 NPPAIJ *aij;
|
alpar@9
|
724 int count, ret;
|
alpar@9
|
725 xassert(npp->sol == GLP_MIP);
|
alpar@9
|
726 xassert(parm == parm);
|
alpar@9
|
727 /*==============================================================*/
|
alpar@9
|
728 /* perform basic MIP processing */
|
alpar@9
|
729 ret = npp_process_prob(npp, 1);
|
alpar@9
|
730 if (ret != 0) goto done;
|
alpar@9
|
731 /*==============================================================*/
|
alpar@9
|
732 /* binarize problem, if required */
|
alpar@9
|
733 if (parm->binarize)
|
alpar@9
|
734 npp_binarize_prob(npp);
|
alpar@9
|
735 /*==============================================================*/
|
alpar@9
|
736 /* identify hidden packing inequalities */
|
alpar@9
|
737 count = 0;
|
alpar@9
|
738 /* new rows will be added to the end of the row list, so we go
|
alpar@9
|
739 from the end to beginning of the row list */
|
alpar@9
|
740 for (row = npp->r_tail; row != NULL; row = prev_row)
|
alpar@9
|
741 { prev_row = row->prev;
|
alpar@9
|
742 /* skip free row */
|
alpar@9
|
743 if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) continue;
|
alpar@9
|
744 /* skip equality constraint */
|
alpar@9
|
745 if (row->lb == row->ub) continue;
|
alpar@9
|
746 /* skip row having less than two variables */
|
alpar@9
|
747 if (row->ptr == NULL || row->ptr->r_next == NULL) continue;
|
alpar@9
|
748 /* skip row having non-binary variables */
|
alpar@9
|
749 for (aij = row->ptr; aij != NULL; aij = aij->r_next)
|
alpar@9
|
750 { col = aij->col;
|
alpar@9
|
751 if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
|
alpar@9
|
752 break;
|
alpar@9
|
753 }
|
alpar@9
|
754 if (aij != NULL) continue;
|
alpar@9
|
755 count += npp_hidden_packing(npp, row);
|
alpar@9
|
756 }
|
alpar@9
|
757 if (count > 0)
|
alpar@9
|
758 xprintf("%d hidden packing inequaliti(es) were detected\n",
|
alpar@9
|
759 count);
|
alpar@9
|
760 /*==============================================================*/
|
alpar@9
|
761 /* identify hidden covering inequalities */
|
alpar@9
|
762 count = 0;
|
alpar@9
|
763 /* new rows will be added to the end of the row list, so we go
|
alpar@9
|
764 from the end to beginning of the row list */
|
alpar@9
|
765 for (row = npp->r_tail; row != NULL; row = prev_row)
|
alpar@9
|
766 { prev_row = row->prev;
|
alpar@9
|
767 /* skip free row */
|
alpar@9
|
768 if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) continue;
|
alpar@9
|
769 /* skip equality constraint */
|
alpar@9
|
770 if (row->lb == row->ub) continue;
|
alpar@9
|
771 /* skip row having less than three variables */
|
alpar@9
|
772 if (row->ptr == NULL || row->ptr->r_next == NULL ||
|
alpar@9
|
773 row->ptr->r_next->r_next == NULL) continue;
|
alpar@9
|
774 /* skip row having non-binary variables */
|
alpar@9
|
775 for (aij = row->ptr; aij != NULL; aij = aij->r_next)
|
alpar@9
|
776 { col = aij->col;
|
alpar@9
|
777 if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
|
alpar@9
|
778 break;
|
alpar@9
|
779 }
|
alpar@9
|
780 if (aij != NULL) continue;
|
alpar@9
|
781 count += npp_hidden_covering(npp, row);
|
alpar@9
|
782 }
|
alpar@9
|
783 if (count > 0)
|
alpar@9
|
784 xprintf("%d hidden covering inequaliti(es) were detected\n",
|
alpar@9
|
785 count);
|
alpar@9
|
786 /*==============================================================*/
|
alpar@9
|
787 /* reduce inequality constraint coefficients */
|
alpar@9
|
788 count = 0;
|
alpar@9
|
789 /* new rows will be added to the end of the row list, so we go
|
alpar@9
|
790 from the end to beginning of the row list */
|
alpar@9
|
791 for (row = npp->r_tail; row != NULL; row = prev_row)
|
alpar@9
|
792 { prev_row = row->prev;
|
alpar@9
|
793 /* skip equality constraint */
|
alpar@9
|
794 if (row->lb == row->ub) continue;
|
alpar@9
|
795 count += npp_reduce_ineq_coef(npp, row);
|
alpar@9
|
796 }
|
alpar@9
|
797 if (count > 0)
|
alpar@9
|
798 xprintf("%d constraint coefficient(s) were reduced\n", count);
|
alpar@9
|
799 /*==============================================================*/
|
alpar@9
|
800 #ifdef GLP_DEBUG
|
alpar@9
|
801 routine(npp);
|
alpar@9
|
802 #endif
|
alpar@9
|
803 /*==============================================================*/
|
alpar@9
|
804 /* all seems ok */
|
alpar@9
|
805 ret = 0;
|
alpar@9
|
806 done: return ret;
|
alpar@9
|
807 }
|
alpar@9
|
808
|
alpar@9
|
809 /* eof */
|