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