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