/*
  Reintroduce the column (y) and doubleton row (irow) removed in presolve.
  Correct the other column (x) involved in the doubleton, update the solution,
  etc.

  A fair amount of complication arises because the presolve transform saves the
  shorter of x or y. Postsolve thus includes portions to restore either.
*/
void doubleton_action::postsolve(CoinPostsolveMatrix *prob) const
{
  const action *const actions = actions_ ;
  const int nactions = nactions_ ;

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

  double *clo	= prob->clo_ ;
  double *cup	= prob->cup_ ;

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

  double *dcost	= prob->cost_ ;

  double *sol	= prob->sol_ ;
  double *acts	= prob->acts_ ;
  double *rowduals = prob->rowduals_ ;
  double *rcosts = prob->rcosts_ ;

  unsigned char *colstat = prob->colstat_ ;
  unsigned char *rowstat = prob->rowstat_ ;

  const double maxmin	= prob->maxmin_ ;

  CoinBigIndex &free_list = prob->free_list_ ;

  const double ztolzb	= prob->ztolzb_ ;
  const double ztoldj	= prob->ztoldj_ ;
  const double ztolzero = 1.0e-12 ;

  int nrows = prob->nrows_ ;

  // Arrays to rebuild the unsaved column.
  int *index1 = new int[nrows] ;
  double *element1 = new double[nrows] ;
  CoinZeroN(element1,nrows) ;

# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
  char *cdone	= prob->cdone_ ;
  char *rdone	= prob->rdone_ ;

  presolve_check_threads(prob) ;
  presolve_check_sol(prob,2,2,2) ;
  presolve_check_nbasic(prob) ;
  presolve_check_reduced_costs(prob) ;

# if PRESOLVE_DEBUG > 0
  std::cout
    << "Entering doubleton_action::postsolve, " << nactions
    << " transforms to undo." << std::endl ;
# endif
# endif
/*
  The outer loop: step through the doubletons in this array of actions.
  The first activity is to unpack the doubleton.
*/
  for (const action *f = &actions[nactions-1] ; actions <= f ; f--) {

    const int irow = f->row ;
    const double lo0 = f->clox ;
    const double up0 = f->cupx ;


    const double coeffx = f->coeffx ;
    const double coeffy = f->coeffy ;
    const int jcolx = f->icolx ;
    const int jcoly = f->icoly ;

    const double rhs = f->rlo ;

#   if PRESOLVE_DEBUG > 2
    std::cout
      << std::endl
      << "  restoring doubleton " << irow << ", elim x(" << jcoly
      << "), kept x(" << jcolx << "); stored col " ;
    if (f->ncoly)
      std::cout << jcoly ;
    else 
      std::cout << jcolx ;
    std::cout << "." << std::endl ;
    std::cout
      << "  x(" << jcolx << ") " << prob->columnStatusString(jcolx) << " "
      << clo[jcolx] << " <= " << sol[jcolx] << " <= " << cup[jcolx]
      << "; cj " << f->costx << " dj " << rcosts[jcolx] << "." << std::endl ;
#   endif
/*
  jcolx is in the problem (for whatever reason), and the doubleton row (irow)
  and column (jcoly) have only been processed by empty row/column postsolve
  (i.e., reintroduced with length 0).
*/
    PRESOLVEASSERT(cdone[jcolx] && rdone[irow] == DROP_ROW) ;
    PRESOLVEASSERT(cdone[jcoly] == DROP_COL) ;

/*
  Restore bounds for doubleton row, bounds and objective coefficient for x,
  objective for y.

  Original comment: restoration of rlo and rup likely isn't necessary.
*/
    rlo[irow] = f->rlo ;
    rup[irow] = f->rlo ;

    clo[jcolx] = lo0 ;
    cup[jcolx] = up0 ;

    dcost[jcolx] = f->costx ;
    dcost[jcoly] = f->costy ;

/*
  Set primal solution for y (including status) and row activity for the
  doubleton row. The motivation (up in presolve) for wanting coeffx < coeffy
  is to avoid inflation into sol[y]. Since this is a (satisfied) equality,
  activity is the rhs value and the logical is nonbasic.
*/
    const double diffy = rhs-coeffx*sol[jcolx] ;
    if (fabs(diffy) < ztolzero)
      sol[jcoly] = 0 ;
    else
      sol[jcoly] = diffy/coeffy ;
    acts[irow] = rhs ;
    if (rowstat)
      prob->setRowStatus(irow,CoinPrePostsolveMatrix::atLowerBound) ;

#   if PRESOLVE_DEBUG > 2
/*
  Original comment: I've forgotten what this is about

  We have sol[y] = (rhs - coeffx*sol[x])/coeffy. As best I can figure,
  the original check here tested for the possibility of loss of significant
  digits through cancellation, followed by inflation if coeffy is small.
  The hazard is clear enough, but the test was puzzling. Overly complicated
  and it generated false warnings for the common case of sol[y] a clean zero.
  Replaced with something that I hope is more useful. The tolerances are, sad
  to say, completely arbitrary.    -- lh, 121106 --
*/
    if ((fabs(diffy) < 1.0e-6) && (fabs(diffy) >= ztolzero) &&
        (fabs(coeffy) < 1.0e-3))
      std::cout
        << "  loss of significance? rhs " << rhs
	<< " (coeffx*sol[jcolx])" << (coeffx*sol[jcolx])
	<< " diff " << diffy << "." << std::endl ;
#   endif

/*
  Time to get into the correction/restoration of coefficients for columns x
  and y, with attendant correction of row bounds and activities. Accumulate
  partial reduced costs (missing the contribution from the doubleton row) so
  that we can eventually calculate a dual for the doubleton row.
*/
    double djy = maxmin*dcost[jcoly] ;
    double djx = maxmin*dcost[jcolx] ;
/*
  We saved column y in the action, so we'll use it to reconstruct column x.
  There are two aspects: correction of existing x coefficients, and fill in.
  Given
    coeffx'[k] = coeffx[k]+coeffy[k]*coeff_factor
  we have
    coeffx[k] = coeffx'[k]-coeffy[k]*coeff_factor
  where
    coeff_factor = -coeffx[dblton]/coeffy[dblton].

  Keep in mind that the major vector stored in the action does not include
  the coefficient from the doubleton row --- the doubleton coefficients are
  held in coeffx and coeffy.
*/
    if (f->ncoly) {
      int ncoly = f->ncoly-1 ;
      int *indy = reinterpret_cast<int *>(f->colel+ncoly) ;
/*
  Rebuild a threaded column y, starting with the end of the thread and working
  back to the beginning. In the process, accumulate corrections to column x
  in element1 and index1. Fix row bounds and activity as we go (add back the
  constant correction removed in presolve), and accumulate contributions to
  the reduced cost for y. Don't tweak finite infinity.

  The PRESOLVEASSERT says this row should already be present. 
*/
      int ystart = NO_LINK ;
      int nX = 0 ;
      for (int kcol = 0 ; kcol < ncoly ; ++kcol) {
	const int i = indy[kcol] ;
	PRESOLVEASSERT(rdone[i]) ;

	double yValue = f->colel[kcol] ;

	if (-PRESOLVE_INF < rlo[i])
	  rlo[i] += (yValue*rhs)/coeffy ;
	if (rup[i] < PRESOLVE_INF)
	  rup[i] += (yValue*rhs)/coeffy ;

	acts[i] += (yValue*rhs)/coeffy ;

	djy -= rowduals[i]*yValue ;
/*
  Link the coefficient into column y: Acquire the first free slot in the
  bulk arrays and store the row index and coefficient. Then link the slot
  in front of coefficients we've already processed.
*/
	const CoinBigIndex kfree = free_list ;
	assert(kfree >= 0 && kfree < prob->bulk0_) ;
	free_list = link[free_list] ;
	hrow[kfree] = i ;
	colels[kfree] = yValue ;
	link[kfree] = ystart ;
	ystart = kfree ;

#       if PRESOLVE_DEBUG > 4
	std::cout
	  << "  link y " << kfree << " row " << i << " coeff " << yValue
	  << " dual " << rowduals[i] << std::endl ;
#       endif
/*
  Calculate and store the correction to the x coefficient.
*/
	yValue = (yValue*coeffx)/coeffy ;
	element1[i] = yValue ;
	index1[nX++] = i ;
      }
#     if PRESOLVE_CONSISTENCY > 0
      presolve_check_free_list(prob) ;
#     endif
/*
  Handle the coefficients of the doubleton row. Insert coeffy, coeffx.
*/
      const CoinBigIndex kfree = free_list ;
      assert(kfree >= 0 && kfree < prob->bulk0_) ;
      free_list = link[free_list] ;
      hrow[kfree] = irow ;
      colels[kfree] = coeffy ;
      link[kfree] = ystart ;
      ystart = kfree ;

#     if PRESOLVE_DEBUG > 4
      std::cout
	<< "  link y " << kfree << " row " << irow << " coeff " << coeffy
	<< " dual n/a" << std::endl ;
#     endif

      element1[irow] = coeffx ;
      index1[nX++] = irow ;
/*
  Attach the threaded column y to mcstrt and record the length.
*/
      mcstrt[jcoly] = ystart ;
      hincol[jcoly] = f->ncoly ;
/*
  Now integrate the corrections to column x. Scan the column and correct the
  existing entries.  The correction could cancel the existing coefficient and
  we don't want to leave an explicit zero. In this case, relink the column
  around it.  The freed slot is linked at the beginning of the free list.
*/
      CoinBigIndex kcs = mcstrt[jcolx] ;
      CoinBigIndex last_nonzero = NO_LINK ;
      int numberInColumn = hincol[jcolx] ;
      const int numberToDo = numberInColumn ;
      for (int kcol = 0 ; kcol < numberToDo ; ++kcol) {
	const int i = hrow[kcs] ;
	assert(i >= 0 && i < nrows && i != irow) ;
	double value = colels[kcs]+element1[i] ;
	element1[i] = 0.0 ;
	if (fabs(value) >= 1.0e-15) {
	  colels[kcs] = value ;
	  last_nonzero = kcs ;
	  kcs = link[kcs] ;
	  djx -= rowduals[i]*value ;

#         if PRESOLVE_DEBUG > 4
	  std::cout
	    << "  link x " << last_nonzero << " row " << i << " coeff "
	    << value << " dual " << rowduals[i] << std::endl ;
#         endif

	} else {

#         if PRESOLVE_DEBUG > 4
	  std::cout
	    << "  link x skipped row  " << i << " dual "
	    << rowduals[i] << std::endl ;
#         endif

	  numberInColumn-- ;
	  // add to free list
	  int nextk = link[kcs] ;
	  assert(free_list >= 0) ;
	  link[kcs] = free_list ;
	  free_list = kcs ;
	  assert(kcs >= 0) ;
	  kcs = nextk ;
	  if (last_nonzero != NO_LINK)
	    link[last_nonzero] = kcs ;
	  else
	    mcstrt[jcolx] = kcs ;
	}
      }
      if (last_nonzero != NO_LINK)
	link[last_nonzero] = NO_LINK ;
/*
  We've dealt with the existing nonzeros in column x. Any remaining
  nonzeros in element1 will be fill in, which we insert at the beginning of
  the column.
*/
      for (int kcol = 0 ; kcol < nX ; kcol++) {
	const int i = index1[kcol] ;
	double xValue = element1[i] ;
	element1[i] = 0.0 ;
	if (fabs(xValue) >= 1.0e-15) {
	  if (i != irow)
	    djx -= rowduals[i]*xValue ;
	  numberInColumn++ ;
	  CoinBigIndex kfree = free_list ;
	  assert(kfree >= 0 && kfree < prob->bulk0_) ;
	  free_list = link[free_list] ;
	  hrow[kfree] = i ;
	  PRESOLVEASSERT(rdone[hrow[kfree]] || (hrow[kfree] == irow)) ;
	  colels[kfree] = xValue ;
	  link[kfree] = mcstrt[jcolx] ;
	  mcstrt[jcolx] = kfree ;
#         if PRESOLVE_DEBUG > 4
	  std::cout
	    << "  link x " << kfree << " row " << i << " coeff " << xValue
	    << " dual " ;
	  if (i != irow)
	    std::cout << rowduals[i] ;
	  else
	    std::cout << "n/a" ;
	  std::cout << std::endl ;
#         endif
	}
      }
	  
#     if PRESOLVE_CONSISTENCY > 0
      presolve_check_free_list(prob) ;
#     endif
	  
/*
  Whew! Set the column length and we're done.
*/
      assert(numberInColumn) ;
      hincol[jcolx] = numberInColumn ;
    } else {
/*
  Of course, we could have saved column x in the action. Now we need to
  regenerate coefficients of column y.
  Given
    coeffx'[k] = coeffx[k]+coeffy[k]*coeff_factor
  we have
    coeffy[k] = (coeffx'[k]-coeffx[k])*(1/coeff_factor)
  where
    coeff_factor = -coeffx[dblton]/coeffy[dblton].
*/
      const int ncolx = f->ncolx-1 ;
      int *indx = reinterpret_cast<int *> (f->colel+ncolx) ;
/*
  Scan existing column x to find the end. While we're at it, accumulate part
  of the new y coefficients in index1 and element1.
*/
      CoinBigIndex kcs = mcstrt[jcolx] ;
      int nX = 0 ;
      for (int kcol = 0 ; kcol < hincol[jcolx]-1 ; ++kcol) {
	if (colels[kcs]) {
	  const int i = hrow[kcs] ;
	  index1[nX++] = i ;
	  element1[i] = -(colels[kcs]*coeffy)/coeffx ;
	}
	kcs = link[kcs] ;
      }
      if (colels[kcs]) {
        const int i = hrow[kcs] ;
        index1[nX++] = i ;
        element1[i] = -(colels[kcs]*coeffy)/coeffx ;
      }
/*
  Replace column x with the the original column x held in the doubleton action
  (recall that this column does not include coeffx). We first move column
  x to the free list, then thread a column with the original coefficients,
  back to front.  While we're at it, add the second part of the y coefficients
  to index1 and element1.
*/
      link[kcs] = free_list ;
      free_list = mcstrt[jcolx] ;
      int xstart = NO_LINK ;
      for (int kcol = 0 ; kcol < ncolx ; ++kcol) {
	const int i = indx[kcol] ;
	PRESOLVEASSERT(rdone[i] && i != irow) ;

	double xValue = f->colel[kcol] ;
	CoinBigIndex k = free_list ;
	assert(k >= 0 && k < prob->bulk0_) ;
	free_list = link[free_list] ;
	hrow[k] = i ;
	colels[k] = xValue ;
	link[k] = xstart ;
	xstart = k ;

	djx -= rowduals[i]*xValue ;

	xValue = (xValue*coeffy)/coeffx ;
	if (!element1[i]) {
	  element1[i] = xValue ;
	  index1[nX++] = i ;
	} else {
	  element1[i] += xValue ;
	}
      }
#     if PRESOLVE_CONSISTENCY > 0
      presolve_check_free_list(prob) ;
#     endif
/*
  The same, for the doubleton row.
*/
      {
	double xValue = coeffx ;
	CoinBigIndex k = free_list ;
	assert(k >= 0 && k < prob->bulk0_) ;
	free_list = link[free_list] ;
	hrow[k] = irow ;
	colels[k] = xValue ;
	link[k] = xstart ;
	xstart = k ;
	element1[irow] = coeffy ;
	index1[nX++] = irow ;
      }
/*
  Link the new column x to mcstrt and set the length.
*/
      mcstrt[jcolx] = xstart ;
      hincol[jcolx] = f->ncolx ;
/*
  Now get to work building a threaded column y from the nonzeros in element1.
  As before, build the thread in reverse.
*/
      int ystart = NO_LINK ;
      int leny = 0 ;
      for (int kcol = 0 ; kcol < nX ; kcol++) {
	const int i = index1[kcol] ;
	PRESOLVEASSERT(rdone[i] || i == irow) ;
	double yValue = element1[i] ;
	element1[i] = 0.0 ;
	if (fabs(yValue) >= ztolzero) {
	  leny++ ;
	  CoinBigIndex k = free_list ;
	  assert(k >= 0 && k < prob->bulk0_) ;
	  free_list = link[free_list] ;
	  hrow[k] = i ;
	  colels[k] = yValue ;
	  link[k] = ystart ;
	  ystart = k ;
	}
      }
#     if PRESOLVE_CONSISTENCY > 0
      presolve_check_free_list(prob) ;
#     endif
/*
  Tidy up --- link the new column into mcstrt and set the length.
*/
      mcstrt[jcoly] = ystart ;
      assert(leny) ;
      hincol[jcoly] = leny ;
/*
  Now that we have the original y, we can scan it and do the corrections to
  the row bounds and activity, and get a start on a reduced cost for y.
*/
      kcs = mcstrt[jcoly] ;
      const int ny = hincol[jcoly] ;
      for (int kcol = 0 ; kcol < ny ; ++kcol) {
	const int row = hrow[kcs] ;
	const double coeff = colels[kcs] ;
	kcs = link[kcs] ;

	if (row != irow) {
	  
	  // undo elim_doubleton(1)
	  if (-PRESOLVE_INF < rlo[row])
	    rlo[row] += (coeff*rhs)/coeffy ;
	  
	  // undo elim_doubleton(2)
	  if (rup[row] < PRESOLVE_INF)
	    rup[row] += (coeff*rhs)/coeffy ;
	  
	  acts[row] += (coeff*rhs)/coeffy ;
	  
	  djy -= rowduals[row]*coeff ;
	}
      }
    }
#   if PRESOLVE_DEBUG > 2
/*
  Sanity checks. The doubleton coefficients should be linked in the first
  position of the each column (for no good reason except that it makes it much
  easier to write these checks).
*/
#   if PRESOLVE_DEBUG > 4
    std::cout
      << "  kept: saved " << jcolx << " " << coeffx << ", reconstructed "
      << hrow[mcstrt[jcolx]] << " " << colels[mcstrt[jcolx]]
      << "." << std::endl ;
    std::cout
      << "  elim: saved " << jcoly << " " << coeffy << ", reconstructed "
      << hrow[mcstrt[jcoly]] << " " << colels[mcstrt[jcoly]]
      << "." << std::endl ;
#   endif
    assert((coeffx == colels[mcstrt[jcolx]]) &&
	   (coeffy == colels[mcstrt[jcoly]])) ;
#   endif
/*
  Time to calculate a dual for the doubleton row, and settle the status of x
  and y. Ideally, we'll leave x at whatever nonbasic status it currently has
  and make y basic. There's a potential problem, however: Remember that we
  transferred bounds from y to x when we eliminated y. If those bounds were
  tighter than x's original bounds, we may not be able to maintain x at its
  present status, or even as nonbasic.

  We'll make two claims here:

    * If the dual value for the doubleton row is chosen to keep the reduced
      cost djx of col x at its prior value, then the reduced cost djy of col
      y will be 0. (Crank through the linear algebra to convince yourself.)

    * If the bounds on x have loosened, then it must be possible to make y
      nonbasic, because we've transferred the tight bound back to y. (Yeah,
      I'm waving my hands. But it sounds good.  -- lh, 040907 --)

  So ... if we can maintain x nonbasic, then we need to set y basic, which
  means we should calculate rowduals[dblton] so that rcost[jcoly] == 0. We
  may need to change the status of x (an artifact of loosening a bound when
  x was previously a fixed variable).
  
  If we need to push x into the basis, then we calculate rowduals[dblton] so
  that rcost[jcolx] == 0 and make y nonbasic.
*/
#   if PRESOLVE_DEBUG > 2
    std::cout
      << "  pre status: x(" << jcolx << ") " << prob->columnStatusString(jcolx)
      << " " << clo[jcolx] << " <= " << sol[jcolx] << " <= " << cup[jcolx]
      << ", cj " << dcost[jcolx]
      << ", dj " << djx << "." << std::endl ;
    std::cout
      << "  pre status: x(" << jcoly << ") "
      << clo[jcoly] << " <= " << sol[jcoly] << " <= " << cup[jcoly]
      << ", cj " << dcost[jcoly]
      << ", dj " << djy << "." << std::endl ;
#   endif
    if (colstat) {
      bool basicx = prob->columnIsBasic(jcolx) ;
      bool nblbxok = (fabs(lo0 - sol[jcolx]) < ztolzb) &&
		     (rcosts[jcolx] >= -ztoldj) ;
      bool nbubxok = (fabs(up0 - sol[jcolx]) < ztolzb) &&
		     (rcosts[jcolx] <= ztoldj) ;
      if (basicx || nblbxok || nbubxok) {
        if (!basicx) {
	  if (nblbxok) {
	    prob->setColumnStatus(jcolx,
				  CoinPrePostsolveMatrix::atLowerBound) ;
	  } else if (nbubxok) {
	    prob->setColumnStatus(jcolx,
				  CoinPrePostsolveMatrix::atUpperBound) ;
	  }
	}
	prob->setColumnStatus(jcoly,CoinPrePostsolveMatrix::basic) ;
	rowduals[irow] = djy/coeffy ;
	rcosts[jcolx] = djx-rowduals[irow]*coeffx ;
	rcosts[jcoly] = 0.0 ;
      } else {
	prob->setColumnStatus(jcolx,CoinPrePostsolveMatrix::basic) ;
	prob->setColumnStatusUsingValue(jcoly) ;
	rowduals[irow] = djx/coeffx ;
	rcosts[jcoly] = djy-rowduals[irow]*coeffy ;
	rcosts[jcolx] = 0.0 ;
      }
#     if PRESOLVE_DEBUG > 2
      std::cout
        << "  post status: " << irow << " dual " << rowduals[irow]
	<< " rhs " << rlo[irow]
	<< std::endl ;
      std::cout
	<< "  post status: x(" << jcolx << ") "
	<< prob->columnStatusString(jcolx) << " "
	<< clo[jcolx] << " <= " << sol[jcolx] << " <= " << cup[jcolx]
	<< ", cj " << dcost[jcolx]
	<< ", dj = " << rcosts[jcolx] << "." << std::endl ;
      std::cout
	<< "  post status: x(" << jcoly << ") "
	<< prob->columnStatusString(jcoly) << " "
	<< clo[jcoly] << " <= " << sol[jcoly] << " <= " << cup[jcoly]
	<< ", cj " << dcost[jcoly]
	<< ", dj " << rcosts[jcoly] << "." << std::endl ;
/*
  These asserts are valid but need a scaled tolerance to work well over
  a range of problems. Occasionally useful for a hard stop while debugging.

      assert(!prob->columnIsBasic(jcolx) || (fabs(rcosts[jcolx]) < 1.0e-5)) ;
      assert(!prob->columnIsBasic(jcoly) || (fabs(rcosts[jcoly]) < 1.0e-5)) ;
*/
#     endif
    } else {
      // No status array
      // this is the coefficient we need to force col y's reduced cost to 0.0 ;
      // for example, this is obviously true if y is a singleton column
      rowduals[irow] = djy/coeffy ;
      rcosts[jcoly] = 0.0 ;
    }
    
#   if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
/*
  Mark the column and row as processed by doubleton action. Then check
  integrity of the threaded matrix.
*/
    cdone[jcoly] = DOUBLETON ;
    rdone[irow] = DOUBLETON ;
    presolve_check_threads(prob) ;
#   endif
#   if PRESOLVE_DEBUG > 0
/*
  Confirm accuracy of reduced cost for columns x and y.
*/
    {
      CoinBigIndex k = mcstrt[jcolx] ;
      const int nx = hincol[jcolx] ;
      double dj = maxmin*dcost[jcolx] ;
      
      for (int kcol = 0 ; kcol < nx ; ++kcol) {
	const int row = hrow[k] ;
	const double coeff = colels[k] ;
	k = link[k] ;
	dj -= rowduals[row]*coeff ;
      }
      if (!(fabs(rcosts[jcolx]-dj) < 100*ZTOLDP))
	printf("BAD DOUBLE X DJ:  %d %d %g %g\n",
	       irow,jcolx,rcosts[jcolx],dj) ;
      rcosts[jcolx] = dj ;
    }
    {
      CoinBigIndex k = mcstrt[jcoly] ;
      const int ny = hincol[jcoly] ;
      double dj = maxmin*dcost[jcoly] ;
      
      for (int kcol = 0 ; kcol < ny ; ++kcol) {
	const int row = hrow[k] ;
	const double coeff = colels[k] ;
	k = link[k] ;
	dj -= rowduals[row]*coeff ;
      }
      if (!(fabs(rcosts[jcoly]-dj) < 100*ZTOLDP))
	printf("BAD DOUBLE Y DJ:  %d %d %g %g\n",
	       irow,jcoly,rcosts[jcoly],dj) ;
      rcosts[jcoly] = dj ;
    }
#   endif
  }
/*
  Done at last. Delete the scratch arrays.
*/
  delete [] index1 ;
  delete [] element1 ;

# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
  presolve_check_sol(prob,2,2,2) ;
  presolve_check_nbasic(prob) ;
  presolve_check_reduced_costs(prob) ;
# if PRESOLVE_DEBUG > 0
  std::cout << "Leaving doubleton_action::postsolve." << std::endl ;
# endif
# endif
}
示例#2
0
/*
  Undo the substitutions from presolve and reintroduce the target constraint
  and column.
*/
void subst_constraint_action::postsolve(CoinPostsolveMatrix *prob) const
{

# if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
# if PRESOLVE_DEBUG > 0
  std::cout
    << "Entering subst_constraint_action::postsolve, "
    << nactions_ << " constraints to process." << std::endl ;
# endif
  int ncols = prob->ncols_ ;
  char *cdone = prob->cdone_ ;
  char *rdone = prob->rdone_ ;
  const double ztolzb = prob->ztolzb_ ;

  presolve_check_threads(prob) ;
  presolve_check_free_list(prob) ;
  presolve_check_reduced_costs(prob) ;
  presolve_check_duals(prob) ;
  presolve_check_sol(prob,2,2,2) ;
  presolve_check_nbasic(prob) ;
# endif

/*
  Unpack the column-major representation.
*/
  CoinBigIndex *colStarts = prob->mcstrt_ ;
  int *colLengths = prob->hincol_ ;
  int *rowIndices = prob->hrow_ ;
  double *colCoeffs = prob->colels_ ;
/*
  Rim vectors, solution, reduced costs, duals, row activity.
*/
  double *rlo = prob->rlo_ ;
  double *rup = prob->rup_ ;
  double *cost = prob->cost_ ;
  double *sol = prob->sol_ ;
  double *rcosts = prob->rcosts_ ;
  double *acts = prob->acts_ ;
  double *rowduals = prob->rowduals_ ;

  CoinBigIndex *link = prob->link_ ;
  CoinBigIndex &free_list = prob->free_list_ ;

  const double maxmin = prob->maxmin_ ;

  const action *const actions = actions_ ;
  const int nactions = nactions_ ;

/*
  Open the main loop to step through the postsolve objects.

  First activity is to unpack the postsolve object. We have the target
  column and row indices, the full target column, and complete copies of
  all entangled rows (column indices, coefficients, lower and upper bounds).
  There may be a vector of objective coefficients which we'll get to later.
*/
  for (const action *f = &actions[nactions-1] ; actions <= f ; f--) {
    const int tgtcol = f->col ;
    const int tgtrow = f->rowy ;

    const int tgtcol_len = f->nincol ;
    const double *tgtcol_coeffs = f->coeffxs ;

    const int *entngld_rows = f->rows ;
    const int *entngld_lens = f->ninrowxs ;
    const int *entngld_colndxs = f->rowcolsxs ;
    const double *entngld_colcoeffs = f->rowelsxs ;
    const double *entngld_rlos = f->rlos ;
    const double *entngld_rups = f->rups ;
    const double *costs = f->costsx ;

#   if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
#   if PRESOLVE_DEBUG > 1
    std::cout
      << "  reintroducing column x(" << tgtcol << ") and row " << tgtrow ;
      if (costs) std::cout << ", nonzero costs" ;
      std::cout << "." << std::endl ;
#   endif
/*
  We're about to reintroduce the target row and column; empty stubs should be
  present. All other rows should already be present.
*/
    PRESOLVEASSERT(cdone[tgtcol] == DROP_COL) ;
    PRESOLVEASSERT(colLengths[tgtcol] == 0) ;
    PRESOLVEASSERT(rdone[tgtrow] == DROP_ROW) ;
    for (int cndx = 0 ; cndx < tgtcol_len ; ++cndx) {
      if (entngld_rows[cndx] != tgtrow)
	PRESOLVEASSERT(rdone[entngld_rows[cndx]]) ;
    }
/*
  In a postsolve matrix, we can't just check that the length of the row is
  zero. We need to look at all columns and confirm its absence.
*/
    for (int j = 0 ; j < ncols ; ++j) {
      if (colLengths[j] > 0 && cdone[j]) {
        const CoinBigIndex kcs = colStarts[j] ;
        const int lenj = colLengths[j] ;
	CoinBigIndex krow =
	  presolve_find_row3(tgtrow,kcs,lenj,rowIndices,link) ;
	if (krow >= 0) {
	  std::cout
	    << "  BAD COEFF! row " << tgtrow << " present in column " << j
	    << " before reintroduction; a(" << tgtrow << "," << j
	    << ") = " << colCoeffs[krow] << "; x(" << j << ") = " << sol[j]
	    << "; cdone " << static_cast<int>(cdone[j]) << "." << std::endl ;
	}
      }
    }
#   endif

/*
  Find the copy of the target row. Restore the upper and lower bounds
  of entangled rows while we're looking. Recall that the target row is
  an equality.
*/
    int tgtrow_len = -1 ;
    const int *tgtrow_colndxs = NULL ;
    const double *tgtrow_coeffs = NULL ;
    double tgtcoeff = 0.0 ;
    double tgtrhs = 1.0e50 ;

    int nel = 0 ;
    for (int cndx = 0 ; cndx < tgtcol_len ; ++cndx) {
      int i = entngld_rows[cndx] ;
      rlo[i] = entngld_rlos[cndx] ;
      rup[i] = entngld_rups[cndx] ;
      if (i == tgtrow) {
	tgtrow_len = entngld_lens[cndx] ;
	tgtrow_colndxs = &entngld_colndxs[nel] ;
	tgtrow_coeffs  = &entngld_colcoeffs[nel] ;
	tgtcoeff = tgtcol_coeffs[cndx] ;
	tgtrhs = rlo[i] ;
      }
      nel += entngld_lens[cndx] ;
    }
/*
  Solve the target equality to find the solution for the eliminated col.
  tgtcol is present in tgtrow_colndxs, so initialise sol[tgtcol] to zero
  to make sure it doesn't contribute.

  If we're debugging, check that the result is within bounds.
*/
    double tgtexp = tgtrhs ;
    sol[tgtcol] = 0.0 ;
    for (int ndx = 0 ; ndx < tgtrow_len ; ++ndx) {
      int j = tgtrow_colndxs[ndx] ;
      double coeffj = tgtrow_coeffs[ndx] ;
      tgtexp -= coeffj*sol[j] ;
    }
    sol[tgtcol] = tgtexp/tgtcoeff ;

#   if PRESOLVE_DEBUG > 0
    double *clo = prob->clo_ ;
    double *cup = prob->cup_ ;

    if (!(sol[tgtcol] > (clo[tgtcol]-ztolzb) &&
	  (cup[tgtcol]+ztolzb) > sol[tgtcol])) {
      std::cout
	<< "BAD SOL: x(" << tgtcol << ") " << sol[tgtcol]
	<< "; lb " << clo[tgtcol] << "; ub " << cup[tgtcol] << "."
	<< std::endl ;
    }
#   endif
/*
  Now restore the original entangled rows. We first delete any columns present
  in tgtrow. This will remove any fillin, but may also remove columns that
  were originally present in both the entangled row and the target row.

  Note that even cancellations (explicit zeros) are present at this
  point --- in presolve, they were removed after the substition transform
  completed, hence they're already restored. What isn't present is the target
  column, which is deleted as part of the transform.
*/
    {
#     if PRESOLVE_DEBUG > 2
      std::cout << "    removing coefficients:" ;
#     endif
      for (int rndx = 0 ; rndx < tgtrow_len ; ++rndx) {
	int j = tgtrow_colndxs[rndx] ;
	if (j != tgtcol)
	  for (int cndx = 0 ; cndx < tgtcol_len ; ++cndx) {
	    if (entngld_rows[cndx] != tgtrow) {
#             if PRESOLVE_DEBUG > 2
	      std::cout << " a(" << entngld_rows[cndx] << "," << j << ")" ;
#             endif
	      presolve_delete_from_col2(entngld_rows[cndx],j,colStarts,
				      colLengths,rowIndices,link,&free_list) ;
	    }
	  }
      }
#     if PRESOLVE_DEBUG > 2
      std::cout << std::endl ;
#     endif
#     if PRESOLVE_CONSISTENCY > 0
      presolve_check_threads(prob) ;
      presolve_check_free_list(prob) ;
#     endif
/*
  Next we restore the original coefficients. The outer loop walks tgtcol;
  cols_i and coeffs_i are advanced as we go to point to each entangled
  row. The inner loop walks the entangled row and restores the row's
  coefficients. Tgtcol is handled as any other column. Skip tgtrow, we'll
  do it below.

  Since we don't have a row-major representation, we have to look for a(i,j)
  from entangled row i in the existing column j. If we find a(i,j), simply
  update it (and a(tgtrow,j) should not exist). If we don't find a(i,j),
  introduce it (and a(tgtrow,j) should exist).

  Recalculate the row activity while we're at it.
*/
#     if PRESOLVE_DEBUG > 2
      std::cout << "    restoring coefficients:" ;
#     endif

      colLengths[tgtcol] = 0 ;
      const int *cols_i = entngld_colndxs ;
      const double *coeffs_i = entngld_colcoeffs ;

      for (int cndx = 0 ; cndx < tgtcol_len ; ++cndx) {
	const int leni = entngld_lens[cndx] ;
	const int i = entngld_rows[cndx] ;

	if (i != tgtrow) {
	  double acti = 0.0 ;
	  for (int rndx = 0 ; rndx < leni ; ++rndx) {
	    const int j = cols_i[rndx] ;
	    CoinBigIndex kcoli =
	      presolve_find_row3(i,colStarts[j],
	      			 colLengths[j],rowIndices,link) ;
	    if (kcoli != -1) {
#             if PRESOLVE_DEBUG > 2
	      std::cout << " u a(" << i << "," << j << ")" ;
	      PRESOLVEASSERT(presolve_find_col1(j,0,tgtrow_len,
	      					tgtrow_colndxs) == tgtrow_len) ;
#	      endif
	      colCoeffs[kcoli] = coeffs_i[rndx] ;
	    } else {
#             if PRESOLVE_DEBUG > 2
	      std::cout << " f a(" << i << "," << j << ")" ;
	      PRESOLVEASSERT(presolve_find_col1(j,0,tgtrow_len,
						tgtrow_colndxs) < tgtrow_len) ;
#	      endif
	      CoinBigIndex kk = free_list ;
	      assert(kk >= 0 && kk < prob->bulk0_) ;
	      free_list = link[free_list] ;
	      link[kk] = colStarts[j] ;
	      colStarts[j] = kk ;
	      colCoeffs[kk] = coeffs_i[rndx] ;
	      rowIndices[kk] = i ;
	      ++colLengths[j] ;
	    }
	    acti += coeffs_i[rndx]*sol[j] ;
	  }
	  acts[i] = acti ;
	}
	cols_i += leni ;
	coeffs_i += leni ;
      }
#     if PRESOLVE_DEBUG > 2
      std::cout << std::endl ;
#     endif
#     if PRESOLVE_CONSISTENCY > 0
      presolve_check_threads(prob) ;
      presolve_check_free_list(prob) ;
#     endif
/*
  Restore tgtrow. Arguably we could to this in the previous loop, but we'd do
  a lot of unnecessary work. By construction, the target row is tight.
*/
#     if PRESOLVE_DEBUG > 2
      std::cout << "    restoring row " << tgtrow << ":" ;
#     endif

      for (int rndx = 0 ; rndx < tgtrow_len ; ++rndx) {
	int j = tgtrow_colndxs[rndx] ;
#       if PRESOLVE_DEBUG > 2
	std::cout << " a(" << tgtrow << "," << j << ")" ;
#       endif
	CoinBigIndex kk = free_list ;
	assert(kk >= 0 && kk < prob->bulk0_) ;
	free_list = link[free_list] ;
	link[kk] = colStarts[j] ;
	colStarts[j] = kk ;
	colCoeffs[kk] = tgtrow_coeffs[rndx] ;
	rowIndices[kk] = tgtrow ;
	++colLengths[j] ;
      }
      acts[tgtrow] = tgtrhs ;

#     if PRESOLVE_DEBUG > 2
      std::cout << std::endl ;
#     endif
#     if PRESOLVE_CONSISTENCY > 0
      presolve_check_threads(prob) ;
      presolve_check_free_list(prob) ;
#     endif
    }
/*
  Restore original cost coefficients, if necessary.
*/
    if (costs) {
      for (int ndx = 0 ; ndx < tgtrow_len ; ++ndx) {
	cost[tgtrow_colndxs[ndx]] = costs[ndx] ;
      }
    }
/*
  Calculate the reduced cost for the column absent any contribution from
  tgtrow, then set the dual for tgtrow so that the reduced cost of tgtcol
  is zero.
*/
    double dj = maxmin*cost[tgtcol] ;
    rowduals[tgtrow] = 0.0 ;
    for (int cndx = 0 ; cndx < tgtcol_len ; ++cndx) {
      int i = entngld_rows[cndx] ;
      double coeff = tgtcol_coeffs[cndx] ;
      dj -= rowduals[i]*coeff ;
    }
    rowduals[tgtrow] = dj/tgtcoeff ;
    rcosts[tgtcol] = 0.0 ;
    if (rowduals[tgtrow] > 0)
      prob->setRowStatus(tgtrow,CoinPrePostsolveMatrix::atUpperBound) ;
    else
      prob->setRowStatus(tgtrow,CoinPrePostsolveMatrix::atLowerBound) ;
    prob->setColumnStatus(tgtcol,CoinPrePostsolveMatrix::basic) ;

#   if PRESOLVE_DEBUG > 2
    std::cout
      << "  row " << tgtrow << " "
      << prob->rowStatusString(prob->getRowStatus(tgtrow))
      << " dual " << rowduals[tgtrow] << std::endl ;
    std::cout
      << "  col " << tgtcol << " "
      << prob->columnStatusString(prob->getColumnStatus(tgtcol))
      << " dj " << dj << std::endl ;
#   endif

#   if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0
    cdone[tgtcol] = SUBST_ROW ;
    rdone[tgtrow] = SUBST_ROW ;
#   endif
  }

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

  return ;
}