1 | /* $Id: CoinPresolveDual.cpp 1373 2011-01-03 23:57:44Z lou $ */ |
2 | // Copyright (C) 2002, International Business Machines |
3 | // Corporation and others. All Rights Reserved. |
4 | // This code is licensed under the terms of the Eclipse Public License (EPL). |
5 | |
6 | #include <stdio.h> |
7 | #include <math.h> |
8 | |
9 | #include "CoinPresolveMatrix.hpp" |
10 | #include "CoinPresolveFixed.hpp" |
11 | #include "CoinPresolveDual.hpp" |
12 | #include "CoinMessage.hpp" |
13 | #include "CoinHelperFunctions.hpp" |
14 | #include "CoinFloatEqual.hpp" |
15 | //#define PRESOLVE_TIGHTEN_DUALS 1 |
16 | //#define PRESOLVE_DEBUG 1 |
17 | |
18 | #ifdef PRESOLVE_DEBUG |
19 | #include "CoinPresolvePsdebug.hpp" |
20 | #endif |
21 | |
22 | // this looks for "dominated columns" |
23 | // following ekkredc |
24 | // rdmin == dwrow2 |
25 | // rdmax == dwrow |
26 | // this transformation is applied in: k4.mps, lp22.mps |
27 | |
28 | // make inferences using this constraint on reduced cost: |
29 | // at optimality dj>0 ==> var must be at lb |
30 | // dj<0 ==> var must be at ub |
31 | // |
32 | // This implies: |
33 | // there is no lb ==> dj<=0 at optimality |
34 | // there is no ub ==> dj>=0 at optimality |
35 | |
36 | /* |
37 | This routine looks to be something of a work in progres. See the comment |
38 | that begins with `Gack!'. And down in the bound propagation loop, why do we |
39 | only work with variables with u_j = infty? The corresponding section of code |
40 | for l_j = -infty is ifdef'd away. And why exclude the code protected by |
41 | PRESOLVE_TIGHTEN_DUALS? And why are we using ekkinf instead of PRESOLVE_INF? |
42 | |
43 | There is no postsolve action because once we've identified a variable to fix |
44 | we can invoke make_fixed_action. |
45 | */ |
46 | const CoinPresolveAction *remove_dual_action::presolve(CoinPresolveMatrix *prob, |
47 | const CoinPresolveAction *next) |
48 | { |
49 | double startTime = 0.0; |
50 | int startEmptyRows=0; |
51 | int startEmptyColumns = 0; |
52 | if (prob->tuning_) { |
53 | startTime = CoinCpuTime(); |
54 | startEmptyRows = prob->countEmptyRows(); |
55 | startEmptyColumns = prob->countEmptyCols(); |
56 | } |
57 | double *colels = prob->colels_; |
58 | int *hrow = prob->hrow_; |
59 | CoinBigIndex *mcstrt = prob->mcstrt_; |
60 | int *hincol = prob->hincol_; |
61 | int ncols = prob->ncols_; |
62 | |
63 | double *clo = prob->clo_; |
64 | double *cup = prob->cup_; |
65 | unsigned char *colstat = prob->colstat_ ; |
66 | |
67 | // Used only in `fix if simple' section below. Remove dec'l to avoid |
68 | // GCC compile warning. |
69 | // double *rowels = prob->rowels_; |
70 | int *hcol = prob->hcol_; |
71 | CoinBigIndex *mrstrt = prob->mrstrt_; |
72 | int *hinrow = prob->hinrow_; |
73 | double *csol = prob->sol_; |
74 | int nrows = prob->nrows_; |
75 | |
76 | double *rlo = prob->rlo_; |
77 | double *rup = prob->rup_; |
78 | |
79 | double *dcost = prob->cost_; |
80 | const unsigned char *integerType = prob->integerType_; |
81 | |
82 | const double maxmin = prob->maxmin_; |
83 | |
84 | const double ekkinf = 1e28; |
85 | const double ekkinf2 = 1e20; |
86 | const double ztoldj = prob->ztoldj_; |
87 | |
88 | CoinRelFltEq relEq(prob->ztolzb_) ; |
89 | |
90 | double *rdmin = prob->usefulRowDouble_; //new double[nrows]; |
91 | double *rdmax = reinterpret_cast<double *> (prob->usefulRowInt_); //new double[nrows]; |
92 | |
93 | # if PRESOLVE_DEBUG |
94 | std::cout << "Entering remove_dual_action::presolve, " << nrows << " X " << ncols << "." << std::endl ; |
95 | presolve_check_sol(prob) ; |
96 | presolve_check_nbasic(prob) ; |
97 | # endif |
98 | |
99 | // This combines the initialization of rdmin/rdmax to extreme values |
100 | // (PRESOLVE_INF/-PRESOLVE_INF) with a version of the next loop specialized |
101 | // for row slacks. |
102 | // In this case, it is always the case that dprice==0.0 and coeff==1.0. |
103 | int i; |
104 | for ( i = 0; i < nrows; i++) { |
105 | double sup = -rlo[i]; // slack ub; corresponds to cup[j] |
106 | double slo = -rup[i]; // slack lb; corresponds to clo[j] |
107 | bool no_lb = (slo <= -ekkinf); |
108 | bool no_ub = (sup >= ekkinf); |
109 | |
110 | // here, dj==-row dual |
111 | // the row slack has no lower bound, but it does have an upper bound, |
112 | // then the reduced cost must be <= 0, so the row dual must be >= 0 |
113 | rdmin[i] = (no_lb && !no_ub) ? 0.0 : -PRESOLVE_INF; |
114 | |
115 | rdmax[i] = (no_ub && !no_lb) ? 0.0 : PRESOLVE_INF; |
116 | } |
117 | |
118 | // Look for col singletons and update bounds on dual costs |
119 | // Take the min of the maxes and max of the mins |
120 | int j; |
121 | for ( j = 0; j<ncols; j++) { |
122 | if (integerType[j]) |
123 | continue; // even if it has infinite bound now .... |
124 | bool no_ub = (cup[j] >= ekkinf); |
125 | bool no_lb = (clo[j] <= -ekkinf); |
126 | |
127 | if (hincol[j] == 1 && |
128 | |
129 | // we need singleton cols that have exactly one bound |
130 | (no_ub ^ no_lb)) { |
131 | int row = hrow[mcstrt[j]]; |
132 | double coeff = colels[mcstrt[j]]; |
133 | |
134 | PRESOLVEASSERT(fabs(coeff) > ZTOLDP); |
135 | |
136 | // I don't think the sign of dcost[j] matters |
137 | |
138 | // this row dual would make this col's reduced cost be 0 |
139 | double dprice = maxmin * dcost[j] / coeff; |
140 | |
141 | // no_ub == !no_lb |
142 | // no_ub ==> !(dj<0) |
143 | // no_lb ==> !(dj>0) |
144 | // I don't think the case where !no_ub has actually been tested |
145 | if ((coeff > 0.0) == no_ub) { |
146 | // coeff>0 ==> making the row dual larger would make dj *negative* |
147 | // ==> dprice is an upper bound on dj if no *ub* |
148 | // coeff<0 ==> making the row dual larger would make dj *positive* |
149 | // ==> dprice is an upper bound on dj if no *lb* |
150 | if (rdmax[row] > dprice) // reduced cost may be positive |
151 | rdmax[row] = dprice; |
152 | } else if ((coeff < 0.0) == no_lb) { // no lower bound |
153 | if (rdmin[row] < dprice) // reduced cost may be negative |
154 | rdmin[row] = dprice; |
155 | } |
156 | } |
157 | } |
158 | |
159 | int *fix_cols = prob->usefulColumnInt_; //new int[ncols]; |
160 | |
161 | //int *fixdown_cols = new int[ncols]; |
162 | |
163 | #if PRESOLVE_TIGHTEN_DUALS |
164 | double *djmin = new double[ncols]; |
165 | double *djmax = new double[ncols]; |
166 | #endif |
167 | int nfixup_cols = 0; |
168 | int nfixdown_cols = ncols; |
169 | |
170 | int nPass=100; |
171 | while (nPass-- > 0) { |
172 | int tightened = 0; |
173 | /* Perform duality tests */ |
174 | for (int j = 0; j<ncols; j++) { |
175 | if (hincol[j] > 0) { |
176 | CoinBigIndex kcs = mcstrt[j]; |
177 | CoinBigIndex kce = kcs + hincol[j]; |
178 | // Number of infinite rows |
179 | int nflagu = 0; |
180 | int nflagl = 0; |
181 | // Number of ordinary rows |
182 | int nordu = 0; |
183 | int nordl = 0; |
184 | double ddjlo = maxmin * dcost[j]; |
185 | double ddjhi = ddjlo; |
186 | |
187 | for (CoinBigIndex k = kcs; k < kce; k++) { |
188 | int i = hrow[k]; |
189 | double coeff = colels[k]; |
190 | |
191 | if (coeff > 0.0) { |
192 | if (rdmin[i] >= -ekkinf2) { |
193 | ddjhi -= coeff * rdmin[i]; |
194 | nordu ++; |
195 | } else { |
196 | nflagu ++; |
197 | } |
198 | if (rdmax[i] <= ekkinf2) { |
199 | ddjlo -= coeff * rdmax[i]; |
200 | nordl ++; |
201 | } else { |
202 | nflagl ++; |
203 | } |
204 | } else { |
205 | if (rdmax[i] <= ekkinf2) { |
206 | ddjhi -= coeff * rdmax[i]; |
207 | nordu ++; |
208 | } else { |
209 | nflagu ++; |
210 | } |
211 | if (rdmin[i] >= -ekkinf2) { |
212 | ddjlo -= coeff * rdmin[i]; |
213 | nordl ++; |
214 | } else { |
215 | nflagl ++; |
216 | } |
217 | } |
218 | } |
219 | // See if we may be able to tighten a dual |
220 | if (!integerType[j]) { |
221 | if (cup[j]>ekkinf) { |
222 | // dj can not be negative |
223 | if (nflagu==1&&ddjhi<-ztoldj) { |
224 | // We can make bound finite one way |
225 | for (CoinBigIndex k = kcs; k < kce; k++) { |
226 | int i = hrow[k]; |
227 | double coeff = colels[k]; |
228 | |
229 | if (coeff > 0.0&&rdmin[i] < -ekkinf2) { |
230 | // rdmax[i] has upper bound |
231 | if (ddjhi<rdmax[i]*coeff-ztoldj) { |
232 | double newValue = ddjhi/coeff; |
233 | // re-compute lo |
234 | if (rdmax[i] > ekkinf2 && newValue <= ekkinf2) { |
235 | nflagl--; |
236 | ddjlo -= coeff * newValue; |
237 | } else if (rdmax[i] <= ekkinf2) { |
238 | ddjlo -= coeff * (newValue-rdmax[i]); |
239 | } |
240 | rdmax[i] = newValue; |
241 | tightened++; |
242 | #if PRESOLVE_DEBUG |
243 | printf("Col %d, row %d max pi now %g\n" ,j,i,rdmax[i]); |
244 | #endif |
245 | } |
246 | } else if (coeff < 0.0 && rdmax[i] > ekkinf2) { |
247 | // rdmin[i] has lower bound |
248 | if (ddjhi<rdmin[i]*coeff-ztoldj) { |
249 | double newValue = ddjhi/coeff; |
250 | // re-compute lo |
251 | if (rdmin[i] < -ekkinf2 && newValue >= -ekkinf2) { |
252 | nflagl--; |
253 | ddjlo -= coeff * newValue; |
254 | } else if (rdmax[i] >= -ekkinf2) { |
255 | ddjlo -= coeff * (newValue-rdmin[i]); |
256 | } |
257 | rdmin[i] = newValue; |
258 | tightened++; |
259 | #if PRESOLVE_DEBUG |
260 | printf("Col %d, row %d min pi now %g\n" ,j,i,rdmin[i]); |
261 | #endif |
262 | ddjlo = 0.0; |
263 | } |
264 | } |
265 | } |
266 | } else if (nflagl==0&&nordl==1&&ddjlo<-ztoldj) { |
267 | // We may be able to tighten |
268 | for (CoinBigIndex k = kcs; k < kce; k++) { |
269 | int i = hrow[k]; |
270 | double coeff = colels[k]; |
271 | |
272 | if (coeff > 0.0) { |
273 | rdmax[i] += ddjlo/coeff; |
274 | ddjlo =0.0; |
275 | tightened++; |
276 | #if PRESOLVE_DEBUG |
277 | printf("Col %d, row %d max pi now %g\n" ,j,i,rdmax[i]); |
278 | #endif |
279 | } else if (coeff < 0.0 ) { |
280 | rdmin[i] += ddjlo/coeff; |
281 | ddjlo =0.0; |
282 | tightened++; |
283 | #if PRESOLVE_DEBUG |
284 | printf("Col %d, row %d min pi now %g\n" ,j,i,rdmin[i]); |
285 | #endif |
286 | } |
287 | } |
288 | } |
289 | } |
290 | #if 0 |
291 | if (clo[j]<-ekkinf) { |
292 | // dj can not be positive |
293 | if (ddjlo>ztoldj&&nflagl==1) { |
294 | // We can make bound finite one way |
295 | for (CoinBigIndex k = kcs; k < kce; k++) { |
296 | int i = hrow[k]; |
297 | double coeff = colels[k]; |
298 | |
299 | if (coeff < 0.0&&rdmin[i] < -ekkinf2) { |
300 | // rdmax[i] has upper bound |
301 | if (ddjlo>rdmax[i]*coeff+ztoldj) { |
302 | double newValue = ddjlo/coeff; |
303 | // re-compute hi |
304 | if (rdmax[i] > ekkinf2 && newValue <= ekkinf2) { |
305 | nflagu--; |
306 | ddjhi -= coeff * newValue; |
307 | } else if (rdmax[i] <= ekkinf2) { |
308 | ddjhi -= coeff * (newValue-rdmax[i]); |
309 | } |
310 | rdmax[i] = newValue; |
311 | tightened++; |
312 | #if PRESOLVE_DEBUG |
313 | printf("Col %d, row %d max pi now %g\n" ,j,i,rdmax[i]); |
314 | #endif |
315 | } |
316 | } else if (coeff > 0.0 && rdmax[i] > ekkinf2) { |
317 | // rdmin[i] has lower bound |
318 | if (ddjlo>rdmin[i]*coeff+ztoldj) { |
319 | double newValue = ddjlo/coeff; |
320 | // re-compute lo |
321 | if (rdmin[i] < -ekkinf2 && newValue >= -ekkinf2) { |
322 | nflagu--; |
323 | ddjhi -= coeff * newValue; |
324 | } else if (rdmax[i] >= -ekkinf2) { |
325 | ddjhi -= coeff * (newValue-rdmin[i]); |
326 | } |
327 | rdmin[i] = newValue; |
328 | tightened++; |
329 | #if PRESOLVE_DEBUG |
330 | printf("Col %d, row %d min pi now %g\n" ,j,i,rdmin[i]); |
331 | #endif |
332 | } |
333 | } |
334 | } |
335 | } else if (nflagu==0&&nordu==1&&ddjhi>ztoldj) { |
336 | // We may be able to tighten |
337 | for (CoinBigIndex k = kcs; k < kce; k++) { |
338 | int i = hrow[k]; |
339 | double coeff = colels[k]; |
340 | |
341 | if (coeff < 0.0) { |
342 | rdmax[i] += ddjhi/coeff; |
343 | ddjhi =0.0; |
344 | tightened++; |
345 | #if PRESOLVE_DEBUG |
346 | printf("Col %d, row %d max pi now %g\n" ,j,i,rdmax[i]); |
347 | #endif |
348 | } else if (coeff > 0.0 ) { |
349 | rdmin[i] += ddjhi/coeff; |
350 | ddjhi =0.0; |
351 | tightened++; |
352 | #if PRESOLVE_DEBUG |
353 | printf("Col %d, row %d min pi now %g\n" ,j,i,rdmin[i]); |
354 | #endif |
355 | } |
356 | } |
357 | } |
358 | } |
359 | #endif |
360 | } |
361 | |
362 | #if PRESOLVE_TIGHTEN_DUALS |
363 | djmin[j] = (nflagl ? -PRESOLVE_INF : ddjlo); |
364 | djmax[j] = (nflagu ? PRESOLVE_INF : ddjhi); |
365 | #endif |
366 | |
367 | if (ddjlo > ztoldj && nflagl == 0&&!prob->colProhibited2(j)) { |
368 | // dj>0 at optimality ==> must be at lower bound |
369 | if (clo[j] <= -ekkinf) { |
370 | prob->messageHandler()->message(COIN_PRESOLVE_COLUMNBOUNDB, |
371 | prob->messages()) |
372 | <<j |
373 | <<CoinMessageEol; |
374 | prob->status_ |= 2; |
375 | break; |
376 | } else { |
377 | fix_cols[--nfixdown_cols] = j; |
378 | PRESOLVE_DETAIL_PRINT(printf("pre_duallo %dC E\n" ,j)); |
379 | # if PRESOLVE_DEBUG |
380 | printf("NDUAL: fixing x<%d>" ,fix_cols[nfixdown_cols]) ; |
381 | if (csol) printf(" = %g" ,csol[j]) ; |
382 | printf(" at lb = %g.\n" ,clo[j]) ; |
383 | # endif |
384 | //if (csol[j]-clo[j]>1.0e-7) |
385 | //printf("down %d row %d nincol %d\n",j,hrow[mcstrt[j]],hincol[j]); |
386 | // User may have given us feasible solution - move if simple |
387 | if (csol) { |
388 | # if 0 |
389 | /* |
390 | Except it's not simple. The net result is that we end up with an |
391 | excess of basic variables. |
392 | */ |
393 | if (csol[j]-clo[j]>1.0e-7&&hincol[j]==1) { |
394 | double value_j = colels[mcstrt[j]]; |
395 | double distance_j = csol[j]-clo[j]; |
396 | int row=hrow[mcstrt[j]]; |
397 | // See if another column can take value |
398 | for (CoinBigIndex kk=mrstrt[row];kk<mrstrt[row]+hinrow[row];kk++) { |
399 | int k = hcol[kk]; |
400 | if (colstat[k] == CoinPrePostsolveMatrix::superBasic) |
401 | continue ; |
402 | |
403 | if (hincol[k]==1&&k!=j) { |
404 | double value_k = rowels[kk]; |
405 | double movement; |
406 | if (value_k*value_j>0.0) { |
407 | // k needs to increase |
408 | double distance_k = cup[k]-csol[k]; |
409 | movement = CoinMin((distance_j*value_j)/value_k,distance_k); |
410 | } else { |
411 | // k needs to decrease |
412 | double distance_k = clo[k]-csol[k]; |
413 | movement = CoinMax((distance_j*value_j)/value_k,distance_k); |
414 | } |
415 | if (relEq(movement,0)) continue ; |
416 | |
417 | csol[k] += movement; |
418 | if (relEq(csol[k],clo[k])) |
419 | { colstat[k] = CoinPrePostsolveMatrix::atLowerBound ; } |
420 | else |
421 | if (relEq(csol[k],cup[k])) |
422 | { colstat[k] = CoinPrePostsolveMatrix::atUpperBound ; } |
423 | else |
424 | if (colstat[k] != CoinPrePostsolveMatrix::isFree) |
425 | { colstat[k] = CoinPrePostsolveMatrix::basic ; } |
426 | printf("NDUAL: x<%d> moved %g to %g; " , |
427 | k,movement,csol[k]) ; |
428 | printf("lb = %g, ub = %g, status now %s.\n" , |
429 | clo[k],cup[k],columnStatusString(colstat[k])) ; |
430 | distance_j -= (movement*value_k)/value_j; |
431 | csol[j] -= (movement*value_k)/value_j; |
432 | if (distance_j<1.0e-7) |
433 | break; |
434 | } |
435 | } |
436 | } |
437 | # endif // repair solution. |
438 | |
439 | csol[j] = clo[j] ; // but the bottom line is we've changed x<j> |
440 | colstat[j] = CoinPrePostsolveMatrix::atLowerBound ; |
441 | } |
442 | } |
443 | } else if (ddjhi < -ztoldj && nflagu == 0&&!prob->colProhibited2(j)) { |
444 | // dj<0 at optimality ==> must be at upper bound |
445 | if (cup[j] >= ekkinf) { |
446 | prob->messageHandler()->message(COIN_PRESOLVE_COLUMNBOUNDA, |
447 | prob->messages()) |
448 | <<j |
449 | <<CoinMessageEol; |
450 | prob->status_ |= 2; |
451 | break; |
452 | } else { |
453 | PRESOLVE_DETAIL_PRINT(printf("pre_dualup %dC E\n" ,j)); |
454 | fix_cols[nfixup_cols++] = j; |
455 | # if PRESOLVE_DEBUG |
456 | printf("NDUAL: fixing x<%d>" ,fix_cols[nfixup_cols-1]) ; |
457 | if (csol) printf(" = %g" ,csol[j]) ; |
458 | printf(" at ub = %g.\n" ,cup[j]) ; |
459 | # endif |
460 | // User may have given us feasible solution - move if simple |
461 | // See comments for `fix at lb' case above. |
462 | //if (cup[j]-csol[j]>1.0e-7) |
463 | //printf("up %d row %d nincol %d\n",j,hrow[mcstrt[j]],hincol[j]); |
464 | if (csol) { |
465 | # if 0 |
466 | // See comments above. |
467 | if (cup[j]-csol[j]>1.0e-7&&hincol[j]==1) { |
468 | double value_j = colels[mcstrt[j]]; |
469 | double distance_j = csol[j]-cup[j]; |
470 | int row=hrow[mcstrt[j]]; |
471 | // See if another column can take value |
472 | for (CoinBigIndex kk=mrstrt[row];kk<mrstrt[row]+hinrow[row];kk++) { |
473 | int k = hcol[kk]; |
474 | if (colstat[k] == CoinPrePostsolveMatrix::superBasic) |
475 | continue ; |
476 | |
477 | if (hincol[k]==1&&k!=j) { |
478 | double value_k = rowels[kk]; |
479 | double movement; |
480 | if (value_k*value_j<0.0) { |
481 | // k needs to increase |
482 | double distance_k = cup[k]-csol[k]; |
483 | movement = CoinMin((distance_j*value_j)/value_k,distance_k); |
484 | } else { |
485 | // k needs to decrease |
486 | double distance_k = clo[k]-csol[k]; |
487 | movement = CoinMax((distance_j*value_j)/value_k,distance_k); |
488 | } |
489 | if (relEq(movement,0)) continue ; |
490 | |
491 | csol[k] += movement; |
492 | if (relEq(csol[k],clo[k])) |
493 | { colstat[k] = CoinPrePostsolveMatrix::atLowerBound ; } |
494 | else |
495 | if (relEq(csol[k],cup[k])) |
496 | { colstat[k] = CoinPrePostsolveMatrix::atUpperBound ; } |
497 | else |
498 | if (colstat[k] != CoinPrePostsolveMatrix::isFree) |
499 | { colstat[k] = CoinPrePostsolveMatrix::basic ; } |
500 | printf("NDUAL: x<%d> moved %g to %g; " , |
501 | k,movement,csol[k]) ; |
502 | printf("lb = %g, ub = %g, status now %s.\n" , |
503 | clo[k],cup[k],columnStatusString(colstat[k])) ; |
504 | distance_j -= (movement*value_k)/value_j; |
505 | csol[j] -= (movement*value_k)/value_j; |
506 | if (distance_j>-1.0e-7) |
507 | break; |
508 | } |
509 | } |
510 | } |
511 | # endif |
512 | csol[j] = cup[j] ; // but the bottom line is we've changed x<j> |
513 | colstat[j] = CoinPrePostsolveMatrix::atUpperBound ; |
514 | } |
515 | } |
516 | } |
517 | } |
518 | } |
519 | |
520 | // I don't know why I stopped doing this. |
521 | #if PRESOLVE_TIGHTEN_DUALS |
522 | const double *rowels = prob->rowels_; |
523 | const int *hcol = prob->hcol_; |
524 | const CoinBigIndex *mrstrt = prob->mrstrt_; |
525 | int *hinrow = prob->hinrow_; |
526 | // tighten row dual bounds, as described on p. 229 |
527 | for (int i = 0; i < nrows; i++) { |
528 | bool no_ub = (rup[i] >= ekkinf); |
529 | bool no_lb = (rlo[i] <= -ekkinf); |
530 | |
531 | if ((no_ub ^ no_lb) == true) { |
532 | CoinBigIndex krs = mrstrt[i]; |
533 | CoinBigIndex kre = krs + hinrow[i]; |
534 | double rmax = rdmax[i]; |
535 | double rmin = rdmin[i]; |
536 | |
537 | // all row columns are non-empty |
538 | for (CoinBigIndex k=krs; k<kre; k++) { |
539 | double coeff = rowels[k]; |
540 | int icol = hcol[k]; |
541 | double djmax0 = djmax[icol]; |
542 | double djmin0 = djmin[icol]; |
543 | |
544 | if (no_ub) { |
545 | // dj must not be negative |
546 | if (coeff > ZTOLDP2 && djmax0 <PRESOLVE_INF && cup[icol]>=ekkinf) { |
547 | double bnd = djmax0 / coeff; |
548 | if (rmax > bnd) { |
549 | #if PRESOLVE_DEBUG |
550 | printf("MAX TIGHT[%d,%d]: %g --> %g\n" , i,hrow[k], rdmax[i], bnd); |
551 | #endif |
552 | rdmax[i] = rmax = bnd; |
553 | tightened ++; |
554 | } |
555 | } else if (coeff < -ZTOLDP2 && djmax0 <PRESOLVE_INF && cup[icol] >= ekkinf) { |
556 | double bnd = djmax0 / coeff ; |
557 | if (rmin < bnd) { |
558 | #if PRESOLVE_DEBUG |
559 | printf("MIN TIGHT[%d,%d]: %g --> %g\n" , i, hrow[k], rdmin[i], bnd); |
560 | #endif |
561 | rdmin[i] = rmin = bnd; |
562 | tightened ++; |
563 | } |
564 | } |
565 | } else { // no_lb |
566 | // dj must not be positive |
567 | if (coeff > ZTOLDP2 && djmin0 > -PRESOLVE_INF && clo[icol]<=-ekkinf) { |
568 | double bnd = djmin0 / coeff ; |
569 | if (rmin < bnd) { |
570 | #if PRESOLVE_DEBUG |
571 | printf("MIN1 TIGHT[%d,%d]: %g --> %g\n" , i, hrow[k], rdmin[i], bnd); |
572 | #endif |
573 | rdmin[i] = rmin = bnd; |
574 | tightened ++; |
575 | } |
576 | } else if (coeff < -ZTOLDP2 && djmin0 > -PRESOLVE_INF && clo[icol] <= -ekkinf) { |
577 | double bnd = djmin0 / coeff ; |
578 | if (rmax > bnd) { |
579 | #if PRESOLVE_DEBUG |
580 | printf("MAX TIGHT1[%d,%d]: %g --> %g\n" , i,hrow[k], rdmax[i], bnd); |
581 | #endif |
582 | rdmax[i] = rmax = bnd; |
583 | tightened ++; |
584 | } |
585 | } |
586 | } |
587 | } |
588 | } |
589 | } |
590 | #endif |
591 | |
592 | if (tightened<100||nfixdown_cols<ncols||nfixup_cols) |
593 | break; |
594 | #if PRESOLVE_TIGHTEN_DUALS |
595 | else |
596 | printf("DUAL TIGHTENED! %d\n" , tightened); |
597 | #endif |
598 | } |
599 | assert (nfixup_cols<=nfixdown_cols); |
600 | if (nfixup_cols) { |
601 | #if PRESOLVE_DEBUG |
602 | printf("NDUAL: %d up" , nfixup_cols); |
603 | for (i = 0 ; i < nfixup_cols ; i++) printf(" %d" ,fix_cols[i]) ; |
604 | printf(".\n" ) ; |
605 | #endif |
606 | next = make_fixed_action::presolve(prob, fix_cols, nfixup_cols, false, next); |
607 | } |
608 | |
609 | if (nfixdown_cols<ncols) { |
610 | int * fixdown_cols = fix_cols+nfixdown_cols; |
611 | nfixdown_cols = ncols-nfixdown_cols; |
612 | #if PRESOLVE_DEBUG |
613 | printf("NDUAL: %d down" , nfixdown_cols); |
614 | for (i = 0 ; i < nfixdown_cols ; i++) printf(" %d" ,fixdown_cols[i]) ; |
615 | printf(".\n" ) ; |
616 | #endif |
617 | next = make_fixed_action::presolve(prob, fixdown_cols, nfixdown_cols, true, next); |
618 | } |
619 | // If dual says so then we can make equality row |
620 | // Also if cost is in right direction and only one binding row for variable |
621 | // We may wish to think about giving preference to rows with 2 or 3 elements |
622 | /* |
623 | Gack! Ok, I can appreciate the thought here, but I'm seriously skeptical |
624 | about writing canFix[0] before reading rdmin[0]. After that, we should be out |
625 | of the interference zone for the typical situation where sizeof(double) is |
626 | twice sizeof(int). |
627 | */ |
628 | int * canFix = reinterpret_cast<int *> (rdmin); |
629 | for ( i = 0; i < nrows; i++) { |
630 | bool no_lb = (rlo[i] <= -ekkinf); |
631 | bool no_ub = (rup[i] >= ekkinf); |
632 | canFix[i]=0; |
633 | if (no_ub && !no_lb ) { |
634 | if ( rdmin[i]>0.0) |
635 | canFix[i]=-1; |
636 | else |
637 | canFix[i]=-2; |
638 | } else if (no_lb && !no_ub ) { |
639 | if (rdmax[i]<0.0) |
640 | canFix[i]=1; |
641 | else |
642 | canFix[i]=2; |
643 | } |
644 | } |
645 | for (j = 0; j<ncols; j++) { |
646 | if (hincol[j]<=1) |
647 | continue; |
648 | if (integerType[j]) |
649 | continue; // even if it has infinite bound now .... |
650 | CoinBigIndex kcs = mcstrt[j]; |
651 | CoinBigIndex kce = kcs + hincol[j]; |
652 | int bindingUp=-1; |
653 | int bindingDown=-1; |
654 | if (cup[j]<ekkinf) |
655 | bindingUp=-2; |
656 | if (clo[j]>-ekkinf) |
657 | bindingDown=-2; |
658 | for (CoinBigIndex k = kcs; k < kce; k++) { |
659 | int i = hrow[k]; |
660 | if (abs(canFix[i])!=2) { |
661 | bindingUp=-2; |
662 | bindingDown=-2; |
663 | break; |
664 | } |
665 | double coeff = colels[k]; |
666 | if (coeff>0.0) { |
667 | if (canFix[i]==2) { |
668 | // binding up |
669 | if (bindingUp==-1) |
670 | bindingUp = i; |
671 | else |
672 | bindingUp = -2; |
673 | } else { |
674 | // binding down |
675 | if (bindingDown==-1) |
676 | bindingDown = i; |
677 | else |
678 | bindingDown = -2; |
679 | } |
680 | } else { |
681 | if (canFix[i]==2) { |
682 | // binding down |
683 | if (bindingDown==-1) |
684 | bindingDown = i; |
685 | else |
686 | bindingDown = -2; |
687 | } else { |
688 | // binding up |
689 | if (bindingUp==-1) |
690 | bindingUp = i; |
691 | else |
692 | bindingUp = -2; |
693 | } |
694 | } |
695 | } |
696 | double cost = maxmin * dcost[j]; |
697 | if (bindingUp>-2&&cost<=0.0) { |
698 | // might as well make equality |
699 | if (bindingUp>=0) { |
700 | canFix[bindingUp] /= 2; //So -2 goes to -1 etc |
701 | //printf("fixing row %d to ub by %d\n",bindingUp,j); |
702 | } else { |
703 | //printf("binding up row by %d\n",j); |
704 | } |
705 | } else if (bindingDown>-2 &&cost>=0.0) { |
706 | // might as well make equality |
707 | if (bindingDown>=0) { |
708 | canFix[bindingDown] /= 2; //So -2 goes to -1 etc |
709 | //printf("fixing row %d to lb by %d\n",bindingDown,j); |
710 | } else { |
711 | //printf("binding down row by %d\n",j); |
712 | } |
713 | } |
714 | } |
715 | // can't fix if integer and non-unit coefficient |
716 | //const double *rowels = prob->rowels_; |
717 | //const int *hcol = prob->hcol_; |
718 | //const CoinBigIndex *mrstrt = prob->mrstrt_; |
719 | //int *hinrow = prob->hinrow_; |
720 | for ( i = 0; i < nrows; i++) { |
721 | if (abs(canFix[i])==1) { |
722 | CoinBigIndex krs = mrstrt[i]; |
723 | CoinBigIndex kre = krs + hinrow[i]; |
724 | for (CoinBigIndex k=krs; k<kre; k++) { |
725 | int icol = hcol[k]; |
726 | if (cup[icol]>clo[icol]&&integerType[icol]) { |
727 | canFix[i]=0; // not safe |
728 | #ifdef COIN_DEVELOP |
729 | printf("no dual something CoinPresolveDual row %d col %d\n" , |
730 | i,icol); |
731 | #endif |
732 | } |
733 | } |
734 | } |
735 | if (canFix[i]==1) { |
736 | rlo[i]=rup[i]; |
737 | prob->addRow(i); |
738 | } else if (canFix[i]==-1) { |
739 | rup[i]=rlo[i]; |
740 | prob->addRow(i); |
741 | } |
742 | } |
743 | |
744 | //delete[]rdmin; |
745 | //delete[]rdmax; |
746 | |
747 | //delete[]fixup_cols; |
748 | //delete[]fixdown_cols; |
749 | |
750 | #if PRESOLVE_TIGHTEN_DUALS |
751 | delete[]djmin; |
752 | delete[]djmax; |
753 | #endif |
754 | |
755 | if (prob->tuning_) { |
756 | double thisTime=CoinCpuTime(); |
757 | int droppedRows = prob->countEmptyRows() - startEmptyRows; |
758 | int droppedColumns = prob->countEmptyCols() - startEmptyColumns; |
759 | printf("CoinPresolveDual(1) - %d rows, %d columns dropped in time %g, total %g\n" , |
760 | droppedRows,droppedColumns,thisTime-startTime,thisTime-prob->startTime_); |
761 | } |
762 | |
763 | # if PRESOLVE_DEBUG |
764 | presolve_check_sol(prob) ; |
765 | presolve_check_nbasic(prob) ; |
766 | std::cout << "Leaving remove_dual_action::presolve." << std::endl ; |
767 | # endif |
768 | |
769 | return (next); |
770 | } |
771 | |