Ejemplo n.º 1
0
/*
  We're here to undo the bound changes that were put in place for forcing
  constraints.  This is a bit trickier than it appears.

  Assume we are working with constraint r.  The situation on arrival is
  that constraint r exists and is fully populated with fixed variables, all
  of which are nonbasic. Even though the constraint is tight, the logical
  s(r) is basic and the dual y(r) is zero.
  
  We may need to change that if a bound is relaxed to infinity on some
  variable x(t), making x(t)'s current nonbasic status untenable. We'll need
  to make s(r) nonbasic so that y(r) can be nonzero. Then we can make x(t)
  basic and use y(r) to force cbar(t) to zero. The code below will choose
  the variable x(t) whose reduced cost cbar(t) is most wrong and adjust y(r)
  to drive cbar(t) to zero using
     cbar(t) = c(t) - SUM{i\r} y(i) a(it) - y(r)a(rt)
     cbar(t) = cbar(t\r) - y(r)a(rt)
  Setting cbar(t) to zero,
     y(r) = cbar(t\r)/a(rt)

  We will need to scan row r, correcting cbar(j) for all x(j) entangled
  with the row. We may need to change the nonbasic status of x(j) if the
  adjustment causes cbar(j) to change sign.
*/
void forcing_constraint_action::postsolve(CoinPostsolveMatrix *prob) const
{
  const action *const actions = actions_ ;
  const int nactions = nactions_ ;

  const double *colels = prob->colels_ ;
  const int *hrow = prob->hrow_ ;
  const CoinBigIndex *mcstrt = prob->mcstrt_ ;
  const int *hincol = prob->hincol_ ;
  const int *link = prob->link_ ;

  double *clo = prob->clo_ ;
  double *cup = prob->cup_ ;
  double *rlo = prob->rlo_ ;
  double *rup = prob->rup_ ;

  double *rcosts = prob->rcosts_ ;

  double *acts = prob->acts_ ;
  double *rowduals = prob->rowduals_ ;

  const double ztoldj = prob->ztoldj_ ;
  const double ztolzb = prob->ztolzb_ ;

# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
  const double *sol = prob->sol_ ;
# if PRESOLVE_DEBUG > 0
  std::cout
    << "Entering forcing_constraint_action::postsolve, "
    << nactions << " constraints to process." << std::endl ;
# endif
  presolve_check_threads(prob) ;
  presolve_check_free_list(prob) ;
  presolve_check_sol(prob,2,2,2) ;
  presolve_check_nbasic(prob) ;
# endif
/*
  Open a loop to process the actions. One action per constraint.
*/
  for (const action *f = &actions[nactions-1] ; actions <= f ; f--) {
    const int irow = f->row ;
    const int nlo = f->nlo ;
    const int nup = f->nup ;
    const int ninrow = nlo+nup ;
    const int *rowcols = f->rowcols ;
    const double *bounds = f->bounds ;

#   if PRESOLVE_DEBUG > 1
    std::cout
      << "  Restoring constraint " << irow << ", " << ninrow
      << " variables." << std::endl ;
#   endif

    PRESOLVEASSERT(prob->getRowStatus(irow) == CoinPrePostsolveMatrix::basic) ;
    PRESOLVEASSERT(rowduals[irow] == 0.0) ;
/*
  Process variables where the upper bound is relaxed.
    * If the variable is basic, we should leave the status unchanged. Relaxing
      the bound cannot make nonbasic status feasible.
    * The bound change may be a noop, in which nothing needs to be done.
    * Otherwise, the status should be set to NBLB.
*/
    bool dualfeas = true ;
    for (int k = 0 ; k < nlo ; k++) {
      const int jcol = rowcols[k] ;
      PRESOLVEASSERT(fabs(sol[jcol]-clo[jcol]) <= ztolzb) ;
      const double cbarj = rcosts[jcol] ;
      const double olduj = cup[jcol] ;
      const double newuj = bounds[k] ;
      const bool change = (fabs(newuj-olduj) > ztolzb) ;

#     if PRESOLVE_DEBUG > 2
      std::cout
        << "    x(" << jcol << ") " << prob->columnStatusString(jcol)
	<< " cbar = " << cbarj << ", lb = " << clo[jcol]
	<< ", ub = " << olduj << " -> " << newuj ;
#     endif

      if (change &&
          prob->getColumnStatus(jcol) != CoinPrePostsolveMatrix::basic) {
	prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::atLowerBound) ;
	if (cbarj < -ztoldj || clo[jcol] <= -COIN_DBL_MAX) dualfeas = false ;
      }
      cup[jcol] = bounds[k] ;

#     if PRESOLVE_DEBUG > 2
      std::cout
        << " -> " << prob->columnStatusString(jcol) << "." << std::endl ;
#     endif
    }
/*
  Process variables where the lower bound is relaxed. The comments above
  apply.
*/
    for (int k = nlo ; k < ninrow ; k++) {
      const int jcol = rowcols[k] ;
      PRESOLVEASSERT(fabs(sol[jcol]-cup[jcol]) <= ztolzb) ;
      const double cbarj = rcosts[jcol] ;
      const double oldlj = clo[jcol] ;
      const double newlj = bounds[k] ;
      const bool change = (fabs(newlj-oldlj) > ztolzb) ;

#     if PRESOLVE_DEBUG > 2
      std::cout
        << "    x(" << jcol << ") " << prob->columnStatusString(jcol)
	<< " cbar = " << cbarj << ", ub = " << cup[jcol]
	<< ", lb = " << oldlj << " -> " << newlj ;
#     endif

      if (change &&
          prob->getColumnStatus(jcol) != CoinPrePostsolveMatrix::basic) {
	prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::atUpperBound) ;
	if (cbarj > ztoldj || cup[jcol] >= COIN_DBL_MAX) dualfeas = false ;
      }
      clo[jcol] = bounds[k] ;

#     if PRESOLVE_DEBUG > 2
      std::cout
        << " -> " << prob->columnStatusString(jcol) << "." << std::endl ;
#     endif
    }
