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