1 /* $Id: CoinPresolveSubst.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 "CoinPresolveMatrix.hpp"
10 #include "CoinPresolveEmpty.hpp" // for DROP_COL/DROP_ROW
11 #include "CoinPresolvePsdebug.hpp"
12 #include "CoinPresolveFixed.hpp"
13 #include "CoinPresolveZeros.hpp"
14 #include "CoinPresolveSubst.hpp"
15 #include "CoinMessage.hpp"
16 #include "CoinHelperFunctions.hpp"
17 #include "CoinSort.hpp"
18 #include "CoinError.hpp"
19 #include "CoinFinite.hpp"
20 
21 #if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
22 #include "CoinPresolvePsdebug.hpp"
23 #endif
24 
25 namespace { // begin unnamed file-local namespace
26 
27 #if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
28 /*
29   Special-purpose debug utility to look for coefficient a(i,j) in column j.
30   Intended to be inserted as needed and removed when debugging is complete.
31 */
dbg_find_elem(const CoinPostsolveMatrix * postMtx,int i,int j)32 void dbg_find_elem(const CoinPostsolveMatrix *postMtx, int i, int j)
33 {
34   const CoinBigIndex kcs = postMtx->mcstrt_[j];
35   const CoinBigIndex lenj = postMtx->hincol_[j];
36   CoinBigIndex krow = presolve_find_row3(i, kcs, lenj, postMtx->hrow_, postMtx->link_);
37   if (krow >= 0) {
38     std::cout
39       << "  row " << i << " present in column " << j
40       << ", a(" << i << "," << j
41       << ") = " << postMtx->colels_[krow] << std::endl;
42   } else {
43     std::cout
44       << "  row " << i << " not present in column " << j << std::endl;
45   }
46 }
47 #endif
48 
49 /*
50   Add coeff_factor*rowy to rowx, for coefficients and row bounds. In the
51   terminology used in ::presolve, rowy is the target row, and rowx is an
52   entangled row (entangled with the target column).
53 
54   If a coefficient is < kill_ratio * coeff_factor then kill it
55 
56   Column indices in irowx and iroy must be sorted in increasing order.
57   Normally one might do that here, but this routine is only called from
58   subst_constraint_action::presolve and rowy will be the same over several
59   calls. More efficient to sort in sca::presolve.
60 
61   Given we're called from sca::presolve, rowx will be an equality, with
62   finite rlo[rowx] = rup[rowx] = rhsy.
63 
64   Fill-in in rowx has the potential to trigger compaction of the row-major
65   bulk store. *All* indices into the bulk store are *not* constant if this
66   happens.
67 
68   Returns false if the addition completes without error, true if there's a
69   problem.
70 */
71 static bool
add_row(CoinBigIndex * mrstrt,double * rlo,double * acts,double * rup,double * rowels,int * hcol,int * hinrow,presolvehlink * rlink,int nrows,double coeff_factor,double kill_ratio,int irowx,int irowy,int * x_to_y)72 add_row(CoinBigIndex *mrstrt, double *rlo, double *acts, double *rup,
73   double *rowels, int *hcol, int *hinrow, presolvehlink *rlink,
74   int nrows, double coeff_factor, double kill_ratio, int irowx, int irowy,
75   int *x_to_y)
76 {
77   CoinBigIndex krsy = mrstrt[irowy];
78   CoinBigIndex krey = krsy + hinrow[irowy];
79   CoinBigIndex krsx = mrstrt[irowx];
80   CoinBigIndex krex = krsx + hinrow[irowx];
81 
82 #if PRESOLVE_DEBUG > 3
83   std::cout
84     << "  ADD_ROW: adding (" << coeff_factor << ")*(row " << irowy
85     << ") to row " << irowx << "; len y = " << hinrow[irowy]
86     << ", len x = " << hinrow[irowx] << "." << std::endl;
87 #endif
88 
89   /*
90   Do the simple part first: adjust the row lower and upper bounds, but only if
91   they're finite.
92 */
93   const double rhsy = rlo[irowy];
94   const double rhscorr = rhsy * coeff_factor;
95   const double tolerance = kill_ratio * coeff_factor;
96 
97   if (-PRESOLVE_INF < rlo[irowx]) {
98     const double newrlo = rlo[irowx] + rhscorr;
99 #if PRESOLVE_DEBUG > 3
100     if (rhscorr)
101       std::cout
102         << "  rlo(" << irowx << ") " << rlo[irowx] << " -> "
103         << newrlo << "." << std::endl;
104 #endif
105     rlo[irowx] = newrlo;
106   }
107   if (rup[irowx] < PRESOLVE_INF) {
108     const double newrup = rup[irowx] + rhscorr;
109 #if PRESOLVE_DEBUG > 3
110     if (rhscorr)
111       std::cout
112         << "  rup(" << irowx << ") " << rup[irowx] << " -> "
113         << newrup << "." << std::endl;
114 #endif
115     rup[irowx] = newrup;
116   }
117   if (acts) {
118     acts[irowx] += rhscorr;
119   }
120   /*
121   On to the main show. Open a loop to walk row y.  krowx is keeping track
122   of where we're at in row x.  To find column j in row x, start from the
123   current position and search forward, but no further than the last original
124   coefficient of row x (fill will be added after this element).
125 */
126   CoinBigIndex krowx = krsx;
127   CoinBigIndex krex0 = krex;
128   int x_to_y_i = 0;
129 
130 #if PRESOLVE_DEBUG > 3
131   std::cout << "  ycols:";
132 #endif
133   for (CoinBigIndex krowy = krsy; krowy < krey; krowy++) {
134     int j = hcol[krowy];
135 
136     PRESOLVEASSERT(krex == krsx + hinrow[irowx]);
137 
138     while (krowx < krex0 && hcol[krowx] < j)
139       krowx++;
140 
141 #if PRESOLVE_DEBUG > 3
142     std::cout << " a(" << irowx << "," << j << ") ";
143 #endif
144     /*
145   The easy case: coeff a(xj) already exists and all we need to is modify it.
146 */
147     if (krowx < krex0 && hcol[krowx] == j) {
148       double newcoeff = rowels[krowx] + rowels[krowy] * coeff_factor;
149 
150 #if PRESOLVE_DEBUG > 3
151       std::cout << rowels[krowx] << " -> " << newcoeff << ";";
152 #endif
153 
154       // kill small
155       if (fabs(newcoeff) < tolerance)
156         newcoeff = 0.0;
157       rowels[krowx] = newcoeff;
158       x_to_y[x_to_y_i++] = static_cast< int >(krowx - krsx);
159       krowx++;
160     } else {
161       /*
162   The hard case: a(xj) will be fill-in for row x. Make sure we have room. The
163   process of making room can trigger bulk store compaction which can move all
164   rows, so recalculate all pointers into the bulk store. Only then can we add
165   the new coefficient.
166 */
167       double newValue = rowels[krowy] * coeff_factor;
168       bool outOfSpace = presolve_expand_row(mrstrt, rowels, hcol,
169         hinrow, rlink, nrows, irowx);
170       if (outOfSpace)
171         return (true);
172 
173       krowy = mrstrt[irowy] + (krowy - krsy);
174       krsy = mrstrt[irowy];
175       krey = krsy + hinrow[irowy];
176 
177       krowx = mrstrt[irowx] + (krowx - krsx);
178       krex0 = mrstrt[irowx] + (krex0 - krsx);
179       krsx = mrstrt[irowx];
180       krex = krsx + hinrow[irowx];
181 
182       hcol[krex] = j;
183       rowels[krex] = newValue;
184       x_to_y[x_to_y_i++] = static_cast< int >(krex - krsx);
185       hinrow[irowx]++;
186       krex++;
187 
188 #if PRESOLVE_DEBUG > 3
189       std::cout << rowels[krex - 1] << ";";
190 #endif
191     }
192   }
193 
194 #if PRESOLVE_DEBUG > 3
195   std::cout << std::endl;
196 #endif
197   return (false);
198 }
199 
200 } // end unnamed file-local namespace
201 
name() const202 const char *subst_constraint_action::name() const
203 {
204   return ("subst_constraint_action");
205 }
206 
207 /*
208   This transform is called only from implied_free_action. See the comments at
209   the head of CoinPresolveImpledFree.cpp for background.
210 
211   In addition to natural implied free singletons, implied_free_action will
212   identify implied free variables that are not (yet) column singletons. This
213   transform will process them.
214 
215   Suppose we have a variable x(t) and an equality r which satisfy the implied
216   free condition (i.e., r imposes bounds on x(t) which are equal or better
217   than the original column bounds). Then we can solve r for x(t) to get a
218   substitution formula for x(t). We can use the substitution formula to
219   eliminate x(t) from all other constraints where it is entangled. x(t) is now
220   an implied free column singleton with equality r and we can remove x(t)
221   and equality r from the constraint system.
222 
223   The paired parameter vectors implied_free and whichFree specify the indices
224   for equality r and variable t, respectively. NOTE that these vectors are
225   held in the first two blocks of usefulColumnInt_. Don't reuse them!
226 
227   Fill-in can cause a major vector to be moved to free space at the end
228   of the bulk store. If there's not enough free space, this can trigger
229   compaction of the entire bulk store. The upshot is that *all* major vector
230   starts and ends are *not* constant over calls that could expand a major
231   vector. Deletion, on the other hand, will never move a major vector (but
232   it will move the end element into the hole left by the deleted element).
233 */
234 
presolve(CoinPresolveMatrix * prob,const int * implied_free,const int * whichFree,int numberFree,const CoinPresolveAction * next,int maxLook)235 const CoinPresolveAction *subst_constraint_action::presolve(
236   CoinPresolveMatrix *prob,
237   const int *implied_free, const int *whichFree, int numberFree,
238   const CoinPresolveAction *next, int maxLook)
239 {
240 
241 #if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
242 #if PRESOLVE_DEBUG > 0
243   std::cout
244     << "Entering subst_constraint_action::presolve, fill level "
245     << maxLook << ", " << numberFree << " candidates." << 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 
253 #if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
254   int startEmptyRows = 0;
255   int startEmptyColumns = 0;
256   startEmptyRows = prob->countEmptyRows();
257   startEmptyColumns = prob->countEmptyCols();
258 #if COIN_PRESOLVE_TUNING > 0
259   double startTime = 0.0;
260   if (prob->tuning_)
261     startTime = CoinCpuTime();
262 #endif
263 #endif
264 
265   /*
266   Unpack the row- and column-major representations.
267 */
268   const int ncols = prob->ncols_;
269   const int nrows = prob->nrows_;
270 
271   CoinBigIndex *rowStarts = prob->mrstrt_;
272   int *rowLengths = prob->hinrow_;
273   double *rowCoeffs = prob->rowels_;
274   int *colIndices = prob->hcol_;
275   presolvehlink *rlink = prob->rlink_;
276 
277   CoinBigIndex *colStarts = prob->mcstrt_;
278   int *colLengths = prob->hincol_;
279   double *colCoeffs = prob->colels_;
280   int *rowIndices = prob->hrow_;
281   presolvehlink *clink = prob->clink_;
282 
283   /*
284   Row bounds and activity, objective.
285 */
286   double *rlo = prob->rlo_;
287   double *rup = prob->rup_;
288   double *acts = prob->acts_;
289   double *cost = prob->cost_;
290 
291   const double tol = prob->feasibilityTolerance_;
292 
293   action *actions = new action[ncols];
294 #ifdef ZEROFAULT
295   CoinZeroN(reinterpret_cast< char * >(actions), ncols * sizeof(action));
296 #endif
297   int nactions = 0;
298   /*
299   This array is used to hold the indices of columns involved in substitutions,
300   where we have the potential for cancellation. At the end they'll be
301   checked to eliminate any actual zeros that may result. At the end of
302   processing of each target row, the column indices of the target row are
303   copied into zerocols.
304 
305   NOTE that usefulColumnInt_ is already in use for parameters implied_free and
306   whichFree when this routine is called from implied_free.
307 */
308   int *zerocols = new int[ncols];
309   int nzerocols = 0;
310 
311   int *x_to_y = new int[ncols];
312 
313   int *rowsUsed = &prob->usefulRowInt_[0];
314   int nRowsUsed = 0;
315   /*
316   Open a loop to process the (equality r, implied free variable t) pairs
317   in whichFree and implied_free.
318 
319   It can happen that removal of (row, natural singleton) pairs back in
320   implied_free will reduce the length of column t. It can also happen
321   that previous processing here has resulted in fillin or cancellation. So
322   check again for column length and exclude natural singletons and overly
323   dense columns.
324 */
325   for (int iLook = 0; iLook < numberFree; iLook++) {
326     const int tgtcol = whichFree[iLook];
327     const int tgtcol_len = colLengths[tgtcol];
328     const int tgtrow = implied_free[iLook];
329     const int tgtrow_len = rowLengths[tgtrow];
330 
331     assert(fabs(rlo[tgtrow] - rup[tgtrow]) < tol);
332 
333     if (colLengths[tgtcol] < 2 || colLengths[tgtcol] > maxLook) {
334 #if PRESOLVE_DEBUG > 3
335       std::cout
336         << "    skipping eqn " << tgtrow << " x(" << tgtcol
337         << "); length now " << colLengths[tgtcol] << "." << std::endl;
338 #endif
339       continue;
340     }
341 
342     CoinBigIndex tgtcs = colStarts[tgtcol];
343     CoinBigIndex tgtce = tgtcs + colLengths[tgtcol];
344     /*
345   A few checks to make sure that the candidate pair is still suitable.
346   Processing candidates earlier in the list can eliminate coefficients.
347     * Don't use this pair if any involved row i has become a row singleton
348       or empty.
349     * Don't use this pair if any involved row has been modified as part of
350       the processing for a previous candidate pair on this call.
351     * Don't use this pair if a(i,tgtcol) has become zero.
352 
353   The checks on a(i,tgtcol) seem superfluous but it's possible that
354   implied_free identified two candidate pairs to eliminate the same column. If
355   we've already processed one of them, we could be in trouble.
356 */
357     double tgtcoeff = 0.0;
358     bool dealBreaker = false;
359     for (CoinBigIndex kcol = tgtcs; kcol < tgtce; ++kcol) {
360       const int i = rowIndices[kcol];
361       if (rowLengths[i] < 2 || prob->rowUsed(i)) {
362         dealBreaker = true;
363         break;
364       }
365       const double aij = colCoeffs[kcol];
366       if (fabs(aij) <= ZTOLDP2) {
367         dealBreaker = true;
368         break;
369       }
370       if (i == tgtrow)
371         tgtcoeff = aij;
372     }
373 
374     if (dealBreaker == true) {
375 #if PRESOLVE_DEBUG > 3
376       std::cout
377         << "    skipping eqn " << tgtrow << " x(" << tgtcol
378         << "); deal breaker (1)." << std::endl;
379 #endif
380       continue;
381     }
382     /*
383   Check for numerical stability.A large coeff_factor will inflate the
384   coefficients in the substitution formula.
385 */
386     dealBreaker = false;
387     for (CoinBigIndex kcol = tgtcs; kcol < tgtce; ++kcol) {
388       const double coeff_factor = fabs(colCoeffs[kcol] / tgtcoeff);
389       if (coeff_factor > 10.0)
390         dealBreaker = true;
391     }
392     /*
393   Given enough target rows with sufficient overlap, there's an outside chance
394   we could overflow zerocols. Unlikely to ever happen.
395 */
396     if (!dealBreaker && nzerocols + rowLengths[tgtrow] >= ncols)
397       dealBreaker = true;
398     if (dealBreaker == true) {
399 #if PRESOLVE_DEBUG > 3
400       std::cout
401         << "    skipping eqn " << tgtrow << " x(" << tgtcol
402         << "); deal breaker (2)." << std::endl;
403 #endif
404       continue;
405     }
406     /*
407   If c(t) != 0, we will need to modify the objective coefficients and remember
408   the original objective.
409 */
410     const bool nonzero_cost = (fabs(cost[tgtcol]) > tol);
411     double *costsx = (nonzero_cost ? new double[rowLengths[tgtrow]] : 0);
412 
413 #if PRESOLVE_DEBUG > 1
414     std::cout << "  Eliminating row " << tgtrow << ", col " << tgtcol;
415     if (nonzero_cost)
416       std::cout << ", cost " << cost[tgtcol];
417     std::cout << "." << std::endl;
418 #endif
419 
420     /*
421   Count up the total number of coefficients in entangled rows and mark them as
422   contaminated.
423 */
424     int ntotels = 0;
425     for (CoinBigIndex kcol = tgtcs; kcol < tgtce; ++kcol) {
426       const int i = rowIndices[kcol];
427       ntotels += rowLengths[i];
428       PRESOLVEASSERT(!prob->rowUsed(i));
429       prob->setRowUsed(i);
430       rowsUsed[nRowsUsed++] = i;
431     }
432     /*
433   Create the postsolve object. Copy in all the affected rows. Take the
434   opportunity to mark the entangled rows as changed and put them on the list
435   of rows to process in the next round.
436 
437   coeffxs in particular holds the coefficients of the target column.
438 */
439     action *ap = &actions[nactions++];
440 
441     ap->col = tgtcol;
442     ap->rowy = tgtrow;
443     PRESOLVE_DETAIL_PRINT(printf("pre_subst %dC %dR E\n", tgtcol, tgtrow));
444 
445     ap->nincol = tgtcol_len;
446     ap->rows = new int[tgtcol_len];
447     ap->rlos = new double[tgtcol_len];
448     ap->rups = new double[tgtcol_len];
449 
450     ap->costsx = costsx;
451     ap->coeffxs = new double[tgtcol_len];
452 
453     ap->ninrowxs = new int[tgtcol_len];
454     ap->rowcolsxs = new int[ntotels];
455     ap->rowelsxs = new double[ntotels];
456 
457     ntotels = 0;
458     for (CoinBigIndex kcol = tgtcs; kcol < tgtce; ++kcol) {
459       const int ndx = static_cast< int >(kcol - tgtcs);
460       const int i = rowIndices[kcol];
461       const CoinBigIndex krs = rowStarts[i];
462       prob->addRow(i);
463       ap->rows[ndx] = i;
464       ap->ninrowxs[ndx] = rowLengths[i];
465       ap->rlos[ndx] = rlo[i];
466       ap->rups[ndx] = rup[i];
467       ap->coeffxs[ndx] = colCoeffs[kcol];
468 
469       CoinMemcpyN(&colIndices[krs], rowLengths[i], &ap->rowcolsxs[ntotels]);
470       CoinMemcpyN(&rowCoeffs[krs], rowLengths[i], &ap->rowelsxs[ntotels]);
471 
472       ntotels += rowLengths[i];
473     }
474 
475     CoinBigIndex tgtrs = rowStarts[tgtrow];
476     CoinBigIndex tgtre = tgtrs + rowLengths[tgtrow];
477 
478     /*
479   Adjust the objective coefficients based on the substitution formula
480     c'(j) = c(j) - a(rj)c(t)/a(rt)
481 */
482     if (nonzero_cost) {
483       const double tgtcost = cost[tgtcol];
484       for (CoinBigIndex krow = tgtrs; krow < tgtre; krow++) {
485         const int j = colIndices[krow];
486         prob->addCol(j);
487         costsx[krow - tgtrs] = cost[j];
488         double coeff = rowCoeffs[krow];
489         cost[j] -= (tgtcost * coeff) / tgtcoeff;
490       }
491       prob->change_bias(tgtcost * rlo[tgtrow] / tgtcoeff);
492       cost[tgtcol] = 0.0;
493     }
494 
495 #if PRESOLVE_DEBUG > 1
496     std::cout << "  tgt (" << tgtrow << ") (" << tgtrow_len << "): ";
497     for (CoinBigIndex krow = tgtrs; krow < tgtre; ++krow) {
498       const int j = colIndices[krow];
499       const double arj = rowCoeffs[krow];
500       std::cout
501         << "x(" << j << ") = " << arj << " (" << colLengths[j] << ") ";
502     }
503     std::cout << std::endl;
504 #endif
505     // kill small if wanted
506     int relax = (prob->presolveOptions() & 0x60000) >> 17;
507     double tolerance = 1.0e-12;
508     for (int i = 0; i < relax; i++)
509       tolerance *= 10.0;
510 
511     /*
512   Sort the target row for efficiency when doing elimination.
513 */
514     CoinSort_2(colIndices + tgtrs, colIndices + tgtre, rowCoeffs + tgtrs);
515     /*
516   Get down to the business of substituting for tgtcol in the entangled rows.
517   Open a loop to walk the target column. We walk the saved column because the
518   bulk store can change as we work. We don't want to repeat or miss a row.
519 */
520     for (int colndx = 0; colndx < tgtcol_len; ++colndx) {
521       int i = ap->rows[colndx];
522       if (i == tgtrow)
523         continue;
524 
525       double ait = ap->coeffxs[colndx];
526       double coeff_factor = -ait / tgtcoeff;
527 
528       CoinBigIndex krs = rowStarts[i];
529       CoinBigIndex kre = krs + rowLengths[i];
530 
531 #if PRESOLVE_DEBUG > 1
532       std::cout
533         << "  subst pre (" << i << ") (" << rowLengths[i] << "): ";
534       for (CoinBigIndex krow = krs; krow < kre; ++krow) {
535         const int j = colIndices[krow];
536         const double aij = rowCoeffs[krow];
537         std::cout
538           << "x(" << j << ") = " << aij << " (" << colLengths[j] << ") ";
539       }
540       std::cout << std::endl;
541 #endif
542 
543       /*
544   Sort the row for efficiency and call add_row to do the actual business of
545   changing coefficients due to substitution. This has the potential to trigger
546   compaction of the row-major bulk store, so update bulk store indices.
547 */
548       CoinSort_2(colIndices + krs, colIndices + kre, rowCoeffs + krs);
549 
550       bool outOfSpace = add_row(rowStarts, rlo, acts, rup, rowCoeffs, colIndices,
551         rowLengths, rlink, nrows, coeff_factor, tolerance, i, tgtrow,
552         x_to_y);
553       if (outOfSpace)
554         throwCoinError("out of memory", "CoinImpliedFree::presolve");
555 
556       krs = rowStarts[i];
557       kre = krs + rowLengths[i];
558       tgtrs = rowStarts[tgtrow];
559       tgtre = tgtrs + rowLengths[tgtrow];
560 
561 #if PRESOLVE_DEBUG > 1
562       std::cout
563         << "  subst aft (" << i << ") (" << rowLengths[i] << "): ";
564       for (CoinBigIndex krow = krs; krow < kre; ++krow) {
565         const int j = colIndices[krow];
566         const double aij = rowCoeffs[krow];
567         std::cout
568           << "x(" << j << ") = " << aij << " (" << colLengths[j] << ") ";
569       }
570       std::cout << std::endl;
571 #endif
572 
573       /*
574   Now update the column-major representation from the row-major
575   representation. This is easy if the coefficient already exists, but
576   painful if there's fillin. presolve_find_row1 will return the index of
577   the row in the column vector, or one past the end if it's missing. If the
578   coefficient is fill, presolve_expand_col will make sure that there's room in
579   the column for one more coefficient. This may require that the column be
580   moved in the bulk store, so we need to update kcs and kce.
581 
582   Once we're done, a(it) = 0 (i.e., we've eliminated x(t) from row i).
583   Physically remove the explicit zero from the row-major representation
584   with presolve_delete_from_row.
585 */
586       for (CoinBigIndex rowndx = 0; rowndx < tgtrow_len; ++rowndx) {
587         const CoinBigIndex ktgt = tgtrs + rowndx;
588         const int j = colIndices[ktgt];
589         CoinBigIndex kcs = colStarts[j];
590         CoinBigIndex kce = kcs + colLengths[j];
591 
592         assert(colIndices[krs + x_to_y[rowndx]] == j);
593 
594         const double coeff = rowCoeffs[krs + x_to_y[rowndx]];
595 
596         CoinBigIndex kcol = presolve_find_row1(i, kcs, kce, rowIndices);
597 
598         if (kcol < kce) {
599           colCoeffs[kcol] = coeff;
600         } else {
601           outOfSpace = presolve_expand_col(colStarts, colCoeffs, rowIndices,
602             colLengths, clink, ncols, j);
603           if (outOfSpace)
604             throwCoinError("out of memory", "CoinImpliedFree::presolve");
605           kcs = colStarts[j];
606           kce = kcs + colLengths[j];
607 
608           rowIndices[kce] = i;
609           colCoeffs[kce] = coeff;
610           colLengths[j]++;
611         }
612       }
613       presolve_delete_from_row(i, tgtcol,
614         rowStarts, rowLengths, colIndices, rowCoeffs);
615 #if PRESOLVE_DEBUG > 1
616       kre--;
617       std::cout
618         << "  subst fin (" << i << ") (" << rowLengths[i] << "): ";
619       for (CoinBigIndex krow = krs; krow < kre; ++krow) {
620         const int j = colIndices[krow];
621         const double aij = rowCoeffs[krow];
622         std::cout
623           << "x(" << j << ") = " << aij << " (" << colLengths[j] << ") ";
624       }
625       std::cout << std::endl;
626 #endif
627     }
628     /*
629   End of the substitution loop.
630 
631   Record the column indices of the target row so we can groom these columns
632   later to remove possible explicit zeros.
633 */
634     CoinMemcpyN(&colIndices[rowStarts[tgtrow]], rowLengths[tgtrow],
635       &zerocols[nzerocols]);
636     nzerocols += rowLengths[tgtrow];
637     /*
638   Remove the target equality from the column- and row-major representations
639   Somewhat painful in the colum-major representation.  We have to walk the
640   target row in the row-major representation and look up each coefficient
641   in the column-major representation.
642 */
643     for (CoinBigIndex krow = tgtrs; krow < tgtre; ++krow) {
644       const int j = colIndices[krow];
645 #if PRESOLVE_DEBUG > 1
646       std::cout
647         << "  removing row " << tgtrow << " from col " << j << std::endl;
648 #endif
649       presolve_delete_from_col(tgtrow, j,
650         colStarts, colLengths, rowIndices, colCoeffs);
651       if (colLengths[j] == 0) {
652         PRESOLVE_REMOVE_LINK(clink, j);
653       }
654     }
655     /*
656   Finally, physically remove the column from the column-major representation
657   and the row from the row-major representation.
658 */
659     PRESOLVE_REMOVE_LINK(clink, tgtcol);
660     colLengths[tgtcol] = 0;
661 
662     PRESOLVE_REMOVE_LINK(rlink, tgtrow);
663     rowLengths[tgtrow] = 0;
664 
665     rlo[tgtrow] = 0.0;
666     rup[tgtrow] = 0.0;
667 
668 #if PRESOLVE_CONSISTENCY > 0
669     presolve_links_ok(prob);
670     presolve_consistent(prob);
671 #endif
672   }
673   /*
674   That's it, we've processed all the candidate pairs.
675 
676   Clear the row used flags.
677 */
678   for (int i = 0; i < nRowsUsed; i++)
679     prob->unsetRowUsed(rowsUsed[i]);
680   /*
681   Trim the array of substitution transforms and queue up objects for postsolve.
682   Also groom the problem representation to remove explicit zeros.
683 */
684   if (nactions) {
685 #if PRESOLVE_SUMMARY > 0
686     std::cout << "NSUBSTS: " << nactions << std::endl;
687 #endif
688     next = new subst_constraint_action(nactions,
689       CoinCopyOfArray(actions, nactions), next);
690     next = drop_zero_coefficients_action::presolve(prob, zerocols,
691       nzerocols, next);
692 #if PRESOLVE_CONSISTENCY > 0
693     presolve_links_ok(prob);
694     presolve_consistent(prob);
695 #endif
696   }
697 
698   deleteAction(actions, action *);
699   delete[] x_to_y;
700   delete[] zerocols;
701 
702 #if COIN_PRESOLVE_TUNING > 0
703   double thisTime = 0.0;
704   if (prob->tuning_)
705     thisTime = CoinCpuTime();
706 #endif
707 #if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
708   presolve_check_sol(prob);
709 #endif
710 #if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
711   int droppedRows = prob->countEmptyRows() - startEmptyRows;
712   int droppedColumns = prob->countEmptyCols() - startEmptyColumns;
713   std::cout
714     << "Leaving subst_constraint_action::presolve, "
715     << droppedRows << " rows, " << droppedColumns << " columns dropped";
716 #if COIN_PRESOLVE_TUNING > 0
717   std::cout << " in " << thisTime - startTime << "s";
718 #endif
719   std::cout << "." << std::endl;
720 #endif
721 
722   return (next);
723 }
724 
725 /*
726   Undo the substitutions from presolve and reintroduce the target constraint
727   and column.
728 */
postsolve(CoinPostsolveMatrix * prob) const729 void subst_constraint_action::postsolve(CoinPostsolveMatrix *prob) const
730 {
731 
732 #if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
733 #if PRESOLVE_DEBUG > 0
734   std::cout
735     << "Entering subst_constraint_action::postsolve, "
736     << nactions_ << " constraints to process." << std::endl;
737 #endif
738   int ncols = prob->ncols_;
739   char *cdone = prob->cdone_;
740   char *rdone = prob->rdone_;
741   const double ztolzb = prob->ztolzb_;
742 
743   presolve_check_threads(prob);
744   presolve_check_free_list(prob);
745   presolve_check_reduced_costs(prob);
746   presolve_check_duals(prob);
747   presolve_check_sol(prob, 2, 2, 2);
748   presolve_check_nbasic(prob);
749 #endif
750 
751   /*
752   Unpack the column-major representation.
753 */
754   CoinBigIndex *colStarts = prob->mcstrt_;
755   int *colLengths = prob->hincol_;
756   int *rowIndices = prob->hrow_;
757   double *colCoeffs = prob->colels_;
758   /*
759   Rim vectors, solution, reduced costs, duals, row activity.
760 */
761   double *rlo = prob->rlo_;
762   double *rup = prob->rup_;
763   double *cost = prob->cost_;
764   double *sol = prob->sol_;
765   double *rcosts = prob->rcosts_;
766   double *acts = prob->acts_;
767   double *rowduals = prob->rowduals_;
768 
769   CoinBigIndex *link = prob->link_;
770   CoinBigIndex &free_list = prob->free_list_;
771 
772   const double maxmin = prob->maxmin_;
773 
774   const action *const actions = actions_;
775   const int nactions = nactions_;
776 
777   /*
778   Open the main loop to step through the postsolve objects.
779 
780   First activity is to unpack the postsolve object. We have the target
781   column and row indices, the full target column, and complete copies of
782   all entangled rows (column indices, coefficients, lower and upper bounds).
783   There may be a vector of objective coefficients which we'll get to later.
784 */
785   for (const action *f = &actions[nactions - 1]; actions <= f; f--) {
786     const int tgtcol = f->col;
787     const int tgtrow = f->rowy;
788 
789     const int tgtcol_len = f->nincol;
790     const double *tgtcol_coeffs = f->coeffxs;
791 
792     const int *entngld_rows = f->rows;
793     const int *entngld_lens = f->ninrowxs;
794     const int *entngld_colndxs = f->rowcolsxs;
795     const double *entngld_colcoeffs = f->rowelsxs;
796     const double *entngld_rlos = f->rlos;
797     const double *entngld_rups = f->rups;
798     const double *costs = f->costsx;
799 
800 #if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
801 #if PRESOLVE_DEBUG > 1
802     std::cout
803       << "  reintroducing column x(" << tgtcol << ") and row " << tgtrow;
804     if (costs)
805       std::cout << ", nonzero costs";
806     std::cout << "." << std::endl;
807 #endif
808     /*
809   We're about to reintroduce the target row and column; empty stubs should be
810   present. All other rows should already be present.
811 */
812     PRESOLVEASSERT(cdone[tgtcol] == DROP_COL);
813     PRESOLVEASSERT(colLengths[tgtcol] == 0);
814     PRESOLVEASSERT(rdone[tgtrow] == DROP_ROW);
815     for (int cndx = 0; cndx < tgtcol_len; ++cndx) {
816       if (entngld_rows[cndx] != tgtrow)
817         PRESOLVEASSERT(rdone[entngld_rows[cndx]]);
818     }
819     /*
820   In a postsolve matrix, we can't just check that the length of the row is
821   zero. We need to look at all columns and confirm its absence.
822 */
823     for (int j = 0; j < ncols; ++j) {
824       if (colLengths[j] > 0 && cdone[j]) {
825         const CoinBigIndex kcs = colStarts[j];
826         const int lenj = colLengths[j];
827         CoinBigIndex krow = presolve_find_row3(tgtrow, kcs, lenj, rowIndices, link);
828         if (krow >= 0) {
829           std::cout
830             << "  BAD COEFF! row " << tgtrow << " present in column " << j
831             << " before reintroduction; a(" << tgtrow << "," << j
832             << ") = " << colCoeffs[krow] << "; x(" << j << ") = " << sol[j]
833             << "; cdone " << static_cast< int >(cdone[j]) << "." << std::endl;
834         }
835       }
836     }
837 #endif
838 
839     /*
840   Find the copy of the target row. Restore the upper and lower bounds
841   of entangled rows while we're looking. Recall that the target row is
842   an equality.
843 */
844     int tgtrow_len = -1;
845     const int *tgtrow_colndxs = NULL;
846     const double *tgtrow_coeffs = NULL;
847     double tgtcoeff = 0.0;
848     double tgtrhs = 1.0e50;
849 
850     int nel = 0;
851     for (int cndx = 0; cndx < tgtcol_len; ++cndx) {
852       int i = entngld_rows[cndx];
853       rlo[i] = entngld_rlos[cndx];
854       rup[i] = entngld_rups[cndx];
855       if (i == tgtrow) {
856         tgtrow_len = entngld_lens[cndx];
857         tgtrow_colndxs = &entngld_colndxs[nel];
858         tgtrow_coeffs = &entngld_colcoeffs[nel];
859         tgtcoeff = tgtcol_coeffs[cndx];
860         tgtrhs = rlo[i];
861       }
862       nel += entngld_lens[cndx];
863     }
864     /*
865   Solve the target equality to find the solution for the eliminated col.
866   tgtcol is present in tgtrow_colndxs, so initialise sol[tgtcol] to zero
867   to make sure it doesn't contribute.
868 
869   If we're debugging, check that the result is within bounds.
870 */
871     double tgtexp = tgtrhs;
872     sol[tgtcol] = 0.0;
873     for (int ndx = 0; ndx < tgtrow_len; ++ndx) {
874       int j = tgtrow_colndxs[ndx];
875       double coeffj = tgtrow_coeffs[ndx];
876       tgtexp -= coeffj * sol[j];
877     }
878     sol[tgtcol] = tgtexp / tgtcoeff;
879 
880 #if PRESOLVE_DEBUG > 0
881     double *clo = prob->clo_;
882     double *cup = prob->cup_;
883 
884     if (!(sol[tgtcol] > (clo[tgtcol] - ztolzb) && (cup[tgtcol] + ztolzb) > sol[tgtcol])) {
885       std::cout
886         << "BAD SOL: x(" << tgtcol << ") " << sol[tgtcol]
887         << "; lb " << clo[tgtcol] << "; ub " << cup[tgtcol] << "."
888         << std::endl;
889     }
890 #endif
891     /*
892   Now restore the original entangled rows. We first delete any columns present
893   in tgtrow. This will remove any fillin, but may also remove columns that
894   were originally present in both the entangled row and the target row.
895 
896   Note that even cancellations (explicit zeros) are present at this
897   point --- in presolve, they were removed after the substition transform
898   completed, hence they're already restored. What isn't present is the target
899   column, which is deleted as part of the transform.
900 */
901     {
902 #if PRESOLVE_DEBUG > 2
903       std::cout << "    removing coefficients:";
904 #endif
905       for (int rndx = 0; rndx < tgtrow_len; ++rndx) {
906         int j = tgtrow_colndxs[rndx];
907         if (j != tgtcol)
908           for (int cndx = 0; cndx < tgtcol_len; ++cndx) {
909             if (entngld_rows[cndx] != tgtrow) {
910 #if PRESOLVE_DEBUG > 2
911               std::cout << " a(" << entngld_rows[cndx] << "," << j << ")";
912 #endif
913               presolve_delete_from_col2(entngld_rows[cndx], j, colStarts,
914                 colLengths, rowIndices, link, &free_list);
915             }
916           }
917       }
918 #if PRESOLVE_DEBUG > 2
919       std::cout << std::endl;
920 #endif
921 #if PRESOLVE_CONSISTENCY > 0
922       presolve_check_threads(prob);
923       presolve_check_free_list(prob);
924 #endif
925 /*
926   Next we restore the original coefficients. The outer loop walks tgtcol;
927   cols_i and coeffs_i are advanced as we go to point to each entangled
928   row. The inner loop walks the entangled row and restores the row's
929   coefficients. Tgtcol is handled as any other column. Skip tgtrow, we'll
930   do it below.
931 
932   Since we don't have a row-major representation, we have to look for a(i,j)
933   from entangled row i in the existing column j. If we find a(i,j), simply
934   update it (and a(tgtrow,j) should not exist). If we don't find a(i,j),
935   introduce it (and a(tgtrow,j) should exist).
936 
937   Recalculate the row activity while we're at it.
938 */
939 #if PRESOLVE_DEBUG > 2
940       std::cout << "    restoring coefficients:";
941 #endif
942 
943       colLengths[tgtcol] = 0;
944       const int *cols_i = entngld_colndxs;
945       const double *coeffs_i = entngld_colcoeffs;
946 
947       for (int cndx = 0; cndx < tgtcol_len; ++cndx) {
948         const int leni = entngld_lens[cndx];
949         const int i = entngld_rows[cndx];
950 
951         if (i != tgtrow) {
952           double acti = 0.0;
953           for (int rndx = 0; rndx < leni; ++rndx) {
954             const int j = cols_i[rndx];
955             CoinBigIndex kcoli = presolve_find_row3(i, colStarts[j],
956               colLengths[j], rowIndices, link);
957             if (kcoli != -1) {
958 #if PRESOLVE_DEBUG > 2
959               std::cout << " u a(" << i << "," << j << ")";
960               PRESOLVEASSERT(presolve_find_col1(j, 0, tgtrow_len,
961                                tgtrow_colndxs)
962                 == tgtrow_len);
963 #endif
964               colCoeffs[kcoli] = coeffs_i[rndx];
965             } else {
966 #if PRESOLVE_DEBUG > 2
967               std::cout << " f a(" << i << "," << j << ")";
968               PRESOLVEASSERT(presolve_find_col1(j, 0, tgtrow_len,
969                                tgtrow_colndxs)
970                 < tgtrow_len);
971 #endif
972               CoinBigIndex kk = free_list;
973               assert(kk >= 0 && kk < prob->bulk0_);
974               free_list = link[free_list];
975               link[kk] = colStarts[j];
976               colStarts[j] = kk;
977               colCoeffs[kk] = coeffs_i[rndx];
978               rowIndices[kk] = i;
979               ++colLengths[j];
980             }
981             acti += coeffs_i[rndx] * sol[j];
982           }
983           acts[i] = acti;
984         }
985         cols_i += leni;
986         coeffs_i += leni;
987       }
988 #if PRESOLVE_DEBUG > 2
989       std::cout << std::endl;
990 #endif
991 #if PRESOLVE_CONSISTENCY > 0
992       presolve_check_threads(prob);
993       presolve_check_free_list(prob);
994 #endif
995 /*
996   Restore tgtrow. Arguably we could to this in the previous loop, but we'd do
997   a lot of unnecessary work. By construction, the target row is tight.
998 */
999 #if PRESOLVE_DEBUG > 2
1000       std::cout << "    restoring row " << tgtrow << ":";
1001 #endif
1002 
1003       for (int rndx = 0; rndx < tgtrow_len; ++rndx) {
1004         int j = tgtrow_colndxs[rndx];
1005 #if PRESOLVE_DEBUG > 2
1006         std::cout << " a(" << tgtrow << "," << j << ")";
1007 #endif
1008         CoinBigIndex kk = free_list;
1009         assert(kk >= 0 && kk < prob->bulk0_);
1010         free_list = link[free_list];
1011         link[kk] = colStarts[j];
1012         colStarts[j] = kk;
1013         colCoeffs[kk] = tgtrow_coeffs[rndx];
1014         rowIndices[kk] = tgtrow;
1015         ++colLengths[j];
1016       }
1017       acts[tgtrow] = tgtrhs;
1018 
1019 #if PRESOLVE_DEBUG > 2
1020       std::cout << std::endl;
1021 #endif
1022 #if PRESOLVE_CONSISTENCY > 0
1023       presolve_check_threads(prob);
1024       presolve_check_free_list(prob);
1025 #endif
1026     }
1027     /*
1028   Restore original cost coefficients, if necessary.
1029 */
1030     if (costs) {
1031       for (int ndx = 0; ndx < tgtrow_len; ++ndx) {
1032         cost[tgtrow_colndxs[ndx]] = costs[ndx];
1033       }
1034     }
1035     /*
1036   Calculate the reduced cost for the column absent any contribution from
1037   tgtrow, then set the dual for tgtrow so that the reduced cost of tgtcol
1038   is zero.
1039 */
1040     double dj = maxmin * cost[tgtcol];
1041     rowduals[tgtrow] = 0.0;
1042     for (int cndx = 0; cndx < tgtcol_len; ++cndx) {
1043       int i = entngld_rows[cndx];
1044       double coeff = tgtcol_coeffs[cndx];
1045       dj -= rowduals[i] * coeff;
1046     }
1047     rowduals[tgtrow] = dj / tgtcoeff;
1048     rcosts[tgtcol] = 0.0;
1049     if (rowduals[tgtrow] > 0)
1050       prob->setRowStatus(tgtrow, CoinPrePostsolveMatrix::atUpperBound);
1051     else
1052       prob->setRowStatus(tgtrow, CoinPrePostsolveMatrix::atLowerBound);
1053     prob->setColumnStatus(tgtcol, CoinPrePostsolveMatrix::basic);
1054 
1055 #if PRESOLVE_DEBUG > 2
1056     std::cout
1057       << "  row " << tgtrow << " "
1058       << prob->rowStatusString(prob->getRowStatus(tgtrow))
1059       << " dual " << rowduals[tgtrow] << std::endl;
1060     std::cout
1061       << "  col " << tgtcol << " "
1062       << prob->columnStatusString(prob->getColumnStatus(tgtcol))
1063       << " dj " << dj << std::endl;
1064 #endif
1065 
1066 #if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
1067     cdone[tgtcol] = SUBST_ROW;
1068     rdone[tgtrow] = SUBST_ROW;
1069 #endif
1070   }
1071 
1072 #if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
1073   presolve_check_threads(prob);
1074   presolve_check_free_list(prob);
1075   presolve_check_reduced_costs(prob);
1076   presolve_check_duals(prob);
1077   presolve_check_sol(prob, 2, 2, 2);
1078   presolve_check_nbasic(prob);
1079 #if PRESOLVE_DEBUG > 0
1080   std::cout << "Leaving subst_constraint_action::postsolve." << std::endl;
1081 #endif
1082 #endif
1083 
1084   return;
1085 }
1086 
1087 /*
1088   Next time someone builds this code on Windows, check to see if deleteAction
1089   is still necessary.   -- lh, 121114 --
1090 */
~subst_constraint_action()1091 subst_constraint_action::~subst_constraint_action()
1092 {
1093   const action *actions = actions_;
1094 
1095   for (int i = 0; i < nactions_; ++i) {
1096     delete[] actions[i].rows;
1097     delete[] actions[i].rlos;
1098     delete[] actions[i].rups;
1099     delete[] actions[i].coeffxs;
1100     delete[] actions[i].ninrowxs;
1101     delete[] actions[i].rowcolsxs;
1102     delete[] actions[i].rowelsxs;
1103 
1104     //delete [](double*)actions[i].costsx ;
1105     deleteAction(actions[i].costsx, double *);
1106   }
1107 
1108   // Must add cast to placate MS compiler
1109   //delete [] (subst_constraint_action::action*)actions_ ;
1110   deleteAction(actions_, subst_constraint_action::action *);
1111 }
1112 
1113 /* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2
1114 */
1115