1 /* $Id: CoinPresolveFixed.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 "CoinPresolveFixed.hpp"
11 #include "CoinHelperFunctions.hpp"
12 #include "CoinFinite.hpp"
13
14 #if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
15 #include "CoinPresolvePsdebug.hpp"
16 #endif
17
18 /* Begin routines associated with remove_fixed_action */
19
name() const20 const char *remove_fixed_action::name() const
21 {
22 return ("remove_fixed_action");
23 }
24
25 /*
26 * Original comment:
27 *
28 * invariant: both reps are loosely packed.
29 * coefficients of both reps remain consistent.
30 *
31 * Note that this concerns variables whose column bounds determine that
32 * they are slack; this does NOT concern singleton row constraints that
33 * determine that the relevant variable is slack.
34 *
35 * Invariant: col and row rep are consistent
36 */
37
38 /*
39 This routine empties the columns for the list of fixed variables passed in
40 (fcols, nfcols). As each coefficient a<ij> is set to 0, rlo<i> and rup<i>
41 are adjusted accordingly. Note, however, that c<j> is not considered to be
42 removed from the objective until column j is physically removed from the
43 matrix (drop_empty_cols_action), so the correction to the objective is
44 adjusted there.
45
46 If a column solution is available, row activity (acts_) is adjusted.
47 remove_fixed_action implicitly assumes that the value of the variable has
48 already been forced within bounds. If this isn't true, the correction to
49 acts_ will be wrong. See make_fixed_action if you need to force the value
50 within bounds first.
51 */
52 const remove_fixed_action *
presolve(CoinPresolveMatrix * prob,int * fcols,int nfcols,const CoinPresolveAction * next)53 remove_fixed_action::presolve(CoinPresolveMatrix *prob,
54 int *fcols, int nfcols,
55 const CoinPresolveAction *next)
56 {
57 double *colels = prob->colels_;
58 int *hrow = prob->hrow_;
59 CoinBigIndex *mcstrt = prob->mcstrt_;
60 int *hincol = prob->hincol_;
61
62 double *rowels = prob->rowels_;
63 int *hcol = prob->hcol_;
64 CoinBigIndex *mrstrt = prob->mrstrt_;
65 int *hinrow = prob->hinrow_;
66
67 double *clo = prob->clo_;
68 double *rlo = prob->rlo_;
69 double *rup = prob->rup_;
70 double *sol = prob->sol_;
71 double *acts = prob->acts_;
72
73 presolvehlink *clink = prob->clink_;
74 presolvehlink *rlink = prob->rlink_;
75
76 action *actions = new action[nfcols + 1];
77
78 #if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
79 #if PRESOLVE_DEBUG > 0
80 std::cout
81 << "Entering remove_fixed_action::presolve; processing " << nfcols
82 << " fixed columns." << std::endl;
83 #endif
84 presolve_check_sol(prob);
85 presolve_check_nbasic(prob);
86 #endif
87
88 /*
89 Scan columns to be removed and total up the number of coefficients.
90 */
91 int estsize = 0;
92 int ckc;
93 int n = 0;
94 for (ckc = 0; ckc < nfcols; ckc++) {
95 int j = fcols[ckc];
96 if (!prob->colProhibited2(j)) {
97 estsize += hincol[j];
98 fcols[n++] = j;
99 }
100 }
101 nfcols = n;
102 // Allocate arrays to hold coefficients and associated row indices
103 double *els_action = new double[estsize];
104 int *rows_action = new int[estsize];
105 int actsize = 0;
106 // faster to do all deletes in row copy at once
107 int nrows = prob->nrows_;
108 CoinBigIndex *rstrt = new CoinBigIndex[nrows + 1];
109 CoinZeroN(rstrt, nrows);
110
111 /*
112 Open a loop to excise each column a<j>. The first thing to do is load the
113 action entry with the index j, the value of x<j>, and the number of
114 entries in a<j>. After we walk the column and tweak the row-major
115 representation, we'll simply claim this column is empty by setting
116 hincol[j] = 0.
117 */
118 for (ckc = 0; ckc < nfcols; ckc++) {
119 int j = fcols[ckc];
120 double solj = clo[j];
121 CoinBigIndex kcs = mcstrt[j];
122 CoinBigIndex kce = kcs + hincol[j];
123 CoinBigIndex k;
124
125 {
126 action &f = actions[ckc];
127 f.col = j;
128 f.sol = solj;
129 f.start = actsize;
130 }
131 /*
132 Now walk a<j>. For each row i with a coefficient a<ij> != 0:
133 * save the coefficient and row index,
134 * substitute the value of x<j>, adjusting the row bounds and lhs value
135 accordingly, then
136 * delete a<ij> from the row-major representation.
137 * Finally: mark the row as changed and add it to the list of rows to be
138 processed next. Then, for each remaining column in the row, put it on
139 the list of columns to be processed.
140 */
141 for (k = kcs; k < kce; k++) {
142 int row = hrow[k];
143 double coeff = colels[k];
144
145 els_action[actsize] = coeff;
146 rstrt[row]++; // increase counts
147 rows_action[actsize++] = row;
148
149 // Avoid reducing finite infinity.
150 if (-PRESOLVE_INF < rlo[row])
151 rlo[row] -= solj * coeff;
152 if (rup[row] < PRESOLVE_INF)
153 rup[row] -= solj * coeff;
154 if (sol) {
155 acts[row] -= solj * coeff;
156 }
157 #define TRY2
158 #ifndef TRY2
159 presolve_delete_from_row(row, j, mrstrt, hinrow, hcol, rowels);
160 if (hinrow[row] == 0) {
161 PRESOLVE_REMOVE_LINK(rlink, row);
162 }
163
164 // mark unless already marked
165 if (!prob->rowChanged(row)) {
166 prob->addRow(row);
167 CoinBigIndex krs = mrstrt[row];
168 CoinBigIndex kre = krs + hinrow[row];
169 for (CoinBigIndex k = krs; k < kre; k++) {
170 int jcol = hcol[k];
171 prob->addCol(jcol);
172 }
173 }
174 #endif
175 }
176 /*
177 Remove the column's link from the linked list of columns, and declare
178 it empty in the column-major representation. Link removal must execute
179 even if the column is already of length 0 when it arrives.
180 */
181 PRESOLVE_REMOVE_LINK(clink, j);
182 hincol[j] = 0;
183 }
184 /*
185 Set the actual end of the coefficient and row index arrays.
186 */
187 actions[nfcols].start = actsize;
188 #if PRESOLVE_SUMMARY
189 printf("NFIXED: %d", nfcols);
190 if (estsize - actsize > 0) {
191 printf(", overalloc %d", estsize - actsize);
192 }
193 printf("\n");
194 #endif
195 // Now get columns by row
196 int *column = new int[actsize];
197 CoinBigIndex nel = 0;
198 int iRow;
199 for (iRow = 0; iRow < nrows; iRow++) {
200 CoinBigIndex n = rstrt[iRow];
201 rstrt[iRow] = nel;
202 nel += n;
203 }
204 rstrt[nrows] = nel;
205 for (ckc = 0; ckc < nfcols; ckc++) {
206 int kcs = actions[ckc].start;
207 int j = actions[ckc].col;
208 int kce;
209 if (ckc < nfcols - 1)
210 kce = actions[ckc + 1].start;
211 else
212 kce = actsize;
213 for (int k = kcs; k < kce; k++) {
214 int iRow = rows_action[k];
215 CoinBigIndex put = rstrt[iRow];
216 rstrt[iRow]++;
217 column[put] = j;
218 }
219 }
220 // Now do rows
221 int ncols = prob->ncols_;
222 char *mark = new char[ncols];
223 memset(mark, 0, ncols);
224 // rstrts are now one out i.e. rstrt[0] is end of row 0
225 nel = 0;
226 #ifdef TRY2
227 for (iRow = 0; iRow < nrows; iRow++) {
228 CoinBigIndex k;
229 for (k = nel; k < rstrt[iRow]; k++) {
230 mark[column[k]] = 1;
231 }
232 presolve_delete_many_from_major(iRow, mark, mrstrt, hinrow, hcol, rowels);
233 #if PRESOLVE_DEBUG > 0
234 for (k = nel; k < rstrt[iRow]; k++) {
235 assert(mark[column[k]] == 0);
236 }
237 #endif
238 if (hinrow[iRow] == 0) {
239 PRESOLVE_REMOVE_LINK(rlink, iRow);
240 }
241 // mark unless already marked
242 if (!prob->rowChanged(iRow)) {
243 prob->addRow(iRow);
244 CoinBigIndex krs = mrstrt[iRow];
245 CoinBigIndex kre = krs + hinrow[iRow];
246 for (CoinBigIndex k = krs; k < kre; k++) {
247 int jcol = hcol[k];
248 prob->addCol(jcol);
249 }
250 }
251 nel = rstrt[iRow];
252 }
253 #endif
254 delete[] mark;
255 delete[] column;
256 delete[] rstrt;
257
258 /*
259 Create the postsolve object, link it at the head of the list of postsolve
260 objects, and return a pointer.
261 */
262 const remove_fixed_action *fixedActions = new remove_fixed_action(nfcols, actions, els_action, rows_action, next);
263
264 #if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
265 presolve_check_sol(prob);
266 #if PRESOLVE_DEBUG > 0
267 std::cout << "Leaving remove_fixed_action::presolve." << std::endl;
268 #endif
269 #endif
270
271 return (fixedActions);
272 }
273
remove_fixed_action(int nactions,action * actions,double * els_action,int * rows_action,const CoinPresolveAction * next)274 remove_fixed_action::remove_fixed_action(int nactions,
275 action *actions,
276 double *els_action,
277 int *rows_action,
278 const CoinPresolveAction *next)
279 : CoinPresolveAction(next)
280 , colrows_(rows_action)
281 , colels_(els_action)
282 , nactions_(nactions)
283 , actions_(actions)
284 {
285 }
286
~remove_fixed_action()287 remove_fixed_action::~remove_fixed_action()
288 {
289 deleteAction(actions_, action *);
290 delete[] colels_;
291 delete[] colrows_;
292 }
293
294 /*
295 * Say we determined that cup - clo <= ztolzb, so we fixed sol at clo.
296 * This involved subtracting clo*coeff from ub/lb for each row the
297 * variable occurred in.
298 * Now when we put the variable back in, by construction the variable
299 * is within tolerance, the non-slacks are unchanged, and the
300 * distances of the affected slacks from their bounds should remain
301 * unchanged (ignoring roundoff errors).
302 * It may be that by adding the term back in, the affected constraints
303 * now aren't as accurate due to round-off errors; this could happen
304 * if only one summand and the slack in the original formulation were large
305 * (and naturally had opposite signs), and the new term in the constraint
306 * is about the size of the old slack, so the new slack becomes about 0.
307 * It may be that there is catastrophic cancellation in the summation,
308 * so it might not compute to 0.
309 */
postsolve(CoinPostsolveMatrix * prob) const310 void remove_fixed_action::postsolve(CoinPostsolveMatrix *prob) const
311 {
312 action *actions = actions_;
313 const int nactions = nactions_;
314
315 double *colels = prob->colels_;
316 int *hrow = prob->hrow_;
317 CoinBigIndex *mcstrt = prob->mcstrt_;
318 int *hincol = prob->hincol_;
319 CoinBigIndex *link = prob->link_;
320 CoinBigIndex &free_list = prob->free_list_;
321
322 double *clo = prob->clo_;
323 double *cup = prob->cup_;
324 double *rlo = prob->rlo_;
325 double *rup = prob->rup_;
326
327 double *sol = prob->sol_;
328 double *dcost = prob->cost_;
329 double *rcosts = prob->rcosts_;
330
331 double *acts = prob->acts_;
332 double *rowduals = prob->rowduals_;
333
334 unsigned char *colstat = prob->colstat_;
335
336 const double maxmin = prob->maxmin_;
337
338 #if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
339 char *cdone = prob->cdone_;
340 #if PRESOLVE_DEBUG > 0
341 std::cout
342 << "Entering remove_fixed_action::postsolve, repopulating " << nactions
343 << " columns." << std::endl;
344 #endif
345 presolve_check_threads(prob);
346 presolve_check_free_list(prob);
347 presolve_check_sol(prob, 2, 2, 2);
348 presolve_check_nbasic(prob);
349 #endif
350
351 double *els_action = colels_;
352 int *rows_action = colrows_;
353 int end = actions[nactions].start;
354
355 /*
356 At one point, it turned out that forcing_constraint_action was putting
357 duplicates in the column list it passed to remove_fixed_action. This is now
358 fixed, but ... it looks to me like we could be in trouble here if we
359 reinstate a column multiple times. Hence the assert.
360 */
361 for (const action *f = &actions[nactions - 1]; actions <= f; f--) {
362 int icol = f->col;
363 const double thesol = f->sol;
364
365 #if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
366 if (cdone[icol] == FIXED_VARIABLE) {
367 std::cout
368 << "RFA::postsolve: column " << icol << " already unfixed!"
369 << std::endl;
370 assert(cdone[icol] != FIXED_VARIABLE);
371 }
372 cdone[icol] = FIXED_VARIABLE;
373 #endif
374
375 sol[icol] = thesol;
376 clo[icol] = thesol;
377 cup[icol] = thesol;
378
379 CoinBigIndex cs = NO_LINK;
380 int start = f->start;
381 double dj = maxmin * dcost[icol];
382
383 for (int i = start; i < end; ++i) {
384 int row = rows_action[i];
385 double coeff = els_action[i];
386
387 // pop free_list
388 CoinBigIndex k = free_list;
389 assert(k >= 0 && k < prob->bulk0_);
390 free_list = link[free_list];
391 // restore
392 hrow[k] = row;
393 colels[k] = coeff;
394 link[k] = cs;
395 cs = k;
396
397 if (-PRESOLVE_INF < rlo[row])
398 rlo[row] += coeff * thesol;
399 if (rup[row] < PRESOLVE_INF)
400 rup[row] += coeff * thesol;
401 acts[row] += coeff * thesol;
402
403 dj -= rowduals[row] * coeff;
404 }
405
406 #if PRESOLVE_CONSISTENCY > 0
407 presolve_check_free_list(prob);
408 #endif
409
410 mcstrt[icol] = cs;
411
412 rcosts[icol] = dj;
413 hincol[icol] = end - start;
414 end = start;
415
416 /* Original comment:
417 * the bounds in the reduced problem were tightened.
418 * that means that this variable may not have been basic
419 * because it didn't have to be,
420 * but now it may have to.
421 * no - the bounds aren't changed by this operation
422 */
423 /*
424 We've reintroduced the variable, but it's still fixed (equal bounds).
425 Pick the nonbasic status that agrees with the reduced cost. Later, if
426 postsolve unfixes the variable, we'll need to confirm that this status is
427 still viable. We live in a minimisation world here.
428 */
429 if (colstat) {
430 if (dj < 0)
431 prob->setColumnStatus(icol, CoinPrePostsolveMatrix::atUpperBound);
432 else
433 prob->setColumnStatus(icol, CoinPrePostsolveMatrix::atLowerBound);
434 }
435 }
436
437 #if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
438 presolve_check_threads(prob);
439 presolve_check_sol(prob, 2, 2, 2);
440 presolve_check_nbasic(prob);
441 #if PRESOLVE_DEBUG > 0
442 std::cout << "Leaving remove_fixed_action::postsolve." << std::endl;
443 #endif
444 #endif
445
446 return;
447 }
448
449 /*
450 Scan the problem for variables that are already fixed, and remove them.
451 There's an implicit assumption that the value of the variable is already
452 within bounds. If you want to protect against this possibility, you want to
453 use make_fixed.
454 */
remove_fixed(CoinPresolveMatrix * prob,const CoinPresolveAction * next)455 const CoinPresolveAction *remove_fixed(CoinPresolveMatrix *prob,
456 const CoinPresolveAction *next)
457 {
458 int ncols = prob->ncols_;
459 int *fcols = new int[ncols];
460 int nfcols = 0;
461
462 int *hincol = prob->hincol_;
463
464 double *clo = prob->clo_;
465 double *cup = prob->cup_;
466
467 for (int i = 0; i < ncols; i++)
468 if (hincol[i] > 0 && clo[i] == cup[i] && !prob->colProhibited2(i))
469 fcols[nfcols++] = i;
470
471 if (nfcols > 0) {
472 next = remove_fixed_action::presolve(prob, fcols, nfcols, next);
473 }
474 delete[] fcols;
475 return (next);
476 }
477
478 /* End routines associated with remove_fixed_action */
479
480 /* Begin routines associated with make_fixed_action */
481
name() const482 const char *make_fixed_action::name() const
483 {
484 return ("make_fixed_action");
485 }
486
487 /*
488 This routine does the actual job of fixing one or more variables. The set
489 of indices to be fixed is specified by nfcols and fcols. fix_to_lower
490 specifies the bound where the variable(s) should be fixed. The other bound
491 is preserved as part of the action and the bounds are set equal. Note that
492 you don't get to specify the bound on a per-variable basis.
493
494 If a primal solution is available, make_fixed_action will adjust the the
495 row activity to compensate for forcing the variable within bounds. If the
496 bounds are already equal, and the variable is within bounds, you should
497 consider remove_fixed_action.
498 */
499 const CoinPresolveAction *
presolve(CoinPresolveMatrix * prob,int * fcols,int nfcols,bool fix_to_lower,const CoinPresolveAction * next)500 make_fixed_action::presolve(CoinPresolveMatrix *prob,
501 int *fcols, int nfcols,
502 bool fix_to_lower,
503 const CoinPresolveAction *next)
504
505 {
506 double *clo = prob->clo_;
507 double *cup = prob->cup_;
508 double *csol = prob->sol_;
509
510 double *colels = prob->colels_;
511 int *hrow = prob->hrow_;
512 CoinBigIndex *mcstrt = prob->mcstrt_;
513 int *hincol = prob->hincol_;
514
515 double *acts = prob->acts_;
516
517 #if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
518 #if PRESOLVE_DEBUG > 0
519 std::cout
520 << "Entering make_fixed_action::presolve, fixed = " << nfcols << "."
521 << std::endl;
522 #endif
523 presolve_check_sol(prob);
524 presolve_check_nbasic(prob);
525 #endif
526
527 /*
528 Shouldn't happen, but ...
529 */
530 if (nfcols <= 0) {
531 #if PRESOLVE_DEBUG > 0
532 std::cout
533 << "make_fixed_action::presolve: useless call, " << nfcols
534 << " to fix." << std::endl;
535 #endif
536 return (next);
537 }
538
539 action *actions = new action[nfcols];
540
541 /*
542 Scan the set of indices specifying variables to be fixed. For each variable,
543 stash the unused bound in the action and set the bounds equal. If the client
544 has passed in a primal solution, update it if the value of the variable
545 changes.
546 */
547 for (int ckc = 0; ckc < nfcols; ckc++) {
548 int j = fcols[ckc];
549 if (prob->colProhibited2(j))
550 abort();
551 double movement = 0;
552
553 action &f = actions[ckc];
554
555 f.col = j;
556 if (fix_to_lower) {
557 f.bound = cup[j];
558 cup[j] = clo[j];
559 if (csol) {
560 movement = clo[j] - csol[j];
561 csol[j] = clo[j];
562 }
563 } else {
564 f.bound = clo[j];
565 clo[j] = cup[j];
566 if (csol) {
567 movement = cup[j] - csol[j];
568 csol[j] = cup[j];
569 }
570 }
571 if (movement) {
572 CoinBigIndex k;
573 for (k = mcstrt[j]; k < mcstrt[j] + hincol[j]; k++) {
574 int row = hrow[k];
575 acts[row] += movement * colels[k];
576 }
577 }
578 }
579 /*
580 Original comment:
581 This is unusual in that the make_fixed_action transform contains within it
582 a remove_fixed_action transform. Bad idea?
583
584 Explanatory comment:
585 Now that we've adjusted the bounds, time to create the postsolve action
586 that will restore the original bounds. But wait! We're not done. By calling
587 remove_fixed_action::presolve, we will (virtually) remove these variables
588 from the model by substituting for the variable where it occurs and emptying
589 the column. Cache the postsolve transform that will repopulate the column
590 inside the postsolve transform for fixing the bounds.
591 */
592 if (nfcols > 0) {
593 next = new make_fixed_action(nfcols, actions, fix_to_lower,
594 remove_fixed_action::presolve(prob, fcols, nfcols, 0),
595 next);
596 }
597
598 #if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
599 presolve_check_sol(prob);
600 presolve_check_nbasic(prob);
601 #if PRESOLVE_DEBUG > 0
602 std::cout << "Leaving make_fixed_action::presolve." << std::endl;
603 #endif
604 #endif
605
606 return (next);
607 }
608
609 /*
610 Recall that in presolve, make_fixed_action forced a bound to fix a variable,
611 then called remove_fixed_action to empty the column. removed_fixed_action
612 left a postsolve object hanging off faction_, and our first act here is to
613 call r_f_a::postsolve to repopulate the columns. The m_f_a postsolve activity
614 consists of relaxing one of the bounds and making sure that the status is
615 still viable (we can potentially eliminate the bound here).
616 */
postsolve(CoinPostsolveMatrix * prob) const617 void make_fixed_action::postsolve(CoinPostsolveMatrix *prob) const
618 {
619 const action *const actions = actions_;
620 const int nactions = nactions_;
621 const bool fix_to_lower = fix_to_lower_;
622
623 double *clo = prob->clo_;
624 double *cup = prob->cup_;
625 double *sol = prob->sol_;
626 unsigned char *colstat = prob->colstat_;
627
628 #if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
629 #if PRESOLVE_DEBUG > 0
630 std::cout << "Entering make_fixed_action::postsolve." << std::endl;
631 #endif
632 presolve_check_threads(prob);
633 presolve_check_sol(prob, 2, 2, 2);
634 presolve_check_nbasic(prob);
635 #endif
636
637 /*
638 Repopulate the columns.
639 */
640 assert(nactions == faction_->nactions_);
641 faction_->postsolve(prob);
642 /*
643 Walk the actions: restore each bound and check that the status is still
644 appropriate. Given that we're unfixing a fixed variable, it's safe to assume
645 that the unaffected bound is finite.
646 */
647 for (int cnt = nactions - 1; cnt >= 0; cnt--) {
648 const action *f = &actions[cnt];
649 int icol = f->col;
650 double xj = sol[icol];
651
652 assert(faction_->actions_[cnt].col == icol);
653
654 if (fix_to_lower) {
655 double ub = f->bound;
656 cup[icol] = ub;
657 if (colstat) {
658 if (ub >= PRESOLVE_INF || xj != ub) {
659 prob->setColumnStatus(icol,
660 CoinPrePostsolveMatrix::atLowerBound);
661 }
662 }
663 } else {
664 double lb = f->bound;
665 clo[icol] = lb;
666 if (colstat) {
667 if (lb <= -PRESOLVE_INF || xj != lb) {
668 prob->setColumnStatus(icol,
669 CoinPrePostsolveMatrix::atUpperBound);
670 }
671 }
672 }
673 }
674
675 #if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0
676 presolve_check_threads(prob);
677 presolve_check_sol(prob, 2, 2, 2);
678 presolve_check_nbasic(prob);
679 std::cout << "Leaving make_fixed_action::postsolve." << std::endl;
680 #endif
681 return;
682 }
683
684 /*
685 Scan the columns and collect indices of columns that have upper and lower
686 bounds within the zero tolerance of one another. Hand this list to
687 make_fixed_action::presolve() to do the heavy lifting.
688
689 make_fixed_action will compensate for variables which are infeasible, forcing
690 them to feasibility and correcting the row activity, before invoking
691 remove_fixed_action to remove the variable from the problem. If you're
692 confident of feasibility, consider remove_fixed.
693 */
make_fixed(CoinPresolveMatrix * prob,const CoinPresolveAction * next)694 const CoinPresolveAction *make_fixed(CoinPresolveMatrix *prob,
695 const CoinPresolveAction *next)
696 {
697 #if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
698 #if PRESOLVE_DEBUG > 0
699 std::cout
700 << "Entering make_fixed, checking " << prob->ncols_ << " columns."
701 << std::endl;
702 #endif
703 presolve_check_sol(prob);
704 presolve_check_nbasic(prob);
705 #endif
706
707 int ncols = prob->ncols_;
708 int *fcols = prob->usefulColumnInt_;
709 int nfcols = 0;
710
711 int *hincol = prob->hincol_;
712
713 double *clo = prob->clo_;
714 double *cup = prob->cup_;
715
716 for (int i = 0; i < ncols; i++) {
717 if (hincol[i] > 0 && fabs(cup[i] - clo[i]) < ZTOLDP && !prob->colProhibited2(i)) {
718 fcols[nfcols++] = i;
719 }
720 }
721
722 /*
723 Call m_f_a::presolve to do the heavy lifting. This will create a new
724 CoinPresolveAction, which will become the head of the list of
725 CoinPresolveAction's currently pointed to by next.
726
727 No point in going through the effort of a call if there are no fixed
728 variables.
729 */
730 if (nfcols > 0)
731 next = make_fixed_action::presolve(prob, fcols, nfcols, true, next);
732
733 #if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
734 presolve_check_sol(prob);
735 presolve_check_nbasic(prob);
736 #if PRESOLVE_DEBUG > 0
737 std::cout
738 << "Leaving make_fixed, fixed " << nfcols << " columns." << std::endl;
739 #endif
740 #endif
741
742 return (next);
743 }
744
745 /*
746 Transfer the cost coefficient of a column singleton in an equality to the
747 cost coefficients of the remaining variables. Suppose x<s> is the singleton
748 and x<t> is some other variable. For movement delta<t>, there must be
749 compensating change delta<s> = -(a<it>/a<is>)delta<t>. Substituting in the
750 objective, c<s>delta<s> + c<t>delta<t> becomes
751 c<s>(-a<it>/a<is>)delta<t> + c<t>delta<t>
752 (c<t> - c<s>(a<it>/a<is>))delta<t>
753 This is transform (A) below.
754 */
transferCosts(CoinPresolveMatrix * prob)755 void transferCosts(CoinPresolveMatrix *prob)
756 {
757 double *colels = prob->colels_;
758 int *hrow = prob->hrow_;
759 CoinBigIndex *mcstrt = prob->mcstrt_;
760 int *hincol = prob->hincol_;
761
762 double *rowels = prob->rowels_;
763 int *hcol = prob->hcol_;
764 CoinBigIndex *mrstrt = prob->mrstrt_;
765 int *hinrow = prob->hinrow_;
766
767 double *rlo = prob->rlo_;
768 double *rup = prob->rup_;
769 double *clo = prob->clo_;
770 double *cup = prob->cup_;
771 int ncols = prob->ncols_;
772 double *cost = prob->cost_;
773 unsigned char *integerType = prob->integerType_;
774 double bias = prob->dobias_;
775
776 #if PRESOLVE_DEBUG > 0
777 std::cout << "Entering transferCosts." << std::endl;
778 presolve_check_sol(prob);
779 presolve_check_nbasic(prob);
780 #endif
781
782 int numberIntegers = 0;
783 for (int icol = 0; icol < ncols; icol++) {
784 if (integerType[icol])
785 numberIntegers++;
786 }
787 /*
788 For unfixed column singletons in equalities, calculate and install transform
789 (A) described in the comments at the head of the method.
790 */
791 int nchanged = 0;
792 for (int js = 0; js < ncols; js++) {
793 if (cost[js] && hincol[js] == 1 && cup[js] > clo[js]) {
794 const CoinBigIndex &jsstrt = mcstrt[js];
795 const int &i = hrow[jsstrt];
796 if (rlo[i] == rup[i]) {
797 const double ratio = cost[js] / colels[jsstrt];
798 bias += rlo[i] * ratio;
799 const CoinBigIndex &istrt = mrstrt[i];
800 const CoinBigIndex iend = istrt + hinrow[i];
801 for (CoinBigIndex jj = istrt; jj < iend; jj++) {
802 int j = hcol[jj];
803 double aij = rowels[jj];
804 cost[j] -= ratio * aij;
805 }
806 cost[js] = 0.0;
807 nchanged++;
808 }
809 }
810 }
811 #if PRESOLVE_DEBUG > 0
812 if (nchanged)
813 std::cout
814 << " transferred costs for " << nchanged << " singleton columns."
815 << std::endl;
816
817 int nPasses = 0;
818 #endif
819 /*
820 We don't really need a singleton column to do this trick, just an equality.
821 But if the column's not a singleton, it's only worth doing if we can move
822 costs onto integer variables that start with costs of zero. Try and find some
823 unfixed variable with a nonzero cost, that's involved in an equality where
824 there are integer variables with costs of zero. If there's a net gain in the
825 number of integer variables with costs (nThen > nNow), do the transform.
826 One per column, please.
827 */
828 if (numberIntegers) {
829 int changed = -1;
830 while (changed) {
831 changed = 0;
832 for (int js = 0; js < ncols; js++) {
833 if (cost[js] && cup[js] > clo[js]) {
834 const CoinBigIndex &jsstrt = mcstrt[js];
835 const CoinBigIndex jsend = jsstrt + hincol[js];
836 for (CoinBigIndex ii = jsstrt; ii < jsend; ii++) {
837 const int &i = hrow[ii];
838 if (rlo[i] == rup[i]) {
839 int nNow = ((integerType[js]) ? 1 : 0);
840 int nThen = 0;
841 const CoinBigIndex &istrt = mrstrt[i];
842 const CoinBigIndex iend = istrt + hinrow[i];
843 for (CoinBigIndex jj = istrt; jj < iend; jj++) {
844 int j = hcol[jj];
845 if (!cost[j] && integerType[j])
846 nThen++;
847 }
848 if (nThen > nNow) {
849 const double ratio = cost[js] / colels[jsstrt];
850 bias += rlo[i] * ratio;
851 for (CoinBigIndex jj = istrt; jj < iend; jj++) {
852 int j = hcol[jj];
853 double aij = rowels[jj];
854 cost[j] -= ratio * aij;
855 }
856 cost[js] = 0.0;
857 changed++;
858 break;
859 }
860 }
861 }
862 }
863 }
864 if (changed) {
865 nchanged += changed;
866 #if PRESOLVE_DEBUG > 0
867 std::cout
868 << " pass " << nPasses++ << " transferred costs to "
869 << changed << " integer variables." << std::endl;
870 #endif
871 }
872 }
873 }
874 #if PRESOLVE_DEBUG > 0
875 if (bias != prob->dobias_)
876 std::cout << " new bias " << bias << "." << std::endl;
877 #endif
878 prob->dobias_ = bias;
879
880 #if PRESOLVE_DEBUG > 0
881 std::cout << "Leaving transferCosts." << std::endl;
882 presolve_check_sol(prob);
883 presolve_check_nbasic(prob);
884 #endif
885 }
886
887 /* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2
888 */
889