1 | /* $Id: CoinPresolveSingleton.cpp 1463 2011-07-30 16:31:31Z stefan $ */ |
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 "CoinHelperFunctions.hpp" |
10 | #include "CoinPresolveMatrix.hpp" |
11 | |
12 | #include "CoinPresolveEmpty.hpp" // for DROP_COL/DROP_ROW |
13 | #include "CoinPresolveFixed.hpp" |
14 | #include "CoinPresolveSingleton.hpp" |
15 | #include "CoinPresolvePsdebug.hpp" |
16 | #include "CoinMessage.hpp" |
17 | #include "CoinFinite.hpp" |
18 | |
19 | // #define PRESOLVE_DEBUG 1 |
20 | // #define PRESOLVE_SUMMARY 1 |
21 | |
22 | /* |
23 | * Transfers singleton row bound information to the corresponding column bounds. |
24 | * What I refer to as a row singleton would be called a doubleton |
25 | * in the paper, since my terminology doesn't refer to the slacks. |
26 | * In terms of the paper, we transfer the bounds of the slack onto |
27 | * the variable (vii) and then "substitute" the slack out of the problem |
28 | * (which is a noop). |
29 | */ |
30 | const CoinPresolveAction * |
31 | slack_doubleton_action::presolve(CoinPresolveMatrix *prob, |
32 | const CoinPresolveAction *next, |
33 | bool & notFinished) |
34 | { |
35 | double startTime = 0.0; |
36 | int startEmptyRows=0; |
37 | int startEmptyColumns = 0; |
38 | if (prob->tuning_) { |
39 | startTime = CoinCpuTime(); |
40 | startEmptyRows = prob->countEmptyRows(); |
41 | startEmptyColumns = prob->countEmptyCols(); |
42 | } |
43 | double *colels = prob->colels_; |
44 | int *hrow = prob->hrow_; |
45 | CoinBigIndex *mcstrt = prob->mcstrt_; |
46 | int *hincol = prob->hincol_; |
47 | //int ncols = prob->ncols_; |
48 | |
49 | double *clo = prob->clo_; |
50 | double *cup = prob->cup_; |
51 | |
52 | double *rowels = prob->rowels_; |
53 | const int *hcol = prob->hcol_; |
54 | const CoinBigIndex *mrstrt = prob->mrstrt_; |
55 | int *hinrow = prob->hinrow_; |
56 | // int nrows = prob->nrows_; |
57 | |
58 | double *rlo = prob->rlo_; |
59 | double *rup = prob->rup_; |
60 | |
61 | // If rowstat exists then all do |
62 | unsigned char *rowstat = prob->rowstat_; |
63 | double *acts = prob->acts_; |
64 | double * sol = prob->sol_; |
65 | // unsigned char * colstat = prob->colstat_; |
66 | |
67 | # if PRESOLVE_DEBUG |
68 | std::cout << "Entering slack_doubleton_action::presolve." << std::endl ; |
69 | presolve_check_sol(prob) ; |
70 | presolve_check_nbasic(prob) ; |
71 | # endif |
72 | |
73 | const unsigned char *integerType = prob->integerType_; |
74 | |
75 | const double ztolzb = prob->ztolzb_; |
76 | |
77 | int numberLook = prob->numberRowsToDo_; |
78 | int iLook; |
79 | int * look = prob->rowsToDo_; |
80 | bool fixInfeasibility = (prob->presolveOptions_&16384)!=0; |
81 | |
82 | action * actions = new action[numberLook]; |
83 | int nactions = 0; |
84 | notFinished = false; |
85 | |
86 | int * fixed_cols = prob->usefulColumnInt_; //new int [ncols]; |
87 | int nfixed_cols = 0; |
88 | |
89 | // this loop can apparently create new singleton rows; |
90 | // I haven't bothered to detect this. |
91 | // wasfor (int irow=0; irow<nrows; irow++) |
92 | for (iLook=0;iLook<numberLook;iLook++) { |
93 | int irow = look[iLook]; |
94 | if (hinrow[irow] == 1) { |
95 | int jcol = hcol[mrstrt[irow]]; |
96 | double coeff = rowels[mrstrt[irow]]; |
97 | double lo = rlo[irow]; |
98 | double up = rup[irow]; |
99 | double acoeff = fabs(coeff); |
100 | // const bool singleton_col = (hincol[jcol] == 1); |
101 | |
102 | if (acoeff < ZTOLDP2) |
103 | continue; |
104 | |
105 | // don't bother with fixed cols |
106 | if (fabs(cup[jcol] - clo[jcol]) < ztolzb) |
107 | continue; |
108 | |
109 | { |
110 | // put column on stack of things to do next time |
111 | prob->addCol(jcol); |
112 | PRESOLVE_DETAIL_PRINT(printf("pre_singleton %dC %dR E\n" ,jcol,irow)); |
113 | action *s = &actions[nactions]; |
114 | nactions++; |
115 | |
116 | s->col = jcol; |
117 | s->clo = clo[jcol]; |
118 | s->cup = cup[jcol]; |
119 | |
120 | s->row = irow; |
121 | s->rlo = rlo[irow]; |
122 | s->rup = rup[irow]; |
123 | |
124 | s->coeff = coeff; |
125 | #if 0 |
126 | if (prob->tuning_) { |
127 | // really for gcc 4.6 compiler bug |
128 | printf("jcol %d %g %g irow %d %g %g coeff %g\n" , |
129 | jcol,clo[jcol],cup[jcol],irow,rlo[irow],rup[irow],coeff); |
130 | } |
131 | #endif |
132 | } |
133 | |
134 | if (coeff < 0.0) { |
135 | CoinSwap(lo, up); |
136 | lo = -lo; |
137 | up = -up; |
138 | } |
139 | |
140 | if (lo <= -PRESOLVE_INF) |
141 | lo = -PRESOLVE_INF; |
142 | else { |
143 | lo /= acoeff; |
144 | if (lo <= -PRESOLVE_INF) |
145 | lo = -PRESOLVE_INF; |
146 | } |
147 | |
148 | if (up > PRESOLVE_INF) |
149 | up = PRESOLVE_INF; |
150 | else { |
151 | up /= acoeff; |
152 | if (up > PRESOLVE_INF) |
153 | up = PRESOLVE_INF; |
154 | } |
155 | |
156 | if (clo[jcol] < lo) { |
157 | // If integer be careful |
158 | if (integerType[jcol]) { |
159 | //#define COIN_DEVELOP |
160 | #ifdef COIN_DEVELOP |
161 | double lo2=lo; |
162 | #endif |
163 | if (fabs(lo-floor(lo+0.5))<0.000001) |
164 | lo=floor(lo+0.5); |
165 | #ifdef COIN_DEVELOP |
166 | if (lo!=lo2&&fabs(lo-floor(lo+0.5))<0.01) |
167 | printf("first lo %g second %g orig %g\n" ,lo2,lo,clo[jcol]); |
168 | #endif |
169 | if (clo[jcol] < lo) |
170 | clo[jcol] = lo; |
171 | } else { |
172 | clo[jcol] = lo; |
173 | } |
174 | } |
175 | |
176 | if (cup[jcol] > up) { |
177 | // If integer be careful |
178 | if (integerType[jcol]) { |
179 | #ifdef COIN_DEVELOP |
180 | double up2=up; |
181 | #endif |
182 | if (fabs(up-floor(up+0.5))<0.000001) |
183 | up=floor(up+0.5); |
184 | #ifdef COIN_DEVELOP |
185 | if (up!=up2&&fabs(up-floor(up+0.5))<0.01) |
186 | printf("first up %g second %g orig %g\n" ,up2,up,cup[jcol]); |
187 | #endif |
188 | if (cup[jcol] > up) |
189 | cup[jcol] = up; |
190 | } else { |
191 | cup[jcol] = up; |
192 | } |
193 | } |
194 | if (fabs(cup[jcol] - clo[jcol]) < ZTOLDP) { |
195 | fixed_cols[nfixed_cols++] = jcol; |
196 | } |
197 | |
198 | if (lo > up) { |
199 | if (lo <= up + prob->feasibilityTolerance_||fixInfeasibility) { |
200 | // If close to integer then go there |
201 | double nearest = floor(lo+0.5); |
202 | if (fabs(nearest-lo)<2.0*prob->feasibilityTolerance_) { |
203 | lo = nearest; |
204 | up = nearest; |
205 | } else { |
206 | lo = up; |
207 | } |
208 | clo[jcol] = lo; |
209 | cup[jcol] = up; |
210 | } else { |
211 | prob->status_ |= 1; |
212 | prob->messageHandler()->message(COIN_PRESOLVE_COLINFEAS, |
213 | prob->messages()) |
214 | <<jcol |
215 | <<lo |
216 | <<up |
217 | <<CoinMessageEol; |
218 | break; |
219 | } |
220 | } |
221 | |
222 | # if PRESOLVE_DEBUG |
223 | printf("SINGLETON R-%d C-%d\n" , irow, jcol); |
224 | # endif |
225 | |
226 | // eliminate the row entirely from the row rep |
227 | hinrow[irow] = 0; |
228 | PRESOLVE_REMOVE_LINK(prob->rlink_,irow) ; |
229 | |
230 | // just to make things squeeky |
231 | rlo[irow] = 0.0; |
232 | rup[irow] = 0.0; |
233 | |
234 | if (rowstat&&sol) { |
235 | // update solution and basis |
236 | int basisChoice=0; |
237 | int numberBasic=0; |
238 | double movement = 0 ; |
239 | if (prob->columnIsBasic(jcol)) { |
240 | numberBasic++; |
241 | basisChoice=2; // move to row to keep consistent |
242 | } |
243 | if (prob->rowIsBasic(irow)) |
244 | numberBasic++; |
245 | if (sol[jcol] <= clo[jcol]+ztolzb) { |
246 | movement = clo[jcol]-sol[jcol] ; |
247 | sol[jcol] = clo[jcol]; |
248 | prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::atLowerBound); |
249 | } else if (sol[jcol] >= cup[jcol]-ztolzb) { |
250 | movement = cup[jcol]-sol[jcol] ; |
251 | sol[jcol] = cup[jcol]; |
252 | prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::atUpperBound); |
253 | } else { |
254 | basisChoice=1; |
255 | } |
256 | if (numberBasic>1||basisChoice==1) |
257 | prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::basic); |
258 | else if (basisChoice==2) |
259 | prob->setRowStatus(irow,CoinPrePostsolveMatrix::basic); |
260 | if (movement) { |
261 | CoinBigIndex k; |
262 | for (k = mcstrt[jcol] ; k < mcstrt[jcol]+hincol[jcol] ; k++) { |
263 | int row = hrow[k]; |
264 | if (hinrow[row]) |
265 | acts[row] += movement*colels[k]; |
266 | } |
267 | } |
268 | } |
269 | |
270 | /* |
271 | Remove the row from this col in the col rep. It can happen that this will |
272 | empty the column, in which case we can delink it. |
273 | */ |
274 | presolve_delete_from_col(irow,jcol,mcstrt,hincol,hrow,colels) ; |
275 | if (hincol[jcol] == 0) |
276 | { PRESOLVE_REMOVE_LINK(prob->clink_,jcol) ; } |
277 | |
278 | if (nactions >= numberLook) { |
279 | notFinished=true; |
280 | break; |
281 | } |
282 | } |
283 | } |
284 | |
285 | if (nactions) { |
286 | # if PRESOLVE_SUMMARY |
287 | printf("SINGLETON ROWS: %d\n" , nactions); |
288 | # endif |
289 | action *save_actions = new action[nactions]; |
290 | CoinMemcpyN(actions, nactions, save_actions); |
291 | next = new slack_doubleton_action(nactions, save_actions, next); |
292 | |
293 | if (nfixed_cols) |
294 | next = make_fixed_action::presolve(prob, fixed_cols, nfixed_cols, |
295 | true, // arbitrary |
296 | next); |
297 | } |
298 | //delete [] fixed_cols; |
299 | if (prob->tuning_) { |
300 | double thisTime=CoinCpuTime(); |
301 | int droppedRows = prob->countEmptyRows() - startEmptyRows ; |
302 | int droppedColumns = prob->countEmptyCols() - startEmptyColumns; |
303 | printf("CoinPresolveSingleton(2) - %d rows, %d columns dropped in time %g, total %g\n" , |
304 | droppedRows,droppedColumns,thisTime-startTime,thisTime-prob->startTime_); |
305 | } |
306 | |
307 | # if PRESOLVE_DEBUG |
308 | presolve_check_sol(prob) ; |
309 | presolve_check_nbasic(prob) ; |
310 | std::cout << "Leaving slack_doubleton_action::presolve." << std::endl ; |
311 | # endif |
312 | delete [] actions; |
313 | |
314 | return (next); |
315 | } |
316 | |
317 | void slack_doubleton_action::postsolve(CoinPostsolveMatrix *prob) const |
318 | { |
319 | const action *const actions = actions_; |
320 | const int nactions = nactions_; |
321 | |
322 | double *colels = prob->colels_; |
323 | int *hrow = prob->hrow_; |
324 | CoinBigIndex *mcstrt = prob->mcstrt_; |
325 | int *hincol = prob->hincol_; |
326 | int *link = prob->link_; |
327 | // int ncols = prob->ncols_; |
328 | |
329 | double *clo = prob->clo_; |
330 | double *cup = prob->cup_; |
331 | |
332 | double *rlo = prob->rlo_; |
333 | double *rup = prob->rup_; |
334 | |
335 | double *sol = prob->sol_; |
336 | double *rcosts = prob->rcosts_; |
337 | |
338 | double *acts = prob->acts_; |
339 | double *rowduals = prob->rowduals_; |
340 | |
341 | unsigned char *colstat = prob->colstat_; |
342 | // unsigned char *rowstat = prob->rowstat_; |
343 | |
344 | # if PRESOLVE_DEBUG |
345 | char *rdone = prob->rdone_; |
346 | |
347 | std::cout << "Entering slack_doubleton_action::postsolve." << std::endl ; |
348 | presolve_check_sol(prob) ; |
349 | presolve_check_nbasic(prob) ; |
350 | # endif |
351 | CoinBigIndex &free_list = prob->free_list_; |
352 | |
353 | const double ztolzb = prob->ztolzb_; |
354 | |
355 | for (const action *f = &actions[nactions-1]; actions<=f; f--) { |
356 | int irow = f->row; |
357 | double lo0 = f->clo; |
358 | double up0 = f->cup; |
359 | double coeff = f->coeff; |
360 | int jcol = f->col; |
361 | |
362 | rlo[irow] = f->rlo; |
363 | rup[irow] = f->rup; |
364 | |
365 | clo[jcol] = lo0; |
366 | cup[jcol] = up0; |
367 | |
368 | acts[irow] = coeff * sol[jcol]; |
369 | |
370 | // add new element |
371 | { |
372 | CoinBigIndex k = free_list; |
373 | assert(k >= 0 && k < prob->bulk0_) ; |
374 | free_list = link[free_list]; |
375 | hrow[k] = irow; |
376 | colels[k] = coeff; |
377 | link[k] = mcstrt[jcol]; |
378 | mcstrt[jcol] = k; |
379 | } |
380 | hincol[jcol]++; // right? |
381 | |
382 | /* |
383 | * Have to compute rowstat and rowduals, since we are adding the row. |
384 | * that satisfy complentarity slackness. |
385 | * |
386 | * We may also have to modify colstat and rcosts if bounds |
387 | * have been relaxed. |
388 | */ |
389 | if (!colstat) { |
390 | // ???? |
391 | rowduals[irow] = 0.0; |
392 | } else { |
393 | if (prob->columnIsBasic(jcol)) { |
394 | /* variable is already basic, so slack in this row must be basic */ |
395 | prob->setRowStatus(irow,CoinPrePostsolveMatrix::basic); |
396 | |
397 | rowduals[irow] = 0.0; |
398 | /* hence no reduced costs change */ |
399 | /* since the column was basic, it doesn't matter if it is now |
400 | away from its bounds. */ |
401 | /* the slack is basic and its reduced cost is 0 */ |
402 | } else if ((fabs(sol[jcol] - lo0) <= ztolzb && |
403 | rcosts[jcol] >= 0) || |
404 | |
405 | (fabs(sol[jcol] - up0) <= ztolzb && |
406 | rcosts[jcol] <= 0)) { |
407 | /* up against its bound but the rcost is still ok */ |
408 | prob->setRowStatus(irow,CoinPrePostsolveMatrix::basic); |
409 | |
410 | rowduals[irow] = 0.0; |
411 | /* hence no reduced costs change */ |
412 | } else if (! (fabs(sol[jcol] - lo0) <= ztolzb) && |
413 | ! (fabs(sol[jcol] - up0) <= ztolzb)) { |
414 | /* variable not marked basic, |
415 | * so was at a bound in the reduced problem, |
416 | * but its bounds were tighter in the reduced problem, |
417 | * so now it has to be made basic. |
418 | */ |
419 | prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::basic); |
420 | prob->setRowStatusUsingValue(irow); |
421 | |
422 | /* choose a value for rowduals[irow] that forces rcosts[jcol] to 0.0 */ |
423 | /* new reduced cost = 0 = old reduced cost - new dual * coeff */ |
424 | rowduals[irow] = rcosts[jcol] / coeff; |
425 | rcosts[jcol] = 0.0; |
426 | |
427 | /* this value is provably of the right sign for the slack */ |
428 | /* SHOULD SHOW THIS */ |
429 | } else { |
430 | /* the solution is at a bound, but the rcost is wrong */ |
431 | |
432 | prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::basic); |
433 | prob->setRowStatusUsingValue(irow); |
434 | |
435 | /* choose a value for rowduals[irow] that forcesd rcosts[jcol] to 0.0 */ |
436 | rowduals[irow] = rcosts[jcol] / coeff; |
437 | rcosts[jcol] = 0.0; |
438 | |
439 | /* this value is provably of the right sign for the slack */ |
440 | /*rcosts[irow] = -rowduals[irow];*/ |
441 | } |
442 | } |
443 | |
444 | # if PRESOLVE_DEBUG |
445 | rdone[irow] = SLACK_DOUBLETON; |
446 | # endif |
447 | } |
448 | |
449 | # if PRESOLVE_CONSISTENCY |
450 | presolve_check_threads(prob) ; |
451 | presolve_check_sol(prob) ; |
452 | presolve_check_nbasic(prob) ; |
453 | std::cout << "Leaving slack_doubleton_action::postsolve." << std::endl ; |
454 | # endif |
455 | |
456 | return ; |
457 | } |
458 | /* |
459 | If we have a variable with one entry and no cost then we can |
460 | transform the row from E to G etc. |
461 | If there is a row objective region then we may be able to do |
462 | this even with a cost. |
463 | */ |
464 | const CoinPresolveAction * |
465 | slack_singleton_action::presolve(CoinPresolveMatrix *prob, |
466 | const CoinPresolveAction *next, |
467 | double * rowObjective) |
468 | { |
469 | double startTime = 0.0; |
470 | int startEmptyRows=0; |
471 | int startEmptyColumns = 0; |
472 | if (prob->tuning_) { |
473 | startTime = CoinCpuTime(); |
474 | startEmptyRows = prob->countEmptyRows(); |
475 | startEmptyColumns = prob->countEmptyCols(); |
476 | } |
477 | double *colels = prob->colels_; |
478 | int *hrow = prob->hrow_; |
479 | CoinBigIndex *mcstrt = prob->mcstrt_; |
480 | int *hincol = prob->hincol_; |
481 | //int ncols = prob->ncols_; |
482 | |
483 | double *clo = prob->clo_; |
484 | double *cup = prob->cup_; |
485 | |
486 | double *rowels = prob->rowels_; |
487 | int *hcol = prob->hcol_; |
488 | CoinBigIndex *mrstrt = prob->mrstrt_; |
489 | int *hinrow = prob->hinrow_; |
490 | int nrows = prob->nrows_; |
491 | |
492 | double *rlo = prob->rlo_; |
493 | double *rup = prob->rup_; |
494 | |
495 | // If rowstat exists then all do |
496 | unsigned char *rowstat = prob->rowstat_; |
497 | double *acts = prob->acts_; |
498 | double * sol = prob->sol_; |
499 | //unsigned char * colstat = prob->colstat_; |
500 | |
501 | const unsigned char *integerType = prob->integerType_; |
502 | |
503 | const double ztolzb = prob->ztolzb_; |
504 | double *dcost = prob->cost_; |
505 | //const double maxmin = prob->maxmin_; |
506 | |
507 | # if PRESOLVE_DEBUG |
508 | std::cout << "Entering slack_singleton_action::presolve." << std::endl ; |
509 | presolve_check_sol(prob) ; |
510 | presolve_check_nbasic(prob) ; |
511 | # endif |
512 | |
513 | int numberLook = prob->numberColsToDo_; |
514 | int iLook; |
515 | int * look = prob->colsToDo_; |
516 | // Make sure we allocate at least one action |
517 | int maxActions = CoinMin(numberLook,nrows/10)+1; |
518 | action * actions = new action[maxActions]; |
519 | int nactions = 0; |
520 | int * fixed_cols = new int [numberLook]; |
521 | int nfixed_cols=0; |
522 | int nWithCosts=0; |
523 | double costOffset=0.0; |
524 | for (iLook=0;iLook<numberLook;iLook++) { |
525 | int iCol = look[iLook]; |
526 | if (dcost[iCol]) |
527 | continue; |
528 | if (hincol[iCol] == 1) { |
529 | int iRow=hrow[mcstrt[iCol]]; |
530 | double coeff = colels[mcstrt[iCol]]; |
531 | double acoeff = fabs(coeff); |
532 | if (acoeff < ZTOLDP2) |
533 | continue; |
534 | // don't bother with fixed cols |
535 | if (fabs(cup[iCol] - clo[iCol]) < ztolzb) |
536 | continue; |
537 | if (integerType&&integerType[iCol]) { |
538 | // only possible if everything else integer and unit coefficient |
539 | // check everything else a bit later |
540 | if (acoeff!=1.0) |
541 | continue; |
542 | double currentLower = rlo[iRow]; |
543 | double currentUpper = rup[iRow]; |
544 | if (coeff==1.0&¤tLower==1.0&¤tUpper==1.0) { |
545 | // leave if integer slack on sum x == 1 |
546 | bool allInt=true; |
547 | for (CoinBigIndex j=mrstrt[iRow]; |
548 | j<mrstrt[iRow]+hinrow[iRow];j++) { |
549 | int iColumn = hcol[j]; |
550 | double value = fabs(rowels[j]); |
551 | if (!integerType[iColumn]||value!=1.0) { |
552 | allInt=false; |
553 | break; |
554 | } |
555 | } |
556 | if (allInt) |
557 | continue; // leave as may help search |
558 | } |
559 | } |
560 | if (!prob->colProhibited(iCol)) { |
561 | double currentLower = rlo[iRow]; |
562 | double currentUpper = rup[iRow]; |
563 | if (!rowObjective) { |
564 | if (dcost[iCol]) |
565 | continue; |
566 | } else if ((dcost[iCol]&¤tLower!=currentUpper)||rowObjective[iRow]) { |
567 | continue; |
568 | } |
569 | double newLower=currentLower; |
570 | double newUpper=currentUpper; |
571 | if (coeff<0.0) { |
572 | if (currentUpper>1.0e20||cup[iCol]>1.0e20) { |
573 | newUpper=COIN_DBL_MAX; |
574 | } else { |
575 | newUpper -= coeff*cup[iCol]; |
576 | if (newUpper>1.0e20) |
577 | newUpper=COIN_DBL_MAX; |
578 | } |
579 | if (currentLower<-1.0e20||clo[iCol]<-1.0e20) { |
580 | newLower=-COIN_DBL_MAX; |
581 | } else { |
582 | newLower -= coeff*clo[iCol]; |
583 | if (newLower<-1.0e20) |
584 | newLower=-COIN_DBL_MAX; |
585 | } |
586 | } else { |
587 | if (currentUpper>1.0e20||clo[iCol]<-1.0e20) { |
588 | newUpper=COIN_DBL_MAX; |
589 | } else { |
590 | newUpper -= coeff*clo[iCol]; |
591 | if (newUpper>1.0e20) |
592 | newUpper=COIN_DBL_MAX; |
593 | } |
594 | if (currentLower<-1.0e20||cup[iCol]>1.0e20) { |
595 | newLower=-COIN_DBL_MAX; |
596 | } else { |
597 | newLower -= coeff*cup[iCol]; |
598 | if (newLower<-1.0e20) |
599 | newLower=-COIN_DBL_MAX; |
600 | } |
601 | } |
602 | if (integerType&&integerType[iCol]) { |
603 | // only possible if everything else integer |
604 | if (newLower>-1.0e30) { |
605 | if (newLower!=floor(newLower+0.5)) |
606 | continue; |
607 | } |
608 | if (newUpper<1.0e30) { |
609 | if (newUpper!=floor(newUpper+0.5)) |
610 | continue; |
611 | } |
612 | bool allInt=true; |
613 | for (CoinBigIndex j=mrstrt[iRow]; |
614 | j<mrstrt[iRow]+hinrow[iRow];j++) { |
615 | int iColumn = hcol[j]; |
616 | double value = fabs(rowels[j]); |
617 | if (!integerType[iColumn]||value!=floor(value+0.5)) { |
618 | allInt=false; |
619 | break; |
620 | } |
621 | } |
622 | if (!allInt) |
623 | continue; // no good |
624 | } |
625 | if (nactions>=maxActions) { |
626 | maxActions += CoinMin(numberLook-iLook,maxActions); |
627 | action * temp = new action[maxActions]; |
628 | memcpy(temp,actions,nactions*sizeof(action)); |
629 | // changed as 4.6 compiler bug! CoinMemcpyN(actions,nactions,temp); |
630 | delete [] actions; |
631 | actions=temp; |
632 | } |
633 | |
634 | action *s = &actions[nactions]; |
635 | nactions++; |
636 | |
637 | s->col = iCol; |
638 | s->clo = clo[iCol]; |
639 | s->cup = cup[iCol]; |
640 | |
641 | s->row = iRow; |
642 | s->rlo = rlo[iRow]; |
643 | s->rup = rup[iRow]; |
644 | |
645 | s->coeff = coeff; |
646 | |
647 | presolve_delete_from_row(iRow,iCol,mrstrt,hinrow,hcol,rowels) ; |
648 | if (!hinrow[iRow]) |
649 | PRESOLVE_REMOVE_LINK(prob->rlink_,iRow) ; |
650 | // put row on stack of things to do next time |
651 | prob->addRow(iRow); |
652 | #ifdef PRINTCOST |
653 | if (rowObjective&&dcost[iCol]) { |
654 | printf("Singleton %d had coeff of %g in row %d - bounds %g %g - cost %g\n" , |
655 | iCol,coeff,iRow,clo[iCol],cup[iCol],dcost[iCol]); |
656 | printf("Row bounds were %g %g now %g %g\n" , |
657 | rlo[iRow],rup[iRow],newLower,newUpper); |
658 | } |
659 | #endif |
660 | // Row may be redundant but let someone else do that |
661 | rlo[iRow]=newLower; |
662 | rup[iRow]=newUpper; |
663 | if (rowstat&&sol) { |
664 | // update solution and basis |
665 | if ((sol[iCol] < cup[iCol]-ztolzb&& |
666 | sol[iCol] > clo[iCol]+ztolzb)||prob->columnIsBasic(iCol)) |
667 | prob->setRowStatus(iRow,CoinPrePostsolveMatrix::basic); |
668 | prob->setColumnStatusUsingValue(iCol); |
669 | } |
670 | // Force column to zero |
671 | clo[iCol]=0.0; |
672 | cup[iCol]=0.0; |
673 | if (rowObjective&&dcost[iCol]) { |
674 | rowObjective[iRow]=-dcost[iCol]/coeff; |
675 | nWithCosts++; |
676 | // adjust offset |
677 | costOffset += currentLower*rowObjective[iRow]; |
678 | prob->dobias_ -= currentLower*rowObjective[iRow]; |
679 | } |
680 | if (sol) { |
681 | double movement; |
682 | if (fabs(sol[iCol]-clo[iCol])<fabs(sol[iCol]-cup[iCol])) { |
683 | movement = clo[iCol]-sol[iCol] ; |
684 | sol[iCol]=clo[iCol]; |
685 | } else { |
686 | movement = cup[iCol]-sol[iCol] ; |
687 | sol[iCol]=cup[iCol]; |
688 | } |
689 | if (movement) |
690 | acts[iRow] += movement*coeff; |
691 | } |
692 | /* |
693 | Remove the row from this col in the col rep.and delink it. |
694 | */ |
695 | presolve_delete_from_col(iRow,iCol,mcstrt,hincol,hrow,colels) ; |
696 | assert (hincol[iCol] == 0); |
697 | PRESOLVE_REMOVE_LINK(prob->clink_,iCol) ; |
698 | //clo[iCol] = 0.0; |
699 | //cup[iCol] = 0.0; |
700 | fixed_cols[nfixed_cols++] = iCol; |
701 | //presolve_consistent(prob); |
702 | } |
703 | } |
704 | } |
705 | |
706 | if (nactions) { |
707 | # if PRESOLVE_SUMMARY |
708 | printf("SINGLETON COLS: %d\n" , nactions); |
709 | # endif |
710 | #ifdef COIN_DEVELOP |
711 | printf("%d singletons, %d with costs - offset %g\n" ,nactions, |
712 | nWithCosts, costOffset); |
713 | #endif |
714 | action *save_actions = new action[nactions]; |
715 | CoinMemcpyN(actions, nactions, save_actions); |
716 | next = new slack_singleton_action(nactions, save_actions, next); |
717 | |
718 | if (nfixed_cols) |
719 | next = make_fixed_action::presolve(prob, fixed_cols, nfixed_cols, |
720 | true, // arbitrary |
721 | next); |
722 | } |
723 | delete [] actions; |
724 | delete [] fixed_cols; |
725 | if (prob->tuning_) { |
726 | double thisTime=CoinCpuTime(); |
727 | int droppedRows = prob->countEmptyRows() - startEmptyRows ; |
728 | int droppedColumns = prob->countEmptyCols() - startEmptyColumns; |
729 | printf("CoinPresolveSingleton(3) - %d rows, %d columns dropped in time %g, total %g\n" , |
730 | droppedRows,droppedColumns,thisTime-startTime,thisTime-prob->startTime_); |
731 | } |
732 | |
733 | # if PRESOLVE_DEBUG |
734 | presolve_check_sol(prob) ; |
735 | presolve_check_nbasic(prob) ; |
736 | std::cout << "Leaving slack_singleton_action::presolve." << std::endl ; |
737 | # endif |
738 | |
739 | return (next); |
740 | } |
741 | |
742 | void slack_singleton_action::postsolve(CoinPostsolveMatrix *prob) const |
743 | { |
744 | const action *const actions = actions_; |
745 | const int nactions = nactions_; |
746 | |
747 | double *colels = prob->colels_; |
748 | int *hrow = prob->hrow_; |
749 | CoinBigIndex *mcstrt = prob->mcstrt_; |
750 | int *hincol = prob->hincol_; |
751 | int *link = prob->link_; |
752 | // int ncols = prob->ncols_; |
753 | |
754 | //double *rowels = prob->rowels_; |
755 | //int *hcol = prob->hcol_; |
756 | //CoinBigIndex *mrstrt = prob->mrstrt_; |
757 | //int *hinrow = prob->hinrow_; |
758 | |
759 | double *clo = prob->clo_; |
760 | double *cup = prob->cup_; |
761 | |
762 | double *rlo = prob->rlo_; |
763 | double *rup = prob->rup_; |
764 | |
765 | double *sol = prob->sol_; |
766 | double *rcosts = prob->rcosts_; |
767 | |
768 | double *acts = prob->acts_; |
769 | double *rowduals = prob->rowduals_; |
770 | double *dcost = prob->cost_; |
771 | //const double maxmin = prob->maxmin_; |
772 | |
773 | unsigned char *colstat = prob->colstat_; |
774 | // unsigned char *rowstat = prob->rowstat_; |
775 | |
776 | # if PRESOLVE_DEBUG |
777 | char *rdone = prob->rdone_; |
778 | |
779 | std::cout << "Entering slack_singleton_action::postsolve." << std::endl ; |
780 | presolve_check_sol(prob) ; |
781 | presolve_check_nbasic(prob) ; |
782 | # endif |
783 | |
784 | CoinBigIndex &free_list = prob->free_list_; |
785 | |
786 | const double ztolzb = prob->ztolzb_; |
787 | #ifdef CHECK_ONE_ROW |
788 | { |
789 | double act=0.0; |
790 | for (int i=0;i<prob->ncols_;i++) { |
791 | double solV = sol[i]; |
792 | assert (solV>=clo[i]-ztolzb&&solV<=cup[i]+ztolzb); |
793 | int j=mcstrt[i]; |
794 | for (int k=0;k<hincol[i];k++) { |
795 | if (hrow[j]==CHECK_ONE_ROW) { |
796 | act += colels[j]*solV; |
797 | } |
798 | j=link[j]; |
799 | } |
800 | } |
801 | assert (act>=rlo[CHECK_ONE_ROW]-ztolzb&&act<=rup[CHECK_ONE_ROW]+ztolzb); |
802 | printf("start %g %g %g %g\n" ,rlo[CHECK_ONE_ROW],act,acts[CHECK_ONE_ROW],rup[CHECK_ONE_ROW]); |
803 | } |
804 | #endif |
805 | for (const action *f = &actions[nactions-1]; actions<=f; f--) { |
806 | int iRow = f->row; |
807 | double lo0 = f->clo; |
808 | double up0 = f->cup; |
809 | double coeff = f->coeff; |
810 | int iCol = f->col; |
811 | assert (!hincol[iCol]); |
812 | #ifdef CHECK_ONE_ROW |
813 | if (iRow==CHECK_ONE_ROW) |
814 | printf("Col %d coeff %g old bounds %g,%g new %g,%g - new rhs %g,%g - act %g\n" , |
815 | iCol,coeff,clo[iCol],cup[iCol],lo0,up0,f->rlo,f->rup,acts[CHECK_ONE_ROW]); |
816 | #endif |
817 | rlo[iRow] = f->rlo; |
818 | rup[iRow] = f->rup; |
819 | |
820 | clo[iCol] = lo0; |
821 | cup[iCol] = up0; |
822 | double movement=0.0; |
823 | // acts was without coefficient - adjust |
824 | acts[iRow] += coeff*sol[iCol]; |
825 | if (acts[iRow]<rlo[iRow]-ztolzb) |
826 | movement = rlo[iRow]-acts[iRow]; |
827 | else if (acts[iRow]>rup[iRow]+ztolzb) |
828 | movement = rup[iRow]-acts[iRow]; |
829 | double cMove = movement/coeff; |
830 | sol[iCol] += cMove; |
831 | acts[iRow] += movement; |
832 | if (!dcost[iCol]) { |
833 | // and to get column feasible |
834 | cMove=0.0; |
835 | if (sol[iCol]>cup[iCol]+ztolzb) |
836 | cMove = cup[iCol]-sol[iCol]; |
837 | else if (sol[iCol]<clo[iCol]-ztolzb) |
838 | cMove = clo[iCol]-sol[iCol]; |
839 | sol[iCol] += cMove; |
840 | acts[iRow] += cMove*coeff; |
841 | /* |
842 | * Have to compute status. At most one can be basic. It's possible that |
843 | both are nonbasic and nonbasic status must change. |
844 | */ |
845 | if (colstat) { |
846 | int numberBasic =0; |
847 | if (prob->columnIsBasic(iCol)) |
848 | numberBasic++; |
849 | if (prob->rowIsBasic(iRow)) |
850 | numberBasic++; |
851 | #ifdef COIN_DEVELOP |
852 | if (numberBasic>1) |
853 | printf("odd in singleton\n" ); |
854 | #endif |
855 | if (sol[iCol]>clo[iCol]+ztolzb&&sol[iCol]<cup[iCol]-ztolzb) { |
856 | prob->setColumnStatus(iCol,CoinPrePostsolveMatrix::basic); |
857 | prob->setRowStatusUsingValue(iRow); |
858 | } else if (acts[iRow]>rlo[iRow]+ztolzb&&acts[iRow]<rup[iRow]-ztolzb) { |
859 | prob->setRowStatus(iRow,CoinPrePostsolveMatrix::basic); |
860 | prob->setColumnStatusUsingValue(iCol); |
861 | } else if (numberBasic) { |
862 | prob->setRowStatus(iRow,CoinPrePostsolveMatrix::basic); |
863 | prob->setColumnStatusUsingValue(iCol); |
864 | } else { |
865 | prob->setRowStatusUsingValue(iRow); |
866 | prob->setColumnStatusUsingValue(iCol); |
867 | } |
868 | } |
869 | # if PRESOLVE_DEBUG |
870 | printf("SLKSING: %d = %g restored %d lb = %g ub = %g.\n" , |
871 | iCol,sol[iCol],prob->getColumnStatus(iCol),clo[iCol],cup[iCol]) ; |
872 | # endif |
873 | } else { |
874 | // must have been equality row |
875 | assert (rlo[iRow]==rup[iRow]); |
876 | double cost = rcosts[iCol]; |
877 | // adjust for coefficient |
878 | cost -= rowduals[iRow]*coeff; |
879 | bool basic=true; |
880 | if (fabs(sol[iCol]-cup[iCol])<ztolzb&&cost<-1.0e-6) |
881 | basic=false; |
882 | else if (fabs(sol[iCol]-clo[iCol])<ztolzb&&cost>1.0e-6) |
883 | basic=false; |
884 | //printf("Singleton %d had coeff of %g in row %d (dual %g) - bounds %g %g - cost %g, (dj %g)\n", |
885 | // iCol,coeff,iRow,rowduals[iRow],clo[iCol],cup[iCol],dcost[iCol],rcosts[iCol]); |
886 | //if (prob->columnIsBasic(iCol)) |
887 | //printf("column basic! "); |
888 | //if (prob->rowIsBasic(iRow)) |
889 | //printf("row basic "); |
890 | //printf("- make column basic %s\n",basic ? "yes" : "no"); |
891 | if (basic&&!prob->rowIsBasic(iRow)) { |
892 | #ifdef PRINTCOST |
893 | printf("Singleton %d had coeff of %g in row %d (dual %g) - bounds %g %g - cost %g, (dj %g - new %g)\n" , |
894 | iCol,coeff,iRow,rowduals[iRow],clo[iCol],cup[iCol],dcost[iCol],rcosts[iCol],cost); |
895 | #endif |
896 | #ifdef COIN_DEVELOP |
897 | if (prob->columnIsBasic(iCol)) |
898 | printf("column basic!\n" ); |
899 | #endif |
900 | basic=false; |
901 | } |
902 | if (fabs(rowduals[iRow])>1.0e-6&&prob->rowIsBasic(iRow)) |
903 | basic=true; |
904 | if (basic) { |
905 | // Make basic have zero reduced cost |
906 | rowduals[iRow] = rcosts[iCol] / coeff; |
907 | rcosts[iCol] = 0.0; |
908 | } else { |
909 | rcosts[iCol]=cost; |
910 | //rowduals[iRow]=0.0; |
911 | } |
912 | if (colstat) { |
913 | if (basic) { |
914 | if (!prob->rowIsBasic(iRow)) { |
915 | #if 0 |
916 | // find column in row |
917 | int jCol=-1; |
918 | //for (CoinBigIndex j=mrstrt[iRow];j<mrstrt |
919 | for (int k=0;k<prob->ncols0_;k++) { |
920 | CoinBigIndex j=mcstrt[k]; |
921 | for (int i=0;i<hincol[k];i++) { |
922 | if (hrow[k]==iRow) { |
923 | break; |
924 | } |
925 | k=link[k]; |
926 | } |
927 | } |
928 | #endif |
929 | } else { |
930 | prob->setColumnStatus(iCol,CoinPrePostsolveMatrix::basic); |
931 | } |
932 | prob->setRowStatusUsingValue(iRow); |
933 | } else { |
934 | //prob->setRowStatus(iRow,CoinPrePostsolveMatrix::basic); |
935 | prob->setColumnStatusUsingValue(iCol); |
936 | } |
937 | } |
938 | } |
939 | #if 0 |
940 | int nb=0; |
941 | int kk; |
942 | for (kk=0;kk<prob->nrows_;kk++) |
943 | if (prob->rowIsBasic(kk)) |
944 | nb++; |
945 | for (kk=0;kk<prob->ncols_;kk++) |
946 | if (prob->columnIsBasic(kk)) |
947 | nb++; |
948 | assert (nb==prob->nrows_); |
949 | #endif |
950 | // add new element |
951 | { |
952 | CoinBigIndex k = free_list; |
953 | assert(k >= 0 && k < prob->bulk0_) ; |
954 | free_list = link[free_list]; |
955 | hrow[k] = iRow; |
956 | colels[k] = coeff; |
957 | link[k] = mcstrt[iCol]; |
958 | mcstrt[iCol] = k; |
959 | } |
960 | hincol[iCol]++; // right? |
961 | #ifdef CHECK_ONE_ROW |
962 | { |
963 | double act=0.0; |
964 | for (int i=0;i<prob->ncols_;i++) { |
965 | double solV = sol[i]; |
966 | assert (solV>=clo[i]-ztolzb&&solV<=cup[i]+ztolzb); |
967 | int j=mcstrt[i]; |
968 | for (int k=0;k<hincol[i];k++) { |
969 | if (hrow[j]==CHECK_ONE_ROW) { |
970 | //printf("c %d el %g sol %g old act %g new %g\n", |
971 | // i,colels[j],solV,act, act+colels[j]*solV); |
972 | act += colels[j]*solV; |
973 | } |
974 | j=link[j]; |
975 | } |
976 | } |
977 | assert (act>=rlo[CHECK_ONE_ROW]-ztolzb&&act<=rup[CHECK_ONE_ROW]+ztolzb); |
978 | printf("rhs now %g %g %g %g\n" ,rlo[CHECK_ONE_ROW],act,acts[CHECK_ONE_ROW],rup[CHECK_ONE_ROW]); |
979 | } |
980 | #endif |
981 | |
982 | # if PRESOLVE_DEBUG |
983 | rdone[iRow] = SLACK_SINGLETON; |
984 | # endif |
985 | } |
986 | |
987 | # if PRESOLVE_DEBUG |
988 | presolve_check_sol(prob) ; |
989 | presolve_check_nbasic(prob) ; |
990 | std::cout << "Leaving slack_singleton_action::postsolve." << std::endl ; |
991 | # endif |
992 | |
993 | return ; |
994 | } |
995 | |