/*
  The reduced costs and status for the columns may or may not be ok for
  the relaxed column bounds.  If not, find the variable x<joow> most
  out-of-whack with respect to reduced cost and calculate the value of
  y<irow> required to reduce cbar<joow> to zero.
*/

    if (dualfeas == false) {
      int joow = -1 ;
      double yi = 0.0 ;
      for (int k = 0 ; k < ninrow ; k++) {
	int jcol = rowcols[k] ;
	CoinBigIndex kk = presolve_find_row2(irow,mcstrt[jcol],
					     hincol[jcol],hrow,link) ;
	const double &cbarj = rcosts[jcol] ;
	const CoinPrePostsolveMatrix::Status statj =
					prob->getColumnStatus(jcol) ;
	if ((cbarj < -ztoldj &&
	     statj != CoinPrePostsolveMatrix::atUpperBound) ||
	    (cbarj > ztoldj &&
	     statj != CoinPrePostsolveMatrix::atLowerBound)) {
	  double yi_j = cbarj/colels[kk] ;
	  if (fabs(yi_j) > fabs(yi)) {
	    joow = jcol ;
	    yi = yi_j ;
	  }
#         if PRESOLVE_DEBUG > 3
	  std::cout
	    << "      oow: x(" << jcol << ") "
	    << prob->columnStatusString(jcol) << " cbar " << cbarj << " aij "
	    << colels[kk] << " corr " << yi_j << "." << std::endl ;
#         endif
	}
      }
      assert(joow != -1) ;
/*
  Make x<joow> basic and set the row status according to whether we're
  tight at the lower or upper bound. Keep in mind the convention that a
  <= constraint has a slack 0 <= s <= infty, while a >= constraint has a
  surplus -infty <= s <= 0.
*/

#     if PRESOLVE_DEBUG > 1
      std::cout
	<< "    Adjusting row dual; x(" << joow
	<< ") " << prob->columnStatusString(joow) << " -> "
	<< statusName(CoinPrePostsolveMatrix::basic)
	<< ", y = 0.0 -> " << yi << "." << std::endl ;
#     endif

      prob->setColumnStatus(joow,CoinPrePostsolveMatrix::basic) ;
      if (acts[irow]-rlo[irow] < rup[irow]-acts[irow])
	prob->setRowStatus(irow,CoinPrePostsolveMatrix::atUpperBound) ;
      else
	prob->setRowStatus(irow,CoinPrePostsolveMatrix::atLowerBound) ;
      rowduals[irow] = yi ;

#     if PRESOLVE_DEBUG > 1
      std::cout
	<< "    Row status " << prob->rowStatusString(irow)
	<< ", lb = " << rlo[irow] << ", ax = " << acts[irow]
	<< ", ub = " << rup[irow] << "." << std::endl ;
#     endif
/*
  Now correct the reduced costs for other variables in the row. This may
  cause a reduced cost to change sign, in which case we need to change status.

  The code implicitly assumes that if it's necessary to change the status
  of a variable because the reduced cost has changed sign, then it will be
  possible to do it. I'm not sure I could prove that, however.
  -- lh, 121108 --
*/
      for (int k = 0 ; k < ninrow ; k++) {
	int jcol = rowcols[k] ;
	CoinBigIndex kk = presolve_find_row2(irow,mcstrt[jcol],
					     hincol[jcol],hrow,link) ;
	const double old_cbarj = rcosts[jcol] ;
	rcosts[jcol] -= yi*colels[kk] ;
	const double new_cbarj = rcosts[jcol] ;

	if ((old_cbarj < 0) != (new_cbarj < 0)) {
	  if (new_cbarj < -ztoldj && cup[jcol] < COIN_DBL_MAX)
	    prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::atUpperBound) ;
	  else if (new_cbarj > ztoldj && clo[jcol] > -COIN_DBL_MAX)
	    prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::atLowerBound) ;
	}

