Exemplo n.º 1
0
/*
  Original comments from 040916:

  This routine looks to be something of a work in progress.  Down in the
  bound propagation loop, why do we only work with variables with u_j =
  infty? The corresponding section of code for l_j = -infty is ifdef'd away.
  l<j> = -infty is uncommon; perhaps it's not worth the effort?

  Why exclude the code protected by PRESOLVE_TIGHTEN_DUALS? Why are we
  using ekkinf instead of PRESOLVE_INF?
*/
const CoinPresolveAction
  *remove_dual_action::presolve (CoinPresolveMatrix *prob,
				 const CoinPresolveAction *next)
{
# if PRESOLVE_DEBUG > 0
  std::cout
    << "Entering remove_dual_action::presolve, " << prob->nrows_ 
    << "x" << prob->ncols_ << "." << std::endl ;
# endif
# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
  presolve_check_sol(prob,2,1,1) ;
  presolve_check_nbasic(prob) ;
# endif
# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
  int startEmptyRows = 0 ;
  int startEmptyColumns = 0 ;
  startEmptyRows = prob->countEmptyRows() ;
  startEmptyColumns = prob->countEmptyCols() ;
# if COIN_PRESOLVE_TUNING > 0
  double startTime = 0.0 ;
  if (prob->tuning_) startTime = CoinCpuTime() ;
# endif
# endif

  // column-major representation
  const int ncols = prob->ncols_ ;
  const CoinBigIndex *const mcstrt = prob->mcstrt_ ;
  const int *const hincol = prob->hincol_ ;
  const int *const hrow = prob->hrow_ ;
  const double *const colels = prob->colels_ ;
  const double *const cost = prob->cost_ ;

  // column type, bounds, solution, and status
  const unsigned char *const integerType = prob->integerType_ ;
  const double *const clo = prob->clo_ ;
  const double *const cup = prob->cup_ ;
  double *const csol = prob->sol_ ;
  unsigned char *&colstat = prob->colstat_ ;

  // row-major representation
  const int nrows = prob->nrows_ ;
  const CoinBigIndex *const mrstrt = prob->mrstrt_ ;
  const int *const hinrow = prob->hinrow_ ;
  const int *const hcol = prob->hcol_ ;
# if REMOVE_DUAL_ACTION_REPAIR_SOLN > 0
  const double *const rowels = prob->rowels_ ;
# endif

  // row bounds
  double *const rlo = prob->rlo_ ;
  double *const rup = prob->rup_ ;

  // tolerances
  const double ekkinf2 = PRESOLVE_SMALL_INF ;
  const double ekkinf = ekkinf2*1.0e8 ;
  const double ztolcbarj = prob->ztoldj_ ;
  const CoinRelFltEq relEq(prob->ztolzb_) ;

/*
  Grab one of the preallocated scratch arrays to hold min and max values of
  row duals.
*/
  double *ymin	= prob->usefulRowDouble_ ;
  double *ymax	= ymin+nrows ;
/*
  Initialise row dual min/max. The defaults are +/- infty, but if we know
  that the logical has no upper (lower) bound, it can only be nonbasic at
  the other bound. Given minimisation, we can conclude:
    * <= constraint ==> [0,infty] ==> NBLB ==> cbar<i> > 0 ==> y<i> < 0
    * >= constraint ==> [-infty,0] ==> NBUB ==> cbar<i> < 0 ==> y<i> > 0
  Range constraints are not helpful here, the dual can be either sign. There's
  no calculation because we assume the objective coefficient c<i> = 0  and the
  coefficient a<ii> = 1.0, hence cbar<i> = -y<i>.
*/
  for (int i = 0; i < nrows; i++) {
    const bool no_lb = (rup[i] >= ekkinf) ;
    const bool no_ub = (rlo[i] <= -ekkinf) ;

    ymin[i] = ((no_lb && !no_ub)?0.0:(-PRESOLVE_INF)) ;
    ymax[i] = ((no_ub && !no_lb)?0.0:PRESOLVE_INF) ;
  }
/*
  We can do a similar calculation with singleton columns where the variable
  has only one finite bound, but we have to work a bit harder, as the cost
  coefficient c<j> is not necessarily 0.0 and a<ij> is not necessarily 1.0.

  cbar<j> = c<j> - y<i>a<ij>, hence y<i> = c<j>/a<ij> at cbar<j> = 0. The
  question is whether this is an upper or lower bound on y<i>.
    * x<j> NBLB ==> cbar<j> >= 0
      a<ij> > 0 ==> increasing y<i> decreases cbar<j> ==> upper bound 
      a<ij> < 0 ==> increasing y<i> increases cbar<j> ==> lower bound 
    * x<j> NBUB ==> cbar<j> <= 0
      a<ij> > 0 ==> increasing y<i> decreases cbar<j> ==> lower bound 
      a<ij> < 0 ==> increasing y<i> increases cbar<j> ==> upper bound 
  The condition below (simple test for equality to choose the bound) looks
  a bit odd, but a bit of boolean algebra should convince you it's correct.
  We have a bound; the only question is whether it's upper or lower.

  Skip integer variables; it's far too likely that we'll tighten infinite
  bounds elsewhere in presolve.

  NOTE: If bound propagation is applied to continuous variables, the same
  	hazard will apply.  -- lh, 110611 --
*/
  for (int j = 0 ; j < ncols ; j++) {
    if (integerType[j]) continue ;
    if (hincol[j] != 1) continue ;
    const bool no_ub = (cup[j] >= ekkinf) ;
    const bool no_lb = (clo[j] <= -ekkinf) ;
    if (no_ub != no_lb) {
      const int &i = hrow[mcstrt[j]] ;
      double aij = colels[mcstrt[j]] ;
      PRESOLVEASSERT(fabs(aij) > ZTOLDP) ;
      const double yzero = cost[j]/aij ;
      if ((aij > 0.0) == no_ub) {
	if (ymax[i] > yzero)
	  ymax[i] = yzero ;
      } else {
	if (ymin[i] < yzero)
	  ymin[i] = yzero ;
      }
    }
  }
  int nfixup_cols = 0 ;
  int nfixdown_cols = ncols ;
  // Grab another work array, sized to ncols_
  int *fix_cols	= prob->usefulColumnInt_ ;
# if PRESOLVE_TIGHTEN_DUALS > 0
  double *cbarmin = new double[ncols] ;
  double *cbarmax = new double[ncols] ;
# endif
/*
  Now we have (admittedly weak) bounds on the dual for each row. We can use
  these to calculate upper and lower bounds on cbar<j>. Open loops to
  take multiple passes over all columns.
*/
  int nPass = 0 ;
  while (nPass++ < 100) {
    int tightened = 0 ;
    for (int j = 0 ; j < ncols ; j++) {
      if (hincol[j] <= 0) continue ;
/*
  Calculate min cbar<j> and max cbar<j> for the column by calculating the
  contribution to c<j>-ya<j> using ymin<i> and ymax<i> from above.
*/
      const CoinBigIndex &kcs = mcstrt[j] ;
      const CoinBigIndex kce = kcs + hincol[j] ;
      // Number of infinite rows
      int nflagu = 0 ;
      int nflagl = 0 ;
      // Number of ordinary rows
      int nordu = 0 ;
      int nordl = 0 ;
      double cbarjmin = cost[j] ;
      double cbarjmax = cbarjmin ;
      for (CoinBigIndex k = kcs ; k < kce ; k++) {
	const int &i = hrow[k] ;
	const double &aij = colels[k] ;
	const double mindelta = aij*ymin[i] ;
	const double maxdelta = aij*ymax[i] ;
	
	if (aij > 0.0) {
	  if (ymin[i] >= -ekkinf2) {
	    cbarjmax -= mindelta ;
	    nordu++ ;
	  } else {
	    nflagu++ ;
	  }
	  if (ymax[i] <= ekkinf2) {
	    cbarjmin -= maxdelta ;
	    nordl++ ;
	  } else {
	    nflagl++ ;
	  }
	} else {
	  if (ymax[i] <= ekkinf2) {
	    cbarjmax -= maxdelta ;
	    nordu++ ;
	  } else {
	    nflagu++ ;
	  }
	  if (ymin[i] >= -ekkinf2) {
	    cbarjmin -= mindelta ;
	    nordl++ ;
	  } else {
	    nflagl++ ;
	  }
	}
      }
/*
  See if we can tighten bounds on a dual y<t>. See the comments at the head of
  the file for the linear algebra.

  At this point, I don't understand the restrictions on propagation. Neither
  are necessary. The net effect is to severely restrict the circumstances
  where we'll propagate. Requiring nflagu == 1 excludes the case where all
  duals have finite bounds (unlikely?). And why cbarjmax < -ztolcbarj?

  In any event, we're looking for the row that's contributing the infinity. If
  a<tj> > 0, the contribution is due to ymin<t> and we tighten ymax<t>;
  a<tj> < 0, ymax<t> and ymin<t>, respectively.

  The requirement cbarjmax < (ymax[i]*aij-ztolcbarj) ensures we don't propagate
  tiny changes. If we make a change, it will affect cbarjmin. Make the
  adjustment immediately.

  Continuous variables only.
*/
      if (!integerType[j]) {
	if (cup[j] > ekkinf) {
	  if (nflagu == 1 && cbarjmax < -ztolcbarj) {
	    for (CoinBigIndex k = kcs ; k < kce; k++) {
	      const int i = hrow[k] ;
	      const double aij = colels[k] ;
	      if (aij > 0.0 && ymin[i] < -ekkinf2) {
		if (cbarjmax < (ymax[i]*aij-ztolcbarj)) {
		  const double newValue = cbarjmax/aij ;
		  if (ymax[i] > ekkinf2 && newValue <= ekkinf2) {
		    nflagl-- ;
		    cbarjmin -= aij*newValue ;
		  } else if (ymax[i] <= ekkinf2) {
		    cbarjmin -= aij*(newValue-ymax[i]) ;
		  }
#		  if PRESOLVE_DEBUG > 1
		  std::cout
		    << "NDUAL(infu/inf): u(" << j << ") = " << cup[j]
		    << ": max y(" << i << ") was " << ymax[i]
		    << " now " << newValue << "." << std::endl ;
#		  endif
		  ymax[i] = newValue ;
		  tightened++ ;
		}
	      } else if (aij < 0.0 && ymax[i] > ekkinf2) {
		if (cbarjmax < (ymin[i]*aij-ztolcbarj)) {
		  const double newValue = cbarjmax/aij ;
		  if (ymin[i] < -ekkinf2 && newValue >= -ekkinf2) {
		    nflagl-- ;
		    cbarjmin -= aij*newValue ;
		  } else if (ymin[i] >= -ekkinf2) {
		    cbarjmin -= aij*(newValue-ymin[i]) ;
		  }
#		  if PRESOLVE_DEBUG > 1
		  std::cout
		    << "NDUAL(infu/inf): u(" << j << ") = " << cup[j]
		    << ": min y(" << i << ") was " << ymin[i]
		    << " now " << newValue << "." << std::endl ;
#		  endif
		  ymin[i] = newValue ;
		  tightened++ ;
		  // Huh? asymmetric 
		  // cbarjmin = 0.0 ;
		}
	      }
	    }
	  } else if (nflagl == 0 && nordl == 1 && cbarjmin < -ztolcbarj) {
/*
  This is a column singleton. Why are we doing this? It's not like changes
  to other y will affect this.
*/
	    for (CoinBigIndex k = kcs; k < kce; k++) {
	      const int i = hrow[k] ;
	      const double aij = colels[k] ;
	      if (aij > 0.0) {
#		if PRESOLVE_DEBUG > 1
		std::cout
		  << "NDUAL(infu/sing): u(" << j << ") = " << cup[j]
		  << ": max y(" << i << ") was " << ymax[i]
		  << " now " << ymax[i]+cbarjmin/aij << "." << std::endl ;
#		endif
		ymax[i] += cbarjmin/aij ;
		cbarjmin = 0.0 ;
		tightened++ ;
	      } else if (aij < 0.0 ) {
#		if PRESOLVE_DEBUG > 1
		std::cout
		  << "NDUAL(infu/sing): u(" << j << ") = " << cup[j]
		  << ": min y(" << i << ") was " << ymin[i]
		  << " now " << ymin[i]+cbarjmin/aij << "." << std::endl ;
#		endif
		ymin[i] += cbarjmin/aij ;
		cbarjmin = 0.0 ;
		tightened++ ;
	      }
	    }
	  }
	}   // end u<j> = infty
#       if PROCESS_INFINITE_LB
/*
  Unclear why this section is commented out, except for the possibility that
  bounds of -infty < x < something are rare and it likely suffered fromm the
  same errors. Consider the likelihood that this whole block needs to be
  edited to sway min/max, & similar.
*/
	if (clo[j]<-ekkinf) {
	  // cbarj can not be positive
	  if (cbarjmin > ztolcbarj&&nflagl == 1) {
	    // We can make bound finite one way
	    for (CoinBigIndex k = kcs; k < kce; k++) {
	      const int i = hrow[k] ;
	      const double coeff = colels[k] ;
	      
	      if (coeff < 0.0&&ymin[i] < -ekkinf2) {
		// ymax[i] has upper bound
		if (cbarjmin>ymax[i]*coeff+ztolcbarj) {
		  const double newValue = cbarjmin/coeff ;
		  // re-compute hi
		  if (ymax[i] > ekkinf2 && newValue <= ekkinf2) {
		    nflagu-- ;
		    cbarjmax -= coeff * newValue ;
		  } else if (ymax[i] <= ekkinf2) {
		    cbarjmax -= coeff * (newValue-ymax[i]) ;
		  }
		  ymax[i] = newValue ;
		  tightened++ ;
#		  if PRESOLVE_DEBUG > 1
		  printf("Col %d, row %d max pi now %g\n",j,i,ymax[i]) ;
#		  endif
		}
	      } else if (coeff > 0.0 && ymax[i] > ekkinf2) {
		// ymin[i] has lower bound
		if (cbarjmin>ymin[i]*coeff+ztolcbarj) {
		  const double newValue = cbarjmin/coeff ;
		  // re-compute lo
		  if (ymin[i] < -ekkinf2 && newValue >= -ekkinf2) {
		    nflagu-- ;
		    cbarjmax -= coeff * newValue ;
		  } else if (ymin[i] >= -ekkinf2) {
		    cbarjmax -= coeff*(newValue-ymin[i]) ;
		  }
		  ymin[i] = newValue ;
		  tightened++ ;
#		  if PRESOLVE_DEBUG > 1
		  printf("Col %d, row %d min pi now %g\n",j,i,ymin[i]) ;
#		  endif
		}
	      }
	    }
	  } else if (nflagu == 0 && nordu == 1 && cbarjmax > ztolcbarj) {
	    // We may be able to tighten
	    for (CoinBigIndex k = kcs; k < kce; k++) {
	      const int i = hrow[k] ;
	      const double coeff = colels[k] ;
	      
	      if (coeff < 0.0) {
		ymax[i] += cbarjmax/coeff ;
		cbarjmax =0.0 ;
		tightened++ ;
#		if PRESOLVE_DEBUG > 1
		printf("Col %d, row %d max pi now %g\n",j,i,ymax[i]) ;
#		endif
	      } else if (coeff > 0.0 ) {
		ymin[i] += cbarjmax/coeff ;
		cbarjmax =0.0 ;
		tightened++ ;
#		if PRESOLVE_DEBUG > 1
		printf("Col %d, row %d min pi now %g\n",j,i,ymin[i]) ;
#		endif
	      }
	    }
	  }
	}    // end l<j> < -infty
#       endif	// PROCESS_INFINITE_LB
      }
/*
  That's the end of propagation of bounds for dual variables.
*/
#     if PRESOLVE_TIGHTEN_DUALS > 0
      cbarmin[j] = (nflagl?(-PRESOLVE_INF):cbarjmin) ;
      cbarmax[j] = (nflagu?PRESOLVE_INF:cbarjmax) ;
#     endif
/*
  If cbarmin<j> > 0 (strict inequality) then x<j> NBLB at optimality. If l<j>
  is -infinity, notify the user and set the status to unbounded.
*/
      if (cbarjmin > ztolcbarj && nflagl == 0 && !prob->colProhibited2(j)) {
	if (clo[j] <= -ekkinf) {
	  CoinMessageHandler *msghdlr = prob->messageHandler() ;
	  msghdlr->message(COIN_PRESOLVE_COLUMNBOUNDB,prob->messages())
	    << j << CoinMessageEol ;
	  prob->status_ |= 2 ;
	  break ;
	} else {
	  fix_cols[--nfixdown_cols] = j ;
#	  if PRESOLVE_DEBUG > 1
	  std::cout << "NDUAL(fix l): fix x(" << j << ")" ;
	  if (csol) std::cout << " = " << csol[j] ;
	  std::cout
	    << " at l(" << j << ") = " << clo[j] << "; cbar("
	    << j << ") > " << cbarjmin << "." << std::endl ;
#	  endif
	  if (csol) {
#           if REMOVE_DUAL_ACTION_REPAIR_SOLN > 0
/*
  Original comment: User may have given us feasible solution - move if simple

  Except it's not simple. The net result is that we end up with an excess of
  basic variables. Mark x<j> NBLB and let the client recalculate the solution
  after establishing the basis.
*/
	    if (csol[j]-clo[j] > 1.0e-7 && hincol[j] == 1) {
	      double value_j = colels[mcstrt[j]] ;
	      double distance_j = csol[j]-clo[j] ;
	      int row = hrow[mcstrt[j]] ;
	      // See if another column can take value
	      for (CoinBigIndex kk = mrstrt[row] ; kk < mrstrt[row]+hinrow[row] ; kk++) {
		const int k = hcol[kk] ;
		if (colstat[k] == CoinPrePostsolveMatrix::superBasic)
		  continue ;

		if (hincol[k] == 1 && k != j) {
		  const double value_k = rowels[kk] ;
		  double movement ;
		  if (value_k*value_j>0.0) {
		    // k needs to increase
		    double distance_k = cup[k]-csol[k] ;
		    movement = CoinMin((distance_j*value_j)/value_k,distance_k) ;
		  } else {
		    // k needs to decrease
		    double distance_k = clo[k]-csol[k] ;
		    movement = CoinMax((distance_j*value_j)/value_k,distance_k) ;
		  }
		  if (relEq(movement,0)) continue ;

		  csol[k] += movement ;
		  if (relEq(csol[k],clo[k]))
		  { colstat[k] = CoinPrePostsolveMatrix::atLowerBound ; }
		  else
		  if (relEq(csol[k],cup[k]))
		  { colstat[k] = CoinPrePostsolveMatrix::atUpperBound ; }
		  else
		  if (colstat[k] != CoinPrePostsolveMatrix::isFree)
		  { colstat[k] = CoinPrePostsolveMatrix::basic ; }
		  printf("NDUAL: x<%d> moved %g to %g; ",
			 k,movement,csol[k]) ;
		  printf("lb = %g, ub = %g, status now %s.\n",
			 clo[k],cup[k],columnStatusString(k)) ;
		  distance_j -= (movement*value_k)/value_j ;
		  csol[j] -= (movement*value_k)/value_j ;
		  if (distance_j<1.0e-7)
		    break ;
		}
	      }
	    }
#	    endif    // repair solution.

	    csol[j] = clo[j] ;
	    colstat[j] = CoinPrePostsolveMatrix::atLowerBound ;
	  }
	}
      } else if (cbarjmax < -ztolcbarj && nflagu == 0 &&
      		 !prob->colProhibited2(j)) {
/*
  If cbarmax<j> < 0 (strict inequality) then x<j> NBUB at optimality. If u<j>
  is infinity, notify the user and set the status to unbounded.
*/
	if (cup[j] >= ekkinf) {
	  CoinMessageHandler *msghdlr = prob->messageHandler() ;
	  msghdlr->message(COIN_PRESOLVE_COLUMNBOUNDA,prob->messages())
	    << j << CoinMessageEol ;
	  prob->status_ |= 2 ;
	  break ;
	} else {
	  fix_cols[nfixup_cols++] = j ;
#	  if PRESOLVE_DEBUG > 1
	  std::cout << "NDUAL(fix u): fix x(" << j << ")" ;
	  if (csol) std::cout << " = " << csol[j] ;
	  std::cout
	    << " at u(" << j << ") = " << cup[j] << "; cbar("
	    << j << ") < " << cbarjmax << "." << std::endl ;
#	  endif
	  if (csol) {
#	    if 0
	    // See comments above for 'fix at lb'.
	    if (cup[j]-csol[j] > 1.0e-7 && hincol[j] == 1) {
	      double value_j = colels[mcstrt[j]] ;
	      double distance_j = csol[j]-cup[j] ;
	      int row = hrow[mcstrt[j]] ;
	      // See if another column can take value
	      for (CoinBigIndex kk = mrstrt[row] ; kk < mrstrt[row]+hinrow[row] ; kk++) {
		const int k = hcol[kk] ;
		if (colstat[k] == CoinPrePostsolveMatrix::superBasic)
		  continue ;

		if (hincol[k] == 1 && k != j) {
		  const double value_k = rowels[kk] ;
		  double movement ;
		  if (value_k*value_j<0.0) {
		    // k needs to increase
		    double distance_k = cup[k]-csol[k] ;
		    movement = CoinMin((distance_j*value_j)/value_k,distance_k) ;
		  } else {
		    // k needs to decrease
		    double distance_k = clo[k]-csol[k] ;
		    movement = CoinMax((distance_j*value_j)/value_k,distance_k) ;
		  }
		  if (relEq(movement,0)) continue ;

		  csol[k] += movement ;
		  if (relEq(csol[k],clo[k]))
		  { colstat[k] = CoinPrePostsolveMatrix::atLowerBound ; }
		  else
		  if (relEq(csol[k],cup[k]))
		  { colstat[k] = CoinPrePostsolveMatrix::atUpperBound ; }
		  else
		  if (colstat[k] != CoinPrePostsolveMatrix::isFree)
		  { colstat[k] = CoinPrePostsolveMatrix::basic ; }
		  printf("NDUAL: x<%d> moved %g to %g; ",
			 k,movement,csol[k]) ;
		  printf("lb = %g, ub = %g, status now %s.\n",
			 clo[k],cup[k],columnStatusString(k)) ;
		  distance_j -= (movement*value_k)/value_j ;
		  csol[j] -= (movement*value_k)/value_j ;
		  if (distance_j>-1.0e-7)
		    break ;
		}
	      }
	    }
#	    endif
	    csol[j] = cup[j] ;
	    colstat[j] = CoinPrePostsolveMatrix::atUpperBound ;
	  }
	}
      }    // end cbar<j> < 0
    }
/*
  That's the end of this walk through the columns.
*/
    // I don't know why I stopped doing this.
#   if PRESOLVE_TIGHTEN_DUALS > 0
    const double *rowels	= prob->rowels_ ;
    const int *hcol	= prob->hcol_ ;
    const CoinBigIndex *mrstrt	= prob->mrstrt_ ;
    int *hinrow	= prob->hinrow_ ;
    // tighten row dual bounds, as described on p. 229
    for (int i = 0; i < nrows; i++) {
      const bool no_ub = (rup[i] >= ekkinf) ;
      const bool no_lb = (rlo[i] <= -ekkinf) ;

      if ((no_ub ^ no_lb) == true) {
	const CoinBigIndex krs = mrstrt[i] ;
	const CoinBigIndex kre = krs + hinrow[i] ;
	const double rmax  = ymax[i] ;
	const double rmin  = ymin[i] ;

	// all row columns are non-empty
	for (CoinBigIndex k = krs ; k < kre ; k++) {
	  const double coeff = rowels[k] ;
	  const int icol = hcol[k] ;
	  const double cbarmax0 = cbarmax[icol] ;
	  const double cbarmin0 = cbarmin[icol] ;

	  if (no_ub) {
	    // cbarj must not be negative
	    if (coeff > ZTOLDP2 &&
	    	cbarjmax0 < PRESOLVE_INF && cup[icol] >= ekkinf) {
	      const double bnd = cbarjmax0 / coeff ;
	      if (rmax > bnd) {
#		if PRESOLVE_DEBUG > 1
		printf("MAX TIGHT[%d,%d]: %g --> %g\n",i,hrow[k],ymax[i],bnd) ;
#		endif
		ymax[i] = rmax = bnd ;
		tightened ++; ;
	      }
	    } else if (coeff < -ZTOLDP2 &&
	    	       cbarjmax0 <PRESOLVE_INF && cup[icol] >= ekkinf) {
	      const double bnd = cbarjmax0 / coeff ;
	      if (rmin < bnd) {
#		if PRESOLVE_DEBUG > 1
		printf("MIN TIGHT[%d,%d]: %g --> %g\n",i,hrow[k],ymin[i],bnd) ;
#		endif
		ymin[i] = rmin = bnd ;
		tightened ++; ;
	      }
	    }
	  } else {	// no_lb
	    // cbarj must not be positive
	    if (coeff > ZTOLDP2 &&
	    	cbarmin0 > -PRESOLVE_INF && clo[icol] <= -ekkinf) {
	      const double bnd = cbarmin0 / coeff ;
	      if (rmin < bnd) {
#		if PRESOLVE_DEBUG > 1
		printf("MIN1 TIGHT[%d,%d]: %g --> %g\n",i,hrow[k],ymin[i],bnd) ;
#		endif
		ymin[i] = rmin = bnd ;
		tightened ++; ;
	      }
	    } else if (coeff < -ZTOLDP2 &&
	    	       cbarmin0 > -PRESOLVE_INF && clo[icol] <= -ekkinf) {
	      const double bnd = cbarmin0 / coeff ;
	      if (rmax > bnd) {
#		if PRESOLVE_DEBUG > 1
		printf("MAX TIGHT1[%d,%d]: %g --> %g\n",i,hrow[k],ymax[i],bnd) ;
#		endif
		ymax[i] = rmax = bnd ;
		tightened ++; ;
	      }
	    }
	  }
	}
      }
    }
#   endif    // PRESOLVE_TIGHTEN_DUALS
/*
  Is it productive to continue with another pass? Essentially, we need lots of
  tightening but no fixing. If we fixed any variables, break and process them.
*/
#   if PRESOLVE_DEBUG > 1
    std::cout
      << "NDUAL: pass " << nPass << ": fixed " << (ncols-nfixdown_cols)
      << " down, " << nfixup_cols << " up, tightened " << tightened
      << " duals." << std::endl ;
#   endif
    if (tightened < 100 || nfixdown_cols < ncols || nfixup_cols)
      break ;
  }
  assert (nfixup_cols <= nfixdown_cols) ;
/*
  Process columns fixed at upper bound.
*/
  if (nfixup_cols) {
#   if PRESOLVE_DEBUG > 1
    std::cout << "NDUAL(upper):" ;
    for (int k = 0 ; k < nfixup_cols ; k++)
      std::cout << " " << fix_cols[k] ;
    std::cout << "." << std::endl ;
#   endif
    next = make_fixed_action::presolve(prob,fix_cols,nfixup_cols,false,next) ;
  }
/*
  Process columns fixed at lower bound.
*/
  if (nfixdown_cols < ncols) {
    int *fixdown_cols = fix_cols+nfixdown_cols ; 
    nfixdown_cols = ncols-nfixdown_cols ;
#   if PRESOLVE_DEBUG > 1
    std::cout << "NDUAL(lower):" ;
    for (int k = 0 ; k < nfixdown_cols ; k++)
      std::cout << " " << fixdown_cols[k] ;
    std::cout << "." << std::endl ;
#   endif
    next = make_fixed_action::presolve(prob,fixdown_cols,
    				       nfixdown_cols,true,next) ;
  }
/*
  Now look for variables that, when moved in the favourable direction
  according to reduced cost, will naturally tighten an inequality to an
  equality. We can convert that inequality to an equality. See the comments
  at the head of the routine.

  Start with logicals. Open a loop and look for suitable rows. At the
  end of this loop, rows marked with +/-1 will be forced to equality by
  their logical. Rows marked with +/-2 are inequalities that (perhaps)
  can be forced to equality using architecturals. Rows marked with 0 are
  not suitable (range or nonbinding).

  Note that usefulRowInt_ is 3*nrows_; we'll use the second partition below.
*/
  int *canFix = prob->usefulRowInt_ ;
  for (int i = 0 ; i < nrows ; i++) {
    const bool no_rlb = (rlo[i] <= -ekkinf) ;
    const bool no_rub = (rup[i] >= ekkinf) ;
    canFix[i] = 0 ;
    if (no_rub && !no_rlb ) {
      if (ymin[i] > 0.0) 
	canFix[i] = -1 ;
      else
	canFix[i] = -2 ;
    } else if (no_rlb && !no_rub ) {
      if (ymax[i] < 0.0)
	canFix[i] = 1 ;
      else
	canFix[i] = 2 ;
    }
#   if PRESOLVE_DEBUG > 1
    if (abs(canFix[i]) == 1) {
      std::cout
        << "NDUAL(eq): candidate row (" << i << ") (" << rlo[i]
	<< "," << rup[i] << "), logical must be "
	<< ((canFix[i] == -1)?"NBUB":"NBLB") << "." << std::endl ;
    }
#   endif
  }
/*
  Can we do a similar trick with architectural variables? Here, we're looking
  for x<j> such that
  (1) Exactly one of l<j> or u<j> is infinite.
  (2) Moving x<j> towards the infinite bound can tighten exactly one
      constraint i to equality.  If x<j> is entangled with other constraints,
      moving x<j> towards the infinite bound will loosen those constraints.
  (3) Moving x<j> towards the infinite bound is a good idea according to the
      cost c<j> (note we don't have to consider reduced cost here).
  If we can find a suitable x<j>, constraint i can become an equality.

  This is yet another instance of bound propagation, but we're looking for
  a very specific pattern: A variable that can be increased arbitrarily
  in all rows it's entangled with, except for one, which bounds it. And
  we're going to push the variable so as to make that row an equality.
  But note what we're *not* doing: No actual comparison of finite bound
  values to the amount necessary to force an equality. So no worries about
  accuracy, the bane of bound propagation.

  Open a loop to scan columns. bindingUp and bindingDown indicate the result
  of the analysis; -1 says `possible', -2 is ruled out. Test first for
  condition (1). Column singletons are presumably handled elsewhere. Integer
  variables need not apply. If both bounds are finite, no need to look
  further.
*/
  for (int j = 0 ; j < ncols ; j++) {
    if (hincol[j] <= 1) continue ;
    if (integerType[j]) continue ;
    int bindingUp = -1 ;
    int bindingDown = -1 ;
    if (cup[j] < ekkinf)
      bindingUp = -2 ;
    if (clo[j] > -ekkinf)
      bindingDown = -2 ;
    if (bindingUp == -2 && bindingDown == -2) continue ;
/*
  Open a loop to walk the column and check for condition (2).

  The test for |canFix[i]| != 2 is a non-interference check. We don't want to
  mess with constraints where we've already decided to use the logical to
  force equality. Nor do we want to deal with range or nonbinding constraints.
*/
    const CoinBigIndex &kcs = mcstrt[j] ;
    const CoinBigIndex kce = kcs+hincol[j] ;
    for (CoinBigIndex k = kcs; k < kce; k++) {
      const int &i = hrow[k] ;
      if (abs(canFix[i]) != 2) {
	bindingUp = -2 ;
	bindingDown = -2 ;
	break ;
      }
      double aij = colels[k] ;
/*
  For a<ij> > 0 in a <= constraint (canFix = 2), the up direction is
  binding. For a >= constraint, it'll be the down direction. If the relevant
  binding code is still -1, set it to the index of the row. Similarly for
  a<ij> < 0.

  If this is the second or subsequent binding constraint in that direction,
  set binding[Up,Down] to -2 (we don't want to get into the business of
  calculating which constraint is actually binding).
*/
      if (aij > 0.0) {
	if (canFix[i] == 2) {
	  if (bindingUp == -1)
	    bindingUp = i ;
	  else
	    bindingUp = -2 ;
	} else {
	  if (bindingDown == -1)
	    bindingDown = i ;
	  else
	    bindingDown = -2 ;
	}
      } else {
	if (canFix[i] == 2) {
	  if (bindingDown == -1)
	    bindingDown = i ;
	  else
	    bindingDown = -2 ;
	} else {
	  if (bindingUp == -1)
	    bindingUp = i ;
	  else
	    bindingUp = -2 ;
	}
      }
    }
    if (bindingUp == -2 && bindingDown == -2) continue ;
/*
  If bindingUp > -2, then either no constraint provided a bound (-1) or
  there's a single constraint (0 <= i < m) that bounds x<j>.  If we have
  just one binding constraint, check that the reduced cost is favourable
  (c<j> <= 0 for x<j> NBUB at optimum for minimisation). If so, declare
  that we will force the row to equality (canFix[i] = +/-1). Note that we
  don't adjust the primal solution value for x<j>.

  If no constraint provided a bound, we might be headed for unboundedness,
  but leave that for some other code to determine.
*/
    double cj = cost[j] ;
    if (bindingUp > -2 && cj <= 0.0) {
      if (bindingUp >= 0) {
	canFix[bindingUp] /= 2 ;
#       if PRESOLVE_DEBUG > 1
	std::cout
	  << "NDUAL(eq): candidate row (" << bindingUp << ") ("
	  << rlo[bindingUp] << "," << rup[bindingUp] << "), "
	  << " increasing x(" << j << "), cbar = " << cj << "."
	  << std::endl ;
      } else {
          std::cout
	    << "NDUAL(eq): no binding upper bound for x(" << j
	    << "), cbar = " << cj << "." << std::endl ;
#        endif
      }
    } else if (bindingDown > -2 && cj >= 0.0) {
      if (bindingDown >= 0) {
	canFix[bindingDown] /= 2 ;
#       if PRESOLVE_DEBUG > 1
	std::cout
	  << "NDUAL(eq): candidate row (" << bindingDown << ") ("
	  << rlo[bindingDown] << "," << rup[bindingDown] << "), "
	  << " decreasing x(" << j << "), cbar = " << cj << "."
	  << std::endl ;
      } else {
          std::cout
	    << "NDUAL(eq): no binding lower bound for x(" << j
	    << "), cbar = " << cj << "." << std::endl ;
#        endif
      }
    }
  }
/*
  We have candidate rows. We've avoided scanning full rows until now,
  but there's one remaining hazard: if the row contains unfixed integer
  variables then we don't want to just pin the row to a fixed rhs; that
  might prevent us from achieving integrality. Scan canFix, count and
  record suitable rows (use the second partition of usefulRowInt_).
*/
# if PRESOLVE_DEBUG > 0
  int makeEqCandCnt = 0 ;
  for (int i = 0 ; i < nrows ; i++) {
    if (abs(canFix[i]) == 1) makeEqCandCnt++ ;
  }
# endif
  int makeEqCnt = nrows ;
  for (int i = 0 ; i < nrows ; i++) {
    if (abs(canFix[i]) == 1) {
      const CoinBigIndex &krs = mrstrt[i] ;
      const CoinBigIndex kre = krs+hinrow[i] ;
      for (CoinBigIndex k = krs ; k < kre ; k++) {
	const int j = hcol[k] ;
	if (cup[j] > clo[j] && (integerType[j]||prob->colProhibited2(j))) {
	  canFix[i] = 0 ;
#	  if PRESOLVE_DEBUG > 1
	  std::cout
	    << "NDUAL(eq): cannot convert row " << i << " to equality; "
	    << "unfixed integer variable x(" << j << ")." << std::endl ;
#         endif
          break ;
	}
      }
      if (canFix[i] != 0) canFix[makeEqCnt++] = i ;
    }
  }
  makeEqCnt -= nrows ;
# if PRESOLVE_DEBUG > 0
  if ((makeEqCandCnt-makeEqCnt) > 0) {
    std::cout
      << "NDUAL(eq): rejected " << (makeEqCandCnt-makeEqCnt)
      << " rows due to unfixed integer variables." << std::endl ;
  }
# endif
/*
  If we've identified inequalities to convert, do the conversion, record
  the information needed to restore bounds in postsolve, and finally create
  the postsolve object.
*/
  if (makeEqCnt > 0) {
    action *bndRecords = new action[makeEqCnt] ;
    for (int k = 0 ; k < makeEqCnt ; k++) {
      const int &i = canFix[k+nrows] ;
#     if PRESOLVE_DEBUG > 1
      std::cout << "NDUAL(eq): forcing row " << i << " to equality;" ;
      if (canFix[i] == -1)
	std::cout << " dropping b = " << rup[i] << " to " << rlo[i] ;
      else
	std::cout << " raising blow = " << rlo[i] << " to " << rup[i] ;
      std::cout << "." << std::endl ;
#     endif
      action &bndRec = bndRecords[(k)] ;
      bndRec.rlo_ = rlo[i] ;
      bndRec.rup_ = rup[i] ;
      bndRec.ndx_ = i ;
      if (canFix[i] == 1) {
	rlo[i] = rup[i] ;
	prob->addRow(i) ;
      } else if (canFix[i] == -1) {
	rup[i] = rlo[i] ;
	prob->addRow(i) ;
      }
    }
    next = new remove_dual_action(makeEqCnt,bndRecords,next) ;
  }

# if PRESOLVE_TIGHTEN_DUALS > 0
  delete[] cbarmin ;
  delete[] cbarmax ;
# endif

# if COIN_PRESOLVE_TUNING > 0
  double thisTime = 0.0 ;
  if (prob->tuning_) thisTime = CoinCpuTime() ;
# endif
# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
  presolve_check_sol(prob,2,1,1) ;
  presolve_check_nbasic(prob) ;
# endif
# if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0
  int droppedRows = prob->countEmptyRows()-startEmptyRows ;
  int droppedColumns = prob->countEmptyCols()-startEmptyColumns ;
  std::cout
    << "Leaving remove_dual_action::presolve, dropped " << droppedRows
    << " rows, " << droppedColumns << " columns, forced "
    << makeEqCnt << " equalities" ;
# if COIN_PRESOLVE_TUNING > 0
  if (prob->tuning_)
    std::cout << " in " << (thisTime-prob->startTime_) << "s" ;
# endif
  std::cout << "." << std::endl ;
# endif

  return (next) ;
}
Exemplo n.º 2
0
/*
  This routine looks to be something of a work in progres. See the comment
  that begins with `Gack!'. And down in the bound propagation loop, why do we
  only work with variables with u_j = infty? The corresponding section of code
  for l_j = -infty is ifdef'd away. And why exclude the code protected by
  PRESOLVE_TIGHTEN_DUALS? And why are we using ekkinf instead of PRESOLVE_INF?

  There is no postsolve action because once we've identified a variable to fix
  we can invoke make_fixed_action.
*/
const CoinPresolveAction *remove_dual_action::presolve(CoinPresolveMatrix *prob,
				   const CoinPresolveAction *next)
{
  double startTime = 0.0;
  int startEmptyRows=0;
  int startEmptyColumns = 0;
  if (prob->tuning_) {
    startTime = CoinCpuTime();
    startEmptyRows = prob->countEmptyRows();
    startEmptyColumns = prob->countEmptyCols();
  }
  double *colels	= prob->colels_;
  int *hrow		= prob->hrow_;
  CoinBigIndex *mcstrt		= prob->mcstrt_;
  int *hincol		= prob->hincol_;
  int ncols		= prob->ncols_;

  double *clo	= prob->clo_;
  double *cup	= prob->cup_;
  unsigned char *colstat = prob->colstat_ ;

  // Used only in `fix if simple' section below. Remove dec'l to avoid
  // GCC compile warning.
  // double *rowels	= prob->rowels_;
  int *hcol		= prob->hcol_;
  CoinBigIndex *mrstrt		= prob->mrstrt_;
  int *hinrow		= prob->hinrow_;
  double *csol	= prob->sol_;
  int nrows		= prob->nrows_;

  double *rlo	= prob->rlo_;
  double *rup	= prob->rup_;

  double *dcost	= prob->cost_;
  const unsigned char *integerType = prob->integerType_;

  const double maxmin	= prob->maxmin_;

  const double ekkinf = 1e28;
  const double ekkinf2 = 1e20;
  const double ztoldj = prob->ztoldj_;

  CoinRelFltEq relEq(prob->ztolzb_) ;

  double *rdmin	= prob->usefulRowDouble_; //new double[nrows];
  double *rdmax	= reinterpret_cast<double *> (prob->usefulRowInt_); //new double[nrows];

# if PRESOLVE_DEBUG
  std::cout << "Entering remove_dual_action::presolve, " << nrows << " X " << ncols << "." << std::endl ;
  presolve_check_sol(prob) ;
  presolve_check_nbasic(prob) ;
# endif

  // This combines the initialization of rdmin/rdmax to extreme values
  // (PRESOLVE_INF/-PRESOLVE_INF) with a version of the next loop specialized
  // for row slacks.
  // In this case, it is always the case that dprice==0.0 and coeff==1.0.
  int i;
  for ( i = 0; i < nrows; i++) {
    double sup = -rlo[i];	// slack ub; corresponds to cup[j]
    double slo = -rup[i];	// slack lb; corresponds to clo[j]
    bool no_lb = (slo <= -ekkinf);
    bool no_ub = (sup >= ekkinf);

    // here, dj==-row dual
    // the row slack has no lower bound, but it does have an upper bound,
    // then the reduced cost must be <= 0, so the row dual must be >= 0
    rdmin[i] = (no_lb && !no_ub) ? 0.0 : -PRESOLVE_INF;

    rdmax[i] = (no_ub && !no_lb) ? 0.0 :  PRESOLVE_INF;
  }

  // Look for col singletons and update bounds on dual costs
  // Take the min of the maxes and max of the mins
  int j;
  for ( j = 0; j<ncols; j++) {
    if (integerType[j])
      continue; // even if it has infinite bound now ....
    bool no_ub = (cup[j] >= ekkinf);
    bool no_lb = (clo[j] <= -ekkinf);

    if (hincol[j] == 1 &&

	// we need singleton cols that have exactly one bound
	(no_ub ^ no_lb)) {
      int row = hrow[mcstrt[j]];
      double coeff = colels[mcstrt[j]];

      PRESOLVEASSERT(fabs(coeff) > ZTOLDP);

      // I don't think the sign of dcost[j] matters

      // this row dual would make this col's reduced cost be 0
      double dprice = maxmin * dcost[j] / coeff;

      // no_ub == !no_lb
      // no_ub ==> !(dj<0)
      // no_lb ==> !(dj>0)
      // I don't think the case where !no_ub has actually been tested
      if ((coeff > 0.0) == no_ub) {
	// coeff>0 ==> making the row dual larger would make dj *negative*
	//		==> dprice is an upper bound on dj if no *ub*
	// coeff<0 ==> making the row dual larger would make dj *positive*
	//		==> dprice is an upper bound on dj if no *lb*
	if (rdmax[row] > dprice)	// reduced cost may be positive
	  rdmax[row] = dprice;
      } else if ((coeff < 0.0) == no_lb) { // no lower bound
	if (rdmin[row] < dprice) 	// reduced cost may be negative
	  rdmin[row] = dprice;
      }
    }
  }

  int *fix_cols	= prob->usefulColumnInt_; //new int[ncols];

  //int *fixdown_cols	= new int[ncols];

#if	PRESOLVE_TIGHTEN_DUALS
  double *djmin	= new double[ncols];
  double *djmax	= new double[ncols];
#endif
  int nfixup_cols	= 0;
  int nfixdown_cols	= ncols;

  int nPass=100;
  while (nPass-->0) {
    int tightened = 0;
    /* Perform duality tests */
    for (int j = 0; j<ncols; j++) {
      if (hincol[j] > 0) {
	CoinBigIndex kcs = mcstrt[j];
	CoinBigIndex kce = kcs + hincol[j];
	// Number of infinite rows
	int nflagu = 0;
	int nflagl = 0;
	// Number of ordinary rows
	int nordu = 0;
	int nordl = 0;
	double ddjlo = maxmin * dcost[j];
	double ddjhi = ddjlo;

	for (CoinBigIndex k = kcs; k < kce; k++) {
	  int i = hrow[k];
	  double coeff = colels[k];

	  if (coeff > 0.0) {
	    if (rdmin[i] >= -ekkinf2) {
	      ddjhi -= coeff * rdmin[i];
	      nordu ++;
	    } else {
	      nflagu ++;
	    }
	    if (rdmax[i] <= ekkinf2) {
	      ddjlo -= coeff * rdmax[i];
	      nordl ++;
	    } else {
	      nflagl ++;
	    }
	  } else {
	    if (rdmax[i] <= ekkinf2) {
	      ddjhi -= coeff * rdmax[i];
	      nordu ++;
	    } else {
	      nflagu ++;
	    }
	    if (rdmin[i] >= -ekkinf2) {
	      ddjlo -= coeff * rdmin[i];
	      nordl ++;
	    } else {
	      nflagl ++;
	    }
	  }
	}
	// See if we may be able to tighten a dual
	if (!integerType[j]) {
	  if (cup[j]>ekkinf) {
	    // dj can not be negative
	    if (nflagu==1&&ddjhi<-ztoldj) {
	      // We can make bound finite one way
	      for (CoinBigIndex k = kcs; k < kce; k++) {
		int i = hrow[k];
		double coeff = colels[k];

		if (coeff > 0.0&&rdmin[i] < -ekkinf2) {
		  // rdmax[i] has upper bound
		  if (ddjhi<rdmax[i]*coeff-ztoldj) {
		    double newValue = ddjhi/coeff;
		    // re-compute lo
		    if (rdmax[i] > ekkinf2 && newValue <= ekkinf2) {
		      nflagl--;
		      ddjlo -= coeff * newValue;
		    } else if (rdmax[i] <= ekkinf2) {
		      ddjlo -= coeff * (newValue-rdmax[i]);
		    }
		    rdmax[i] = newValue;
		    tightened++;
#if	PRESOLVE_DEBUG
		    printf("Col %d, row %d max pi now %g\n",j,i,rdmax[i]);
#endif
		  }
		} else if (coeff < 0.0 && rdmax[i] > ekkinf2) {
		  // rdmin[i] has lower bound
		  if (ddjhi<rdmin[i]*coeff-ztoldj) {
		    double newValue = ddjhi/coeff;
		    // re-compute lo
		    if (rdmin[i] < -ekkinf2 && newValue >= -ekkinf2) {
		      nflagl--;
		      ddjlo -= coeff * newValue;
		    } else if (rdmax[i] >= -ekkinf2) {
		      ddjlo -= coeff * (newValue-rdmin[i]);
		    }
		    rdmin[i] = newValue;
		    tightened++;
#if	PRESOLVE_DEBUG
		    printf("Col %d, row %d min pi now %g\n",j,i,rdmin[i]);
#endif
		    ddjlo = 0.0;
		  }
		}
	      }
	    } else if (nflagl==0&&nordl==1&&ddjlo<-ztoldj) {
	      // We may be able to tighten
	      for (CoinBigIndex k = kcs; k < kce; k++) {
		int i = hrow[k];
		double coeff = colels[k];

		if (coeff > 0.0) {
		  rdmax[i] += ddjlo/coeff;
		  ddjlo =0.0;
		  tightened++;
#if	PRESOLVE_DEBUG
		  printf("Col %d, row %d max pi now %g\n",j,i,rdmax[i]);
#endif
		} else if (coeff < 0.0 ) {
		  rdmin[i] += ddjlo/coeff;
		  ddjlo =0.0;
		  tightened++;
#if	PRESOLVE_DEBUG
		  printf("Col %d, row %d min pi now %g\n",j,i,rdmin[i]);
#endif
		}
	      }
	    }
	  }
#if 0
	  if (clo[j]<-ekkinf) {
	    // dj can not be positive
	    if (ddjlo>ztoldj&&nflagl==1) {
	      // We can make bound finite one way
	      for (CoinBigIndex k = kcs; k < kce; k++) {
		int i = hrow[k];
		double coeff = colels[k];

		if (coeff < 0.0&&rdmin[i] < -ekkinf2) {
		  // rdmax[i] has upper bound
		  if (ddjlo>rdmax[i]*coeff+ztoldj) {
		    double newValue = ddjlo/coeff;
		    // re-compute hi
		    if (rdmax[i] > ekkinf2 && newValue <= ekkinf2) {
		      nflagu--;
		      ddjhi -= coeff * newValue;
		    } else if (rdmax[i] <= ekkinf2) {
		      ddjhi -= coeff * (newValue-rdmax[i]);
		    }
		    rdmax[i] = newValue;
		    tightened++;
#if	PRESOLVE_DEBUG
		    printf("Col %d, row %d max pi now %g\n",j,i,rdmax[i]);
#endif
		  }
		} else if (coeff > 0.0 && rdmax[i] > ekkinf2) {
		  // rdmin[i] has lower bound
		  if (ddjlo>rdmin[i]*coeff+ztoldj) {
		    double newValue = ddjlo/coeff;
		    // re-compute lo
		    if (rdmin[i] < -ekkinf2 && newValue >= -ekkinf2) {
		      nflagu--;
		      ddjhi -= coeff * newValue;
		    } else if (rdmax[i] >= -ekkinf2) {
		      ddjhi -= coeff * (newValue-rdmin[i]);
		    }
		    rdmin[i] = newValue;
		    tightened++;
#if	PRESOLVE_DEBUG
		    printf("Col %d, row %d min pi now %g\n",j,i,rdmin[i]);
#endif
		  }
		}
	      }
	    } else if (nflagu==0&&nordu==1&&ddjhi>ztoldj) {
	      // We may be able to tighten
	      for (CoinBigIndex k = kcs; k < kce; k++) {
		int i = hrow[k];
		double coeff = colels[k];

		if (coeff < 0.0) {
		  rdmax[i] += ddjhi/coeff;
		  ddjhi =0.0;
		  tightened++;
#if	PRESOLVE_DEBUG
		  printf("Col %d, row %d max pi now %g\n",j,i,rdmax[i]);
#endif
		} else if (coeff > 0.0 ) {
		  rdmin[i] += ddjhi/coeff;
		  ddjhi =0.0;
		  tightened++;
#if	PRESOLVE_DEBUG
		  printf("Col %d, row %d min pi now %g\n",j,i,rdmin[i]);
#endif
		}
	      }
	    }
	  }
#endif
	}

#if	PRESOLVE_TIGHTEN_DUALS
	djmin[j] = (nflagl ?  -PRESOLVE_INF : ddjlo);
	djmax[j] = (nflagu ? PRESOLVE_INF : ddjhi);
#endif

	if (ddjlo > ztoldj && nflagl == 0&&!prob->colProhibited2(j)) {
	  // dj>0 at optimality ==> must be at lower bound
	  if (clo[j] <= -ekkinf) {
	    prob->messageHandler()->message(COIN_PRESOLVE_COLUMNBOUNDB,
					    prob->messages())
					      <<j
					      <<CoinMessageEol;
	    prob->status_ |= 2;
	    break;
	  } else {
	    fix_cols[--nfixdown_cols] = j;
	    PRESOLVE_DETAIL_PRINT(printf("pre_duallo %dC E\n",j));
#	    if PRESOLVE_DEBUG
	    printf("NDUAL: fixing x<%d>",fix_cols[nfixdown_cols]) ;
	    if (csol) printf(" = %g",csol[j]) ;
	    printf(" at lb = %g.\n",clo[j]) ;
#	    endif
	    //if (csol[j]-clo[j]>1.0e-7)
	    //printf("down %d row %d nincol %d\n",j,hrow[mcstrt[j]],hincol[j]);
	    // User may have given us feasible solution - move if simple
	    if (csol) {
# if 0
	/*
	  Except it's not simple. The net result is that we end up with an
	  excess of basic variables.
	*/
	      if (csol[j]-clo[j]>1.0e-7&&hincol[j]==1) {
		double value_j = colels[mcstrt[j]];
		double distance_j = csol[j]-clo[j];
		int row=hrow[mcstrt[j]];
		// See if another column can take value
		for (CoinBigIndex kk=mrstrt[row];kk<mrstrt[row]+hinrow[row];kk++) {
		  int k = hcol[kk];
		  if (colstat[k] == CoinPrePostsolveMatrix::superBasic)
		    continue ;

		  if (hincol[k]==1&&k!=j) {
		    double value_k = rowels[kk];
		    double movement;
		    if (value_k*value_j>0.0) {
		      // k needs to increase
		      double distance_k = cup[k]-csol[k];
		      movement = CoinMin((distance_j*value_j)/value_k,distance_k);
		    } else {
		      // k needs to decrease
		      double distance_k = clo[k]-csol[k];
		      movement = CoinMax((distance_j*value_j)/value_k,distance_k);
		    }
		    if (relEq(movement,0)) continue ;

		    csol[k] += movement;
		    if (relEq(csol[k],clo[k]))
		    { colstat[k] = CoinPrePostsolveMatrix::atLowerBound ; }
		    else
		    if (relEq(csol[k],cup[k]))
		    { colstat[k] = CoinPrePostsolveMatrix::atUpperBound ; }
		    else
		    if (colstat[k] != CoinPrePostsolveMatrix::isFree)
		    { colstat[k] = CoinPrePostsolveMatrix::basic ; }
		    printf("NDUAL: x<%d> moved %g to %g; ",
			   k,movement,csol[k]) ;
		    printf("lb = %g, ub = %g, status now %s.\n",
			   clo[k],cup[k],columnStatusString(colstat[k])) ;
		    distance_j -= (movement*value_k)/value_j;
		    csol[j] -= (movement*value_k)/value_j;
		    if (distance_j<1.0e-7)
		      break;
		  }
		}
	      }
# endif		// repair solution.

	      csol[j] = clo[j] ;	// but the bottom line is we've changed x<j>
	      colstat[j] = CoinPrePostsolveMatrix::atLowerBound ;
	    }
	  }
	} else if (ddjhi < -ztoldj && nflagu == 0&&!prob->colProhibited2(j)) {
	  // dj<0 at optimality ==> must be at upper bound
	  if (cup[j] >= ekkinf) {
	    prob->messageHandler()->message(COIN_PRESOLVE_COLUMNBOUNDA,
					    prob->messages())
					      <<j
					      <<CoinMessageEol;
	    prob->status_ |= 2;
	    break;
	  } else {
	    PRESOLVE_DETAIL_PRINT(printf("pre_dualup %dC E\n",j));
	    fix_cols[nfixup_cols++] = j;
#	    if PRESOLVE_DEBUG
	    printf("NDUAL: fixing x<%d>",fix_cols[nfixup_cols-1]) ;
	    if (csol) printf(" = %g",csol[j]) ;
	    printf(" at ub = %g.\n",cup[j]) ;
#	    endif
	    // User may have given us feasible solution - move if simple
	    // See comments for `fix at lb' case above.
	    //if (cup[j]-csol[j]>1.0e-7)
	    //printf("up %d row %d nincol %d\n",j,hrow[mcstrt[j]],hincol[j]);
	    if (csol) {
# if 0
	// See comments above.
	      if (cup[j]-csol[j]>1.0e-7&&hincol[j]==1) {
		double value_j = colels[mcstrt[j]];
		double distance_j = csol[j]-cup[j];
		int row=hrow[mcstrt[j]];
		// See if another column can take value
		for (CoinBigIndex kk=mrstrt[row];kk<mrstrt[row]+hinrow[row];kk++) {
		  int k = hcol[kk];
		  if (colstat[k] == CoinPrePostsolveMatrix::superBasic)
		    continue ;

		  if (hincol[k]==1&&k!=j) {
		    double value_k = rowels[kk];
		    double movement;
		    if (value_k*value_j<0.0) {
		      // k needs to increase
		      double distance_k = cup[k]-csol[k];
		      movement = CoinMin((distance_j*value_j)/value_k,distance_k);
		    } else {
		      // k needs to decrease
		      double distance_k = clo[k]-csol[k];
		      movement = CoinMax((distance_j*value_j)/value_k,distance_k);
		    }
		    if (relEq(movement,0)) continue ;

		    csol[k] += movement;
		    if (relEq(csol[k],clo[k]))
		    { colstat[k] = CoinPrePostsolveMatrix::atLowerBound ; }
		    else
		    if (relEq(csol[k],cup[k]))
		    { colstat[k] = CoinPrePostsolveMatrix::atUpperBound ; }
		    else
		    if (colstat[k] != CoinPrePostsolveMatrix::isFree)
		    { colstat[k] = CoinPrePostsolveMatrix::basic ; }
		    printf("NDUAL: x<%d> moved %g to %g; ",
			   k,movement,csol[k]) ;
		    printf("lb = %g, ub = %g, status now %s.\n",
			   clo[k],cup[k],columnStatusString(colstat[k])) ;
		    distance_j -= (movement*value_k)/value_j;
		    csol[j] -= (movement*value_k)/value_j;
		    if (distance_j>-1.0e-7)
		      break;
		  }
		}
	      }
# endif
	      csol[j] = cup[j] ;	// but the bottom line is we've changed x<j>
	      colstat[j] = CoinPrePostsolveMatrix::atUpperBound ;
	    }
	  }
	}
      }
    }

    // I don't know why I stopped doing this.
#if	PRESOLVE_TIGHTEN_DUALS
    const double *rowels	= prob->rowels_;
    const int *hcol	= prob->hcol_;
    const CoinBigIndex *mrstrt	= prob->mrstrt_;
    int *hinrow	= prob->hinrow_;
    // tighten row dual bounds, as described on p. 229
    for (int i = 0; i < nrows; i++) {
      bool no_ub = (rup[i] >= ekkinf);
      bool no_lb = (rlo[i] <= -ekkinf);

      if ((no_ub ^ no_lb) == true) {
	CoinBigIndex krs = mrstrt[i];
	CoinBigIndex kre = krs + hinrow[i];
	double rmax  = rdmax[i];
	double rmin  = rdmin[i];

	// all row columns are non-empty
	for (CoinBigIndex k=krs; k<kre; k++) {
	  double coeff = rowels[k];
	  int icol = hcol[k];
	  double djmax0 = djmax[icol];
	  double djmin0 = djmin[icol];

	  if (no_ub) {
	    // dj must not be negative
	    if (coeff > ZTOLDP2 && djmax0 <PRESOLVE_INF && cup[icol]>=ekkinf) {
	      double bnd = djmax0 / coeff;
	      if (rmax > bnd) {
#if	PRESOLVE_DEBUG
		printf("MAX TIGHT[%d,%d]:  %g --> %g\n", i,hrow[k], rdmax[i], bnd);
#endif
		rdmax[i] = rmax = bnd;
		tightened ++;
	      }
	    } else if (coeff < -ZTOLDP2 && djmax0 <PRESOLVE_INF && cup[icol] >= ekkinf) {
	      double bnd = djmax0 / coeff ;
	      if (rmin < bnd) {
#if	PRESOLVE_DEBUG
		printf("MIN TIGHT[%d,%d]:  %g --> %g\n", i, hrow[k], rdmin[i], bnd);
#endif
		rdmin[i] = rmin = bnd;
		tightened ++;
	      }
	    }
	  } else {	// no_lb
	    // dj must not be positive
	    if (coeff > ZTOLDP2 && djmin0 > -PRESOLVE_INF && clo[icol]<=-ekkinf) {
	      double bnd = djmin0 / coeff ;
	      if (rmin < bnd) {
#if	PRESOLVE_DEBUG
		printf("MIN1 TIGHT[%d,%d]:  %g --> %g\n", i, hrow[k], rdmin[i], bnd);
#endif
		rdmin[i] = rmin = bnd;
		tightened ++;
	      }
	    } else if (coeff < -ZTOLDP2 && djmin0 > -PRESOLVE_INF && clo[icol] <= -ekkinf) {
	      double bnd = djmin0 / coeff ;
	      if (rmax > bnd) {
#if	PRESOLVE_DEBUG
		printf("MAX TIGHT1[%d,%d]:  %g --> %g\n", i,hrow[k], rdmax[i], bnd);
#endif
		rdmax[i] = rmax = bnd;
		tightened ++;
	      }
	    }
	  }
	}
      }
    }
#endif

    if (tightened<100||nfixdown_cols<ncols||nfixup_cols)
      break;
#if	PRESOLVE_TIGHTEN_DUALS
    else
      printf("DUAL TIGHTENED!  %d\n", tightened);
#endif
  }
  assert (nfixup_cols<=nfixdown_cols);
  if (nfixup_cols) {
#if	PRESOLVE_DEBUG
    printf("NDUAL: %d up", nfixup_cols);
    for (i = 0 ; i < nfixup_cols ; i++) printf(" %d",fix_cols[i]) ;
    printf(".\n") ;
#endif
    next = make_fixed_action::presolve(prob, fix_cols, nfixup_cols, false, next);
  }

  if (nfixdown_cols<ncols) {
    int * fixdown_cols = fix_cols+nfixdown_cols;
    nfixdown_cols = ncols-nfixdown_cols;
#if	PRESOLVE_DEBUG
    printf("NDUAL: %d down", nfixdown_cols);
    for (i = 0 ; i < nfixdown_cols ; i++) printf(" %d",fixdown_cols[i]) ;
    printf(".\n") ;
#endif
    next = make_fixed_action::presolve(prob, fixdown_cols, nfixdown_cols, true, next);
  }
  // If dual says so then we can make equality row
  // Also if cost is in right direction and only one binding row for variable
  // We may wish to think about giving preference to rows with 2 or 3 elements
/*
  Gack! Ok, I can appreciate the thought here, but I'm seriously skeptical
  about writing canFix[0] before reading rdmin[0]. After that, we should be out
  of the interference zone for the typical situation where sizeof(double) is
  twice sizeof(int).
*/
  int * canFix = reinterpret_cast<int *> (rdmin);
  for ( i = 0; i < nrows; i++) {
    bool no_lb = (rlo[i] <= -ekkinf);
    bool no_ub = (rup[i] >= ekkinf);
    canFix[i]=0;
    if (no_ub && !no_lb ) {
      if ( rdmin[i]>0.0)
	canFix[i]=-1;
      else
	canFix[i]=-2;
    } else if (no_lb && !no_ub ) {
      if (rdmax[i]<0.0)
	canFix[i]=1;
      else
	canFix[i]=2;
    }
  }
  for (j = 0; j<ncols; j++) {
    if (hincol[j]<=1)
      continue;
    if (integerType[j])
      continue; // even if it has infinite bound now ....
    CoinBigIndex kcs = mcstrt[j];
    CoinBigIndex kce = kcs + hincol[j];
    int bindingUp=-1;
    int bindingDown=-1;
    if (cup[j]<ekkinf)
      bindingUp=-2;
    if (clo[j]>-ekkinf)
      bindingDown=-2;
    for (CoinBigIndex k = kcs; k < kce; k++) {
      int i = hrow[k];
      if (abs(canFix[i])!=2) {
	bindingUp=-2;
	bindingDown=-2;
	break;
      }
      double coeff = colels[k];
      if (coeff>0.0) {
	if (canFix[i]==2) {
	  // binding up
	  if (bindingUp==-1)
	    bindingUp = i;
	  else
	    bindingUp = -2;
	} else {
	  // binding down
	  if (bindingDown==-1)
	    bindingDown = i;
	  else
	    bindingDown = -2;
	}
      } else {
	if (canFix[i]==2) {
	  // binding down
	  if (bindingDown==-1)
	    bindingDown = i;
	  else
	    bindingDown = -2;
	} else {
	  // binding up
	  if (bindingUp==-1)
	    bindingUp = i;
	  else
	    bindingUp = -2;
	}
      }
    }
    double cost = maxmin * dcost[j];
    if (bindingUp>-2&&cost<=0.0) {
      // might as well make equality
      if (bindingUp>=0) {
	canFix[bindingUp] /= 2; //So -2 goes to -1 etc
	//printf("fixing row %d to ub by %d\n",bindingUp,j);
      } else {
	//printf("binding up row by %d\n",j);
      }
    } else if (bindingDown>-2 &&cost>=0.0) {
      // might as well make equality
      if (bindingDown>=0) {
	canFix[bindingDown] /= 2; //So -2 goes to -1 etc
	//printf("fixing row %d to lb by %d\n",bindingDown,j);
      } else {
	//printf("binding down row by %d\n",j);
      }
    }
  }
  // can't fix if integer and non-unit coefficient
  //const double *rowels	= prob->rowels_;
  //const int *hcol	= prob->hcol_;
  //const CoinBigIndex *mrstrt	= prob->mrstrt_;
  //int *hinrow	= prob->hinrow_;
  for ( i = 0; i < nrows; i++) {
    if (abs(canFix[i])==1) {
      CoinBigIndex krs = mrstrt[i];
      CoinBigIndex kre = krs + hinrow[i];
      for (CoinBigIndex k=krs; k<kre; k++) {
	int icol = hcol[k];
	if (cup[icol]>clo[icol]&&integerType[icol]) {
	  canFix[i]=0; // not safe
#ifdef COIN_DEVELOP
	  printf("no dual something CoinPresolveDual row %d col %d\n",
		 i,icol);
#endif
	}
      }
    }
    if (canFix[i]==1) {
      rlo[i]=rup[i];
      prob->addRow(i);
    } else if (canFix[i]==-1) {
      rup[i]=rlo[i];
      prob->addRow(i);
    }
  }

  //delete[]rdmin;
  //delete[]rdmax;

  //delete[]fixup_cols;
  //delete[]fixdown_cols;

#if	PRESOLVE_TIGHTEN_DUALS
  delete[]djmin;
  delete[]djmax;
#endif

  if (prob->tuning_) {
    double thisTime=CoinCpuTime();
    int droppedRows = prob->countEmptyRows() - startEmptyRows;
    int droppedColumns =  prob->countEmptyCols() - startEmptyColumns;
    printf("CoinPresolveDual(1) - %d rows, %d columns dropped in time %g, total %g\n",
	   droppedRows,droppedColumns,thisTime-startTime,thisTime-prob->startTime_);
  }

# if PRESOLVE_DEBUG
  presolve_check_sol(prob) ;
  presolve_check_nbasic(prob) ;
  std::cout << "Leaving remove_dual_action::presolve." << std::endl ;
# endif

  return (next);
}