1 /* $Id: CoinPresolveDoubleton.cpp 2083 2019-01-06 19:38:09Z unxusr $ */
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 "CoinFinite.hpp"
10 #include "CoinHelperFunctions.hpp"
11 #include "CoinPresolveMatrix.hpp"
12
13 #include "CoinPresolveEmpty.hpp" // for DROP_COL/DROP_ROW
14 #include "CoinPresolveZeros.hpp"
15 #include "CoinPresolveFixed.hpp"
16 #include "CoinPresolveDoubleton.hpp"
17
18 #include "CoinPresolvePsdebug.hpp"
19 #include "CoinMessage.hpp"
20
21 #if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
22 #include "CoinPresolvePsdebug.hpp"
23 #endif
24
25 namespace { /* begin unnamed local namespace */
26
27 #if PRESOLVE_DEBUG > 0
28 #define DBGPARAM(zz_param_zz) zz_param_zz
29 #else
30 #define DBGPARAM(zz_param_zz)
31 #endif
32
33 /*
34 This routine does the grunt work needed to substitute x for y in all rows i
35 where coeff[i,y] != 0. Given ax + by = c, we have
36
37 y = (c - a*x)/b = c/b + (-a/b)*x
38
39 Suppose we're fixing row i. We need to adjust the row bounds by
40 -coeff[i,y]*(c/b) and coeff[i,x] by coeff[i,y]*(-a/b). The value
41 c/b is passed as the bounds_factor, and -a/b as the coeff_factor.
42
43 row0 is the doubleton row. It is assumed that coeff[row0,y] has been
44 removed from the column major representation before this routine is
45 called. (Otherwise, we'd have to check for it to avoid a useless row
46 update.)
47
48 Both the row and col representations are updated. There are two cases:
49
50 * coeff[i,x] != 0:
51 in the column rep, modify coeff[i,x] ;
52 in the row rep, modify coeff[i,x] and drop coeff[i,y].
53
54 * coeff[i,x] == 0 (i.e., non-existent):
55 in the column rep, add coeff[i,x]; mcstrt is modified if the column
56 must be moved ;
57 in the row rep, convert coeff[i,y] to coeff[i,x].
58
59 The row and column reps are inconsistent during the routine and at
60 completion. In the row rep, column x and y are updated except for
61 the doubleton row, and in the column rep only column x is updated
62 except for coeff[row0,x]. On return, column y and row row0 will be deleted
63 and consistency will be restored.
64 */
65
elim_doubleton(const char * DBGPARAM (msg),CoinBigIndex * mcstrt,double * rlo,double * rup,double * colels,int * hrow,int * hcol,int * hinrow,int * hincol,presolvehlink * clink,int ncols,CoinBigIndex * mrstrt,double * rowels,double coeff_factor,double bounds_factor,int DBGPARAM (row0),int icolx,int icoly)66 bool elim_doubleton(const char *DBGPARAM(msg),
67 CoinBigIndex *mcstrt,
68 double *rlo, double *rup,
69 double *colels,
70 int *hrow, int *hcol,
71 int *hinrow, int *hincol,
72 presolvehlink *clink, int ncols,
73 CoinBigIndex *mrstrt, double *rowels,
74 double coeff_factor,
75 double bounds_factor,
76 int DBGPARAM(row0),
77 int icolx, int icoly)
78
79 {
80 CoinBigIndex kcsx = mcstrt[icolx];
81 CoinBigIndex kcex = kcsx + hincol[icolx];
82
83 #if PRESOLVE_DEBUG > 1
84 printf("%s %d x=%d y=%d cf=%g bf=%g nx=%d yrows=(", msg,
85 row0, icolx, icoly, coeff_factor, bounds_factor, hincol[icolx]);
86 #endif
87 /*
88 Open a loop to scan column y. For each nonzero coefficient (row,y),
89 update column x and the row bounds for the row.
90
91 The initial assert checks that we're properly updating column x.
92 */
93 CoinBigIndex base = mcstrt[icoly];
94 int numberInY = hincol[icoly];
95 for (int kwhere = 0; kwhere < numberInY; kwhere++) {
96 PRESOLVEASSERT(kcex == kcsx + hincol[icolx]);
97 const CoinBigIndex kcoly = base + kwhere;
98 const int row = hrow[kcoly];
99 const double coeffy = colels[kcoly];
100 double delta = coeffy * coeff_factor;
101 /*
102 Look for coeff[row,x], then update accordingly.
103 */
104 CoinBigIndex kcolx = presolve_find_row1(row, kcsx, kcex, hrow);
105 #if PRESOLVE_DEBUG > 1
106 printf("%d%s ", row, (kcolx < kcex) ? "+" : "");
107 #endif
108 /*
109 Case 1: coeff[i,x] != 0: update it in column and row reps; drop coeff[i,y]
110 from row rep.
111 */
112 if (kcolx < kcex) {
113 colels[kcolx] += delta;
114
115 const CoinBigIndex kmi = presolve_find_col(icolx, mrstrt[row], mrstrt[row] + hinrow[row], hcol);
116 rowels[kmi] = colels[kcolx];
117 presolve_delete_from_row(row, icoly, mrstrt, hinrow, hcol, rowels);
118 /*
119 Case 2: coeff[i,x] == 0: add it in the column rep; convert coeff[i,y] in
120 the row rep. presolve_expand_col ensures an empty entry exists at the
121 end of the column. The location of column x may change with expansion.
122 */
123 } else {
124 const bool no_mem = presolve_expand_col(mcstrt, colels, hrow, hincol,
125 clink, ncols, icolx);
126 if (no_mem)
127 return (true);
128
129 kcsx = mcstrt[icolx];
130 kcex = kcsx + hincol[icolx];
131 // recompute y as well
132 base = mcstrt[icoly];
133
134 hrow[kcex] = row;
135 colels[kcex] = delta;
136 hincol[icolx]++;
137 kcex++;
138
139 CoinBigIndex k2 = presolve_find_col(icoly, mrstrt[row], mrstrt[row] + hinrow[row], hcol);
140 hcol[k2] = icolx;
141 rowels[k2] = delta;
142 }
143 /*
144 Update the row bounds, if necessary. Avoid updating finite infinity.
145 */
146 if (bounds_factor != 0.0) {
147 delta = coeffy * bounds_factor;
148 if (-PRESOLVE_INF < rlo[row])
149 rlo[row] -= delta;
150 if (rup[row] < PRESOLVE_INF)
151 rup[row] -= delta;
152 }
153 }
154
155 #if PRESOLVE_DEBUG > 1
156 printf(")\n");
157 #endif
158
159 return (false);
160 }
161
162 #if PRESOLVE_DEBUG > 0
163 /*
164 Debug helpers
165 */
166
167 double *doubleton_mult;
168 int *doubleton_id;
169
check_doubletons(const CoinPresolveAction * paction)170 void check_doubletons(const CoinPresolveAction *paction)
171 {
172 const CoinPresolveAction *paction0 = paction;
173
174 if (paction) {
175 check_doubletons(paction->next);
176
177 if (strcmp(paction0->name(), "doubleton_action") == 0) {
178 const doubleton_action *daction = dynamic_cast< const doubleton_action * >(paction0);
179 for (int i = daction->nactions_ - 1; i >= 0; --i) {
180 int icolx = daction->actions_[i].icolx;
181 int icoly = daction->actions_[i].icoly;
182 double coeffx = daction->actions_[i].coeffx;
183 double coeffy = daction->actions_[i].coeffy;
184
185 doubleton_mult[icoly] = -coeffx / coeffy;
186 doubleton_id[icoly] = icolx;
187 }
188 }
189 }
190 }
191
check_doubletons1(const CoinPresolveAction * paction,int ncols)192 void check_doubletons1(const CoinPresolveAction *paction,
193 int ncols)
194 {
195 doubleton_mult = new double[ncols];
196 doubleton_id = new int[ncols];
197 int i;
198 for (i = 0; i < ncols; ++i)
199 doubleton_id[i] = i;
200 check_doubletons(paction);
201 double minmult = 1.0;
202 int minid = -1;
203 for (i = 0; i < ncols; ++i) {
204 double mult = 1.0;
205 int j = i;
206 if (doubleton_id[j] != j) {
207 printf("MULTS (%d): ", j);
208 while (doubleton_id[j] != j) {
209 printf("%d %g, ", doubleton_id[j], doubleton_mult[j]);
210 mult *= doubleton_mult[j];
211 j = doubleton_id[j];
212 }
213 printf(" == %g\n", mult);
214 if (minmult > fabs(mult)) {
215 minmult = fabs(mult);
216 minid = i;
217 }
218 }
219 }
220 if (minid != -1)
221 printf("MIN MULT: %d %g\n", minid, minmult);
222 }
223 #endif // PRESOLVE_DEBUG
224
225 } /* end unnamed local namespace */
226
227 /*
228 It is always the case that one of the variables of a doubleton is, or
229 can be made, implied free, but neither will necessarily be a singleton.
230 Since in the case of a doubleton the number of non-zero entries will never
231 increase if one is eliminated, it makes sense to always eliminate them.
232
233 The col rep and row rep must be consistent.
234 */
235 const CoinPresolveAction
236 *
presolve(CoinPresolveMatrix * prob,const CoinPresolveAction * next)237 doubleton_action::presolve(CoinPresolveMatrix *prob,
238 const CoinPresolveAction *next)
239
240 {
241 #if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
242 #if PRESOLVE_DEBUG > 0
243 std::cout
244 << "Entering doubleton_action::presolve; considering "
245 << prob->numberRowsToDo_ << " rows." << std::endl;
246 #endif
247 presolve_consistent(prob);
248 presolve_links_ok(prob);
249 presolve_check_sol(prob);
250 presolve_check_nbasic(prob);
251 #endif
252 #if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
253 int startEmptyRows = 0;
254 int startEmptyColumns = 0;
255 startEmptyRows = prob->countEmptyRows();
256 startEmptyColumns = prob->countEmptyCols();
257 #if COIN_PRESOLVE_TUNING > 0
258 double startTime = 0.0;
259 if (prob->tuning_)
260 startTime = CoinCpuTime();
261 #endif
262 #endif
263
264 const int n = prob->ncols_;
265 const int m = prob->nrows_;
266
267 /*
268 Unpack column-major and row-major representations, along with rim vectors.
269 */
270 CoinBigIndex *colStarts = prob->mcstrt_;
271 int *colLengths = prob->hincol_;
272 double *colCoeffs = prob->colels_;
273 int *rowIndices = prob->hrow_;
274 presolvehlink *clink = prob->clink_;
275
276 double *clo = prob->clo_;
277 double *cup = prob->cup_;
278
279 CoinBigIndex *rowStarts = prob->mrstrt_;
280 int *rowLengths = prob->hinrow_;
281 double *rowCoeffs = prob->rowels_;
282 int *colIndices = prob->hcol_;
283 presolvehlink *rlink = prob->rlink_;
284
285 double *rlo = prob->rlo_;
286 double *rup = prob->rup_;
287
288 const unsigned char *integerType = prob->integerType_;
289
290 double *cost = prob->cost_;
291
292 int numberLook = prob->numberRowsToDo_;
293 int *look = prob->rowsToDo_;
294 const double ztolzb = prob->ztolzb_;
295 const double ztolzero = 1.0e-12;
296
297 action *actions = new action[m];
298 int nactions = 0;
299
300 /*
301 zeros will hold columns that should be groomed to remove explicit zeros when
302 we're finished.
303
304 fixed will hold columns that have ended up as fixed variables.
305 */
306 int *zeros = prob->usefulColumnInt_;
307 int nzeros = 0;
308
309 int *fixed = zeros + n;
310 int nfixed = 0;
311
312 unsigned char *rowstat = prob->rowstat_;
313 double *acts = prob->acts_;
314 double *sol = prob->sol_;
315 /*
316 More like `ignore infeasibility'.
317 */
318 bool fixInfeasibility = ((prob->presolveOptions_ & 0x4000) != 0);
319
320 /*
321 Open the main loop to scan for doubleton candidates.
322 */
323 for (int iLook = 0; iLook < numberLook; iLook++) {
324 const int tgtrow = look[iLook];
325 /*
326 We need an equality with two coefficients. Avoid isolated constraints, lest
327 both variables vanish.
328
329 Failure of the assert indicates that the row- and column-major
330 representations are out of sync.
331 */
332 if ((rowLengths[tgtrow] != 2) || (fabs(rup[tgtrow] - rlo[tgtrow]) > ZTOLDP))
333 continue;
334
335 const CoinBigIndex krs = rowStarts[tgtrow];
336 int tgtcolx = colIndices[krs];
337 int tgtcoly = colIndices[krs + 1];
338
339 PRESOLVEASSERT(colLengths[tgtcolx] > 0 || colLengths[tgtcoly] > 0);
340 if (colLengths[tgtcolx] == 1 && colLengths[tgtcoly] == 1)
341 continue;
342 /*
343 Avoid prohibited columns and fixed columns. Make sure the coefficients are
344 nonzero.
345 JJF - test should allow one to be prohibited as long as you leave that
346 one. I modified earlier code but hope I have got this right.
347 */
348 if (prob->colProhibited(tgtcolx) && prob->colProhibited(tgtcoly))
349 continue;
350 if (fabs(rowCoeffs[krs]) < ZTOLDP2 || fabs(rowCoeffs[krs + 1]) < ZTOLDP2)
351 continue;
352 if ((fabs(cup[tgtcolx] - clo[tgtcolx]) < ZTOLDP) || (fabs(cup[tgtcoly] - clo[tgtcoly]) < ZTOLDP))
353 continue;
354
355 #if PRESOLVE_DEBUG > 2
356 std::cout
357 << " row " << tgtrow << " colx " << tgtcolx << " coly " << tgtcoly
358 << " passes preliminary eval." << std::endl;
359 #endif
360
361 /*
362 Find this row in each column. The indices are not const because we may flip
363 them below, once we decide which column will be eliminated.
364 */
365 CoinBigIndex krowx = presolve_find_row(tgtrow, colStarts[tgtcolx],
366 colStarts[tgtcolx] + colLengths[tgtcolx], rowIndices);
367 double coeffx = colCoeffs[krowx];
368 CoinBigIndex krowy = presolve_find_row(tgtrow, colStarts[tgtcoly],
369 colStarts[tgtcoly] + colLengths[tgtcoly], rowIndices);
370 double coeffy = colCoeffs[krowy];
371 const double rhs = rlo[tgtrow];
372 /*
373 Avoid obscuring a requirement for integrality.
374
375 If only one variable is integer, keep it and substitute for the continuous
376 variable.
377
378 If both are integer, substitute only for the forms x = k*y (k integral
379 and non-empty intersection on bounds on x) or x = 1-y, where both x and
380 y are binary.
381
382 flag bits for integerStatus: 0x01: x integer; 0x02: y integer
383
384 This bit of code works because 0 is continuous, 1 is integer. Make sure
385 that's true.
386 */
387 assert((integerType[tgtcolx] == 0) || (integerType[tgtcolx] == 1));
388 assert((integerType[tgtcoly] == 0) || (integerType[tgtcoly] == 1));
389
390 int integerX = integerType[tgtcolx];
391 int integerY = integerType[tgtcoly];
392 /* if one prohibited then treat that as integer. This
393 may be pessimistic - but will catch SOS etc */
394 if (prob->colProhibited2(tgtcolx))
395 integerX = 1;
396 if (prob->colProhibited2(tgtcoly))
397 integerY = 1;
398 int integerStatus = (integerY << 1) | integerX;
399
400 if (integerStatus == 3) {
401 int good = 0;
402 double rhs2 = rhs;
403 if (coeffx < 0.0) {
404 coeffx = -coeffx;
405 rhs2 += 1;
406 }
407 if ((cup[tgtcolx] == 1.0) && (clo[tgtcolx] == 0.0) && (fabs(coeffx - 1.0) < 1.0e-7) && !prob->colProhibited2(tgtcoly))
408 good = 1;
409 if (coeffy < 0.0) {
410 coeffy = -coeffy;
411 rhs2 += 1;
412 }
413 if ((cup[tgtcoly] == 1.0) && (clo[tgtcoly] == 0.0) && (fabs(coeffy - 1.0) < 1.0e-7) && !prob->colProhibited2(tgtcolx))
414 good |= 2;
415 if (!(good == 3 && fabs(rhs2 - 1.0) < 1.0e-7))
416 integerStatus = -1;
417 /*
418 Not x+y = 1. Try for ax+by = 0
419 */
420 if (integerStatus < 0 && rhs == 0.0) {
421 coeffx = colCoeffs[krowx];
422 coeffy = colCoeffs[krowy];
423 double ratio;
424 bool swap = false;
425 if (fabs(coeffx) > fabs(coeffy)) {
426 ratio = coeffx / coeffy;
427 } else {
428 ratio = coeffy / coeffx;
429 swap = true;
430 }
431 ratio = fabs(ratio);
432 if (fabs(ratio - floor(ratio + 0.5)) < ztolzero) {
433 integerStatus = swap ? 2 : 1;
434 }
435 }
436 /*
437 One last try --- just require an integral substitution formula.
438
439 But ax+by = 0 above is a subset of ax+by = c below and should pass the
440 test below. For that matter, so will x+y = 1. Why separate special cases
441 above? -- lh, 121106 --
442 */
443 if (integerStatus < 0) {
444 bool canDo = false;
445 coeffx = colCoeffs[krowx];
446 coeffy = colCoeffs[krowy];
447 double ratio;
448 bool swap = false;
449 double rhsRatio;
450 if (fabs(coeffx) > fabs(coeffy)) {
451 ratio = coeffx / coeffy;
452 rhsRatio = rhs / coeffx;
453 } else {
454 ratio = coeffy / coeffx;
455 rhsRatio = rhs / coeffy;
456 swap = true;
457 }
458 ratio = fabs(ratio);
459 if (fabs(ratio - floor(ratio + 0.5)) < ztolzero) {
460 // possible
461 integerStatus = swap ? 2 : 1;
462 // but check rhs
463 if (rhsRatio == floor(rhsRatio + 0.5))
464 canDo = true;
465 }
466 #ifdef COIN_DEVELOP2
467 if (canDo)
468 printf("Good CoinPresolveDoubleton tgtcolx %d (%g and bounds %g %g) tgtcoly %d (%g and bound %g %g) - rhs %g\n",
469 tgtcolx, colCoeffs[krowx], clo[tgtcolx], cup[tgtcolx],
470 tgtcoly, colCoeffs[krowy], clo[tgtcoly], cup[tgtcoly], rhs);
471 else
472 printf("Bad CoinPresolveDoubleton tgtcolx %d (%g) tgtcoly %d (%g) - rhs %g\n",
473 tgtcolx, colCoeffs[krowx], tgtcoly, colCoeffs[krowy], rhs);
474 #endif
475 if (!canDo)
476 continue;
477 }
478 }
479 /*
480 We've resolved integrality concerns. If we concluded that we need to
481 switch the roles of x and y because of integrality, do that now. If both
482 variables are continuous, we may still want to swap for numeric stability.
483 Eliminate the variable with the larger coefficient.
484 */
485 if (integerStatus == 2) {
486 CoinSwap(tgtcoly, tgtcolx);
487 CoinSwap(krowy, krowx);
488 } else if (integerStatus == 0) {
489 if (fabs(colCoeffs[krowy]) < fabs(colCoeffs[krowx])) {
490 CoinSwap(tgtcoly, tgtcolx);
491 CoinSwap(krowy, krowx);
492 }
493 }
494 /*
495 Don't eliminate y just yet if it's entangled in a singleton row (we want to
496 capture that explicit bound in a column bound).
497 */
498 const CoinBigIndex kcsy = colStarts[tgtcoly];
499 const CoinBigIndex kcey = kcsy + colLengths[tgtcoly];
500 bool singletonRow = false;
501 for (CoinBigIndex kcol = kcsy; kcol < kcey; kcol++) {
502 if (rowLengths[rowIndices[kcol]] == 1) {
503 singletonRow = true;
504 break;
505 }
506 }
507 // skip if y prohibited
508 if (singletonRow || prob->colProhibited2(tgtcoly))
509 continue;
510
511 coeffx = colCoeffs[krowx];
512 coeffy = colCoeffs[krowy];
513 #if PRESOLVE_DEBUG > 2
514 std::cout
515 << " doubleton row " << tgtrow << ", keep x(" << tgtcolx
516 << ") elim x(" << tgtcoly << ")." << std::endl;
517 #endif
518 PRESOLVE_DETAIL_PRINT(printf("pre_doubleton %dC %dC %dR E\n",
519 tgtcoly, tgtcolx, tgtrow));
520 /*
521 Capture the existing columns and other information before we start to modify
522 the constraint system. Save the shorter column.
523 */
524 action *s = &actions[nactions];
525 nactions++;
526 s->row = tgtrow;
527 s->icolx = tgtcolx;
528 s->clox = clo[tgtcolx];
529 s->cupx = cup[tgtcolx];
530 s->costx = cost[tgtcolx];
531 s->icoly = tgtcoly;
532 s->costy = cost[tgtcoly];
533 s->rlo = rlo[tgtrow];
534 s->coeffx = coeffx;
535 s->coeffy = coeffy;
536 s->ncolx = colLengths[tgtcolx];
537 s->ncoly = colLengths[tgtcoly];
538 if (s->ncoly < s->ncolx) {
539 s->colel = presolve_dupmajor(colCoeffs, rowIndices, colLengths[tgtcoly],
540 colStarts[tgtcoly], tgtrow);
541 s->ncolx = 0;
542 } else {
543 s->colel = presolve_dupmajor(colCoeffs, rowIndices, colLengths[tgtcolx],
544 colStarts[tgtcolx], tgtrow);
545 s->ncoly = 0;
546 }
547 /*
548 Move finite bound information from y to x, so that y is implied free.
549 a x + b y = c
550 l1 <= x <= u1
551 l2 <= y <= u2
552
553 l2 <= (c - a x) / b <= u2
554 b/-a > 0 ==> (b l2 - c) / -a <= x <= (b u2 - c) / -a
555 b/-a < 0 ==> (b u2 - c) / -a <= x <= (b l2 - c) / -a
556 */
557 {
558 double lo1 = -PRESOLVE_INF;
559 double up1 = PRESOLVE_INF;
560
561 if (-PRESOLVE_INF < clo[tgtcoly]) {
562 if (coeffx * coeffy < 0)
563 lo1 = (coeffy * clo[tgtcoly] - rhs) / -coeffx;
564 else
565 up1 = (coeffy * clo[tgtcoly] - rhs) / -coeffx;
566 }
567
568 if (cup[tgtcoly] < PRESOLVE_INF) {
569 if (coeffx * coeffy < 0)
570 up1 = (coeffy * cup[tgtcoly] - rhs) / -coeffx;
571 else
572 lo1 = (coeffy * cup[tgtcoly] - rhs) / -coeffx;
573 }
574 /*
575 Don't forget the objective coefficient.
576 costy y = costy ((c - a x) / b) = (costy c)/b + x (costy -a)/b
577 */
578 cost[tgtcolx] += (cost[tgtcoly] * -coeffx) / coeffy;
579 prob->change_bias((cost[tgtcoly] * rhs) / coeffy);
580 /*
581 The transfer of bounds could make x infeasible. Patch it up if the problem
582 is minor or if the user was so incautious as to instruct us to ignore it.
583 Prefer an integer value if there's one nearby. If there's nothing to be
584 done, break out of the main loop.
585 */
586 {
587 double lo2 = CoinMax(clo[tgtcolx], lo1);
588 double up2 = CoinMin(cup[tgtcolx], up1);
589 if (lo2 > up2) {
590 if (lo2 <= up2 + prob->feasibilityTolerance_ || fixInfeasibility) {
591 double nearest = floor(lo2 + 0.5);
592 if (fabs(nearest - lo2) < 2.0 * prob->feasibilityTolerance_) {
593 lo2 = nearest;
594 up2 = nearest;
595 } else {
596 lo2 = up2;
597 }
598 } else {
599 prob->status_ |= 1;
600 prob->messageHandler()->message(COIN_PRESOLVE_COLINFEAS,
601 prob->messages())
602 << tgtcolx << lo2 << up2 << CoinMessageEol;
603 break;
604 }
605 }
606 #if PRESOLVE_DEBUG > 2
607 std::cout
608 << " x(" << tgtcolx << ") lb " << clo[tgtcolx] << " --> " << lo2
609 << ", ub " << cup[tgtcolx] << " --> " << up2 << std::endl;
610 #endif
611 if (integerType[tgtcolx]) {
612 lo2 = ceil(lo2 - 1.0e-7);
613 up2 = floor(up2 + 1.0e-7);
614 }
615 clo[tgtcolx] = lo2;
616 cup[tgtcolx] = up2;
617 /*
618 Do we have a solution to maintain? If so, take a stab at it. If x ends up at
619 bound, prefer to set it nonbasic, but if we're short of basic variables
620 after eliminating y and the logical for the row, make it basic.
621
622 This code will snap the value of x to bound if it's within the primal
623 feasibility tolerance.
624 */
625 if (rowstat && sol) {
626 int numberBasic = 0;
627 double movement = 0;
628 if (prob->columnIsBasic(tgtcolx))
629 numberBasic++;
630 if (prob->columnIsBasic(tgtcoly))
631 numberBasic++;
632 if (prob->rowIsBasic(tgtrow))
633 numberBasic++;
634 if (sol[tgtcolx] <= lo2 + ztolzb) {
635 movement = lo2 - sol[tgtcolx];
636 sol[tgtcolx] = lo2;
637 prob->setColumnStatus(tgtcolx,
638 CoinPrePostsolveMatrix::atLowerBound);
639 } else if (sol[tgtcolx] >= up2 - ztolzb) {
640 movement = up2 - sol[tgtcolx];
641 sol[tgtcolx] = up2;
642 prob->setColumnStatus(tgtcolx,
643 CoinPrePostsolveMatrix::atUpperBound);
644 }
645 if (numberBasic > 1)
646 prob->setColumnStatus(tgtcolx, CoinPrePostsolveMatrix::basic);
647 /*
648 We need to compensate if x was forced to move. Beyond that, even if x
649 didn't move, we've forced y = (c-ax)/b, and that might not have been
650 true before. So even if x didn't move, y may have moved. Note that the
651 constant term c/b is subtracted out as the constraints are modified,
652 so we don't include it when calculating movement for y.
653 */
654 if (movement) {
655 const CoinBigIndex kkcsx = colStarts[tgtcolx];
656 const CoinBigIndex kkcex = kkcsx + colLengths[tgtcolx];
657 for (CoinBigIndex kcol = kkcsx; kcol < kkcex; kcol++) {
658 int row = rowIndices[kcol];
659 if (rowLengths[row])
660 acts[row] += movement * colCoeffs[kcol];
661 }
662 }
663 movement = ((-coeffx * sol[tgtcolx]) / coeffy) - sol[tgtcoly];
664 if (movement) {
665 const CoinBigIndex kkcsy = colStarts[tgtcoly];
666 const CoinBigIndex kkcey = kkcsy + colLengths[tgtcoly];
667 for (CoinBigIndex kcol = kkcsy; kcol < kkcey; kcol++) {
668 int row = rowIndices[kcol];
669 if (rowLengths[row])
670 acts[row] += movement * colCoeffs[kcol];
671 }
672 }
673 }
674 if (lo2 == up2)
675 fixed[nfixed++] = tgtcolx;
676 }
677 }
678 /*
679 We're done transferring bounds from y to x, and we've patched up the
680 solution if one existed to patch. One last thing to do before we eliminate
681 column y and the doubleton row: put column x and the entangled rows on
682 the lists of columns and rows to look at in the next round of transforms.
683 */
684 {
685 prob->addCol(tgtcolx);
686 const CoinBigIndex kkcsy = colStarts[tgtcoly];
687 const CoinBigIndex kkcey = kkcsy + colLengths[tgtcoly];
688 for (CoinBigIndex kcol = kkcsy; kcol < kkcey; kcol++) {
689 int row = rowIndices[kcol];
690 prob->addRow(row);
691 }
692 const CoinBigIndex kkcsx = colStarts[tgtcolx];
693 const CoinBigIndex kkcex = kkcsx + colLengths[tgtcolx];
694 for (CoinBigIndex kcol = kkcsx; kcol < kkcex; kcol++) {
695 int row = rowIndices[kcol];
696 prob->addRow(row);
697 }
698 }
699
700 /*
701 Empty tgtrow in the column-major matrix. Deleting the coefficient for
702 (tgtrow,tgtcoly) is a bit costly (given that we're about to drop the whole
703 column), but saves the trouble of checking for it in elim_doubleton.
704 */
705 presolve_delete_from_col(tgtrow, tgtcolx,
706 colStarts, colLengths, rowIndices, colCoeffs);
707 presolve_delete_from_col(tgtrow, tgtcoly,
708 colStarts, colLengths, rowIndices, colCoeffs);
709 /*
710 Drop tgtrow in the row-major representation: set the length to 0
711 and reclaim the major vector space in bulk storage.
712 */
713 rowLengths[tgtrow] = 0;
714 PRESOLVE_REMOVE_LINK(rlink, tgtrow);
715
716 /*
717 Transfer the colx factors to coly. This modifies coefficients in column x
718 as it removes coefficients in column y.
719 */
720 bool no_mem = elim_doubleton("ELIMD",
721 colStarts, rlo, rup, colCoeffs,
722 rowIndices, colIndices, rowLengths, colLengths,
723 clink, n,
724 rowStarts, rowCoeffs,
725 -coeffx / coeffy,
726 rhs / coeffy,
727 tgtrow, tgtcolx, tgtcoly);
728 if (no_mem)
729 throwCoinError("out of memory", "doubleton_action::presolve");
730
731 /*
732 Eliminate coly entirely from the col rep. We'll want to groom colx to remove
733 explicit zeros.
734 */
735 colLengths[tgtcoly] = 0;
736 PRESOLVE_REMOVE_LINK(clink, tgtcoly);
737 cost[tgtcoly] = 0.0;
738
739 rlo[tgtrow] = 0.0;
740 rup[tgtrow] = 0.0;
741
742 zeros[nzeros++] = tgtcolx;
743
744 #if PRESOLVE_CONSISTENCY > 0
745 presolve_consistent(prob);
746 presolve_links_ok(prob);
747 #endif
748 }
749 /*
750 Tidy up the collected actions and clean up explicit zeros and fixed
751 variables. Don't bother unless we're feasible (status of 0).
752 */
753 if (nactions && !prob->status_) {
754 #if PRESOLVE_SUMMARY > 0
755 printf("NDOUBLETONS: %d\n", nactions);
756 #endif
757 action *actions1 = new action[nactions];
758 CoinMemcpyN(actions, nactions, actions1);
759
760 next = new doubleton_action(nactions, actions1, next);
761
762 if (nzeros)
763 next = drop_zero_coefficients_action::presolve(prob, zeros, nzeros, next);
764 if (nfixed)
765 next = remove_fixed_action::presolve(prob, fixed, nfixed, next);
766 }
767
768 deleteAction(actions, action *);
769
770 #if COIN_PRESOLVE_TUNING > 0
771 double thisTime = 0.0;
772 if (prob->tuning_)
773 thisTime = CoinCpuTime();
774 #endif
775 #if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
776 presolve_check_sol(prob);
777 #endif
778 #if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
779 int droppedRows = prob->countEmptyRows() - startEmptyRows;
780 int droppedColumns = prob->countEmptyCols() - startEmptyColumns;
781 std::cout
782 << "Leaving doubleton_action::presolve, " << droppedRows << " rows, "
783 << droppedColumns << " columns dropped";
784 #if COIN_PRESOLVE_TUNING > 0
785 std::cout << " in " << thisTime - startTime << "s";
786 #endif
787 std::cout << "." << std::endl;
788 #endif
789
790 return (next);
791 }
792
793 /*
794 Reintroduce the column (y) and doubleton row (irow) removed in presolve.
795 Correct the other column (x) involved in the doubleton, update the solution,
796 etc.
797
798 A fair amount of complication arises because the presolve transform saves the
799 shorter of x or y. Postsolve thus includes portions to restore either.
800 */
postsolve(CoinPostsolveMatrix * prob) const801 void doubleton_action::postsolve(CoinPostsolveMatrix *prob) const
802 {
803 const action *const actions = actions_;
804 const int nactions = nactions_;
805
806 double *colels = prob->colels_;
807 int *hrow = prob->hrow_;
808 CoinBigIndex *mcstrt = prob->mcstrt_;
809 int *hincol = prob->hincol_;
810 CoinBigIndex *link = prob->link_;
811
812 double *clo = prob->clo_;
813 double *cup = prob->cup_;
814
815 double *rlo = prob->rlo_;
816 double *rup = prob->rup_;
817
818 double *dcost = prob->cost_;
819
820 double *sol = prob->sol_;
821 double *acts = prob->acts_;
822 double *rowduals = prob->rowduals_;
823 double *rcosts = prob->rcosts_;
824
825 unsigned char *colstat = prob->colstat_;
826 unsigned char *rowstat = prob->rowstat_;
827
828 const double maxmin = prob->maxmin_;
829
830 CoinBigIndex &free_list = prob->free_list_;
831
832 const double ztolzb = prob->ztolzb_;
833 const double ztoldj = prob->ztoldj_;
834 const double ztolzero = 1.0e-12;
835
836 int nrows = prob->nrows_;
837
838 // Arrays to rebuild the unsaved column.
839 int *index1 = new int[nrows];
840 double *element1 = new double[nrows];
841 CoinZeroN(element1, nrows);
842
843 #if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
844 char *cdone = prob->cdone_;
845 char *rdone = prob->rdone_;
846
847 presolve_check_threads(prob);
848 presolve_check_sol(prob, 2, 2, 2);
849 presolve_check_nbasic(prob);
850 presolve_check_reduced_costs(prob);
851
852 #if PRESOLVE_DEBUG > 0
853 std::cout
854 << "Entering doubleton_action::postsolve, " << nactions
855 << " transforms to undo." << std::endl;
856 #endif
857 #endif
858 /*
859 The outer loop: step through the doubletons in this array of actions.
860 The first activity is to unpack the doubleton.
861 */
862 for (const action *f = &actions[nactions - 1]; actions <= f; f--) {
863
864 const int irow = f->row;
865 const double lo0 = f->clox;
866 const double up0 = f->cupx;
867
868 const double coeffx = f->coeffx;
869 const double coeffy = f->coeffy;
870 const int jcolx = f->icolx;
871 const int jcoly = f->icoly;
872
873 const double rhs = f->rlo;
874
875 #if PRESOLVE_DEBUG > 2
876 std::cout
877 << std::endl
878 << " restoring doubleton " << irow << ", elim x(" << jcoly
879 << "), kept x(" << jcolx << "); stored col ";
880 if (f->ncoly)
881 std::cout << jcoly;
882 else
883 std::cout << jcolx;
884 std::cout << "." << std::endl;
885 std::cout
886 << " x(" << jcolx << ") " << prob->columnStatusString(jcolx) << " "
887 << clo[jcolx] << " <= " << sol[jcolx] << " <= " << cup[jcolx]
888 << "; cj " << f->costx << " dj " << rcosts[jcolx] << "." << std::endl;
889 #endif
890 /*
891 jcolx is in the problem (for whatever reason), and the doubleton row (irow)
892 and column (jcoly) have only been processed by empty row/column postsolve
893 (i.e., reintroduced with length 0).
894 */
895 PRESOLVEASSERT(cdone[jcolx] && rdone[irow] == DROP_ROW);
896 PRESOLVEASSERT(cdone[jcoly] == DROP_COL);
897
898 /*
899 Restore bounds for doubleton row, bounds and objective coefficient for x,
900 objective for y.
901
902 Original comment: restoration of rlo and rup likely isn't necessary.
903 */
904 rlo[irow] = f->rlo;
905 rup[irow] = f->rlo;
906
907 clo[jcolx] = lo0;
908 cup[jcolx] = up0;
909
910 dcost[jcolx] = f->costx;
911 dcost[jcoly] = f->costy;
912
913 /*
914 Set primal solution for y (including status) and row activity for the
915 doubleton row. The motivation (up in presolve) for wanting coeffx < coeffy
916 is to avoid inflation into sol[y]. Since this is a (satisfied) equality,
917 activity is the rhs value and the logical is nonbasic.
918 */
919 const double diffy = rhs - coeffx * sol[jcolx];
920 if (fabs(diffy) < ztolzero)
921 sol[jcoly] = 0;
922 else
923 sol[jcoly] = diffy / coeffy;
924 acts[irow] = rhs;
925 if (rowstat)
926 prob->setRowStatus(irow, CoinPrePostsolveMatrix::atLowerBound);
927
928 #if PRESOLVE_DEBUG > 2
929 /*
930 Original comment: I've forgotten what this is about
931
932 We have sol[y] = (rhs - coeffx*sol[x])/coeffy. As best I can figure,
933 the original check here tested for the possibility of loss of significant
934 digits through cancellation, followed by inflation if coeffy is small.
935 The hazard is clear enough, but the test was puzzling. Overly complicated
936 and it generated false warnings for the common case of sol[y] a clean zero.
937 Replaced with something that I hope is more useful. The tolerances are, sad
938 to say, completely arbitrary. -- lh, 121106 --
939 */
940 if ((fabs(diffy) < 1.0e-6) && (fabs(diffy) >= ztolzero) && (fabs(coeffy) < 1.0e-3))
941 std::cout
942 << " loss of significance? rhs " << rhs
943 << " (coeffx*sol[jcolx])" << (coeffx * sol[jcolx])
944 << " diff " << diffy << "." << std::endl;
945 #endif
946
947 /*
948 Time to get into the correction/restoration of coefficients for columns x
949 and y, with attendant correction of row bounds and activities. Accumulate
950 partial reduced costs (missing the contribution from the doubleton row) so
951 that we can eventually calculate a dual for the doubleton row.
952 */
953 double djy = maxmin * dcost[jcoly];
954 double djx = maxmin * dcost[jcolx];
955 /*
956 We saved column y in the action, so we'll use it to reconstruct column x.
957 There are two aspects: correction of existing x coefficients, and fill in.
958 Given
959 coeffx'[k] = coeffx[k]+coeffy[k]*coeff_factor
960 we have
961 coeffx[k] = coeffx'[k]-coeffy[k]*coeff_factor
962 where
963 coeff_factor = -coeffx[dblton]/coeffy[dblton].
964
965 Keep in mind that the major vector stored in the action does not include
966 the coefficient from the doubleton row --- the doubleton coefficients are
967 held in coeffx and coeffy.
968 */
969 if (f->ncoly) {
970 int ncoly = f->ncoly - 1;
971 int *indy = reinterpret_cast< int * >(f->colel + ncoly);
972 /*
973 Rebuild a threaded column y, starting with the end of the thread and working
974 back to the beginning. In the process, accumulate corrections to column x
975 in element1 and index1. Fix row bounds and activity as we go (add back the
976 constant correction removed in presolve), and accumulate contributions to
977 the reduced cost for y. Don't tweak finite infinity.
978
979 The PRESOLVEASSERT says this row should already be present.
980 */
981 CoinBigIndex ystart = NO_LINK;
982 int nX = 0;
983 for (int kcol = 0; kcol < ncoly; ++kcol) {
984 const int i = indy[kcol];
985 PRESOLVEASSERT(rdone[i]);
986
987 double yValue = f->colel[kcol];
988
989 if (-PRESOLVE_INF < rlo[i])
990 rlo[i] += (yValue * rhs) / coeffy;
991 if (rup[i] < PRESOLVE_INF)
992 rup[i] += (yValue * rhs) / coeffy;
993
994 acts[i] += (yValue * rhs) / coeffy;
995
996 djy -= rowduals[i] * yValue;
997 /*
998 Link the coefficient into column y: Acquire the first free slot in the
999 bulk arrays and store the row index and coefficient. Then link the slot
1000 in front of coefficients we've already processed.
1001 */
1002 const CoinBigIndex kfree = free_list;
1003 assert(kfree >= 0 && kfree < prob->bulk0_);
1004 free_list = link[free_list];
1005 hrow[kfree] = i;
1006 colels[kfree] = yValue;
1007 link[kfree] = ystart;
1008 ystart = kfree;
1009
1010 #if PRESOLVE_DEBUG > 4
1011 std::cout
1012 << " link y " << kfree << " row " << i << " coeff " << yValue
1013 << " dual " << rowduals[i] << std::endl;
1014 #endif
1015 /*
1016 Calculate and store the correction to the x coefficient.
1017 */
1018 yValue = (yValue * coeffx) / coeffy;
1019 element1[i] = yValue;
1020 index1[nX++] = i;
1021 }
1022 #if PRESOLVE_CONSISTENCY > 0
1023 presolve_check_free_list(prob);
1024 #endif
1025 /*
1026 Handle the coefficients of the doubleton row. Insert coeffy, coeffx.
1027 */
1028 const CoinBigIndex kfree = free_list;
1029 assert(kfree >= 0 && kfree < prob->bulk0_);
1030 free_list = link[free_list];
1031 hrow[kfree] = irow;
1032 colels[kfree] = coeffy;
1033 link[kfree] = ystart;
1034 ystart = kfree;
1035
1036 #if PRESOLVE_DEBUG > 4
1037 std::cout
1038 << " link y " << kfree << " row " << irow << " coeff " << coeffy
1039 << " dual n/a" << std::endl;
1040 #endif
1041
1042 element1[irow] = coeffx;
1043 index1[nX++] = irow;
1044 /*
1045 Attach the threaded column y to mcstrt and record the length.
1046 */
1047 mcstrt[jcoly] = ystart;
1048 hincol[jcoly] = f->ncoly;
1049 /*
1050 Now integrate the corrections to column x. Scan the column and correct the
1051 existing entries. The correction could cancel the existing coefficient and
1052 we don't want to leave an explicit zero. In this case, relink the column
1053 around it. The freed slot is linked at the beginning of the free list.
1054 */
1055 CoinBigIndex kcs = mcstrt[jcolx];
1056 CoinBigIndex last_nonzero = NO_LINK;
1057 int numberInColumn = hincol[jcolx];
1058 const int numberToDo = numberInColumn;
1059 for (int kcol = 0; kcol < numberToDo; ++kcol) {
1060 const int i = hrow[kcs];
1061 assert(i >= 0 && i < nrows && i != irow);
1062 double value = colels[kcs] + element1[i];
1063 element1[i] = 0.0;
1064 if (fabs(value) >= 1.0e-15) {
1065 colels[kcs] = value;
1066 last_nonzero = kcs;
1067 kcs = link[kcs];
1068 djx -= rowduals[i] * value;
1069
1070 #if PRESOLVE_DEBUG > 4
1071 std::cout
1072 << " link x " << last_nonzero << " row " << i << " coeff "
1073 << value << " dual " << rowduals[i] << std::endl;
1074 #endif
1075
1076 } else {
1077
1078 #if PRESOLVE_DEBUG > 4
1079 std::cout
1080 << " link x skipped row " << i << " dual "
1081 << rowduals[i] << std::endl;
1082 #endif
1083
1084 numberInColumn--;
1085 // add to free list
1086 CoinBigIndex nextk = link[kcs];
1087 assert(free_list >= 0);
1088 link[kcs] = free_list;
1089 free_list = kcs;
1090 assert(kcs >= 0);
1091 kcs = nextk;
1092 if (last_nonzero != NO_LINK)
1093 link[last_nonzero] = kcs;
1094 else
1095 mcstrt[jcolx] = kcs;
1096 }
1097 }
1098 if (last_nonzero != NO_LINK)
1099 link[last_nonzero] = NO_LINK;
1100 /*
1101 We've dealt with the existing nonzeros in column x. Any remaining
1102 nonzeros in element1 will be fill in, which we insert at the beginning of
1103 the column.
1104 */
1105 for (int kcol = 0; kcol < nX; kcol++) {
1106 const int i = index1[kcol];
1107 double xValue = element1[i];
1108 element1[i] = 0.0;
1109 if (fabs(xValue) >= 1.0e-15) {
1110 if (i != irow)
1111 djx -= rowduals[i] * xValue;
1112 numberInColumn++;
1113 CoinBigIndex kfree = free_list;
1114 assert(kfree >= 0 && kfree < prob->bulk0_);
1115 free_list = link[free_list];
1116 hrow[kfree] = i;
1117 PRESOLVEASSERT(rdone[hrow[kfree]] || (hrow[kfree] == irow));
1118 colels[kfree] = xValue;
1119 link[kfree] = mcstrt[jcolx];
1120 mcstrt[jcolx] = kfree;
1121 #if PRESOLVE_DEBUG > 4
1122 std::cout
1123 << " link x " << kfree << " row " << i << " coeff " << xValue
1124 << " dual ";
1125 if (i != irow)
1126 std::cout << rowduals[i];
1127 else
1128 std::cout << "n/a";
1129 std::cout << std::endl;
1130 #endif
1131 }
1132 }
1133
1134 #if PRESOLVE_CONSISTENCY > 0
1135 presolve_check_free_list(prob);
1136 #endif
1137
1138 /*
1139 Whew! Set the column length and we're done.
1140 */
1141 assert(numberInColumn);
1142 hincol[jcolx] = numberInColumn;
1143 } else {
1144 /*
1145 Of course, we could have saved column x in the action. Now we need to
1146 regenerate coefficients of column y.
1147 Given
1148 coeffx'[k] = coeffx[k]+coeffy[k]*coeff_factor
1149 we have
1150 coeffy[k] = (coeffx'[k]-coeffx[k])*(1/coeff_factor)
1151 where
1152 coeff_factor = -coeffx[dblton]/coeffy[dblton].
1153 */
1154 const int ncolx = f->ncolx - 1;
1155 int *indx = reinterpret_cast< int * >(f->colel + ncolx);
1156 /*
1157 Scan existing column x to find the end. While we're at it, accumulate part
1158 of the new y coefficients in index1 and element1.
1159 */
1160 CoinBigIndex kcs = mcstrt[jcolx];
1161 int nX = 0;
1162 for (int kcol = 0; kcol < hincol[jcolx] - 1; ++kcol) {
1163 if (colels[kcs]) {
1164 const int i = hrow[kcs];
1165 index1[nX++] = i;
1166 element1[i] = -(colels[kcs] * coeffy) / coeffx;
1167 }
1168 kcs = link[kcs];
1169 }
1170 if (colels[kcs]) {
1171 const int i = hrow[kcs];
1172 index1[nX++] = i;
1173 element1[i] = -(colels[kcs] * coeffy) / coeffx;
1174 }
1175 /*
1176 Replace column x with the the original column x held in the doubleton action
1177 (recall that this column does not include coeffx). We first move column
1178 x to the free list, then thread a column with the original coefficients,
1179 back to front. While we're at it, add the second part of the y coefficients
1180 to index1 and element1.
1181 */
1182 link[kcs] = free_list;
1183 free_list = mcstrt[jcolx];
1184 CoinBigIndex xstart = NO_LINK;
1185 for (int kcol = 0; kcol < ncolx; ++kcol) {
1186 const int i = indx[kcol];
1187 PRESOLVEASSERT(rdone[i] && i != irow);
1188
1189 double xValue = f->colel[kcol];
1190 CoinBigIndex k = free_list;
1191 assert(k >= 0 && k < prob->bulk0_);
1192 free_list = link[free_list];
1193 hrow[k] = i;
1194 colels[k] = xValue;
1195 link[k] = xstart;
1196 xstart = k;
1197
1198 djx -= rowduals[i] * xValue;
1199
1200 xValue = (xValue * coeffy) / coeffx;
1201 if (!element1[i]) {
1202 element1[i] = xValue;
1203 index1[nX++] = i;
1204 } else {
1205 element1[i] += xValue;
1206 }
1207 }
1208 #if PRESOLVE_CONSISTENCY > 0
1209 presolve_check_free_list(prob);
1210 #endif
1211 /*
1212 The same, for the doubleton row.
1213 */
1214 {
1215 double xValue = coeffx;
1216 CoinBigIndex k = free_list;
1217 assert(k >= 0 && k < prob->bulk0_);
1218 free_list = link[free_list];
1219 hrow[k] = irow;
1220 colels[k] = xValue;
1221 link[k] = xstart;
1222 xstart = k;
1223 element1[irow] = coeffy;
1224 index1[nX++] = irow;
1225 }
1226 /*
1227 Link the new column x to mcstrt and set the length.
1228 */
1229 mcstrt[jcolx] = xstart;
1230 hincol[jcolx] = f->ncolx;
1231 /*
1232 Now get to work building a threaded column y from the nonzeros in element1.
1233 As before, build the thread in reverse.
1234 */
1235 CoinBigIndex ystart = NO_LINK;
1236 int leny = 0;
1237 for (int kcol = 0; kcol < nX; kcol++) {
1238 const int i = index1[kcol];
1239 PRESOLVEASSERT(rdone[i] || i == irow);
1240 double yValue = element1[i];
1241 element1[i] = 0.0;
1242 if (fabs(yValue) >= ztolzero) {
1243 leny++;
1244 CoinBigIndex k = free_list;
1245 assert(k >= 0 && k < prob->bulk0_);
1246 free_list = link[free_list];
1247 hrow[k] = i;
1248 colels[k] = yValue;
1249 link[k] = ystart;
1250 ystart = k;
1251 }
1252 }
1253 #if PRESOLVE_CONSISTENCY > 0
1254 presolve_check_free_list(prob);
1255 #endif
1256 /*
1257 Tidy up --- link the new column into mcstrt and set the length.
1258 */
1259 mcstrt[jcoly] = ystart;
1260 assert(leny);
1261 hincol[jcoly] = leny;
1262 /*
1263 Now that we have the original y, we can scan it and do the corrections to
1264 the row bounds and activity, and get a start on a reduced cost for y.
1265 */
1266 kcs = mcstrt[jcoly];
1267 const int ny = hincol[jcoly];
1268 for (int kcol = 0; kcol < ny; ++kcol) {
1269 const int row = hrow[kcs];
1270 const double coeff = colels[kcs];
1271 kcs = link[kcs];
1272
1273 if (row != irow) {
1274
1275 // undo elim_doubleton(1)
1276 if (-PRESOLVE_INF < rlo[row])
1277 rlo[row] += (coeff * rhs) / coeffy;
1278
1279 // undo elim_doubleton(2)
1280 if (rup[row] < PRESOLVE_INF)
1281 rup[row] += (coeff * rhs) / coeffy;
1282
1283 acts[row] += (coeff * rhs) / coeffy;
1284
1285 djy -= rowduals[row] * coeff;
1286 }
1287 }
1288 }
1289 #if PRESOLVE_DEBUG > 2
1290 /*
1291 Sanity checks. The doubleton coefficients should be linked in the first
1292 position of the each column (for no good reason except that it makes it much
1293 easier to write these checks).
1294 */
1295 #if PRESOLVE_DEBUG > 4
1296 std::cout
1297 << " kept: saved " << jcolx << " " << coeffx << ", reconstructed "
1298 << hrow[mcstrt[jcolx]] << " " << colels[mcstrt[jcolx]]
1299 << "." << std::endl;
1300 std::cout
1301 << " elim: saved " << jcoly << " " << coeffy << ", reconstructed "
1302 << hrow[mcstrt[jcoly]] << " " << colels[mcstrt[jcoly]]
1303 << "." << std::endl;
1304 #endif
1305 assert((coeffx == colels[mcstrt[jcolx]]) && (coeffy == colels[mcstrt[jcoly]]));
1306 #endif
1307 /*
1308 Time to calculate a dual for the doubleton row, and settle the status of x
1309 and y. Ideally, we'll leave x at whatever nonbasic status it currently has
1310 and make y basic. There's a potential problem, however: Remember that we
1311 transferred bounds from y to x when we eliminated y. If those bounds were
1312 tighter than x's original bounds, we may not be able to maintain x at its
1313 present status, or even as nonbasic.
1314
1315 We'll make two claims here:
1316
1317 * If the dual value for the doubleton row is chosen to keep the reduced
1318 cost djx of col x at its prior value, then the reduced cost djy of col
1319 y will be 0. (Crank through the linear algebra to convince yourself.)
1320
1321 * If the bounds on x have loosened, then it must be possible to make y
1322 nonbasic, because we've transferred the tight bound back to y. (Yeah,
1323 I'm waving my hands. But it sounds good. -- lh, 040907 --)
1324
1325 So ... if we can maintain x nonbasic, then we need to set y basic, which
1326 means we should calculate rowduals[dblton] so that rcost[jcoly] == 0. We
1327 may need to change the status of x (an artifact of loosening a bound when
1328 x was previously a fixed variable).
1329
1330 If we need to push x into the basis, then we calculate rowduals[dblton] so
1331 that rcost[jcolx] == 0 and make y nonbasic.
1332 */
1333 #if PRESOLVE_DEBUG > 2
1334 std::cout
1335 << " pre status: x(" << jcolx << ") " << prob->columnStatusString(jcolx)
1336 << " " << clo[jcolx] << " <= " << sol[jcolx] << " <= " << cup[jcolx]
1337 << ", cj " << dcost[jcolx]
1338 << ", dj " << djx << "." << std::endl;
1339 std::cout
1340 << " pre status: x(" << jcoly << ") "
1341 << clo[jcoly] << " <= " << sol[jcoly] << " <= " << cup[jcoly]
1342 << ", cj " << dcost[jcoly]
1343 << ", dj " << djy << "." << std::endl;
1344 #endif
1345 if (colstat) {
1346 bool basicx = prob->columnIsBasic(jcolx);
1347 bool nblbxok = (fabs(lo0 - sol[jcolx]) < ztolzb) && (rcosts[jcolx] >= -ztoldj);
1348 bool nbubxok = (fabs(up0 - sol[jcolx]) < ztolzb) && (rcosts[jcolx] <= ztoldj);
1349 if (basicx || nblbxok || nbubxok) {
1350 if (!basicx) {
1351 if (nblbxok) {
1352 prob->setColumnStatus(jcolx,
1353 CoinPrePostsolveMatrix::atLowerBound);
1354 } else if (nbubxok) {
1355 prob->setColumnStatus(jcolx,
1356 CoinPrePostsolveMatrix::atUpperBound);
1357 }
1358 }
1359 prob->setColumnStatus(jcoly, CoinPrePostsolveMatrix::basic);
1360 rowduals[irow] = djy / coeffy;
1361 rcosts[jcolx] = djx - rowduals[irow] * coeffx;
1362 rcosts[jcoly] = 0.0;
1363 } else {
1364 prob->setColumnStatus(jcolx, CoinPrePostsolveMatrix::basic);
1365 prob->setColumnStatusUsingValue(jcoly);
1366 rowduals[irow] = djx / coeffx;
1367 rcosts[jcoly] = djy - rowduals[irow] * coeffy;
1368 rcosts[jcolx] = 0.0;
1369 }
1370 #if PRESOLVE_DEBUG > 2
1371 std::cout
1372 << " post status: " << irow << " dual " << rowduals[irow]
1373 << " rhs " << rlo[irow]
1374 << std::endl;
1375 std::cout
1376 << " post status: x(" << jcolx << ") "
1377 << prob->columnStatusString(jcolx) << " "
1378 << clo[jcolx] << " <= " << sol[jcolx] << " <= " << cup[jcolx]
1379 << ", cj " << dcost[jcolx]
1380 << ", dj = " << rcosts[jcolx] << "." << std::endl;
1381 std::cout
1382 << " post status: x(" << jcoly << ") "
1383 << prob->columnStatusString(jcoly) << " "
1384 << clo[jcoly] << " <= " << sol[jcoly] << " <= " << cup[jcoly]
1385 << ", cj " << dcost[jcoly]
1386 << ", dj " << rcosts[jcoly] << "." << std::endl;
1387 /*
1388 These asserts are valid but need a scaled tolerance to work well over
1389 a range of problems. Occasionally useful for a hard stop while debugging.
1390
1391 assert(!prob->columnIsBasic(jcolx) || (fabs(rcosts[jcolx]) < 1.0e-5)) ;
1392 assert(!prob->columnIsBasic(jcoly) || (fabs(rcosts[jcoly]) < 1.0e-5)) ;
1393 */
1394 #endif
1395 } else {
1396 // No status array
1397 // this is the coefficient we need to force col y's reduced cost to 0.0 ;
1398 // for example, this is obviously true if y is a singleton column
1399 rowduals[irow] = djy / coeffy;
1400 rcosts[jcoly] = 0.0;
1401 }
1402
1403 #if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
1404 /*
1405 Mark the column and row as processed by doubleton action. Then check
1406 integrity of the threaded matrix.
1407 */
1408 cdone[jcoly] = DOUBLETON;
1409 rdone[irow] = DOUBLETON;
1410 presolve_check_threads(prob);
1411 #endif
1412 #if PRESOLVE_DEBUG > 0
1413 /*
1414 Confirm accuracy of reduced cost for columns x and y.
1415 */
1416 {
1417 CoinBigIndex k = mcstrt[jcolx];
1418 const int nx = hincol[jcolx];
1419 double dj = maxmin * dcost[jcolx];
1420
1421 for (int kcol = 0; kcol < nx; ++kcol) {
1422 const int row = hrow[k];
1423 const double coeff = colels[k];
1424 k = link[k];
1425 dj -= rowduals[row] * coeff;
1426 }
1427 if (!(fabs(rcosts[jcolx] - dj) < 100 * ZTOLDP))
1428 printf("BAD DOUBLE X DJ: %d %d %g %g\n",
1429 irow, jcolx, rcosts[jcolx], dj);
1430 rcosts[jcolx] = dj;
1431 }
1432 {
1433 CoinBigIndex k = mcstrt[jcoly];
1434 const int ny = hincol[jcoly];
1435 double dj = maxmin * dcost[jcoly];
1436
1437 for (int kcol = 0; kcol < ny; ++kcol) {
1438 const int row = hrow[k];
1439 const double coeff = colels[k];
1440 k = link[k];
1441 dj -= rowduals[row] * coeff;
1442 }
1443 if (!(fabs(rcosts[jcoly] - dj) < 100 * ZTOLDP))
1444 printf("BAD DOUBLE Y DJ: %d %d %g %g\n",
1445 irow, jcoly, rcosts[jcoly], dj);
1446 rcosts[jcoly] = dj;
1447 }
1448 #endif
1449 }
1450 /*
1451 Done at last. Delete the scratch arrays.
1452 */
1453 delete[] index1;
1454 delete[] element1;
1455
1456 #if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
1457 presolve_check_sol(prob, 2, 2, 2);
1458 presolve_check_nbasic(prob);
1459 presolve_check_reduced_costs(prob);
1460 #if PRESOLVE_DEBUG > 0
1461 std::cout << "Leaving doubleton_action::postsolve." << std::endl;
1462 #endif
1463 #endif
1464 }
1465
~doubleton_action()1466 doubleton_action::~doubleton_action()
1467 {
1468 for (int i = nactions_ - 1; i >= 0; i--) {
1469 delete[] actions_[i].colel;
1470 }
1471 deleteAction(actions_, action *);
1472 }
1473
1474 /* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2
1475 */
1476