#       if PRESOLVE_DEBUG > 3
	const CoinPrePostsolveMatrix::Status statj =
						prob->getColumnStatus(jcol) ;
	std::cout
	  << "      corr: x(" << jcol << ") "
	  << prob->columnStatusString(jcol) << " cbar " << new_cbarj ;
	if ((new_cbarj < -ztoldj &&
	     statj != CoinPrePostsolveMatrix::atUpperBound) ||
	    (new_cbarj > ztoldj &&
	     statj != CoinPrePostsolveMatrix::atLowerBound) ||
	    (statj == CoinPrePostsolveMatrix::basic &&
	     fabs(new_cbarj) > ztoldj))
	  std::cout << " error!" << std::endl ;
	else
	  std::cout << "." << std::endl ;
#       endif

      }
    }
# if PRESOLVE_DEBUG > 0
  presolve_check_nbasic(prob) ;
# endif
  }

# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
  presolve_check_threads(prob) ;
  presolve_check_sol(prob,2,2,2) ;
  presolve_check_nbasic(prob) ;
# if PRESOLVE_DEBUG > 0
  std::cout << "Leaving forcing_constraint_action::postsolve." << std::endl ;
# endif
# endif

}
Ejemplo n.º 2
0
void forcing_constraint_action::postsolve(CoinPostsolveMatrix *prob) const
{
  const action *const actions = actions_;
  const int nactions = nactions_;

  const double *colels	= prob->colels_;
  const int *hrow		= prob->hrow_;
  const CoinBigIndex *mcstrt		= prob->mcstrt_;
  const int *hincol		= prob->hincol_;
  const int *link		= prob->link_;

  //  CoinBigIndex free_list = prob->free_list_;

  double *clo	= prob->clo_;
  double *cup	= prob->cup_;
  double *rlo	= prob->rlo_;
  double *rup	= prob->rup_;

  const double *sol	= prob->sol_;
  double *rcosts	= prob->rcosts_;

  double *acts	= prob->acts_;
  double *rowduals = prob->rowduals_;

  const double ztoldj	= prob->ztoldj_;
  const double ztolzb	= prob->ztolzb_;

  for (const action *f = &actions[nactions-1]; actions<=f; f--) {

    const int irow	= f->row;
    const int nlo	= f->nlo;
    const int nup	= f->nup;
    const int ninrow	= nlo + nup;
    const int *rowcols	= f->rowcols;
    const double *bounds= f->bounds;
    int k;
/*
  Original comment: When we restore bounds here, we need to allow for the
	possibility that the restored bound is infinite. This implies a check
	for viable status.

  Hmmm ... I'm going to argue that in fact we have no choice: the status
  of the variable must reflect the value it was fixed at, else we lose
  feasibility. We don't care what the other bound does.   -- lh, 040903 --
*/
    for (k=0; k<nlo; k++) {
      int jcol = rowcols[k];
      cup[jcol] = bounds[k];
      prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::atLowerBound) ;
/*
      PRESOLVEASSERT(prob->getColumnStatus(jcol)!=CoinPrePostsolveMatrix::basic);
      if (cup[jcol] >= PRESOLVE_INF)
      { CoinPrePostsolveMatrix::Status statj = prob->getColumnStatus(jcol) ;
	if (statj == CoinPrePostsolveMatrix::atUpperBound)
	{ if (clo[jcol] > -PRESOLVE_INF)
	  { statj = CoinPrePostsolveMatrix::atLowerBound ; }
	  else
	  { statj = CoinPrePostsolveMatrix::isFree ; }
	  prob->setColumnStatus(jcol,statj) ; } }
*/
    }

    for (k=nlo; k<ninrow; k++) {
      int jcol = rowcols[k];
      clo[jcol] = bounds[k];
      prob->setColumnStatus(jcol,CoinPrePostsolveMatrix::atUpperBound) ;
/*
      PRESOLVEASSERT(prob->getColumnStatus(jcol)!=CoinPrePostsolveMatrix::basic);
      if (clo[jcol] <= -PRESOLVE_INF)
      { CoinPrePostsolveMatrix::Status statj = prob->getColumnStatus(jcol) ;
	if (statj == CoinPrePostsolveMatrix::atLowerBound)
	{ if (cup[jcol] < PRESOLVE_INF)
	  { statj = CoinPrePostsolveMatrix::atUpperBound ; }
	  else
	  { statj = CoinPrePostsolveMatrix::isFree ; }
	  prob->setColumnStatus(jcol,statj) ; } }
*/
    }

    PRESOLVEASSERT(prob->getRowStatus(irow)==CoinPrePostsolveMatrix::basic);
    PRESOLVEASSERT(rowduals[irow] == 0.0);

    // this is a lazy implementation.
    // we tightened the col bounds, then let them be eliminated
    // by repeated uses of FIX_VARIABLE and a final DROP_ROW.
    // Therefore, by this point the row has been marked basic,
    // the rowdual of this row is 0.0,
    // and the reduced costs for the cols may or may not be ok
    // for the relaxed column bounds.
    //
    // find the one most out of whack and fix it.
    int whacked = -1;
    double whack = 0.0;
    for (k=0; k<ninrow; k++) {
      int jcol = rowcols[k];
      CoinBigIndex kk = presolve_find_row2(irow, mcstrt[jcol], hincol[jcol], hrow, link);

      // choose rowdual to cancel out reduced cost
      double whack0 = rcosts[jcol] / colels[kk];

      if (((rcosts[jcol] > ztoldj  && !(fabs(sol[jcol] - clo[jcol]) <= ztolzb)) ||
	   (rcosts[jcol] < -ztoldj && !(fabs(sol[jcol] - cup[jcol]) <= ztolzb))) &&
	  fabs(whack0) > fabs(whack)) {
	whacked = jcol;
	whack = whack0;
      }
    }

    if (whacked != -1) {
      prob->setColumnStatus(whacked,CoinPrePostsolveMatrix::basic);
      if (acts[irow]-rlo[irow]<rup[irow]-acts[irow])
	prob->setRowStatus(irow,CoinPrePostsolveMatrix::atLowerBound);
      else
	prob->setRowStatus(irow,CoinPrePostsolveMatrix::atUpperBound);
      rowduals[irow] = whack;

      for (k=0; k<ninrow; k++) {
	int jcol = rowcols[k];
	CoinBigIndex kk = presolve_find_row2(irow, mcstrt[jcol], hincol[jcol], hrow, link);
	      
	rcosts[jcol] -= (rowduals[irow] * colels[kk]);
      }
    }
  }

# if PRESOLVE_CONSISTENCY
  presolve_check_threads(prob) ;
# endif

}