/* $Id: AbcSimplexDual.cpp 2078 2015-01-05 12:39:49Z forrest $ */
// Copyright (C) 2002, International Business Machines
// Corporation and others, Copyright (C) 2012, FasterCoin.  All Rights Reserved.
// This code is licensed under the terms of the Eclipse Public License (EPL).

/* Notes on implementation of dual simplex algorithm.
   
   When dual feasible:
   
   If primal feasible, we are optimal.  Otherwise choose an infeasible
   basic variable to leave basis (normally going to nearest bound) (B).  We
   now need to find an incoming variable which will leave problem
   dual feasible so we get the row of the tableau corresponding to
   the basic variable (with the correct sign depending if basic variable
   above or below feasibility region - as that affects whether reduced
   cost on outgoing variable has to be positive or negative).
   
   We now perform a ratio test to determine which incoming variable will
   preserve dual feasibility (C).  If no variable found then problem
   is infeasible (in primal sense).  If there is a variable, we then
   perform pivot and repeat.  Trivial?
   
   -------------------------------------------
   
   A) How do we get dual feasible?  If all variables have bounds then
   it is trivial to get feasible by putting non-basic variables to
   correct bounds.  OSL did not have a phase 1/phase 2 approach but
   instead effectively put fake bounds on variables and this is the
   approach here, although I had hoped to make it cleaner.
   
   If there is a weight of X on getting dual feasible:
   Non-basic variables with negative reduced costs are put to
   lesser of their upper bound and their lower bound + X.
   Similarly, mutatis mutandis, for positive reduced costs.
   
   Free variables should normally be in basis, otherwise I have
   coding which may be able to come out (and may not be correct).
   
   In OSL, this weight was changed heuristically, here at present
   it is only increased if problem looks finished.  If problem is
   feasible I check for unboundedness.  If not unbounded we
   could play with going into primal.  As long as weights increase
   any algorithm would be finite.
   
   B) Which outgoing variable to choose is a virtual base class.
   For difficult problems steepest edge is preferred while for
   very easy (large) problems we will need partial scan.
   
   C) Sounds easy, but this is hardest part of algorithm.
   1) Instead of stopping at first choice, we may be able
   to flip that variable to other bound and if objective
   still improving choose again.  These mini iterations can
   increase speed by orders of magnitude but we may need to
   go to more of a bucket choice of variable rather than looking
   at them one by one (for speed).
   2) Accuracy.  Reduced costs may be of wrong sign but less than
   tolerance.  Pivoting on these makes objective go backwards.
   OSL modified cost so a zero move was made, Gill et al
   (in primal analogue) modified so a strictly positive move was
   made.  It is not quite as neat in dual but that is what we
   try and do.  The two problems are that re-factorizations can
   change reduced costs above and below tolerances and that when
   finished we need to reset costs and try again.
   3) Degeneracy.  Gill et al helps but may not be enough.  We
   may need more.  Also it can improve speed a lot if we perturb
   the costs significantly.
   
   References:
   Forrest and Goldfarb, Steepest-edge simplex algorithms for
   linear programming - Mathematical Programming 1992
   Forrest and Tomlin, Implementing the simplex method for
   the Optimization Subroutine Library - IBM Systems Journal 1992
   Gill, Murray, Saunders, Wright A Practical Anti-Cycling
   Procedure for Linear and Nonlinear Programming SOL report 1988
   
   
   TODO:
   
   a) Better recovery procedures.  At present I never check on forward
   progress.  There is checkpoint/restart with reducing
   re-factorization frequency, but this is only on singular
   factorizations.
   b) Fast methods for large easy problems (and also the option for
   the code to automatically choose which method).
   c) We need to be able to stop in various ways for OSI - this
   is fairly easy.
   
*/

#include "CoinPragma.hpp"

#include <math.h>

#include "CoinHelperFunctions.hpp"
#include "CoinAbcHelperFunctions.hpp"
#include "AbcSimplexDual.hpp"
#include "ClpEventHandler.hpp"
#include "AbcSimplexFactorization.hpp"
#include "AbcNonLinearCost.hpp"
#include "CoinPackedMatrix.hpp"
#include "CoinIndexedVector.hpp"
#include "CoinFloatEqual.hpp"
#include "AbcDualRowDantzig.hpp"
#include "AbcDualRowSteepest.hpp"
#include "ClpMessage.hpp"
#include "ClpLinearObjective.hpp"
class ClpSimplex;
#include <cfloat>
#include <cassert>
#include <string>
#include <stdio.h>
#include <iostream>
//#define CLP_DEBUG 1
#ifdef NDEBUG
#define NDEBUG_CLP
#endif
#ifndef CLP_INVESTIGATE
#define NDEBUG_CLP
#endif
// dual

/* *** Method
   This is a vanilla version of dual simplex.
   
   It tries to be a single phase approach with a weight of 1.0 being
   given to getting optimal and a weight of dualBound_ being
   given to getting dual feasible.  In this version I have used the
   idea that this weight can be thought of as a fake bound.  If the
   distance between the lower and upper bounds on a variable is less
   than the feasibility weight then we are always better off flipping
   to other bound to make dual feasible.  If the distance is greater
   then we make up a fake bound dualBound_ away from one bound.
   If we end up optimal or primal infeasible, we check to see if
   bounds okay.  If so we have finished, if not we increase dualBound_
   and continue (after checking if unbounded). I am undecided about
   free variables - there is coding but I am not sure about it.  At
   present I put them in basis anyway.
   
   The code is designed to take advantage of sparsity so arrays are
   seldom zeroed out from scratch or gone over in their entirety.
   The only exception is a full scan to find outgoing variable.  This
   will be changed to keep an updated list of infeasibilities (or squares
   if steepest edge).  Also on easy problems we don't need full scan - just
   pick first reasonable.
   
   One problem is how to tackle degeneracy and accuracy.  At present
   I am using the modification of costs which I put in OSL and which was
   extended by Gill et al.  I am still not sure of the exact details.
   
   The flow of dual is three while loops as follows:
   
   while (not finished) {
   
   while (not clean solution) {
   
   Factorize and/or clean up solution by flipping variables so
   dual feasible.  If looks finished check fake dual bounds.
   Repeat until status is iterating (-1) or finished (0,1,2)
   
   }
   
   while (status==-1) {
   
   Iterate until no pivot in or out or time to re-factorize.
   
   Flow is:
   
   choose pivot row (outgoing variable).  if none then
   we are primal feasible so looks as if done but we need to
   break and check bounds etc.
   
   Get pivot row in tableau
   
   Choose incoming column.  If we don't find one then we look
   primal infeasible so break and check bounds etc.  (Also the
   pivot tolerance is larger after any iterations so that may be
   reason)
   
   If we do find incoming column, we may have to adjust costs to
   keep going forwards (anti-degeneracy).  Check pivot will be stable
   and if unstable throw away iteration (we will need to implement
   flagging of basic variables sometime) and break to re-factorize.
   If minor error re-factorize after iteration.
   
   Update everything (this may involve flipping variables to stay
   dual feasible.
   
   }
   
   }
   
   At present we never check we are going forwards.  I overdid that in
   OSL so will try and make a last resort.
   
   Needs partial scan pivot out option.
   Needs dantzig, uninitialized and full steepest edge options (can still
   use partial scan)
   
   May need other anti-degeneracy measures, especially if we try and use
   loose tolerances as a way to solve in fewer iterations.
   
   I like idea of dynamic scaling.  This gives opportunity to decouple
   different implications of scaling for accuracy, iteration count and
   feasibility tolerance.
   
*/
#define CLEAN_FIXED 0
// Startup part of dual (may be extended to other algorithms)
// To force to follow another run put logfile name here and define
//#define FORCE_FOLLOW
#ifdef FORCE_FOLLOW
static FILE * fpFollow = NULL;
static const char * forceFile = NULL;
static int force_in = -1;
static int force_out = -1;
static int force_way_in = -1;
static int force_way_out = -1;
static int force_iterations = 0;
int force_argc=0;
const char ** force_argv=NULL;
#endif
void
AbcSimplexDual::startupSolve()
{
#ifdef FORCE_FOLLOW
  int ifld;
  for (ifld=1;ifld<force_argc;ifld++) {
    if (strstr(argv[ifld],".log")) {
      forceFile=argv[ifld];
      break;
    }
  }
  if (!fpFollow && strlen(forceFile)) {
    fpFollow = fopen(forceFile, "r");
    assert (fpFollow);
  }
  if (fpFollow) {
    int numberRead= atoi(argv[ifld+1]);
    force_iterations=atoi(argv[ifld+1]);
    printf("skipping %d iterations and then doing %d\n",numberRead,force_iterations);
    for (int iteration=0;iteration<numberRead;iteration++) {
      // read to next Clp0102
      char temp[300];
      while (fgets(temp, 250, fpFollow)) {
	if (!strncmp(temp, "dirOut", 6))
	  break;
      }
      sscanf(temp+7 , "%d%*s%d%*s%*s%d",
	     &force_way_out, &force_way_in);
      fgets(temp, 250, fpFollow);
      char cin, cout;
      int whichIteration;
      sscanf(temp , "%d%*f%*s%*c%c%d%*s%*c%c%d",
	     &whichIteration, &cin, &force_in, &cout, &force_out);
      assert (whichIterations==iteration+1);
      if (cin == 'C')
	force_in += numberColumns_;
      if (cout == 'C')
	force_out += numberColumns_;
      printf("Iteration %d will force %d out (way %d) and %d in (way %d)\n",
	     whichIteration, force_out, force_way_out,force_in,force_way_in);
      assert (getInternalStatus(force_out)==basic);
      assert (getInternalStatus(force_in)!=basic);
      setInternalStatus(force_in,basic);
      if (force_way_out==-1)
	setInternalStatus(force_out,atUpperBound);
      else
	setInternalStatus(force_out,atLowerBound);
    }
    // clean up
    int numberBasic=0;
    for (int i=0;i<numberTotal_;i++) {
      if (getInternalStatus(i)==basic) {
	abcPivotVariable_[numberBasic++]=i;
      } else if (getInternalStatus(i)==atLowerBound) {
	if (abcLower_[i]<-1.0e30) {
	  abcLower_[i]=abcUpper_[i]-dualBound_;
	  setFakeLower(i);
	}
      } else if (getInternalStatus(i)==atUpperBound) {
	if (abcUpper_[i]>1.0e30) {
	  abcUpper_[i]=abcLower_[i]+dualBound_;
	  setFakeUpper(i);
	}
      }
    }
    assert (numberBasic==numberRows_);
  }
#endif
  // initialize - no values pass and algorithm_ is -1
  // put in standard form (and make row copy)
  // create modifiable copies of model rim and do optional scaling
  // If problem looks okay
  // Do initial factorization
  numberFake_ = 0; // Number of variables at fake bounds
  numberChanged_ = 0; // Number of variables with changed costs
  /// Initial coding here
  statusOfProblemInDual(0);
}
void
AbcSimplexDual::finishSolve()
{
  assert (problemStatus_ || !sumPrimalInfeasibilities_);
}
void
AbcSimplexDual::gutsOfDual()
{
  double largestPrimalError = 0.0;
  double largestDualError = 0.0;
  lastCleaned_ = 0; // last time objective or bounds cleaned up
  numberDisasters_=0;
  
  // This says whether to restore things etc
  //startupSolve();
  // startup will have factorized so can skip
  // Start check for cycles
  abcProgress_.startCheck();
  // Say change made on first iteration
  changeMade_ = 1;
  // Say last objective infinite
  //lastObjectiveValue_=-COIN_DBL_MAX;
  if ((stateOfProblem_&VALUES_PASS)!=0) {
    // modify costs so nonbasic dual feasible with fake
    for (int iSequence = 0; iSequence < numberTotal_; iSequence++) {
      switch(getInternalStatus(iSequence)) {
      case basic:
      case AbcSimplex::isFixed:
	break;
      case isFree:
      case superBasic:
	//abcCost_[iSequence]-=djSaved_[iSequence];
	//abcDj_[iSequence]-=djSaved_[iSequence];
	djSaved_[iSequence]=0.0;
	break;
      case atLowerBound:
	if (djSaved_[iSequence]<0.0) {
	  //abcCost_[iSequence]-=djSaved_[iSequence];
	  //abcDj_[iSequence]-=djSaved_[iSequence];
	  djSaved_[iSequence]=0.0;
	}
	break;
      case atUpperBound:
	if (djSaved_[iSequence]>0.0) {
	  //abcCost_[iSequence]-=djSaved_[iSequence];
	  //abcDj_[iSequence]-=djSaved_[iSequence];
	  djSaved_[iSequence]=0.0;
	}
	break;
      }
    }
  }
  progressFlag_ = 0;
  /*
    Status of problem:
    0 - optimal
    1 - infeasible
    2 - unbounded
    -1 - iterating
    -2 - factorization wanted
    -3 - redo checking without factorization
    -4 - looks infeasible
  */
  int factorizationType=1;
  double pivotTolerance=abcFactorization_->pivotTolerance();
  while (problemStatus_ < 0) {
    // If getting nowhere - return
    double limit = numberRows_ + numberColumns_;
    limit = 10000.0 +2000.0 * limit;
#if ABC_NORMAL_DEBUG>0
    if (numberIterations_ > limit) {
      printf("Set flag so ClpSimplexDual done\n");
      abort();
    }
#endif
    bool disaster = false;
    if (disasterArea_ && disasterArea_->check()) {
      disasterArea_->saveInfo();
      disaster = true;
    }
    if (numberIterations_>baseIteration_) {
      // may factorize, checks if problem finished
      statusOfProblemInDual(factorizationType);
      factorizationType=1;
      largestPrimalError = CoinMax(largestPrimalError, largestPrimalError_);
      largestDualError = CoinMax(largestDualError, largestDualError_);
      if (disaster)
	problemStatus_ = 3;
    }
    int saveNumberIterations=numberIterations_;
    // exit if victory declared
    if (problemStatus_ >= 0)
      break;
    
    // test for maximum iterations
    if (hitMaximumIterations()) {
      problemStatus_ = 3;
      break;
    }
    // Check event
    int eventStatus = eventHandler_->event(ClpEventHandler::endOfFactorization);
    if (eventStatus >= 0) {
      problemStatus_ = 5;
      secondaryStatus_ = ClpEventHandler::endOfFactorization;
      break;
    }
    if (!numberPrimalInfeasibilities_&&problemStatus_<0) {
#if ABC_NORMAL_DEBUG>0
      printf("Primal feasible - sum dual %g - go to primal\n",sumDualInfeasibilities_);
#endif
      problemStatus_=10;
      break;
    }
    // Do iterations ? loop round
#if PARTITION_ROW_COPY==1
    stateOfProblem_ |= NEED_BASIS_SORT;
#endif
    while (true) {
#if PARTITION_ROW_COPY==1
      if ((stateOfProblem_&NEED_BASIS_SORT)!=0) {
	int iVector=getAvailableArray();
	abcMatrix_->sortUseful(usefulArray_[iVector]);
	setAvailableArray(iVector);
	stateOfProblem_ &= ~NEED_BASIS_SORT;
      }
#endif
      problemStatus_=-1;
      if ((stateOfProblem_&VALUES_PASS)!=0) {
	assert (djSaved_-abcDj_==numberTotal_);
	abcDj_=djSaved_;
	djSaved_=NULL;
      }
#if ABC_PARALLEL
      if (parallelMode_==0) {
#endif
	whileIteratingSerial();
#if ABC_PARALLEL
      } else {
#if ABC_PARALLEL==1
	whileIteratingThread();
#else
	whileIteratingCilk();
#endif
      }
#endif
      if ((stateOfProblem_&VALUES_PASS)!=0) {
	djSaved_=abcDj_;
	abcDj_=djSaved_-numberTotal_;
      }
      if (pivotRow_!=-100) {
	if (numberIterations_>saveNumberIterations||problemStatus_>=0) {
	  if (problemStatus_==10&&abcFactorization_->pivots()&&numberTimesOptimal_<3) {
	    factorizationType=5;
	    problemStatus_=-4;
	    if (!numberPrimalInfeasibilities_)
	      factorizationType=9;
	  } else if (problemStatus_==-2) {
	    factorizationType=5;
	  }
	  break;
	} else if (abcFactorization_->pivots()||problemStatus_==-6||
		   pivotTolerance<abcFactorization_->pivotTolerance()) {
	  factorizationType=5;
	  if (pivotTolerance<abcFactorization_->pivotTolerance()) {
	    pivotTolerance=abcFactorization_->pivotTolerance();
	    if (!abcFactorization_->pivots())
	      abcFactorization_->minimumPivotTolerance(CoinMin(0.25,1.05*abcFactorization_->minimumPivotTolerance()));
	  }
	  break;
	} else {
	  bool tryFake=numberAtFakeBound()>0&&currentDualBound_<1.0e17;
	  if (problemStatus_==-5||tryFake) {
	    if (numberTimesOptimal_>10)
	      problemStatus_=4;
	    numberTimesOptimal_++;
	    int numberChanged=-1;
	    if (numberFlagged_) {
	      numberFlagged_=0;
	      for (int iRow = 0; iRow < numberRows_; iRow++) {
		int iPivot = abcPivotVariable_[iRow];
		if (flagged(iPivot)) {
		  clearFlagged(iPivot);
		}
	      }
	      numberChanged=0;
	    } else if (tryFake) {
	      double dummyChange;
	      numberChanged = changeBounds(0,dummyChange);
	      if (numberChanged>0) {
		handler_->message(CLP_DUAL_ORIGINAL, messages_)
		  << CoinMessageEol;
		bounceTolerances(3 /*(numberChanged>0) ? 3 : 1*/);
		// temp
#if ABC_NORMAL_DEBUG>0
		//printf("should not need to break out of loop\n");
#endif
		abcProgress_.reset();
		break;
	      } else if (numberChanged<-1) {
		// some flipped
		bounceTolerances(3);
		abcProgress_.reset();
	      }
	    } else if (numberChanged<0) {
	      // what now
	      printf("No iterations since last inverts A - nothing done - think\n");
	      abort();
	    }
	  } else if (problemStatus_!=-4) {
	    // what now
	    printf("No iterations since last inverts B - nothing done - think\n");
	    abort();
	  }
	}
      } else {
	// end of values pass 
	// we need to tell statusOf.. to restore costs etc
	// and take off flag
	bounceTolerances(2);
	assert (!solution_);
	delete [] solution_;
	solution_=NULL;
	gutsOfSolution(3);
	makeNonFreeVariablesDualFeasible();
	stateOfProblem_ &= ~VALUES_PASS;
	problemStatus_=-2;
	factorizationType=5;
	break;
      }
    }
    if (problemStatus_ == 1 && (progressFlag_&8) != 0 &&
	fabs(rawObjectiveValue_) > 1.0e10 ) {
#if ABC_NORMAL_DEBUG>0
      printf("fix looks infeasible when has been\n"); // goto primal
#endif
      problemStatus_ = 10; // infeasible - but has looked feasible
    }
    if (!problemStatus_ && abcFactorization_->pivots()) {
      gutsOfSolution(1); // need to compute duals
      //computeInternalObjectiveValue();
      checkCutoff(true);
    }
  }
  largestPrimalError_ = largestPrimalError;
  largestDualError_ = largestDualError;
}
/// The duals are updated by the given arrays.
static void updateDualsInDualBit2(CoinPartitionedVector & row,
				  double * COIN_RESTRICT djs,
				  double theta, int iBlock)
{
  int offset=row.startPartition(iBlock);
  double * COIN_RESTRICT work=row.denseVector()+offset;
  const int * COIN_RESTRICT which=row.getIndices()+offset;
  int number=row.getNumElements(iBlock);
  for (int i = 0; i < number; i++) {
    int iSequence = which[i];
    double alphaI = work[i];
    work[i] = 0.0;
    double value = djs[iSequence] - theta * alphaI;
    djs[iSequence] = value;
  }
  row.setNumElementsPartition(iBlock,0);
}
static void updateDualsInDualBit(CoinPartitionedVector & row,
				 double * djs,
				 double theta, int numberBlocks)
{
  for (int iBlock=1;iBlock<numberBlocks;iBlock++) {
    cilk_spawn updateDualsInDualBit2(row,djs,theta,iBlock);
  }
  updateDualsInDualBit2(row,djs,theta,0);
  cilk_sync;
}
/// The duals are updated by the given arrays.
   
void
AbcSimplexDual::updateDualsInDual()
{
  //dual->usefulArray(3)->compact();
  CoinPartitionedVector & array=usefulArray_[arrayForTableauRow_];
  //array.compact();
  int numberBlocks=array.getNumPartitions();
  int number=array.getNumElements();
  if(numberBlocks) {
    if (number>100) {
      updateDualsInDualBit(array,abcDj_,theta_,numberBlocks);
    } else {
      for (int iBlock=0;iBlock<numberBlocks;iBlock++) {
	updateDualsInDualBit2(array,abcDj_,theta_,iBlock);
      }
    }
    array.compact();
  } else {
    double * COIN_RESTRICT work=array.denseVector();
    const int * COIN_RESTRICT which=array.getIndices();
    double * COIN_RESTRICT reducedCost=abcDj_;
#pragma cilk grainsize=128
    cilk_for (int i = 0; i < number; i++) {
      //for (int i = 0; i < number; i++) {
      int iSequence = which[i];
      double alphaI = work[i];
      work[i] = 0.0;
      double value = reducedCost[iSequence] - theta_ * alphaI;
      reducedCost[iSequence] = value;
    }
    array.setNumElements(0);
  }
}
int
AbcSimplexDual::nextSuperBasic()
{
  if (firstFree_ >= 0) {
    // make sure valid
    int returnValue = firstFree_;
    int iColumn = firstFree_ + 1;
#ifdef PAN
    if (fakeSuperBasic(firstFree_)<0) {
      // somehow cleaned up
      returnValue=-1;
      for (; iColumn < numberTotal_; iColumn++) {
	if (getInternalStatus(iColumn) == isFree||
	    getInternalStatus(iColumn) == superBasic) {
	  if (fakeSuperBasic(iColumn)>=0) {
	    if (fabs(abcDj_[iColumn]) > 1.0e2 * dualTolerance_)
	      break;
	  }
	}
      }
      if (iColumn<numberTotal_) {
	returnValue=iColumn;
	iColumn++;
      }
    }
#endif
    for (; iColumn < numberTotal_; iColumn++) {
      if (getInternalStatus(iColumn) == isFree||
	  getInternalStatus(iColumn) == superBasic) {
#ifdef PAN
	if (fakeSuperBasic(iColumn)>=0) {
#endif
	  if (fabs(abcDj_[iColumn]) > dualTolerance_)
	    break;
#ifdef PAN
	}
#endif
      }
    }
    firstFree_ = iColumn;
    if (firstFree_ == numberTotal_)
      firstFree_ = -1;
    return returnValue;
  } else {
    return -1;
  }
}
/*
  Chooses dual pivot row
  For easy problems we can just choose one of the first rows we look at
*/
void
AbcSimplexDual::dualPivotRow()
{
  //int lastPivotRow=pivotRow_;
  pivotRow_=-1;
  const double * COIN_RESTRICT lowerBasic = lowerBasic_;
  const double * COIN_RESTRICT upperBasic = upperBasic_;
  const double * COIN_RESTRICT solutionBasic = solutionBasic_;
  const int * COIN_RESTRICT pivotVariable=abcPivotVariable_;
  freeSequenceIn_=-1;
  double worstValuesPass=0.0;
  if ((stateOfProblem_&VALUES_PASS)!=0) {
    for (int iSequence = 0; iSequence < numberTotal_; iSequence++) {
      switch(getInternalStatus(iSequence)) {
      case basic:
#if ABC_NORMAL_DEBUG>0
	if (fabs(abcDj_[iSequence])>1.0e-6)
	  printf("valuespass basic dj %d status %d dj %g\n",iSequence,
		 getInternalStatus(iSequence),abcDj_[iSequence]);
#endif
	break;
      case AbcSimplex::isFixed:
	break;
      case isFree:
      case superBasic:
#if ABC_NORMAL_DEBUG>0
	if (fabs(abcDj_[iSequence])>1.0e-6)
	  printf("Bad valuespass dj %d status %d dj %g\n",iSequence,
		 getInternalStatus(iSequence),abcDj_[iSequence]);
#endif
	break;
      case atLowerBound:
#if ABC_NORMAL_DEBUG>0
	if (abcDj_[iSequence]<-1.0e-6)
	  printf("Bad valuespass dj %d status %d dj %g\n",iSequence,
		 getInternalStatus(iSequence),abcDj_[iSequence]);
#endif
	break;
      case atUpperBound:
#if ABC_NORMAL_DEBUG>0
	if (abcDj_[iSequence]>1.0e-6)
	  printf("Bad valuespass dj %d status %d dj %g\n",iSequence,
		 getInternalStatus(iSequence),abcDj_[iSequence]);
#endif
	break;
      }
    }
    // get worst basic dual - later do faster using steepest infeasibility array
    // does not have to be worst - just bad
    int iWorst=-1;
    double worst=dualTolerance_;
    for (int i=0;i<numberRows_;i++) {
      int iSequence=abcPivotVariable_[i];
      if (fabs(abcDj_[iSequence])>worst) {
	iWorst=i;
	worst=fabs(abcDj_[iSequence]);
      }
    }
    if (iWorst>=0) {
      pivotRow_=iWorst;
      worstValuesPass=abcDj_[abcPivotVariable_[iWorst]];
    } else {
      // factorize and clean up costs
      pivotRow_=-100;
      return;
    }
  }
  if (false&&numberFreeNonBasic_>abcFactorization_->maximumPivots()) {
    lastFirstFree_=-1;
    firstFree_=-1;
  }
  if (firstFree_>=0) {
    // free
    int nextFree = nextSuperBasic();
    if (nextFree>=0) {
      freeSequenceIn_=nextFree;
      // **** should skip price (and maybe weights update)
      // unpack vector and find a good pivot
      unpack(usefulArray_[arrayForBtran_], nextFree);
      abcFactorization_->updateColumn(usefulArray_[arrayForBtran_]);
      
      double *  COIN_RESTRICT work = usefulArray_[arrayForBtran_].denseVector();
      int number = usefulArray_[arrayForBtran_].getNumElements();
      int *  COIN_RESTRICT which = usefulArray_[arrayForBtran_].getIndices();
      double bestFeasibleAlpha = 0.0;
      int bestFeasibleRow = -1;
      double bestInfeasibleAlpha = 0.0;
      int bestInfeasibleRow = -1;
      // Go for big infeasibilities unless big changes
      double maxInfeas = (fabs(dualOut_)>1.0e3) ? 0.001 : 1.0e6;
      for (int i = 0; i < number; i++) {
	int iRow = which[i];
	double alpha = fabs(work[iRow]);
	if (alpha > 1.0e-3) {
	  double value = solutionBasic[iRow];
	  double lower = lowerBasic[iRow];
	  double upper = upperBasic[iRow];
	  double infeasibility = 0.0;
	  if (value > upper)
	    infeasibility = value - upper;
	  else if (value < lower)
	    infeasibility = lower - value;
	  infeasibility=CoinMin(maxInfeas,infeasibility);
	  if (infeasibility * alpha > bestInfeasibleAlpha && alpha > 1.0e-1) {
	    if (!flagged(pivotVariable[iRow])) {
	      bestInfeasibleAlpha = infeasibility * alpha;
	      bestInfeasibleRow = iRow;
	    }
	  }
	  if (alpha > bestFeasibleAlpha && (lower > -1.0e20 || upper < 1.0e20)) {
	    bestFeasibleAlpha = alpha;
	    bestFeasibleRow = iRow;
	  }
	}
      }
      if (bestInfeasibleRow >= 0)
	pivotRow_ = bestInfeasibleRow;
      else if (bestFeasibleAlpha > 1.0e-2)
	pivotRow_ = bestFeasibleRow;
      usefulArray_[arrayForBtran_].clear();
      if (pivotRow_<0) {
 	// no good
 	freeSequenceIn_=-1;
 	if (!abcFactorization_->pivots()) {
 	  lastFirstFree_=-1;
 	  firstFree_=-1;
 	}
      }
    }
  }
  if (pivotRow_<0) {
    // put back so can test
    //pivotRow_=lastPivotRow;
    // get pivot row using whichever method it is
    pivotRow_ = abcDualRowPivot_->pivotRow();
  } 
  
  if (pivotRow_ >= 0) {
    sequenceOut_ = pivotVariable[pivotRow_];
    valueOut_ = solutionBasic[pivotRow_];
    lowerOut_ = lowerBasic[pivotRow_];
    upperOut_ = upperBasic[pivotRow_];
    // if we have problems we could try other way and hope we get a
    // zero pivot?
    if (valueOut_ > upperOut_) {
      directionOut_ = -1;
      dualOut_ = valueOut_ - upperOut_;
    } else if (valueOut_ < lowerOut_) {
      directionOut_ = 1;
      dualOut_ = lowerOut_ - valueOut_;
    } else {
      // odd (could be free) - it's feasible - go to nearest
      if (valueOut_ - lowerOut_ < upperOut_ - valueOut_) {
	directionOut_ = 1;
	dualOut_ = lowerOut_ - valueOut_;
      } else {
	directionOut_ = -1;
	dualOut_ = valueOut_ - upperOut_;
      }
    }
    if (worstValuesPass) {
      // in values pass so just use sign of dj
      // We don't want to go through any barriers so set dualOut low
      // free variables will never be here
      // need to think about tolerances with inexact solutions
      // could try crashing in variables away from bounds and with near zero djs
      // pivot to take out bad slack and increase objective
      double fakeValueOut=solution_[sequenceOut_];
      dualOut_ = 1.0e-10;
      if (upperOut_>lowerOut_||
	  fabs(fakeValueOut-upperOut_)<100.0*primalTolerance_) {
	if (abcDj_[sequenceOut_] > 0.0) {
	  directionOut_ = 1;
	} else {
	  directionOut_ = -1;
	}
      } else {
	// foolishly trust primal solution
	if (fakeValueOut > upperOut_) {
	  directionOut_ = -1;
	} else {
	  directionOut_ = 1;
	}
      }
#if 1
      // make sure plausible but only when fake primals stored
      if (directionOut_ < 0 && fabs(fakeValueOut - upperOut_) > dualBound_ + primalTolerance_) {
	if (fabs(fakeValueOut - upperOut_) > fabs(fakeValueOut - lowerOut_))
	  directionOut_ = 1;
      } else if (directionOut_ > 0 && fabs(fakeValueOut - lowerOut_) > dualBound_ + primalTolerance_) {
	if (fabs(fakeValueOut - upperOut_) < fabs(fakeValueOut - lowerOut_))
	  directionOut_ = -1;
      }
#endif
    }
#if ABC_NORMAL_DEBUG>3
    assert(dualOut_ >= 0.0);
#endif
  } else {
    sequenceOut_=-1;
  }
  alpha_=0.0;
  upperTheta_=COIN_DBL_MAX;
  return ;
}
// Checks if any fake bounds active - if so returns number and modifies
// dualBound_ and everything.
// Free variables will be left as free
// Returns number of bounds changed if >=0
// Returns -1 if not initialize and no effect
// Fills in changeVector which can be used to see if unbounded
// initialize is 0 or 3
// and cost of change vector
int
AbcSimplexDual::changeBounds(int initialize,
                             double & changeCost)
{
  assert (initialize==0||initialize==1||initialize==3||initialize==4);
  numberFake_ = 0;
  double *  COIN_RESTRICT abcLower = abcLower_;
  double *  COIN_RESTRICT abcUpper = abcUpper_;
  double *  COIN_RESTRICT abcSolution = abcSolution_;
  double *  COIN_RESTRICT abcCost = abcCost_;
  if (!initialize) {
    int numberInfeasibilities;
    double newBound;
    newBound = 5.0 * currentDualBound_;
    numberInfeasibilities = 0;
    changeCost = 0.0;
    // put back original bounds and then check
    CoinAbcMemcpy(abcLower,lowerSaved_,numberTotal_);
    CoinAbcMemcpy(abcUpper,upperSaved_,numberTotal_);
    const double * COIN_RESTRICT dj = abcDj_;
    int iSequence;
    // bounds will get bigger - just look at ones at bounds
    int numberFlipped=0;
    double checkBound=1.000000000001*currentDualBound_;
    for (iSequence = 0; iSequence < numberTotal_; iSequence++) {
      double lowerValue = abcLower[iSequence];
      double upperValue = abcUpper[iSequence];
      double value = abcSolution[iSequence];
      setFakeBound(iSequence, AbcSimplexDual::noFake);
      switch(getInternalStatus(iSequence)) {
	
      case basic:
      case AbcSimplex::isFixed:
	break;
      case isFree:
      case superBasic:
	break;
      case atUpperBound:
	if (fabs(value - upperValue) > primalTolerance_) {
	  // can we flip
	  if (value-lowerValue<checkBound&&dj[iSequence]>-currentDualTolerance_) {
	    abcSolution_[iSequence]=lowerValue;
	    setInternalStatus(iSequence,atLowerBound);
	    numberFlipped++;
	  } else {
	    numberInfeasibilities++;
	  }
	}
	break;
      case atLowerBound:
	if (fabs(value - lowerValue) > primalTolerance_) {
	  // can we flip
	  if (upperValue-value<checkBound&&dj[iSequence]<currentDualTolerance_) {
	    abcSolution_[iSequence]=upperValue;
	    setInternalStatus(iSequence,atUpperBound);
	    numberFlipped++;
	  } else {
	    numberInfeasibilities++;
	  }
	}
	break;
      }
    }
    // If dual infeasible then carry on
    if (numberInfeasibilities) {
      handler_->message(CLP_DUAL_CHECKB, messages_)
	<< newBound
	<< CoinMessageEol;
      int iSequence;
      for (iSequence = 0; iSequence < numberRows_ + numberColumns_; iSequence++) {
	double lowerValue = abcLower[iSequence];
	double upperValue = abcUpper[iSequence];
	double newLowerValue;
	double newUpperValue;
	Status status = getInternalStatus(iSequence);
	if (status == atUpperBound ||
	    status == atLowerBound) {
	  double value = abcSolution[iSequence];
	  if (value - lowerValue <= upperValue - value) {
	    newLowerValue = CoinMax(lowerValue, value - 0.666667 * newBound);
	    newUpperValue = CoinMin(upperValue, newLowerValue + newBound);
	  } else {
	    newUpperValue = CoinMin(upperValue, value + 0.666667 * newBound);
	    newLowerValue = CoinMax(lowerValue, newUpperValue - newBound);
	  }
	  abcLower[iSequence] = newLowerValue;
	  abcUpper[iSequence] = newUpperValue;
	  if (newLowerValue > lowerValue) {
	    if (newUpperValue < upperValue) {
	      setFakeBound(iSequence, AbcSimplexDual::bothFake);
#ifdef CLP_INVESTIGATE
	      abort(); // No idea what should happen here - I have never got here
#endif
	      numberFake_++;
	    } else {
	      setFakeBound(iSequence, AbcSimplexDual::lowerFake);
	      assert (abcLower[iSequence]>lowerSaved_[iSequence]);
	      assert (abcUpper[iSequence]==upperSaved_[iSequence]);
	      numberFake_++;
	    }
	  } else {
	    if (newUpperValue < upperValue) {
	      setFakeBound(iSequence, AbcSimplexDual::upperFake);
	      assert (abcLower[iSequence]==lowerSaved_[iSequence]);
	      assert (abcUpper[iSequence]<upperSaved_[iSequence]);
	      numberFake_++;
	    }
	  }
	  if (status == atUpperBound)
	    abcSolution[iSequence] = newUpperValue;
	  else
	    abcSolution[iSequence] = newLowerValue;
	  double movement = abcSolution[iSequence] - value;
	  changeCost += movement * abcCost[iSequence];
	}
      }
      currentDualBound_ = newBound;
#if ABC_NORMAL_DEBUG>0
      printf("new dual bound %g\n",currentDualBound_);
#endif
    } else {
      numberInfeasibilities = -1-numberFlipped;
    }
    return numberInfeasibilities;
  } else {
    int iSequence;
    if (initialize == 3) {
      for (iSequence = 0; iSequence < numberTotal_; iSequence++) {
#if ABC_NORMAL_DEBUG>1
	int bad=-1;
	if (getFakeBound(iSequence)==noFake) {
	  if (abcLower_[iSequence]!=lowerSaved_[iSequence]||
	      abcUpper_[iSequence]!=upperSaved_[iSequence]) 
	    bad=0;
	} else if (getFakeBound(iSequence)==lowerFake) {
	  if (abcLower_[iSequence]==lowerSaved_[iSequence]||
	      abcUpper_[iSequence]!=upperSaved_[iSequence]) 
	    bad=1;
	} else if (getFakeBound(iSequence)==upperFake) {
	  if (abcLower_[iSequence]!=lowerSaved_[iSequence]||
	      abcUpper_[iSequence]==upperSaved_[iSequence]) 
	    bad=2;
	} else {
	  if (abcLower_[iSequence]==lowerSaved_[iSequence]||
	      abcUpper_[iSequence]==upperSaved_[iSequence]) 
	    bad=3;
	}
	if (bad>=0) 
	  printf("%d status %d l %g,%g u %g,%g\n",iSequence,internalStatus_[iSequence],
		 abcLower_[iSequence],lowerSaved_[iSequence],
		 abcUpper_[iSequence],upperSaved_[iSequence]);
#endif
	setFakeBound(iSequence, AbcSimplexDual::noFake);
      }
      CoinAbcMemcpy(abcLower_,lowerSaved_,numberTotal_);
      CoinAbcMemcpy(abcUpper_,upperSaved_,numberTotal_);
    }
    double testBound = /*0.999999 **/ currentDualBound_;
    for (iSequence = 0; iSequence < numberTotal_; iSequence++) {
      Status status = getInternalStatus(iSequence);
      if (status == atUpperBound ||
	  status == atLowerBound) {
	double lowerValue = abcLower[iSequence];
	double upperValue = abcUpper[iSequence];
	double value = abcSolution[iSequence];
	if (lowerValue > -largeValue_ || upperValue < largeValue_) {
	  if (true || lowerValue - value > -0.5 * currentDualBound_ ||
	      upperValue - value < 0.5 * currentDualBound_) {
	    if (fabs(lowerValue - value) <= fabs(upperValue - value)) {
	      if (upperValue > lowerValue + testBound) {
		if (getFakeBound(iSequence) == AbcSimplexDual::noFake)
		  numberFake_++;
		abcUpper[iSequence] = lowerValue + currentDualBound_;
		double difference = upperSaved_[iSequence]-abcUpper[iSequence];
		if (difference<1.0e-10*(1.0+fabs(upperSaved_[iSequence])+dualBound_))
		  abcUpper[iSequence] = upperSaved_[iSequence];
		assert (abcUpper[iSequence]<=upperSaved_[iSequence]+1.0e-3*currentDualBound_);
		assert (abcLower[iSequence]>=lowerSaved_[iSequence]-1.0e-3*currentDualBound_);
		if (upperSaved_[iSequence]-abcUpper[iSequence]>
		    abcLower[iSequence]-lowerSaved_[iSequence]) {
		  setFakeBound(iSequence, AbcSimplexDual::upperFake);
		  assert (abcLower[iSequence]==lowerSaved_[iSequence]);
		  assert (abcUpper[iSequence]<upperSaved_[iSequence]);
		} else {
		  setFakeBound(iSequence, AbcSimplexDual::lowerFake);
		  assert (abcLower[iSequence]>lowerSaved_[iSequence]);
		  assert (abcUpper[iSequence]==upperSaved_[iSequence]);
		}
	      }
	    } else {
	      if (lowerValue < upperValue - testBound) {
		if (getFakeBound(iSequence) == AbcSimplexDual::noFake)
		  numberFake_++;
		abcLower[iSequence] = upperValue - currentDualBound_;
		double difference = abcLower[iSequence]-lowerSaved_[iSequence];
		if (difference<1.0e-10*(1.0+fabs(lowerSaved_[iSequence])+dualBound_))
		  abcLower[iSequence] = lowerSaved_[iSequence];
		assert (abcUpper[iSequence]<=upperSaved_[iSequence]+1.0e-3*currentDualBound_);
		assert (abcLower[iSequence]>=lowerSaved_[iSequence]-1.0e-3*currentDualBound_);
		if (upperSaved_[iSequence]-abcUpper[iSequence]>
		    abcLower[iSequence]-lowerSaved_[iSequence]) {
		  setFakeBound(iSequence, AbcSimplexDual::upperFake);
		  //assert (abcLower[iSequence]==lowerSaved_[iSequence]);
		  abcLower[iSequence]=CoinMax(abcLower[iSequence],lowerSaved_[iSequence]);
		  assert (abcUpper[iSequence]<upperSaved_[iSequence]);
		} else {
		  setFakeBound(iSequence, AbcSimplexDual::lowerFake);
		  assert (abcLower[iSequence]>lowerSaved_[iSequence]);
		  //assert (abcUpper[iSequence]==upperSaved_[iSequence]);
		  abcUpper[iSequence]=CoinMin(abcUpper[iSequence],upperSaved_[iSequence]);
		}
	      }
	    }
	  } else {
	    if (getFakeBound(iSequence) == AbcSimplexDual::noFake)
	      numberFake_++;
	    abcLower[iSequence] = -0.5 * currentDualBound_;
	    abcUpper[iSequence] = 0.5 * currentDualBound_;
	    setFakeBound(iSequence, AbcSimplexDual::bothFake);
	    abort();
	  }
	  if (status == atUpperBound)
	    abcSolution[iSequence] = abcUpper[iSequence];
	  else
	    abcSolution[iSequence] = abcLower[iSequence];
	} else {
	  // set non basic free variables to fake bounds
	  // I don't think we should ever get here
	  CoinAssert(!("should not be here"));
	  abcLower[iSequence] = -0.5 * currentDualBound_;
	  abcUpper[iSequence] = 0.5 * currentDualBound_;
	  setFakeBound(iSequence, AbcSimplexDual::bothFake);
	  numberFake_++;
	  setInternalStatus(iSequence, atUpperBound);
	  abcSolution[iSequence] = 0.5 * currentDualBound_;
	}
      } else if (status == basic) {
	// make sure not at fake bound and bounds correct
	setFakeBound(iSequence, AbcSimplexDual::noFake);
	double gap = abcUpper[iSequence] - abcLower[iSequence];
	if (gap > 0.5 * currentDualBound_ && gap < 2.0 * currentDualBound_) {
	  abcLower[iSequence] = lowerSaved_[iSequence];;
	  abcUpper[iSequence] = upperSaved_[iSequence];;
	}
      }
    }
    return 0;
  }
}
/*
  order of variables is a) atLo/atUp
                        b) free/superBasic
			pre pass done in AbcMatrix to get possibles
			dj's will be stored in a parallel array (tempArray) for first pass
			this pass to be done inside AbcMatrix then as now
			use perturbationArray as variable tolerance
  idea is to use large tolerances and then balance and reduce every so often
  this should be in conjunction with dualBound changes
  variables always stay at bounds on accuracy issues - only deliberate flips allowed
  variable tolerance should be 0.8-1.0 desired (at end)
  use going to clpMatrix_ as last resort
 */
/*
  Array has tableau row
  Puts candidates in list
  Returns upper theta (infinity if no pivot) and may set sequenceIn_ if free
*/
void
AbcSimplexDual::dualColumn1(bool doAll)
{
  const CoinIndexedVector & update = usefulArray_[arrayForBtran_];
  CoinPartitionedVector & tableauRow = usefulArray_[arrayForTableauRow_];
  CoinPartitionedVector & candidateList = usefulArray_[arrayForDualColumn_];
  if ((stateOfProblem_&VALUES_PASS)==0)
    upperTheta_=1.0e31;
  else
    upperTheta_=fabs(abcDj_[sequenceOut_])-0.5*dualTolerance_;
  assert (upperTheta_>0.0);
  if (!doAll) 
    upperTheta_ = abcMatrix_->dualColumn1(update,tableauRow,candidateList);
  else
    upperTheta_ = dualColumn1B();
  //tableauRow.compact();
  //candidateList.compact();
  //tableauRow.setPackedMode(true);
  //candidateList.setPackedMode(true);
}
/*
  Array has tableau row
  Puts candidates in list
  Returns upper theta (infinity if no pivot) and may set sequenceIn_ if free
*/
double
AbcSimplexDual::dualColumn1A()
{
  const CoinIndexedVector & update = usefulArray_[arrayForBtran_];
  CoinPartitionedVector & tableauRow = usefulArray_[arrayForTableauRow_];
  CoinPartitionedVector & candidateList = usefulArray_[arrayForDualColumn_];
  int numberRemaining = 0;
  double upperTheta = upperTheta_;
  // pivot elements
  double *  COIN_RESTRICT arrayCandidate=candidateList.denseVector();
  // indices
  int *  COIN_RESTRICT indexCandidate = candidateList.getIndices();
  const double *  COIN_RESTRICT abcDj = abcDj_;
  //const double *  COIN_RESTRICT abcPerturbation = abcPerturbation_;
  const unsigned char *  COIN_RESTRICT internalStatus = internalStatus_;
  const double *  COIN_RESTRICT pi=update.denseVector();
  const int *  COIN_RESTRICT piIndex = update.getIndices();
  int number = update.getNumElements();
  int *  COIN_RESTRICT index = tableauRow.getIndices();
  double *  COIN_RESTRICT array = tableauRow.denseVector();
  assert (!tableauRow.getNumElements());
  int numberNonZero=0;
  // do first pass to get possibles
  double bestPossible = 0.0;
  // We can also see if infeasible or pivoting on free
  double tentativeTheta = 1.0e25; // try with this much smaller as guess
  double acceptablePivot = currentAcceptablePivot_;
  double dualT=-currentDualTolerance_;
  const double multiplier[] = { 1.0, -1.0};
  if (ordinaryVariables_) {
    for (int i=0;i<number;i++) {
      int iRow=piIndex[i];
      unsigned char type=internalStatus[iRow];
      if ((type&4)==0) {
	index[numberNonZero]=iRow;
	double piValue=pi[iRow];
	array[numberNonZero++]=piValue;
	int iStatus = internalStatus[iRow] & 3;
	double mult = multiplier[iStatus];
	double alpha = piValue * mult;
	double oldValue = abcDj[iRow] * mult;
	double value = oldValue - tentativeTheta * alpha;
	if (value < dualT) {
	  bestPossible = CoinMax(bestPossible, alpha);
	  value = oldValue - upperTheta * alpha;
	  if (value < dualT && alpha >= acceptablePivot) {
	    upperTheta = (oldValue - dualT) / alpha;
	  }
	  // add to list
	  arrayCandidate[numberRemaining] = alpha;
	  indexCandidate[numberRemaining++] = iRow;
	}
      }
    }
  } else {
    double badFree = 0.0;
    double freePivot = currentAcceptablePivot_;
    alpha_ = 0.0;
    // We can also see if infeasible or pivoting on free
    for (int i=0;i<number;i++) {
      int iRow=piIndex[i];
      unsigned char type=internalStatus[iRow];
      double piValue=pi[iRow];
      if ((type&4)==0) {
	index[numberNonZero]=iRow;
	array[numberNonZero++]=piValue;
	int iStatus = internalStatus[iRow] & 3;
	double mult = multiplier[iStatus];
	double alpha = piValue * mult;
	double oldValue = abcDj[iRow] * mult;
	double value = oldValue - tentativeTheta * alpha;
	if (value < dualT) {
	  bestPossible = CoinMax(bestPossible, alpha);
	  value = oldValue - upperTheta * alpha;
	  if (value < dualT && alpha >= acceptablePivot) {
	    upperTheta = (oldValue - dualT) / alpha;
	  }
	  // add to list
	  arrayCandidate[numberRemaining] = alpha;
	  indexCandidate[numberRemaining++] = iRow;
	}
      } else if ((type&7)<6) {
	//} else if (getInternalStatus(iRow)==isFree||getInternalStatus(iRow)==superBasic) {
	bool keep;
	index[numberNonZero]=iRow;
	array[numberNonZero++]=piValue;
	bestPossible = CoinMax(bestPossible, fabs(piValue));
	double oldValue = abcDj[iRow];
	// If free has to be very large - should come in via dualRow
	//if (getInternalStatus(iRow+addSequence)==isFree&&fabs(piValue)<1.0e-3)
	//break;
	if (oldValue > currentDualTolerance_) {
	  keep = true;
	} else if (oldValue < -currentDualTolerance_) {
	  keep = true;
	} else {
	  if (fabs(piValue) > CoinMax(10.0 * currentAcceptablePivot_, 1.0e-5)) {
	    keep = true;
	  } else {
	    keep = false;
	    badFree = CoinMax(badFree, fabs(piValue));
	  }
	}
	if (keep) {
	  // free - choose largest
	  if (fabs(piValue) > freePivot) {
	    freePivot = fabs(piValue);
	    sequenceIn_ = iRow;
	    theta_ = oldValue / piValue;
	    alpha_ = piValue;
	  }
	}
      }
    }
  }
  //tableauRow.setNumElements(numberNonZero);
  //candidateList.setNumElements(numberRemaining);
  tableauRow.setNumElementsPartition(0,numberNonZero);
  candidateList.setNumElementsPartition(0,numberRemaining);
 if (!numberRemaining && sequenceIn_ < 0&&upperTheta_>1.0e29) {
    return COIN_DBL_MAX; // Looks infeasible
  } else {
    return upperTheta;
  }
}
/*
  Array has tableau row
  Puts candidates in list
  Returns upper theta (infinity if no pivot) and may set sequenceIn_ if free
*/
double
AbcSimplexDual::dualColumn1B()
{
  CoinPartitionedVector & tableauRow = usefulArray_[arrayForTableauRow_];
  CoinPartitionedVector & candidateList = usefulArray_[arrayForDualColumn_];
  tableauRow.compact();
  candidateList.clearAndReset();
  tableauRow.setPackedMode(true);
  candidateList.setPackedMode(true);
  int numberRemaining = 0;
  double upperTheta = upperTheta_;
  // pivot elements
  double *  COIN_RESTRICT arrayCandidate=candidateList.denseVector();
  // indices
  int *  COIN_RESTRICT indexCandidate = candidateList.getIndices();
  const double *  COIN_RESTRICT abcDj = abcDj_;
  const unsigned char *  COIN_RESTRICT internalStatus = internalStatus_;
  int *  COIN_RESTRICT index = tableauRow.getIndices();
  double *  COIN_RESTRICT array = tableauRow.denseVector();
  int numberNonZero=tableauRow.getNumElements();
  // do first pass to get possibles
  double bestPossible = 0.0;
  // We can also see if infeasible or pivoting on free
  double tentativeTheta = 1.0e25; // try with this much smaller as guess
  double acceptablePivot = currentAcceptablePivot_;
  double dualT=-currentDualTolerance_;
  const double multiplier[] = { 1.0, -1.0};
  if (ordinaryVariables_) {
    for (int i=0;i<numberNonZero;i++) {
      int iSequence=index[i];
      unsigned char iStatus=internalStatus[iSequence]&7;
      if (iStatus<4) {
	double tableauValue=array[i];
	if (fabs(tableauValue)>zeroTolerance_) {
	  double mult = multiplier[iStatus];
	  double alpha = tableauValue * mult;
	  double oldValue = abcDj[iSequence] * mult;
	  double value = oldValue - tentativeTheta * alpha;
	  if (value < dualT) {
	    bestPossible = CoinMax(bestPossible, alpha);
	    value = oldValue - upperTheta * alpha;
	    if (value < dualT && alpha >= acceptablePivot) {
	      upperTheta = (oldValue - dualT) / alpha;
	    }
	    // add to list
	    arrayCandidate[numberRemaining] = alpha;
	    indexCandidate[numberRemaining++] = iSequence;
	  }
	}
      }
    }
  } else {
    double badFree = 0.0;
    double freePivot = currentAcceptablePivot_;
    double currentDualTolerance = currentDualTolerance_;
    for (int i=0;i<numberNonZero;i++) {
      int iSequence=index[i];
      unsigned char iStatus=internalStatus[iSequence]&7;
      if (iStatus<6) {
	double tableauValue=array[i];
	if (fabs(tableauValue)>zeroTolerance_) {
	  if ((iStatus&4)==0) {
	    double mult = multiplier[iStatus];
	    double alpha = tableauValue * mult;
	    double oldValue = abcDj[iSequence] * mult;
	    double value = oldValue - tentativeTheta * alpha;
	    if (value < dualT) {
	      bestPossible = CoinMax(bestPossible, alpha);
	      value = oldValue - upperTheta * alpha;
	      if (value < dualT && alpha >= acceptablePivot) {
		upperTheta = (oldValue - dualT) / alpha;
	      }
	      // add to list
	      arrayCandidate[numberRemaining] = alpha;
	      indexCandidate[numberRemaining++] = iSequence;
	    }
	  } else {
	    bool keep;
	    bestPossible = CoinMax(bestPossible, fabs(tableauValue));
	    double oldValue = abcDj[iSequence];
	    // If free has to be very large - should come in via dualRow
	    //if (getInternalStatus(iSequence+addSequence)==isFree&&fabs(tableauValue)<1.0e-3)
	    //break;
	    if (oldValue > currentDualTolerance) {
	      keep = true;
	    } else if (oldValue < -currentDualTolerance) {
	      keep = true;
	    } else {
	      if (fabs(tableauValue) > CoinMax(10.0 * acceptablePivot, 1.0e-5)) {
		keep = true;
	      } else {
		keep = false;
		badFree = CoinMax(badFree, fabs(tableauValue));
	      }
	    }
	    if (keep) {
#ifdef PAN
	      if (fakeSuperBasic(iSequence)>=0) {
#endif
		if (iSequence==freeSequenceIn_)
		  tableauValue=COIN_DBL_MAX;
		// free - choose largest
		if (fabs(tableauValue) > fabs(freePivot)) {
		  freePivot = tableauValue;
		  sequenceIn_ = iSequence;
		  theta_ = oldValue / tableauValue;
		  alpha_ = tableauValue;
		}
#ifdef PAN
	      }
#endif
	    }
	  }
	}
      }
    }
  } 
  candidateList.setNumElements(numberRemaining);
  if (!numberRemaining && sequenceIn_ < 0&&upperTheta_>1.0e29) {
    return COIN_DBL_MAX; // Looks infeasible
  } else {
    return upperTheta;
  }
}
//#define MORE_CAREFUL
//#define PRINT_RATIO_PROGRESS
#define MINIMUMTHETA 1.0e-18
#define MAXTRY 100
#define TOL_TYPE -1
#if TOL_TYPE==-1
#define useTolerance1() (0.0)      
#define useTolerance2() (0.0)
#define goToTolerance1() (0.0)
#define goToTolerance2() (0.0)
#elif TOL_TYPE==0
#define useTolerance1() (currentDualTolerance_)      
#define useTolerance2() (currentDualTolerance_)
#define goToTolerance1() (0.0)
#define goToTolerance2() (0.0)
#elif TOL_TYPE==1
#define useTolerance1() (perturbedTolerance)      
#define useTolerance2() (0.0)
#define goToTolerance1() (0.0)
#define goToTolerance2() (0.0)
#elif TOL_TYPE==2
#define useTolerance1() (perturbedTolerance)      
#define useTolerance2() (perturbedTolerance)
#define goToTolerance1() (0.0)
#define goToTolerance2() (0.0)
#elif TOL_TYPE==3
#define useTolerance1() (perturbedTolerance)      
#define useTolerance2() (perturbedTolerance)
#define goToTolerance1() (perturbedTolerance)
#define goToTolerance2() (0.0)
#elif TOL_TYPE==4
#define useTolerance1() (perturbedTolerance)      
#define useTolerance2() (perturbedTolerance)
#define goToTolerance1() (perturbedTolerance)
#define goToTolerance2() (perturbedTolerance)
#else
XXXX
#endif      
#if CLP_CAN_HAVE_ZERO_OBJ<2
#define MODIFYCOST 2
#endif
#define DONT_MOVE_OBJECTIVE
static void dualColumn2Bit(AbcSimplexDual * dual,dualColumnResult * result,
			     int numberBlocks)
{
  for (int iBlock=1;iBlock<numberBlocks;iBlock++) {
    cilk_spawn dual->dualColumn2First(result[iBlock]);
  }
  dual->dualColumn2First(result[0]);
  cilk_sync;
}
void
AbcSimplexDual::dualColumn2First(dualColumnResult & result)
{
  CoinPartitionedVector & candidateList = usefulArray_[arrayForDualColumn_]; 
  CoinPartitionedVector & flipList = usefulArray_[arrayForFlipBounds_];
  int iBlock=result.block;
  int numberSwapped = result.numberSwapped;
  int numberRemaining = result.numberRemaining;
  double tentativeTheta=result.tentativeTheta;
  // pivot elements
  double *  COIN_RESTRICT array=candidateList.denseVector();
  // indices
  int *  COIN_RESTRICT indices = candidateList.getIndices();
  const double *  COIN_RESTRICT abcLower = abcLower_;
  const double *  COIN_RESTRICT abcUpper = abcUpper_;
  const double *  COIN_RESTRICT abcDj = abcDj_;
  const unsigned char *  COIN_RESTRICT internalStatus = internalStatus_;
  const double multiplier[] = { 1.0, -1.0};

  // For list of flipped
  int *  COIN_RESTRICT flippedIndex = flipList.getIndices();
  double *  COIN_RESTRICT flippedElement = flipList.denseVector();
  // adjust
  //if (iBlock>=0) {
    int offset=candidateList.startPartition(iBlock);
    assert(offset==flipList.startPartition(iBlock));
    array += offset;
    indices+=offset;
    flippedIndex+=offset;
    flippedElement+=offset;
    //}
  double thruThis = 0.0;
  
  double bestPivot = currentAcceptablePivot_;
  int bestSequence = -1;
  int numberInList=numberRemaining;
  numberRemaining = 0;
  double upperTheta = 1.0e50;
  double increaseInThis = 0.0; //objective increase in this loop
  for (int i = 0; i < numberInList; i++) {
    int iSequence = indices[i];
    assert (getInternalStatus(iSequence) != isFree
	    && getInternalStatus(iSequence) != superBasic);
    int iStatus = internalStatus[iSequence] & 3;
    // treat as if at lower bound
    double mult = multiplier[iStatus];
    double alpha = array[i];
    double oldValue = abcDj[iSequence]*mult;
    double value = oldValue - tentativeTheta * alpha;
    assert (alpha>0.0);
    //double perturbedTolerance = abcPerturbation[iSequence];
    if (value < -currentDualTolerance_) {
      // possible here or could go through
      double range = abcUpper[iSequence] - abcLower[iSequence];
      thruThis += range * alpha;
      increaseInThis += (oldValue - useTolerance1()) * range;
      // goes on swapped list (also means candidates if too many)
      flippedElement[numberSwapped] = alpha;
      flippedIndex[numberSwapped++] = iSequence;
      if (alpha > bestPivot) {
	bestPivot = alpha;
	bestSequence = iSequence;
      }
    } else {
      // won't go through this time
      value = oldValue - upperTheta * alpha;
      if (value < -currentDualTolerance_ && alpha >= currentAcceptablePivot_)
	upperTheta = (oldValue + currentDualTolerance_) / alpha;
      array[numberRemaining] = alpha;
      indices[numberRemaining++] = iSequence;
    }
  }
  result.bestEverPivot=bestPivot;
  result.sequence=bestSequence;
  result.numberSwapped=numberSwapped;
  result.numberRemaining=numberRemaining;
  result.thruThis=thruThis;
  result.increaseInThis=increaseInThis;
  result.theta=upperTheta;
}
void
AbcSimplexDual::dualColumn2Most(dualColumnResult & result)
{
  CoinPartitionedVector & candidateList = usefulArray_[arrayForDualColumn_]; 
  CoinPartitionedVector & flipList = usefulArray_[arrayForFlipBounds_];
  int numberBlocksReal=candidateList.getNumPartitions();
  flipList.setPartitions(numberBlocksReal,candidateList.startPartitions());
  int numberBlocks;
  if (!numberBlocksReal)
    numberBlocks=1;
  else
    numberBlocks=numberBlocksReal;
  //usefulArray_[arrayForTableauRow_].compact();
  //candidateList.compact();
  int numberSwapped = 0;
  int numberRemaining = candidateList.getNumElements();
  
  double totalThru = 0.0; // for when variables flip
  int sequenceIn=-1;
  double bestEverPivot = currentAcceptablePivot_;
  // If we think we need to modify costs (not if something from broad sweep)
  bool modifyCosts = false;
  // Increase in objective due to swapping bounds (may be negative)
  double increaseInObjective = 0.0;
  // pivot elements
  double *  COIN_RESTRICT array=candidateList.denseVector();
  // indices
  int *  COIN_RESTRICT indices = candidateList.getIndices();
  const double *  COIN_RESTRICT abcLower = abcLower_;
  const double *  COIN_RESTRICT abcUpper = abcUpper_;
  //const double *  COIN_RESTRICT abcSolution = abcSolution_;
  const double *  COIN_RESTRICT abcDj = abcDj_;
  //const double *  COIN_RESTRICT abcPerturbation = abcPerturbation_;
  const unsigned char *  COIN_RESTRICT internalStatus = internalStatus_;
  // We can also see if infeasible or pivoting on free
  double tentativeTheta = 1.0e25; // try with this much smaller as guess
  const double multiplier[] = { 1.0, -1.0};

  // For list of flipped
  int numberLastSwapped=0;
  int *  COIN_RESTRICT flippedIndex = flipList.getIndices();
  double *  COIN_RESTRICT flippedElement = flipList.denseVector();
  // If sum of bad small pivots too much
#ifdef MORE_CAREFUL
  bool badSumPivots = false;
#endif
  // not free
  int lastSequence = -1;
  double lastTheta = 0.0; 
  double lastPivotValue = 0.0;
  double thisPivotValue=0.0;
  // if free then always choose , otherwise ...
  double theta = 1.0e50;
  // now flip flop between spare arrays until reasonable theta
  tentativeTheta = CoinMax(10.0 * upperTheta_, 1.0e-7);
  
  // loops increasing tentative theta until can't go through
#ifdef PRINT_RATIO_PROGRESS
  int iPass=0;
#endif
  dualColumnResult result2[8];
  for (int iBlock=0;iBlock<numberBlocks;iBlock++) {
    result2[iBlock].block=iBlock;
    if (numberBlocksReal)
      result2[iBlock].numberRemaining=candidateList.getNumElements(iBlock);
    else
      result2[iBlock].numberRemaining=candidateList.getNumElements();
    result2[iBlock].numberSwapped=0;
    result2[iBlock].numberLastSwapped=0;
  }
  double useThru=0.0;
  while (tentativeTheta < 1.0e22) {
    double thruThis = 0.0;
    
    double bestPivot = currentAcceptablePivot_;
    int bestSequence = -1;
    sequenceIn=-1;
    thisPivotValue=0.0;
    int numberInList=numberRemaining;
    double upperTheta = 1.0e50;
    double increaseInThis = 0.0; //objective increase in this loop
    for (int iBlock=0;iBlock<numberBlocks;iBlock++) {
      result2[iBlock].tentativeTheta=tentativeTheta;
      //result2[iBlock].numberRemaining=numberRemaining;
      //result2[iBlock].numberSwapped=numberSwapped;
      //result2[iBlock].numberLastSwapped=numberLastSwapped;
    }
    for (int iBlock=1;iBlock<numberBlocks;iBlock++) {
      cilk_spawn dualColumn2First(result2[iBlock]);
    }
    dualColumn2First(result2[0]);
    cilk_sync;
    //dualColumn2Bit(this,result2,numberBlocks);
    numberSwapped=0;
    numberRemaining=0;
    for (int iBlock=0;iBlock<numberBlocks;iBlock++) {
      if (result2[iBlock].bestEverPivot>bestPivot) {
	bestPivot=result2[iBlock].bestEverPivot;
	bestSequence=result2[iBlock].sequence;
      }
      numberSwapped+=result2[iBlock].numberSwapped;
      numberRemaining+=result2[iBlock].numberRemaining;
      thruThis+=result2[iBlock].thruThis;
      increaseInThis+=result2[iBlock].increaseInThis;
      if (upperTheta>result2[iBlock].theta)
	upperTheta=result2[iBlock].theta;
    }
    // end of pass
#ifdef PRINT_RATIO_PROGRESS
    iPass++;
    printf("Iteration %d pass %d dualOut %g thru %g increase %g numberRemain %d\n",
	   numberIterations_,iPass,fabs(dualOut_),totalThru+thruThis,increaseInObjective+increaseInThis,
	   numberRemaining);
#endif
    if (totalThru + thruThis > fabs(dualOut_)-fabs(1.0e-9*dualOut_)-1.0e-12 ||
	(increaseInObjective + increaseInThis < 0.0&&bestSequence>=0) || !numberRemaining) {
      // We should be pivoting in this batch
      // so compress down to this lot
      numberRemaining=0;
      candidateList.clearAndReset();
      for (int iBlock=0;iBlock<numberBlocks;iBlock++) {
	int offset=flipList.startPartition(iBlock);
	// set so can compact
	int numberKeep=result2[iBlock].numberLastSwapped;
	flipList.setNumElementsPartition(iBlock,numberKeep);
	for (int i = offset+numberKeep; i <offset+result2[iBlock].numberSwapped; i++) {
	  array[numberRemaining] = flippedElement[i];
	  flippedElement[i]=0;
	  indices[numberRemaining++] = flippedIndex[i];
	}
      }
      // make sure candidateList will be cleared correctly
      candidateList.setNumElements(numberRemaining);
      candidateList.setPackedMode(true);
      flipList.compact();
      numberSwapped=numberLastSwapped;
      useThru=totalThru;
      assert (totalThru<=fabs(dualOut_));
      int iTry;
      // first get ratio with tolerance
      for (iTry = 0; iTry < MAXTRY; iTry++) {
	
	upperTheta = 1.0e50;
	numberInList=numberRemaining;
	numberRemaining = 0;
	increaseInThis = 0.0; //objective increase in this loop
	thruThis = 0.0;
	for (int i = 0; i < numberInList; i++) {
	  int iSequence = indices[i];
	  assert (getInternalStatus(iSequence) != isFree
		  && getInternalStatus(iSequence) != superBasic);
	  int iStatus = internalStatus[iSequence] & 3;
	  // treat as if at lower bound
	  double mult = multiplier[iStatus];
	  double alpha = array[i];
	  double oldValue = abcDj[iSequence]*mult;
	  double value = oldValue - upperTheta * alpha;
	  assert (alpha>0.0);
	  //double perturbedTolerance = abcPerturbation[iSequence];
	  if (value < -currentDualTolerance_) {
	    if (alpha >= currentAcceptablePivot_) {
	      upperTheta = (oldValue + currentDualTolerance_) / alpha;
	    }
	  }
	}
	bestPivot = currentAcceptablePivot_;
	sequenceIn = -1;
	double largestPivot = currentAcceptablePivot_;
	// Sum of bad small pivots
#ifdef MORE_CAREFUL
	double sumBadPivots = 0.0;
	badSumPivots = false;
#endif
	// Make sure upperTheta will work (-O2 and above gives problems)
	upperTheta *= 1.0000000001;
	for (int i = 0; i < numberInList; i++) {
	  int iSequence = indices[i];
	  int iStatus = internalStatus[iSequence] & 3;
	  // treat as if at lower bound
	  double mult = multiplier[iStatus];
	  double alpha = array[i];
	  double oldValue = abcDj[iSequence]*mult;
	  double value = oldValue - upperTheta * alpha;
	  assert (alpha>0.0);
	  //double perturbedTolerance = abcPerturbation[iSequence];
	  double badDj = 0.0;
	  if (value <= 0.0) {
	    // add to list of swapped
	    flippedElement[numberSwapped] = alpha;
	    flippedIndex[numberSwapped++] = iSequence;
	    badDj = oldValue - useTolerance2();
	    // select if largest pivot
	    bool take = (alpha > bestPivot); 
#ifdef MORE_CAREFUL
	    if (alpha < currentAcceptablePivot_ && upperTheta < 1.0e20) {
	      if (value < -currentDualTolerance_) {
		double gap = abcUpper[iSequence] - abcLower[iSequence];
		if (gap < 1.0e20)
		  sumBadPivots -= value * gap;
		else
		  sumBadPivots += 1.0e20;
		//printf("bad %d alpha %g dj at lower %g\n",
		//     iSequence,alpha,value);
	      }
	    }
#endif
	    if (take&&flagged(iSequence)) {
	      if (bestPivot>currentAcceptablePivot_)
		take=false;
	    }
	    if (take) {
	      sequenceIn = iSequence;
	      thisPivotValue=alpha;
	      bestPivot =  alpha;
	      if (flagged(iSequence)) 
		bestPivot=currentAcceptablePivot_;
	      bestSequence = iSequence;
	      theta = (oldValue+goToTolerance1()) / alpha;
	      //assert (oldValue==abcDj[iSequence]);
	      largestPivot = CoinMax(largestPivot, 0.5 * bestPivot);
	    }
	    double range = abcUpper[iSequence] - abcLower[iSequence];
	    thruThis += range * fabs(alpha);
	    increaseInThis += badDj * range;
	  } else {
	    // add to list of remaining
	    array[numberRemaining] = alpha;
	    indices[numberRemaining++] = iSequence;
	  }
	}
#ifdef MORE_CAREFUL
	// If we have done pivots and things look bad set alpha_ 0.0 to force factorization
	if (sumBadPivots > 1.0e4) {
#if ABC_NORMAL_DEBUG>0
	  if (handler_->logLevel() > 1)
	    printf("maybe forcing re-factorization - sum %g  %d pivots\n", sumBadPivots,
		   abcFactorization_->pivots());
#endif
	  if(abcFactorization_->pivots() > 3) {
	    badSumPivots = true;
#ifdef PRINT_RATIO_PROGRESS
	    printf("maybe forcing re-factorization - sum %g  %d pivots\n", sumBadPivots,
		   abcFactorization_->pivots());
#endif
	    break;
	  }
	}
#endif
	// If we stop now this will be increase in objective (I think)
	double increase = (fabs(dualOut_) - totalThru) * theta;
	increase += increaseInObjective;
	if (theta < 0.0)
	  thruThis += fabs(dualOut_); // force using this one
	if (((increaseInObjective < 0.0 && increase < 0.0)||
	     (theta>1.0e9 && lastTheta < 1.0e-5))
	    && lastSequence >= 0) {
	  // back
	  // We may need to be more careful - we could do by
	  // switch so we always do fine grained?
	  bestPivot = 0.0;
	  bestSequence=-1;
	} else {
	  // add in
	  totalThru += thruThis;
	  increaseInObjective += increaseInThis;
	  lastTheta=theta;
	}
	if (bestPivot < 0.1 * bestEverPivot &&
	    bestEverPivot > 1.0e-6 &&
	    (bestPivot < 1.0e-3 || totalThru * 2.0 > fabs(dualOut_))) {
	  // back to previous one
	  sequenceIn = lastSequence;
	  thisPivotValue=lastPivotValue;
#ifdef PRINT_RATIO_PROGRESS
	  printf("Try %d back to previous bestPivot %g bestEver %g totalThru %g\n",
		 iTry,bestPivot,bestEverPivot,totalThru);
#endif
	  break;
	} else if (sequenceIn == -1 && upperTheta > largeValue_) {
	  if (lastPivotValue > currentAcceptablePivot_) {
	    // back to previous one
	    sequenceIn = lastSequence;
	    thisPivotValue=lastPivotValue;
#ifdef PRINT_RATIO_PROGRESS
	    printf("Try %d no pivot this time large theta %g lastPivot %g\n",
		   iTry,upperTheta,lastPivotValue);
#endif
	  } else {
	    // can only get here if all pivots too small
#ifdef PRINT_RATIO_PROGRESS
	    printf("XXBAD Try %d no pivot this time large theta %g lastPivot %g\n",
		   iTry,upperTheta,lastPivotValue);
#endif
	  }
	  break;
	} else if (totalThru >= fabs(dualOut_)) {
#ifdef PRINT_RATIO_PROGRESS
	  printf("Try %d upperTheta %g totalThru %g - can modify costs\n",
		 iTry,upperTheta,lastPivotValue);
#endif
	  modifyCosts = true; // fine grain - we can modify costs
	  break; // no point trying another loop
	} else {
	  lastSequence = sequenceIn;
	  lastPivotValue=thisPivotValue;
	  if (bestPivot > bestEverPivot) {
	    bestEverPivot = bestPivot;
	    //bestEverSequence=bestSequence;
	  }
	  modifyCosts = true; // fine grain - we can modify costs
	}
#ifdef PRINT_RATIO_PROGRESS
	printf("Onto next pass totalthru %g bestPivot %g\n",
	       totalThru,lastPivotValue);
#endif
	numberLastSwapped=numberSwapped;
      }
      break;
    } else {
      // skip this lot
      if (bestPivot > 1.0e-3 || bestPivot > bestEverPivot) {
#ifdef PRINT_RATIO_PROGRESS
	printf("Continuing bestPivot %g bestEver %g %d swapped - new tentative %g\n",
	       bestPivot,bestEverPivot,numberSwapped,2*upperTheta);
#endif
	bestEverPivot = bestPivot;
	//bestEverSequence=bestSequence;
	lastPivotValue=bestPivot;
	lastSequence = bestSequence;
	for (int iBlock=0;iBlock<numberBlocks;iBlock++) 
	  result2[iBlock].numberLastSwapped=result2[iBlock].numberSwapped;
	numberLastSwapped=numberSwapped;
      } else {
#ifdef PRINT_RATIO_PROGRESS
	printf("keep old swapped bestPivot %g bestEver %g %d swapped - new tentative %g\n",
	       bestPivot,bestEverPivot,numberSwapped,2*upperTheta);
#endif
	// keep old swapped
	numberRemaining=0;
	for (int iBlock=0;iBlock<numberBlocks;iBlock++) {
	  int offset=flipList.startPartition(iBlock);
	  int numberRemaining2=offset+result2[iBlock].numberRemaining;
	  int numberLastSwapped=result2[iBlock].numberLastSwapped;
	  for (int i = offset+numberLastSwapped; 
	       i <offset+result2[iBlock].numberSwapped; i++) {
	    array[numberRemaining2] = flippedElement[i];
	    flippedElement[i]=0;
	    indices[numberRemaining2++] = flippedIndex[i];
	  }
	  result2[iBlock].numberRemaining=numberRemaining2-offset;
	  numberRemaining += result2[iBlock].numberRemaining;
	  result2[iBlock].numberSwapped=numberLastSwapped;
	}
	numberSwapped=numberLastSwapped;
      }
      increaseInObjective += increaseInThis;
      tentativeTheta = 2.0 * upperTheta;
      totalThru += thruThis;
    }
  }
  if (flipList.getNumPartitions()) {
    // need to compress
    numberRemaining=0;
    candidateList.clearAndReset();
    for (int iBlock=0;iBlock<numberBlocks;iBlock++) {
      int offset=flipList.startPartition(iBlock);
      // set so can compact
      int numberKeep=result2[iBlock].numberLastSwapped;
      flipList.setNumElementsPartition(iBlock,numberKeep);
      for (int i = offset+numberKeep; i <offset+result2[iBlock].numberSwapped; i++) {
	array[numberRemaining] = flippedElement[i];
	flippedElement[i]=0;
	indices[numberRemaining++] = flippedIndex[i];
      }
    }
    // make sure candidateList will be cleared correctly
    candidateList.setNumElements(numberRemaining);
    candidateList.setPackedMode(true);
    flipList.compact();
    numberSwapped=numberLastSwapped;
  }
  result.theta=theta; //?
  result.totalThru=totalThru;
  result.useThru=useThru;
  result.bestEverPivot=bestEverPivot; //?
  result.increaseInObjective=increaseInObjective; //?
  result.tentativeTheta=tentativeTheta; //?
  result.lastPivotValue=lastPivotValue;
  result.thisPivotValue=thisPivotValue;
  result.lastSequence=lastSequence;
  result.sequence=sequenceIn;
  //result.block;
  //result.pass;
  //result.phase;
  result.numberSwapped=numberSwapped;
  result.numberLastSwapped=numberLastSwapped;
  result.modifyCosts=modifyCosts;
}
/*
  Chooses incoming
  Puts flipped ones in list
  If necessary will modify costs
*/
void
AbcSimplexDual::dualColumn2()
{
  CoinPartitionedVector & candidateList = usefulArray_[arrayForDualColumn_]; 
  CoinPartitionedVector & flipList = usefulArray_[arrayForFlipBounds_];
  //usefulArray_[arrayForTableauRow_].compact();
  usefulArray_[arrayForTableauRow_].computeNumberElements();
  if (candidateList.getNumElements()<100)
    candidateList.compact();
  //usefulArray_[arrayForTableauRow_].compact();
  // But factorizations complain if <1.0e-8
  //acceptablePivot=CoinMax(acceptablePivot,1.0e-8);
  // do ratio test for normal iteration
  currentAcceptablePivot_ = 1.0e-1 * acceptablePivot_;
  if (numberIterations_ > 100)
    currentAcceptablePivot_ = acceptablePivot_;
  if (abcFactorization_->pivots() > 10 ||
      (abcFactorization_->pivots() && sumDualInfeasibilities_))
    currentAcceptablePivot_ = 1.0e+3 * acceptablePivot_; // if we have iterated be more strict
  else if (abcFactorization_->pivots() > 5)
    currentAcceptablePivot_ = 1.0e+2 * acceptablePivot_; // if we have iterated be slightly more strict
  else if (abcFactorization_->pivots())
    currentAcceptablePivot_ = acceptablePivot_; // relax
  // If very large infeasibility use larger acceptable pivot
  if (abcFactorization_->pivots()) {
    double value=CoinMax(currentAcceptablePivot_,1.0e-12*fabs(dualOut_));
    currentAcceptablePivot_=CoinMin(1.0e2*currentAcceptablePivot_,value);
  }
  // return at once if no free but there were free
  if (lastFirstFree_>=0&&sequenceIn_<0) {
    candidateList.clearAndReset();
    upperTheta_=COIN_DBL_MAX;
  }
  if (upperTheta_==COIN_DBL_MAX) {
    usefulArray_[arrayForTableauRow_].compact();
    assert (!candidateList.getNumElements());
    return;
  }
  int numberSwapped = 0;
  //int numberRemaining = candidateList.getNumElements();
  
  double useThru = 0.0; // for when variables flip
  
  // If we think we need to modify costs (not if something from broad sweep)
  bool modifyCosts = false;
  // pivot elements
  //double *  COIN_RESTRICT array=candidateList.denseVector();
  // indices
  const double *  COIN_RESTRICT abcLower = abcLower_;
  const double *  COIN_RESTRICT abcUpper = abcUpper_;
  const double *  COIN_RESTRICT abcSolution = abcSolution_;
  const double *  COIN_RESTRICT abcDj = abcDj_;
  //const double *  COIN_RESTRICT abcPerturbation = abcPerturbation_;
  const unsigned char *  COIN_RESTRICT internalStatus = internalStatus_;
  // We can also see if infeasible or pivoting on free
  const double multiplier[] = { 1.0, -1.0};

  // For list of flipped
  int numberLastSwapped=0;
  int *  COIN_RESTRICT flippedIndex = flipList.getIndices();
  double *  COIN_RESTRICT flippedElement = flipList.denseVector();
  // If sum of bad small pivots too much
#ifdef MORE_CAREFUL
  bool badSumPivots = false;
#endif
  if (sequenceIn_<0) {
    int lastSequence = -1;
    double lastPivotValue = 0.0;
    double thisPivotValue=0.0;
    dualColumnResult result;
    dualColumn2Most(result);
    sequenceIn_=result.sequence;
    lastSequence=result.lastSequence;
    thisPivotValue=result.thisPivotValue;
    lastPivotValue=result.lastPivotValue;
    numberSwapped=result.numberSwapped;
    numberLastSwapped=result.numberLastSwapped;
    modifyCosts=result.modifyCosts;
    useThru=result.useThru;
#ifdef PRINT_RATIO_PROGRESS
    printf("Iteration %d - out of loop - sequenceIn %d pivotValue %g\n",
	   numberIterations_,sequenceIn_,thisPivotValue);
#endif
    // can get here without sequenceIn_ set but with lastSequence
    if (sequenceIn_ < 0 && lastSequence >= 0) {
      // back to previous one
      sequenceIn_ = lastSequence;
      thisPivotValue=lastPivotValue;
#ifdef PRINT_RATIO_PROGRESS
      printf("BUT back one - out of loop - sequenceIn %d pivotValue %g\n",
	   sequenceIn_,thisPivotValue);
#endif
    }
    
    // Movement should be minimum for anti-degeneracy - unless
    // fixed variable out
    // no need if just one candidate
    assert( numberSwapped-numberLastSwapped>=0);
    double minimumTheta;
    if (upperOut_ > lowerOut_&&numberSwapped-numberLastSwapped>1)
#ifndef TRY_ABC_GUS
      minimumTheta = MINIMUMTHETA;
#else
      minimumTheta = minimumThetaMovement_;
#endif
    else
      minimumTheta = 0.0;
    if (sequenceIn_ >= 0) {
      double oldValue;
      alpha_ = thisPivotValue; 
      // correct sign
      int iStatus = internalStatus[sequenceIn_] & 3;
      alpha_ *= multiplier[iStatus];
      oldValue = abcDj[sequenceIn_];
      theta_ = CoinMax(oldValue / alpha_, 0.0);
      if (theta_ < minimumTheta && fabs(alpha_) < 1.0e5 && 1) {
	// can't pivot to zero
	theta_ = minimumTheta;
      }
      // may need to adjust costs so all dual feasible AND pivoted is exactly 0
      if (modifyCosts
#ifdef MORE_CAREFUL
	  &&!badSumPivots
#endif
	  ) {
	for (int i = numberLastSwapped; i < numberSwapped; i++) {
	  int iSequence = flippedIndex[i];
	  int iStatus = internalStatus[iSequence] & 3;
	  // treat as if at lower bound
	  double mult = multiplier[iStatus];
	  double alpha = flippedElement[i];
	  flippedElement[i]=0.0;
	  if (iSequence==sequenceIn_)
	    continue;
	  double oldValue = abcDj[iSequence]*mult;
	  double value = oldValue - theta_ * alpha;
	  //double perturbedTolerance = abcPerturbation[iSequence];
	  if (-value > currentDualTolerance_) {
	    //thisIncrease = true;
#if MODIFYCOST
	    if (numberIterations_>=normalDualColumnIteration_) {
	      // modify cost to hit new tolerance
	      double modification = alpha * theta_ - oldValue - currentDualTolerance_;
	      if ((specialOptions_&(2048 + 4096)) != 0) {
		if ((specialOptions_ & 2048) != 0) {
		  if (fabs(modification) < 1.0e-10)
		    modification = 0.0;
		} else {
		  if (fabs(modification) < 1.0e-12)
		    modification = 0.0;
		}
	      }
	      abcDj_[iSequence] += mult*modification;
	      abcCost_[iSequence] +=  mult*modification;
	      if (modification)
		numberChanged_ ++; // Say changed costs
	    }
#endif
	  }
	}
	numberSwapped=numberLastSwapped;
      }
    }
  }
  
#ifdef MORE_CAREFUL
  // If we have done pivots and things look bad set alpha_ 0.0 to force factorization
  if ((badSumPivots ||
       fabs(theta_ * badFree) > 10.0 * currentDualTolerance_) && abcFactorization_->pivots()) {
#if ABC_NORMAL_DEBUG>0
    if (handler_->logLevel() > 1)
      printf("forcing re-factorization\n");
#endif
    sequenceIn_ = -1;
  }
#endif
  if (sequenceIn_ >= 0) {
    lowerIn_ = abcLower[sequenceIn_];
    upperIn_ = abcUpper[sequenceIn_];
    valueIn_ = abcSolution[sequenceIn_];
    dualIn_ = abcDj_[sequenceIn_];
    
    if (numberTimesOptimal_) {
      // can we adjust cost back closer to original
      //*** add coding
    }
    if (numberIterations_>=normalDualColumnIteration_) {
#if MODIFYCOST>1
      // modify cost to hit zero exactly
      // so (dualIn_+modification)==theta_*alpha_
      //double perturbedTolerance = abcPerturbation[sequenceIn_];
      double modification = theta_ * alpha_ - (dualIn_+goToTolerance2());
      // But should not move objective too much ??
#ifdef DONT_MOVE_OBJECTIVE
      double moveObjective = fabs(modification * abcSolution[sequenceIn_]);
      double smallMove = CoinMax(fabs(rawObjectiveValue_), 1.0e-3);
      if (moveObjective > smallMove) {
#if ABC_NORMAL_DEBUG>0
	if (handler_->logLevel() > 1)
	  printf("would move objective by %g - original mod %g sol value %g\n", moveObjective,
		 modification, abcSolution[sequenceIn_]);
#endif
	modification *= smallMove / moveObjective;
      }
#endif
#ifdef MORE_CAREFUL
      if (badSumPivots)
	modification = 0.0;
#endif
      if (atFakeBound(sequenceIn_)&&fabs(modification)<currentDualTolerance_)
	modification=0.0;
      if ((specialOptions_&(2048 + 4096)) != 0) {
	if ((specialOptions_ & 16384) != 0) {
	  // in fast dual
	  if (fabs(modification) < 1.0e-7)
	    modification = 0.0;
	} else if ((specialOptions_ & 2048) != 0) {
	  if (fabs(modification) < 1.0e-10)
	    modification = 0.0;
	} else {
	  if (fabs(modification) < 1.0e-12)
	    modification = 0.0;
	}
      }
      
      dualIn_ += modification;
      abcDj_[sequenceIn_] = dualIn_;
      abcCost_[sequenceIn_] += modification;
      if (modification)
	numberChanged_ ++; // Say changed costs
      //int costOffset = numberRows_+numberColumns_;
      //abcCost[sequenceIn_+costOffset] += modification; // save change
      //assert (fabs(modification)<1.0e-6);
#if ABC_NORMAL_DEBUG>3
      if ((handler_->logLevel() & 32) && fabs(modification) > 1.0e-15)
	printf("exact %d new cost %g, change %g\n", sequenceIn_,
	       abcCost_[sequenceIn_], modification);
#endif
#endif
    }
    
    if (alpha_ < 0.0) {
      // as if from upper bound
      directionIn_ = -1;
      upperIn_ = valueIn_;
    } else {
      // as if from lower bound
      directionIn_ = 1;
      lowerIn_ = valueIn_;
    }
  } else {
    // no pivot
    alpha_ = 0.0;
  }
  // clear array
  //printf("dualout %g theta %g alpha %g dj %g thru %g swapped %d product %g guess %g useThru %g\n",
  //	 dualOut_,theta_,alpha_,abcDj_[sequenceIn_],useThru,numberSwapped,
  //	 fabs(dualOut_)*theta_,objectiveValue()+(fabs(dualOut_)-useThru)*theta_,useThru);
  objectiveChange_ = (fabs(dualOut_)-useThru)*theta_;
  rawObjectiveValue_+= objectiveChange_;
  //CoinZeroN(array, maximumNumberInList);
  //candidateList.setNumElements(0);
  candidateList.clearAndReset();
  flipList.setNumElements(numberSwapped);
  if (numberSwapped)
    flipList.setPackedMode(true);
#ifdef PRINT_RATIO_PROGRESS
  printf("%d flipped\n",numberSwapped);
#endif
}
/* Checks if tentative optimal actually means unbounded
   Returns -3 if not, 2 if is unbounded */
int
AbcSimplexDual::checkUnbounded(CoinIndexedVector & ray,
                               double changeCost)
{
  int status = 2; // say unbounded
  abcFactorization_->updateColumn(ray);
  // get reduced cost
  int number = ray.getNumElements();
  int *  COIN_RESTRICT index = ray.getIndices();
  double *  COIN_RESTRICT array = ray.denseVector();
  const int * COIN_RESTRICT abcPivotVariable = abcPivotVariable_;
  for (int i = 0; i < number; i++) {
    int iRow = index[i];
    int iPivot = abcPivotVariable[iRow];
    changeCost -= cost(iPivot) * array[iRow];
  }
  double way;
  if (changeCost > 0.0) {
    //try going down
    way = 1.0;
  } else if (changeCost < 0.0) {
    //try going up
    way = -1.0;
  } else {
#if ABC_NORMAL_DEBUG>3
    printf("can't decide on up or down\n");
#endif
    way = 0.0;
    status = -3;
  }
  double movement = 1.0e10 * way; // some largish number
  double zeroTolerance = 1.0e-14 * dualBound_;
  for (int i = 0; i < number; i++) {
    int iRow = index[i];
    int iPivot = abcPivotVariable[iRow];
    double arrayValue = array[iRow];
    if (fabs(arrayValue) < zeroTolerance)
      arrayValue = 0.0;
    double newValue = solution(iPivot) + movement * arrayValue;
    if (newValue > upper(iPivot) + primalTolerance_ ||
	newValue < lower(iPivot) - primalTolerance_)
      status = -3; // not unbounded
  }
  if (status == 2) {
    // create ray
    delete [] ray_;
    ray_ = new double [numberColumns_];
    CoinZeroN(ray_, numberColumns_);
    for (int i = 0; i < number; i++) {
      int iRow = index[i];
      int iPivot = abcPivotVariable[iRow];
      double arrayValue = array[iRow];
      if (iPivot < numberColumns_ && fabs(arrayValue) >= zeroTolerance)
	ray_[iPivot] = way * array[iRow];
    }
  }
  ray.clear();
  return status;
}
// Saves good status etc 
void 
AbcSimplex::saveGoodStatus()
{
  // save arrays
  CoinMemcpyN(internalStatus_, numberTotal_, internalStatusSaved_);
  // save costs
  CoinMemcpyN(abcCost_,numberTotal_,abcCost_+2*numberTotal_);
  CoinMemcpyN(abcSolution_,numberTotal_,solutionSaved_);
}
// Restores previous good status and says trouble
void 
AbcSimplex::restoreGoodStatus(int type)
{
#if PARTITION_ROW_COPY==1
  stateOfProblem_ |= NEED_BASIS_SORT;
#endif
  if (type) {
    if (alphaAccuracy_ != -1.0)
      alphaAccuracy_ = -2.0;
    // trouble - restore solution
    CoinMemcpyN(internalStatusSaved_, numberTotal_, internalStatus_);
    CoinMemcpyN(abcCost_+2*numberTotal_,numberTotal_,abcCost_);
    CoinMemcpyN(solutionSaved_,numberTotal_, abcSolution_);
    int *  COIN_RESTRICT abcPivotVariable = abcPivotVariable_;
    // redo pivotVariable
    int numberBasic=0;
    for (int i=0;i<numberTotal_;i++) {
      if (getInternalStatus(i)==basic)
	abcPivotVariable[numberBasic++]=i;
    }
    assert (numberBasic==numberRows_);
    forceFactorization_ = 1; // a bit drastic but ..
    changeMade_++; // say something changed
  }
}
static int computePrimalsAndCheck(AbcSimplexDual * model,const int whichArray[2])
{
  CoinIndexedVector * array1 = model->usefulArray(whichArray[0]);
  CoinIndexedVector * array2 = model->usefulArray(whichArray[1]);
  int numberRefinements=model->computePrimals(array1,array2);
  model->checkPrimalSolution(true);
  return numberRefinements;
}
static int computeDualsAndCheck(AbcSimplexDual * model,const int whichArray[2])
{
  CoinIndexedVector * array1 = model->usefulArray(whichArray[0]);
  CoinIndexedVector * array2 = model->usefulArray(whichArray[1]);
  int numberRefinements=model->computeDuals(NULL,array1,array2);
  model->checkDualSolutionPlusFake();
  return numberRefinements;
}
// Computes solutions - 1 do duals, 2 do primals, 3 both
int
AbcSimplex::gutsOfSolution(int type)
{
  double oldLargestPrimalError=largestPrimalError_;
  double oldLargestDualError=largestDualError_;
  AbcSimplexDual * dual = reinterpret_cast<AbcSimplexDual *>(this);
  // do work and check
  int numberRefinements=0;
#if ABC_PARALLEL
  if (type!=3) {
#endif
    if ((type&2)!=0) {
      //work space
      int whichArray[2];
      for (int i=0;i<2;i++)
	whichArray[i]=getAvailableArray();
      numberRefinements=computePrimalsAndCheck(dual,whichArray);
      for (int i=0;i<2;i++)
	setAvailableArray(whichArray[i]);
    }
    if ((type&1)!=0
#if CAN_HAVE_ZERO_OBJ>1
	&&(specialOptions_&2097152)==0
#endif
	) {
      //work space
      int whichArray[2];
      for (int i=0;i<2;i++)
	whichArray[i]=getAvailableArray();
      numberRefinements+=computeDualsAndCheck(dual,whichArray);
      for (int i=0;i<2;i++)
	setAvailableArray(whichArray[i]);
    }
#if ABC_PARALLEL
  } else {
#ifndef NDEBUG
    abcFactorization_->checkMarkArrays();
#endif
    // redo to do in parallel
      //work space
      int whichArray[5];
      for (int i=1;i<5;i++)
	whichArray[i]=getAvailableArray();
      if (parallelMode_==0) {
	numberRefinements+=computePrimalsAndCheck(dual,whichArray+3);
	numberRefinements+=computeDualsAndCheck(dual,whichArray+1);
      } else {
#if ABC_PARALLEL==1
	threadInfo_[0].stuff[0]=whichArray[1];
	threadInfo_[0].stuff[1]=whichArray[2];
	stopStart_=1+32*1;
	startParallelStuff(1);
#else
	whichArray[0]=1;
	CoinThreadInfo info;
	info.status=1;
	info.stuff[0]=whichArray[1];
	info.stuff[1]=whichArray[2];
	int n=cilk_spawn computeDualsAndCheck(dual,whichArray+1);
#endif
	numberRefinements=computePrimalsAndCheck(dual,whichArray+3);
#if ABC_PARALLEL==1
	numberRefinements+=stopParallelStuff(1);
#else
	cilk_sync;
	numberRefinements+=n;
#endif
      }
      for (int i=1;i<5;i++)
	setAvailableArray(whichArray[i]);
  }
#endif
  rawObjectiveValue_ +=sumNonBasicCosts_;
  setClpSimplexObjectiveValue();
  if (handler_->logLevel() > 3 || (largestPrimalError_ > 1.0e-2 ||
				   largestDualError_ > 1.0e-2))
    handler_->message(CLP_SIMPLEX_ACCURACY, messages_)
      << largestPrimalError_
      << largestDualError_
      << CoinMessageEol;
  if ((largestPrimalError_ > 1.0e1||largestDualError_>1.0e1) 
      && numberRows_ > 100 && numberIterations_) {
#if ABC_NORMAL_DEBUG>0
    printf("Large errors - primal %g dual %g\n",
	   largestPrimalError_,largestDualError_);
#endif
    // Change factorization tolerance
    //if (abcFactorization_->zeroTolerance() > 1.0e-18)
    //abcFactorization_->zeroTolerance(1.0e-18);
  }
  bool notChanged=true;
  if (numberIterations_ && (forceFactorization_ > 2 || forceFactorization_<0 || abcFactorization_->pivotTolerance()<0.9899999999) && 
      (oldLargestDualError||oldLargestPrimalError)) {
    double useOldDualError=oldLargestDualError;
    double useDualError=largestDualError_;
    if (algorithm_>0&&abcNonLinearCost_&&
	abcNonLinearCost_->sumInfeasibilities()) {
      double factor=CoinMax(1.0,CoinMin(1.0e3,infeasibilityCost_*1.0e-6));
      useOldDualError /= factor;
      useDualError /= factor;
    }
    if ((largestPrimalError_>1.0e3&&
	 oldLargestPrimalError*1.0e2<largestPrimalError_)||
	(useDualError>1.0e3&&
	 useOldDualError*1.0e2<useDualError)) {
      double pivotTolerance = abcFactorization_->pivotTolerance();
      double factor=(largestPrimalError_>1.0e10||largestDualError_>1.0e10)
	? 2.0 : 1.2;
      if (pivotTolerance<0.1)
	abcFactorization_->pivotTolerance(0.1);
      else if (pivotTolerance<0.98999999)
	abcFactorization_->pivotTolerance(CoinMin(0.99,pivotTolerance*factor));
      notChanged=pivotTolerance==abcFactorization_->pivotTolerance();
#if defined(CLP_USEFUL_PRINTOUT) && !defined(GCC_4_9)
      if (pivotTolerance<0.9899999) {
	double newTolerance=abcFactorization_->pivotTolerance();
	printf("Changing pivot tolerance from %g to %g and backtracking\n",
	       pivotTolerance,newTolerance);
      } 
      printf("because old,new primal error %g,%g - dual %g,%g pivot_tol %g\n",
	     oldLargestPrimalError,largestPrimalError_,
	     oldLargestDualError,largestDualError_,
	     pivotTolerance);
#endif
      if (pivotTolerance<0.9899999) {
	//largestPrimalError_=0.0;
	//largestDualError_=0.0;
	//returnCode=1;
      } 
    }
  }
  if (progress_.iterationNumber_[0]>0&&
      progress_.iterationNumber_[CLP_PROGRESS-1]
      -progress_.iterationNumber_[0]<CLP_PROGRESS*3&&
      abcFactorization_->pivotTolerance()<0.25&&notChanged) {
    double pivotTolerance = abcFactorization_->pivotTolerance();
    abcFactorization_->pivotTolerance(pivotTolerance*1.5);
#if defined(CLP_USEFUL_PRINTOUT) && !defined(GCC_4_9)
    double newTolerance=abcFactorization_->pivotTolerance();
    printf("Changing pivot tolerance from %g to %g - inverting too often\n",
	   pivotTolerance,newTolerance);
#endif
  }
  return numberRefinements;
}
// Make non free variables dual feasible by moving to a bound
int 
AbcSimplexDual::makeNonFreeVariablesDualFeasible(bool changeCosts)
{
  const double multiplier[] = { 1.0, -1.0}; // sign?????????????
  double dualT = - 100.0*currentDualTolerance_;
  int numberMoved=0;
  int numberChanged=0;
  double *  COIN_RESTRICT solution = abcSolution_;
  double *  COIN_RESTRICT lower = abcLower_;
  double *  COIN_RESTRICT upper = abcUpper_;
  double saveNonBasicCosts =sumNonBasicCosts_;
  double largestCost=dualTolerance_;
  for (int iSequence = 0; iSequence < numberTotal_; iSequence++) {
    unsigned char iStatus = internalStatus_[iSequence] & 7;
    if (iStatus<4) {
      double mult = multiplier[iStatus];
      double dj = abcDj_[iSequence] * mult;
      if (dj < dualT) {
	largestCost=CoinMax(fabs(abcPerturbation_[iSequence]),largestCost);
      }
    } else if (iStatus!=7) {
      largestCost=CoinMax(fabs(abcPerturbation_[iSequence]),largestCost);
    }
  }
  for (int iSequence = 0; iSequence < numberTotal_; iSequence++) {
    unsigned char iStatus = internalStatus_[iSequence] & 7;
    if (iStatus<4) {
      double mult = multiplier[iStatus];
      double dj = abcDj_[iSequence] * mult;
      // ? should use perturbationArray
      if (dj < dualT&&changeCosts) {
	double gap=upper[iSequence]-lower[iSequence];
	if (gap>1.1*currentDualBound_) {
	  assert(getFakeBound(iSequence)==AbcSimplexDual::noFake);
	  if (!iStatus) {
	    upper[iSequence]=lower[iSequence]+currentDualBound_;
	    setFakeBound(iSequence, AbcSimplexDual::upperFake);
	  } else {
	    lower[iSequence]=upper[iSequence]-currentDualBound_;
	    setFakeBound(iSequence, AbcSimplexDual::lowerFake);
	  }
	}
	double costDifference=abcPerturbation_[iSequence]-abcCost_[iSequence];
	if (costDifference*mult>0.0) {
#if ABC_NORMAL_DEBUG>0
	  //printf("can improve situation on %d by %g\n",iSequence,costDifference*mult);
#endif
	  dj+=costDifference*mult;
	  abcDj_[iSequence]+=costDifference;
	  abcCost_[iSequence]=abcPerturbation_[iSequence];
	  costDifference=0.0;
	}
	double changeInObjective=-gap*dj;
	// probably need to be more intelligent
	if ((changeInObjective>1.0e3||gap>CoinMax(0.5*dualBound_,1.0e3))&&dj>-1.0e-1) {
	  // change cost
	  costDifference=(-dj-0.5*dualTolerance_)*mult;
	  if (fabs(costDifference)<100000.0*dualTolerance_) {
	    dj+=costDifference*mult;
	    abcDj_[iSequence]+=costDifference;
	    abcCost_[iSequence]+=costDifference;
	    numberChanged++;
	  }
	}
      }
      if (dj < dualT&&!changeCosts) {
	numberMoved++;
	if (iStatus==0) {
	  // at lower bound
	  // to upper bound
	  setInternalStatus(iSequence, atUpperBound);
	  solution[iSequence] = upper[iSequence];
	  sumNonBasicCosts_ += abcCost_[iSequence]*(upper[iSequence]-lower[iSequence]);
	} else {
	  // at upper bound
	  // to lower bound
	  setInternalStatus(iSequence, atLowerBound);
	  solution[iSequence] = lower[iSequence];
	  sumNonBasicCosts_ -= abcCost_[iSequence]*(upper[iSequence]-lower[iSequence]);
	}
      }
    }
  }
#if ABC_NORMAL_DEBUG>0
  if (numberMoved+numberChanged)
  printf("makeDualfeasible %d moved, %d had costs changed - sum dual %g\n",
	 numberMoved,numberChanged,sumDualInfeasibilities_);
#endif
  rawObjectiveValue_ +=(sumNonBasicCosts_-saveNonBasicCosts);
  setClpSimplexObjectiveValue();
  return numberMoved;
}
int 
AbcSimplexDual::whatNext()
{
  int returnCode=0;
  assert (!stateOfIteration_);
  // see if update stable
#if ABC_NORMAL_DEBUG>3
  if ((handler_->logLevel() & 32))
    printf("btran alpha %g, ftran alpha %g\n", btranAlpha_, alpha_);
#endif
  int numberPivots=abcFactorization_->pivots();
  //double checkValue = 1.0e-7; // numberPivots<5 ? 1.0e-7 : 1.0e-6;
  double checkValue = numberPivots ? 1.0e-7 : 1.0e-5;
  // relax if free variable in
  if ((internalStatus_[sequenceIn_]&7)>1)
    checkValue=1.0e-5;
  // if can't trust much and long way from optimal then relax
  if (largestPrimalError_ > 10.0)
    checkValue = CoinMin(1.0e-4, 1.0e-8 * largestPrimalError_);
  if (fabs(btranAlpha_) < 1.0e-12 || fabs(alpha_) < 1.0e-12 ||
      fabs(btranAlpha_ - alpha_) > checkValue*(1.0 + fabs(alpha_))) {
    handler_->message(CLP_DUAL_CHECK, messages_)
      << btranAlpha_
      << alpha_
      << CoinMessageEol;
    // see with more relaxed criterion
    double test;
    if (fabs(btranAlpha_) < 1.0e-8 || fabs(alpha_) < 1.0e-8)
      test = 1.0e-1 * fabs(alpha_);
    else
      test = 10.0*checkValue;//1.0e-4 * (1.0 + fabs(alpha_));
    bool needFlag = (fabs(btranAlpha_) < 1.0e-12 || fabs(alpha_) < 1.0e-12 ||
		     fabs(btranAlpha_ - alpha_) > test);
#if ABC_NORMAL_DEBUG>0
    if (fabs(btranAlpha_ + alpha_) < 1.0e-5*(1.0 + fabs(alpha_))) {
      printf("alpha diff (%g,%g) %g check %g\n",btranAlpha_,alpha_,fabs(btranAlpha_-alpha_),checkValue*(1.0+fabs(alpha_)));
    }
#endif
    if (numberPivots) {
      if (needFlag&&numberPivots<10) {
	// need to reject something
	assert (sequenceOut_>=0);
	char x = isColumn(sequenceOut_) ? 'C' : 'R';
	handler_->message(CLP_SIMPLEX_FLAG, messages_)
	  << x << sequenceWithin(sequenceOut_)
	  << CoinMessageEol;
#if ABC_NORMAL_DEBUG>0
	printf("flag %d as alpha  %g %g - after %d pivots\n", sequenceOut_,
	       btranAlpha_, alpha_,numberPivots);
#endif
	// Make safer?
	abcFactorization_->saferTolerances (1.0, -1.03);
	setFlagged(sequenceOut_);
	// so can't happen immediately again
	sequenceOut_=-1;
	lastBadIteration_ = numberIterations_; // say be more cautious
      }
      // Make safer?
      //if (numberPivots<5)
      //abcFactorization_->saferTolerances (-0.99, -1.01);
      problemStatus_ = -2; // factorize now
      returnCode = -2;
      stateOfIteration_=2;
    } else {
      if (needFlag) {
	// need to reject something
	assert (sequenceOut_>=0);
	char x = isColumn(sequenceOut_) ? 'C' : 'R';
	handler_->message(CLP_SIMPLEX_FLAG, messages_)
	  << x << sequenceWithin(sequenceOut_)
	  << CoinMessageEol;
#if ABC_NORMAL_DEBUG>3
	printf("flag a %g %g\n", btranAlpha_, alpha_);
#endif
	// Make safer?
	double tolerance=abcFactorization_->pivotTolerance();
	abcFactorization_->saferTolerances (1.0, -1.03);
	setFlagged(sequenceOut_);
	// so can't happen immediately again
	sequenceOut_=-1;
	//abcProgress_.clearBadTimes();
	lastBadIteration_ = numberIterations_; // say be more cautious
	if (fabs(alpha_) < 1.0e-10 && fabs(btranAlpha_) < 1.0e-8 && numberIterations_ > 100) {
	  //printf("I think should declare infeasible\n");
	  problemStatus_ = 1;
	  returnCode = 1;
	  stateOfIteration_=2;
	} else {
	  stateOfIteration_=1;
	  if (tolerance<abcFactorization_->pivotTolerance()) {
	    stateOfIteration_=2;
	    returnCode=-2;
	  }
	}
      }
    }
  }
  if (!stateOfIteration_) {
    // check update
    returnCode=abcFactorization_->checkReplacePart2(pivotRow_,btranAlpha_,alpha_,ftAlpha_);
  }
  return returnCode;
}
/* Checks if finished.  
   type 0 initial
   1 normal
   2 initial but we have solved problem before
   3 can skip factorization
   Updates status */
void
AbcSimplexDual::statusOfProblemInDual(int type)
{
  // If lots of iterations then adjust costs if large ones
  int numberPivots = abcFactorization_->pivots();
#if 0
  printf("statusOf %d pivots type %d pstatus %d forceFac %d dont %d\n",
  	 numberPivots,type,problemStatus_,forceFactorization_,dontFactorizePivots_);
#endif
  int saveType=type;
  double lastSumDualInfeasibilities=sumDualInfeasibilities_;
  double lastSumPrimalInfeasibilities=sumPrimalInfeasibilities_;
  if (type>=4) {
    // force factorization
    type &= 3;
    numberPivots=9999999;
  }
  //double realDualInfeasibilities = 0.0;
  double changeCost;
  bool unflagVariables = numberFlagged_>0;
  int weightsSaved = 0;
  int numberBlackMarks=0;
  if (!type) {
    // be optimistic
    stateOfProblem_ &= ~PESSIMISTIC;
    // but use 0.1
    double newTolerance = CoinMax(0.1, saveData_.pivotTolerance_);
    abcFactorization_->pivotTolerance(newTolerance);
  }
  if (type != 3&&(numberPivots>dontFactorizePivots_||numberIterations_==baseIteration_)) {
    // factorize
    // save dual weights
    abcDualRowPivot_->saveWeights(this, 1);
    weightsSaved = 2;
    // is factorization okay?
    int factorizationStatus=0;
  if ((largestPrimalError_ > 1.0e1||largestDualError_>1.0e1) 
      && numberRows_ > 100 && numberIterations_>baseIteration_) {
    double newTolerance = CoinMin(1.1* abcFactorization_->pivotTolerance(), 0.99);
    abcFactorization_->pivotTolerance(newTolerance);
  }
#ifdef EARLY_FACTORIZE
    if ((numberEarly_&0xffff)<=5||!usefulArray_[ABC_NUMBER_USEFUL-1].getNumElements()) {
	//#define KEEP_TRYING_EARLY
#ifdef KEEP_TRYING_EARLY
      int savedEarly=numberEarly_>>16;
      int newEarly=(numberEarly_&0xffff);
      newEarly=CoinMin(savedEarly,1+2*newEarly);
      numberEarly_=(savedEarly<<16)|newEarly;
#endif
      factorizationStatus = internalFactorize(type ? 1 : 2);
    } else {
      CoinIndexedVector & vector = usefulArray_[ABC_NUMBER_USEFUL-1];
      bool bad = vector.getNumElements()<0;
      const int * indices = vector.getIndices();
      double * array = vector.denseVector();
      int capacity = vector.capacity();
      capacity--;
      int numberPivotsStored = indices[capacity];
#if ABC_NORMAL_DEBUG>0
      printf("early status %s nPivots %d\n",bad ? "bad" : "good",numberPivotsStored);
#endif
      if (!bad) {
	// do remaining pivots
	int iterationsDone=abcEarlyFactorization_->pivots();
	factorizationStatus = 
	  abcEarlyFactorization_->replaceColumns(this,vector,
						 iterationsDone,numberPivotsStored,true);
	if (!factorizationStatus) {
	  // should be able to compare e.g. basics 1.0
#define GOOD_EARLY
#ifdef GOOD_EARLY
	  AbcSimplexFactorization * temp = abcFactorization_;
	  abcFactorization_=abcEarlyFactorization_;
	  abcEarlyFactorization_=temp;
#endif
	  moveToBasic();
#ifndef GOOD_EARLY
	  int * pivotSave = CoinCopyOfArray(abcPivotVariable_,numberRows_);
	  factorizationStatus = internalFactorize(type ? 1 : 2);
	  {
	    double * array = usefulArray_[3].denseVector();
	    double * array2 = usefulArray_[4].denseVector();
	    for (int iPivot = 0; iPivot < numberRows_; iPivot++) {
	      int iSequence = abcPivotVariable_[iPivot];
	      unpack(usefulArray_[3], iSequence);
	      unpack(usefulArray_[4], iSequence);
	      abcFactorization_->updateColumn(usefulArray_[3]);
	      abcEarlyFactorization_->updateColumn(usefulArray_[4]);
	      assert (fabs(array[iPivot] - 1.0) < 1.0e-4);
	      array[iPivot] = 0.0;
	      int iPivot2;
	      for (iPivot2=0;iPivot2<numberRows_;iPivot2++) {
		if (pivotSave[iPivot2]==iSequence)
		  break;
	      }
	      assert (iPivot2<numberRows_);
	      assert (fabs(array2[iPivot2] - 1.0) < 1.0e-4);
	      array2[iPivot2] = 0.0;
	      for (int i = 0; i < numberRows_; i++)
		assert (fabs(array[i]) < 1.0e-4);
	      for (int i = 0; i < numberRows_; i++)
		assert (fabs(array2[i]) < 1.0e-4);
	      usefulArray_[3].clear();
	      usefulArray_[4].clear();
	    }
	    delete [] pivotSave;
	  }
#endif
	} else {
	  bad=true;
	}
      }
      // clean up
      vector.setNumElements(0);
      for (int i=0;i<2*numberPivotsStored;i++) {
	array[--capacity]=0.0;
      }
      if (bad) {
	// switch off
#if ABC_NORMAL_DEBUG>0
	printf("switching off early factorization(in statusOf)\n");
#endif
#ifndef KEEP_TRYING_EARLY
	numberEarly_=0;
	delete abcEarlyFactorization_;
	abcEarlyFactorization_=NULL;
#else
	numberEarly_&=0xffff0000;
#endif
	factorizationStatus = internalFactorize(1);
      }
    }
#else
    factorizationStatus = internalFactorize(type ? 1 : 2);
#endif
    if (factorizationStatus) {
      if (type == 1&&lastFlaggedIteration_!=1) {
	// use for real disaster 
	lastFlaggedIteration_ = 1;
	// no - restore previous basis
	unflagVariables = false;
	// restore weights
	weightsSaved = 4;
	changeMade_++; // say something changed
	// Keep any flagged variables
	for (int i = 0; i < numberTotal_; i++) {
	  if (flagged(i))
	    internalStatusSaved_[i] |= 64; //say flagged
	}
	restoreGoodStatus(type);
	// get correct bounds on all variables
	resetFakeBounds(1);
	numberBlackMarks=10;
	if (sequenceOut_>=0) {
	  // need to reject something
	  char x = isColumn(sequenceOut_) ? 'C' : 'R';
	  handler_->message(CLP_SIMPLEX_FLAG, messages_)
	    << x << sequenceWithin(sequenceOut_)
	    << CoinMessageEol;
#if ABC_NORMAL_DEBUG>3
	  printf("flag d\n");
#endif
	  setFlagged(sequenceOut_);
	  lastBadIteration_ = numberIterations_; // say be more cautious
	  // so can't happen immediately again
	  sequenceOut_=-1;
	}
	//abcProgress_.clearBadTimes();
	
	// Go to safe
	abcFactorization_->pivotTolerance(0.99);
      } else {
#if ABC_NORMAL_DEBUG>0
	printf("Bad initial basis\n");
#endif
      }
      if (internalFactorize(1)) {
	// try once more
      if (internalFactorize(0)) 
	abort();
      }
#if PARTITION_ROW_COPY==1
      int iVector=getAvailableArray();
      abcMatrix_->sortUseful(usefulArray_[iVector]);
      setAvailableArray(iVector);
#endif
    } else {
      lastFlaggedIteration_ = 0;
    }
  }
  // get primal and dual solutions
  numberBlackMarks+=gutsOfSolution(3)/2;
  assert (type!=0||numberIterations_==baseIteration_); // may be wrong
  if (!type) {
    initialSumInfeasibilities_=sumPrimalInfeasibilities_;
    initialNumberInfeasibilities_=numberPrimalInfeasibilities_;
    CoinAbcMemcpy(solutionSaved_+numberTotal_,abcSolution_,numberTotal_);
    CoinAbcMemcpy(internalStatusSaved_+numberTotal_,internalStatus_,numberTotal_);
  }
  double savePrimalInfeasibilities=sumPrimalInfeasibilities_;
  if ((moreSpecialOptions_&16384)!=0&&(moreSpecialOptions_&8192)==0) {
    if (numberIterations_==baseIteration_) {
      // If primal feasible and looks suited to primal go to primal
      if (!sumPrimalInfeasibilities_&&sumDualInfeasibilities_>1.0&&
	  numberRows_*4>numberColumns_) {
	// do primal
	// mark so can perturb
	initialSumInfeasibilities_=-1.0;
	problemStatus_=10;
	return;
      }
    } else if ((numberIterations_>1000&&
	       numberIterations_*10>numberRows_&&numberIterations_*4<numberRows_)||(sumPrimalInfeasibilities_+sumDualInfeasibilities_>
										    1.0e10*(initialSumInfeasibilities_+1000.0)&&numberIterations_>10000&&sumDualInfeasibilities_>1.0)) 
 {
      if (sumPrimalInfeasibilities_+1.0e2*sumDualInfeasibilities_>
	  2000.0*(initialSumInfeasibilities_+100.0)) {
#if ABC_NORMAL_DEBUG>0
	printf ("sump %g sumd %g initial %g\n",sumPrimalInfeasibilities_,sumDualInfeasibilities_,
		initialSumInfeasibilities_);
#endif
	// but only if average gone up as well
	if (sumPrimalInfeasibilities_*initialNumberInfeasibilities_>
	    100.0*(initialSumInfeasibilities_+10.0)*numberPrimalInfeasibilities_) {
#if ABC_NORMAL_DEBUG>0
	  printf("returning to do primal\n");
#endif
	  // do primal
	  problemStatus_=10;
	  CoinAbcMemcpy(abcSolution_,solutionSaved_+numberTotal_,numberTotal_);
	  CoinAbcMemcpy(internalStatus_,internalStatusSaved_+numberTotal_,numberTotal_);
	  // mark so can perturb
	  initialSumInfeasibilities_=-1.0;
	  return;
	}
      }
    }
  } else if ((sumPrimalInfeasibilities_+sumDualInfeasibilities_>
	     1.0e6*(initialSumInfeasibilities_+1000.0)&&(moreSpecialOptions_&8192)==0&&
	     numberIterations_>1000&&
	      numberIterations_*10>numberRows_&&numberIterations_*4<numberRows_)||
	     (sumPrimalInfeasibilities_+sumDualInfeasibilities_>
	      1.0e10*(initialSumInfeasibilities_+1000.0)&&(moreSpecialOptions_&8192)==0&&
	      numberIterations_>10000&&sumDualInfeasibilities_>1.0)) {
    // do primal
    problemStatus_=10;
    CoinAbcMemcpy(abcSolution_,solutionSaved_+numberTotal_,numberTotal_);
    CoinAbcMemcpy(internalStatus_,internalStatusSaved_+numberTotal_,numberTotal_);
    // mark so can perturb
    initialSumInfeasibilities_=-1.0;
    return;
  }
  //double saveDualInfeasibilities=sumDualInfeasibilities_;
  // 0 don't ignore, 1 ignore errors, 2 values pass
  int ignoreStuff=(firstFree_<0&&lastFirstFree_<0) ? 0 : 1;
  if ((stateOfProblem_&VALUES_PASS)!=0)
    ignoreStuff=2;
  {
    double thisObj = rawObjectiveValue();
    double lastObj = abcProgress_.lastObjective(0);
    if ((lastObj > thisObj + 1.0e-3 * CoinMax(fabs(thisObj), fabs(lastObj)) + 1.0e-4||
	 (sumPrimalInfeasibilities_>10.0*lastSumPrimalInfeasibilities+1.0e3&&
	  sumDualInfeasibilities_>10.0*CoinMax(lastSumDualInfeasibilities,1.0)))
	&&!ignoreStuff) {
#if ABC_NORMAL_DEBUG>0
      printf("bad - objective backwards %g %g errors %g %g suminf %g %g\n",lastObj,thisObj,largestDualError_,largestPrimalError_,sumDualInfeasibilities_,sumPrimalInfeasibilities_);
#endif
      numberBlackMarks++;
      if (largestDualError_>1.0e-3||largestPrimalError_>1.0e-3||
	  (sumDualInfeasibilities_>10.0*CoinMax(lastSumDualInfeasibilities,1.0)
	   &&firstFree_<0)) {
#if ABC_NORMAL_DEBUG>0
	printf("backtracking %d iterations - dual error %g primal error %g - sumDualInf %g\n",
	       numberPivots,
	       largestDualError_,largestPrimalError_,sumDualInfeasibilities_);
#endif
	// restore previous basis
	unflagVariables = false;
	// restore weights
	weightsSaved = 4;
	changeMade_++; // say something changed
	// Keep any flagged variables
	for (int i = 0; i < numberTotal_; i++) {
	  if (flagged(i))
	    internalStatusSaved_[i] |= 64; //say flagged
	}
	restoreGoodStatus(type);
	// get correct bounds on all variables
	resetFakeBounds(1);
	numberBlackMarks+=10;
	if (sequenceOut_>=0) {
	  // need to reject something
#if ABC_NORMAL_DEBUG>0
	  if (flagged(sequenceOut_))
	    printf("BAD %x already flagged\n",sequenceOut_);
#endif
	  char x = isColumn(sequenceOut_) ? 'C' : 'R';
	  handler_->message(CLP_SIMPLEX_FLAG, messages_)
	    << x << sequenceWithin(sequenceOut_)
	    << CoinMessageEol;
#if ABC_NORMAL_DEBUG>3
	  printf("flag d\n");
#endif
	  setFlagged(sequenceOut_);
	  lastBadIteration_ = numberIterations_; // say be more cautious
#if ABC_NORMAL_DEBUG>0
	} else {
	  printf("backtracking - no valid sequence out\n");
#endif
	}
	// so can't happen immediately again
	sequenceOut_=-1;
	//abcProgress_.clearBadTimes();
	// Go to safe
	//abcFactorization_->pivotTolerance(0.99);
	if (internalFactorize(1)) {
	  abort();
	}
	moveToBasic();
#if PARTITION_ROW_COPY==1
	int iVector=getAvailableArray();
	abcMatrix_->sortUseful(usefulArray_[iVector]);
	setAvailableArray(iVector);
#endif
	// get primal and dual solutions
	numberBlackMarks+=gutsOfSolution(3);
	//gutsOfSolution(1);
	makeNonFreeVariablesDualFeasible();
      }
    }
  }
  //#define PAN
#ifdef PAN
    if (!type&&(specialOptions_&COIN_CBC_USING_CLP)==0&&firstFree_<0) {
    // first time - set large bad ones superbasic
    int whichArray=getAvailableArray();
    double * COIN_RESTRICT work=usefulArray_[whichArray].denseVector();
    int number=0;
    int * COIN_RESTRICT which=usefulArray_[whichArray].getIndices();
    const double * COIN_RESTRICT reducedCost=abcDj_;
    const double * COIN_RESTRICT lower=abcLower_;
    const double * COIN_RESTRICT upper=abcUpper_;
#if PRINT_PAN
    int nAtUb=0;
#endif
    for (int i=0;i<numberTotal_;i++) {
      Status status = getInternalStatus(i);
      double djValue=reducedCost[i];
      double badValue=0.0;
      if (status==atLowerBound&&djValue<-currentDualTolerance_) {
	double gap=upper[i]-lower[i];
	if (gap>100000000.0)
	  badValue = -djValue*CoinMin(gap,1.0e10);
      } else if (status==atUpperBound&&djValue>currentDualTolerance_) {
	double gap=upper[i]-lower[i];
	if (gap>100000000.0) {
	  badValue = djValue*CoinMin(gap,1.0e10);
#if PRINT_PAN
	  nAtUb++;
#endif
	}
      }
      if (badValue) {
	work[number]=badValue;
	which[number++]=i;
      }
    }
    // for now don't do if primal feasible (probably should go to primal)
    if (!numberPrimalInfeasibilities_) {
      number=0;
#if ABC_NORMAL_DEBUG>1
      printf("XXXX doesn't work if primal feasible - also fix switch to Clp primal\n");
#endif
    }
    if (number&&ignoreStuff!=2) {
      CoinSort_2(work,work+number,which);
      int numberToDo=CoinMin(number,numberRows_/10); // ??
#if PRINT_PAN>1
      CoinSort_2(which,which+numberToDo,work);
      int n=0;
#endif
#if PRINT_PAN
      printf("Panning %d variables (out of %d at lb and %d at ub)\n",numberToDo,number-nAtUb,nAtUb);
#endif
      firstFree_=numberTotal_;
      for (int i=0;i<numberToDo;i++) {
	int iSequence=which[i];
#if PRINT_PAN>1
	if (!n)
	  printf("Pan ");
	printf("%d ",iSequence);
	n++;
	if (n==10) {
	  n=0;
	  printf("\n");
	}
#endif
	setInternalStatus(iSequence,superBasic);
	firstFree_=CoinMin(firstFree_,iSequence);
      }
#if PRINT_PAN>1
      if (n)
	printf("\n");
#endif
      ordinaryVariables_=0;
      CoinAbcMemset0(work,number);
      stateOfProblem_ |= FAKE_SUPERBASIC;
    }
    setAvailableArray(whichArray);
  }
#endif
  if (!sumOfRelaxedPrimalInfeasibilities_&&sumDualInfeasibilities_&&type&&saveType<9
      &&ignoreStuff!=2) {
    // say been feasible
    abcState_ |= CLP_ABC_BEEN_FEASIBLE;
    int numberFake=numberAtFakeBound();
    if (!numberFake) {
      makeNonFreeVariablesDualFeasible();
      numberDualInfeasibilities_=0;
      sumDualInfeasibilities_=0.0;
      // just primal
      gutsOfSolution(2);
    }
  }
  bool computeNewSumInfeasibilities=numberIterations_==baseIteration_;
  if ((!type||(firstFree_<0&&lastFirstFree_>=0))&&ignoreStuff!=2) {
#ifdef PAN
    if ((stateOfProblem_&FAKE_SUPERBASIC)!=0&&firstFree_<0&&lastFirstFree_>=0&&type) {
      // clean up
#if PRINT_PAN
      printf("Pan switch off after %d iterations\n",numberIterations_);
#endif
      computeNewSumInfeasibilities=true;
      ordinaryVariables_=1;
      const double * COIN_RESTRICT reducedCost=abcDj_;
      const double * COIN_RESTRICT lower=abcLower_;
      const double * COIN_RESTRICT upper=abcUpper_;
      for (int i=0;i<numberTotal_;i++) {
	Status status = getInternalStatus(i);
	if (status==superBasic) {
	  double djValue=reducedCost[i];
	  double value=abcSolution_[i];
	  if (value<lower[i]+primalTolerance_) {
	    setInternalStatus(i,atLowerBound);
#if ABC_NORMAL_DEBUG>0
	    if(djValue<-dualTolerance_) 
	      printf("Odd at lb %d dj %g\n",i,djValue);
#endif
	  } else if (value>upper[i]-primalTolerance_) {
	    setInternalStatus(i,atUpperBound);
#if ABC_NORMAL_DEBUG>0
	    if(djValue>dualTolerance_) 
	      printf("Odd at ub %d dj %g\n",i,djValue);
#endif
	  } else {
	    assert (status!=superBasic);
	  }
	}
	if (status==isFree)
	  ordinaryVariables_=0;
      }
      stateOfProblem_ &= ~FAKE_SUPERBASIC;
    }
#endif
    // set up perturbation and dualBound_
    // make dual feasible
    if (firstFree_<0) {
      if (numberFlagged_) {
	numberFlagged_=0;
	for (int iRow = 0; iRow < numberRows_; iRow++) {
	  int iPivot = abcPivotVariable_[iRow];
	  if (flagged(iPivot)) {
	    clearFlagged(iPivot);
	  }
	}
      }
      int numberChanged=resetFakeBounds(0);
#if ABC_NORMAL_DEBUG>0
      if (numberChanged>0)
	printf("Re-setting %d fake bounds %d gone dual infeasible - can expect backward objective\n",
	       numberChanged,numberDualInfeasibilities_);
#endif
      if (numberDualInfeasibilities_||numberChanged!=-1) {
	makeNonFreeVariablesDualFeasible();
	numberDualInfeasibilities_=0;
	sumDualInfeasibilities_=0.0;
	sumOfRelaxedDualInfeasibilities_=0.0;
	// just primal
	gutsOfSolution(2);
	if (!numberIterations_ && sumPrimalInfeasibilities_ >
	    1.0e5*(savePrimalInfeasibilities+1.0e3) &&
	    (moreSpecialOptions_ & (256|8192)) == 0) {
	  // Use primal
	  problemStatus_=10;
	  // mark so can perturb
	  initialSumInfeasibilities_=-1.0;
	  CoinAbcMemcpy(abcSolution_,solutionSaved_,numberTotal_);
	  CoinAbcMemcpy(internalStatus_,internalStatusSaved_,numberTotal_);
	  return;
	}
	// redo
	if(computeNewSumInfeasibilities)
	  initialSumInfeasibilities_=sumPrimalInfeasibilities_;
	//computeObjective();
      } 
    }
    //bounceTolerances(type);
  } else if (numberIterations_>numberRows_&&stateDualColumn_==-2) {
    bounceTolerances(4);
  }
  // If bad accuracy treat as singular
  if ((largestPrimalError_ > 1.0e15 || largestDualError_ > 1.0e15) && numberIterations_>1000) {
    problemStatus_=10; //abort();
#if ABC_NORMAL_DEBUG>0
    printf("Big problems - errors %g %g try primal\n",largestPrimalError_,largestDualError_);
#endif
  } else if (goodAccuracy()&&numberIterations_>lastBadIteration_+200) {
    // Can reduce tolerance
    double newTolerance = CoinMax(0.995 * abcFactorization_->pivotTolerance(), saveData_.pivotTolerance_);
    if (!type)
      newTolerance = saveData_.pivotTolerance_;
    if (newTolerance>abcFactorization_->minimumPivotTolerance())
      abcFactorization_->pivotTolerance(newTolerance);
  }
  bestObjectiveValue_ = CoinMax(bestObjectiveValue_,
				rawObjectiveValue_ - bestPossibleImprovement_);
  // Double check infeasibility if no action
  if (abcProgress_.lastIterationNumber(0) == numberIterations_) {
    if (abcDualRowPivot_->looksOptimal()) {
      // say been feasible
      abcState_ |= CLP_ABC_BEEN_FEASIBLE;
      numberPrimalInfeasibilities_ = 0;
      sumPrimalInfeasibilities_ = 0.0;
    }
  } else {
    double thisObj = rawObjectiveValue_ - bestPossibleImprovement_;
#ifdef CLP_INVESTIGATE
    assert (bestPossibleImprovement_ > -1000.0 && rawObjectiveValue_ > -1.0e100);
    if (bestPossibleImprovement_)
      printf("obj %g add in %g -> %g\n", rawObjectiveValue_, bestPossibleImprovement_,
	     thisObj);
#endif
    double lastObj = abcProgress_.lastObjective(0);
#ifndef NDEBUG
#if ABC_NORMAL_DEBUG>3
    resetFakeBounds(-1);
#endif
#endif
    if (lastObj < thisObj - 1.0e-5 * CoinMax(fabs(thisObj), fabs(lastObj)) - 1.0e-3 && saveType<9) {
      numberTimesOptimal_ = 0;
    }
  }
  // Up tolerance if looks a bit odd
  if (numberIterations_ > CoinMax(1000, numberRows_ >> 4) && (specialOptions_ & 64) != 0) {
    if (sumPrimalInfeasibilities_ && sumPrimalInfeasibilities_ < 1.0e5) {
      int backIteration = abcProgress_.lastIterationNumber(CLP_PROGRESS - 1);
      if (backIteration > 0 && numberIterations_ - backIteration < 9 * CLP_PROGRESS) {
	if (abcFactorization_->pivotTolerance() < 0.9) {
	  // up tolerance
	  abcFactorization_->pivotTolerance(CoinMin(abcFactorization_->pivotTolerance() * 1.05 + 0.02, 0.91));
	  //printf("tol now %g\n",abcFactorization_->pivotTolerance());
	  abcProgress_.clearIterationNumbers();
	}
      }
    }
  }
  // Check if looping
  int loop;
  if (type != 2)
    loop = abcProgress_.looping();
  else
    loop = -1;
  if (abcProgress_.reallyBadTimes() > 10) {
    problemStatus_ = 10; // instead - try other algorithm
#if ABC_NORMAL_DEBUG>3
    printf("returning at %d\n", __LINE__);
#endif
  }
  if (loop >= 0) {
    problemStatus_ = loop; //exit if in loop
    if (!problemStatus_) {
      // declaring victory
      // say been feasible
      abcState_ |= CLP_ABC_BEEN_FEASIBLE;
      numberPrimalInfeasibilities_ = 0;
      sumPrimalInfeasibilities_ = 0.0;
    } else {
      problemStatus_ = 10; // instead - try other algorithm
#if ABC_NORMAL_DEBUG>3
      printf("returning at %d\n", __LINE__);
#endif
    }
    return;
  }
  // really for free variables in
  if((progressFlag_ & 2) != 0) {
    //situationChanged = 2;
  }
  progressFlag_ &= (~3); //reset progress flag
  // mark as having gone optimal if looks like it
  if (!numberPrimalInfeasibilities_&&
      !numberDualInfeasibilities_)
    progressFlag_ |= 8;
  if (handler_->detail(CLP_SIMPLEX_STATUS, messages_) < 100) {
    handler_->message(CLP_SIMPLEX_STATUS, messages_)
      << numberIterations_ << objectiveValue();
    handler_->printing(sumPrimalInfeasibilities_ > 0.0)
      << sumPrimalInfeasibilities_ << numberPrimalInfeasibilities_;
    handler_->printing(sumDualInfeasibilities_ > 0.0)
      << sumDualInfeasibilities_ << numberDualInfeasibilities_;
    handler_->printing(numberDualInfeasibilitiesWithoutFree_
		       < numberDualInfeasibilities_)
      << numberDualInfeasibilitiesWithoutFree_;
    handler_->message() << CoinMessageEol;
  }
  double approximateObjective = rawObjectiveValue_;
  //realDualInfeasibilities = sumDualInfeasibilities_;
  // If we need to carry on cleaning variables
  if (!numberPrimalInfeasibilities_ && (specialOptions_ & 1024) != 0 && CLEAN_FIXED) {
    for (int iRow = 0; iRow < numberRows_; iRow++) {
      int iPivot = abcPivotVariable_[iRow];
      if (!flagged(iPivot) && pivoted(iPivot)) {
	// carry on
	numberPrimalInfeasibilities_ = -1;
	sumOfRelaxedPrimalInfeasibilities_ = 1.0;
	sumPrimalInfeasibilities_ = 1.0;
	break;
      }
    }
  }
  /* If we are primal feasible and any dual infeasibilities are on
     free variables then it is better to go to primal */
  if (!numberPrimalInfeasibilities_ && !numberDualInfeasibilitiesWithoutFree_ &&
      numberDualInfeasibilities_) {
    // say been feasible
    abcState_ |= CLP_ABC_BEEN_FEASIBLE;
    if (type&&ignoreStuff!=2)
      problemStatus_ = 10;
    else
      numberPrimalInfeasibilities_=1;
  }
  // check optimal
  // give code benefit of doubt
  if (sumOfRelaxedDualInfeasibilities_ == 0.0 &&
      sumOfRelaxedPrimalInfeasibilities_ == 0.0&&ignoreStuff!=2) {
    // say been feasible
    abcState_ |= CLP_ABC_BEEN_FEASIBLE;
    // say optimal (with these bounds etc)
    numberDualInfeasibilities_ = 0;
    sumDualInfeasibilities_ = 0.0;
    numberPrimalInfeasibilities_ = 0;
    sumPrimalInfeasibilities_ = 0.0;
  } else if (sumOfRelaxedDualInfeasibilities_>1.0e-3&&firstFree_<0&&ignoreStuff!=2
	     &&numberIterations_>lastCleaned_+10) {
#if ABC_NORMAL_DEBUG>0
    printf("Making dual feasible\n");
#endif
    makeNonFreeVariablesDualFeasible(true);
    lastCleaned_=numberIterations_;
    numberDualInfeasibilities_=0;
    sumDualInfeasibilities_=0.0;
    // just primal
    gutsOfSolution(2);
  }
  // see if cutoff reached
  double limit = 0.0;
  getDblParam(ClpDualObjectiveLimit, limit);
  int numberChangedBounds=0;
  if (primalFeasible()&&ignoreStuff!=2) {
    // may be optimal - or may be bounds are wrong
    numberChangedBounds = changeBounds(0, changeCost);
    if (numberChangedBounds)
      gutsOfSolution(2);
  }
  if (primalFeasible()&&ignoreStuff!=2) {
    if (numberChangedBounds <= 0 && !numberDualInfeasibilities_) {
      //looks optimal - do we need to reset tolerance
      if (lastCleaned_ < numberIterations_ && /*numberTimesOptimal_*/ stateDualColumn_ < 4 &&
	  (numberChanged_ || (specialOptions_ & 4096) == 0)) {
#if CLP_CAN_HAVE_ZERO_OBJ
	if ((specialOptions_&2097152)==0) {
#endif
	  numberTimesOptimal_++;
	  if (stateDualColumn_==-2) {
#if ABC_NORMAL_DEBUG>0
	    printf("Going straight from state -2 to 0\n");
#endif
	    stateDualColumn_=-1;
	  }
	  changeMade_++; // say something changed
	  if (numberTimesOptimal_ == 1) {
	    if (fabs(currentDualTolerance_-dualTolerance_)>1.0e-12) {
#if ABC_NORMAL_DEBUG>0
	      printf("changing dual tolerance from %g to %g (numberTimesOptimal_==%d)\n",
		     currentDualTolerance_,dualTolerance_,numberTimesOptimal_);
#endif
	      currentDualTolerance_ = dualTolerance_;
	    }
	  } else {
	    if (numberTimesOptimal_ == 2) {
	      // better to have small tolerance even if slower
	      abcFactorization_->zeroTolerance(CoinMin(abcFactorization_->zeroTolerance(), 1.0e-15));
	    }
#if ABC_NORMAL_DEBUG>0
	    printf("changing dual tolerance from %g to %g (numberTimesOptimal_==%d)\n",
		   currentDualTolerance_,dualTolerance_*pow(2.0,numberTimesOptimal_-1),numberTimesOptimal_);
#endif
	    currentDualTolerance_ = dualTolerance_ * pow(2.0, numberTimesOptimal_ - 1);
	  }
	  if (numberChanged_>0) {
	    handler_->message(CLP_DUAL_ORIGINAL, messages_)
	      << CoinMessageEol;
	    //realDualInfeasibilities = sumDualInfeasibilities_; 
	  } else if (numberChangedBounds<-1) {
	    // bounds were flipped
	    //gutsOfSolution(2);
	  }
	  if (stateDualColumn_>=0)
	    stateDualColumn_++;
#ifndef TRY_ABC_GUS
	  int returnCode=bounceTolerances(1);
	  if (returnCode)
#endif // always go to primal
	    problemStatus_=10;
	  lastCleaned_ = numberIterations_;
#if CLP_CAN_HAVE_ZERO_OBJ
	} else {
	  // no cost - skip checks
	  problemStatus_=0;
	}
#endif
      } else {
	problemStatus_ = 0; // optimal
	if (lastCleaned_ < numberIterations_ && numberChanged_) {
	  handler_->message(CLP_SIMPLEX_GIVINGUP, messages_)
	    << CoinMessageEol;
	}
      }
    } else if (numberChangedBounds<-1) {
      // some flipped
      bounceTolerances(2);
#if ABC_NORMAL_DEBUG>0
      printf("numberChangedBounds %d numberAtFakeBound %d at line %d in file %s\n",
	     numberChangedBounds,numberAtFakeBound(),__LINE__,__FILE__);
#endif
    } else if (numberChangedBounds>0||numberAtFakeBound()) {
      handler_->message(CLP_DUAL_BOUNDS, messages_)
	<< currentDualBound_
	<< CoinMessageEol;
#if ABC_NORMAL_DEBUG>0
      printf("changing bounds\n");
      printf("numberChangedBounds %d numberAtFakeBound %d at line %d in file %s\n",
	     numberChangedBounds,numberAtFakeBound(),__LINE__,__FILE__);
#endif
      if (!numberDualInfeasibilities_&&!numberPrimalInfeasibilities_) {
	// check unbounded
	// find a variable with bad dj
	int iChosen = -1;
	if ((specialOptions_ & 0x03000000) == 0) {
	  double largest = 100.0 * primalTolerance_;
	  for (int iSequence = 0; iSequence < numberTotal_; iSequence++) {
	    double djValue = abcDj_[iSequence];
	    double originalLo = lowerSaved_[iSequence];
	    double originalUp = upperSaved_[iSequence];
	    if (fabs(djValue) > fabs(largest)) {
	      if (getInternalStatus(iSequence) != basic) {
		if (djValue > 0 && originalLo < -1.0e20) {
		  if (djValue > fabs(largest)) {
		    largest = djValue;
		    iChosen = iSequence;
		  }
		} else if (djValue < 0 && originalUp > 1.0e20) {
		  if (-djValue > fabs(largest)) {
		    largest = djValue;
		    iChosen = iSequence;
		  }
		}
	      }
	    }
	  }
	}
	if (iChosen >= 0) {
	  int iVector=getAvailableArray();
	  unpack(usefulArray_[iVector],iChosen);
	  //double changeCost;
	  problemStatus_ = checkUnbounded(usefulArray_[iVector], 0.0/*changeCost*/);
	  usefulArray_[iVector].clear();
	  setAvailableArray(iVector);
	}
      }
      gutsOfSolution(3);
      //bounceTolerances(2);
      //realDualInfeasibilities = sumDualInfeasibilities_; 
    }
    // unflag all variables (we may want to wait a bit?)
    if (unflagVariables) {
      int numberFlagged = numberFlagged_;
      numberFlagged_=0;
      for (int iRow = 0; iRow < numberRows_; iRow++) {
	int iPivot = abcPivotVariable_[iRow];
	if (flagged(iPivot)) {
	  clearFlagged(iPivot);
	}
      }
#if ABC_NORMAL_DEBUG>3
      if (numberFlagged) {
	printf("unflagging %d variables - tentativeStatus %d probStat %d ninf %d nopt %d\n", numberFlagged, tentativeStatus,
	       problemStatus_, numberPrimalInfeasibilities_,
	       numberTimesOptimal_);
      }
#endif
      unflagVariables = numberFlagged > 0;
      if (numberFlagged && !numberPivots) {
	/* looks like trouble as we have not done any iterations.
	   Try changing pivot tolerance then give it a few goes and give up */
	if (abcFactorization_->pivotTolerance() < 0.9) {
	  abcFactorization_->pivotTolerance(0.99);
	  problemStatus_ = -1;
	} else if (numberTimesOptimal_ < 3) {
	  numberTimesOptimal_++;
	  problemStatus_ = -1;
	} else {
	  unflagVariables = false;
	  //secondaryStatus_ = 1; // and say probably infeasible
	  if ((moreSpecialOptions_ & 256) == 0||(abcState_&CLP_ABC_BEEN_FEASIBLE)!=0) {
	    // try primal
	    problemStatus_ = 10;
	  } else {
	    // almost certainly infeasible
	    problemStatus_ = 1;
	  }
#if ABC_NORMAL_DEBUG>3
	  printf("returning at %d\n", __LINE__);
#endif
	}
      }
    }
  }
  if (problemStatus_ < 0) {
    saveGoodStatus();
    if (weightsSaved) {
      // restore weights (if saved) - also recompute infeasibility list
      abcDualRowPivot_->saveWeights(this, weightsSaved);
    } else {
      abcDualRowPivot_->recomputeInfeasibilities();
    }
  }
  // see if cutoff reached
  checkCutoff(false);
  // If we are in trouble and in branch and bound give up
  if ((specialOptions_ & 1024) != 0) {
    int looksBad = 0;
    if (largestPrimalError_ * largestDualError_ > 1.0e2) {
      looksBad = 1;
    } else if (largestPrimalError_ > 1.0e-2
	       && rawObjectiveValue_ > CoinMin(1.0e15, 1.0e3 * limit)) {
      looksBad = 2;
    }
    if (looksBad) {
      if (abcFactorization_->pivotTolerance() < 0.9) {
	// up tolerance
	abcFactorization_->pivotTolerance(CoinMin(abcFactorization_->pivotTolerance() * 1.05 + 0.02, 0.91));
      } else if (numberIterations_ > 10000) {
#if ABC_NORMAL_DEBUG>0
	if (handler_->logLevel() > 2)
	  printf("bad dual - saying infeasible %d\n", looksBad);
#endif
	problemStatus_ = 1;
	secondaryStatus_ = 1; // and say was on cutoff
      } else if (largestPrimalError_ > 1.0e5) {
#if ABC_NORMAL_DEBUG>0
	if (handler_->logLevel() > 2)
	  printf("bad dual - going to primal %d %g\n", looksBad, largestPrimalError_);
#endif
	allSlackBasis();
	problemStatus_ = 10;
      }
    }
  }
  //if (problemStatus_ < 0 && !changeMade_) {
  //problemStatus_ = 4; // unknown
  //}
  lastGoodIteration_ = numberIterations_;
  if (numberIterations_ > lastBadIteration_ + 200) {
    moreSpecialOptions_ &= ~16; // clear check accuracy flag
    if (numberFlagged_) {
      numberFlagged_=0;
      for (int iRow = 0; iRow < numberRows_; iRow++) {
	int iPivot = abcPivotVariable_[iRow];
	if (flagged(iPivot)) {
	  clearFlagged(iPivot);
	}
      }
    }
  }
  if (problemStatus_ < 0&&ignoreStuff!=2) {
    //sumDualInfeasibilities_ = realDualInfeasibilities; // back to say be careful
    if (sumDualInfeasibilities_) {
      numberDualInfeasibilities_ = 1;
    } else if (!numberPrimalInfeasibilities_) {
      // Looks good
      problemStatus_=0;
    }
  }
  double thisObj = abcProgress_.lastObjective(0);
  double lastObj = abcProgress_.lastObjective(1);
  if (lastObj > thisObj + 1.0e-4 * CoinMax(fabs(thisObj), fabs(lastObj)) + 1.0e-4&&
      lastFirstFree_<0) {
    //printf("BAD - objective backwards\n");
    //bounceTolerances(3);
    numberBlackMarks+=3;
  }
  if (numberBlackMarks>0&&numberIterations_>baseIteration_) {
    // be very careful
    int maxFactor = abcFactorization_->maximumPivots();
    if (maxFactor > 10) {
      if ((stateOfProblem_&PESSIMISTIC)==0||true) {
	if (largestDualError_>10.0*CoinMax(lastDualError_,1.0e-6)
	    ||largestPrimalError_>10.0*CoinMax(lastPrimalError_,1.0e-6))
	  maxFactor = CoinMin(maxFactor,20);
	forceFactorization_ = CoinMax(1, (maxFactor >> 1));
      } else if (numberBlackMarks>2) {
	forceFactorization_ = CoinMax(1, (forceFactorization_ >> 1));
      }
    }
    stateOfProblem_ |= PESSIMISTIC;
    if (numberBlackMarks>=10)
      forceFactorization_ = 1;
  }
  lastPrimalError_=largestPrimalError_;
  lastDualError_=largestDualError_;
  lastFirstFree_=firstFree_;
  if (ignoreStuff==2) {
    // in values pass
    lastFirstFree_=-1;
    // firstFree_=-1;
  }
  if (alphaAccuracy_ > 0.0)
    alphaAccuracy_ = 1.0;
  // If we are stopping - use plausible objective
  // Maybe only in fast dual
  if (problemStatus_ > 2)
    rawObjectiveValue_ = approximateObjective;
  if (problemStatus_ == 1 && (progressFlag_&8) != 0 &&
      fabs(rawObjectiveValue_) > 1.0e10 )
    problemStatus_ = 10; // infeasible - but has looked feasible
  checkMoveBack(true);
#if 0
  {
    double * array = usefulArray_[arrayForTableauRow_].denseVector();
    for (int iPivot = 0; iPivot < numberRows_; iPivot++) {
      int iSequence = abcPivotVariable_[iPivot];
      unpack(usefulArray_[arrayForTableauRow_],iSequence);
      abcFactorization_->updateColumn(usefulArray_[arrayForTableauRow_]);
      assert (fabs(array[iPivot] - 1.0) < 1.0e-4);
      array[iPivot] = 0.0;
      for (int i = 0; i < numberRows_; i++)
	assert (fabs(array[i]) < 1.0e-4);
      usefulArray_[arrayForTableauRow_].clear();
    }
  }
#endif
#if 0
  {
    // save status, cost and solution
    unsigned char * saveStatus = CoinCopyOfArray(internalStatus_,numberTotal_);
    double * saveSolution = CoinCopyOfArray(abcSolution_,numberTotal_);
    double * saveCost = CoinCopyOfArray(abcCost_,numberTotal_);
    printf("TestA sumDual %g sumPrimal %g\n",sumDualInfeasibilities_,sumPrimalInfeasibilities_);
    if (perturbation_>100)
      CoinAbcMemcpy(abcCost_,costSaved_,numberTotal_);
    else
      CoinAbcMemcpy(abcCost_,abcPerturbation_,numberTotal_);
    moveToBasic();
    gutsOfSolution(3);
    for (int iSequence = 0; iSequence < numberTotal_; iSequence++) {
      bool changed=fabs(saveCost[iSequence]-abcCost_[iSequence])>1.0e-10;
      bool bad=false;
      int iStatus=internalStatus_[iSequence]&7;
      if (getInternalStatus(iSequence) != basic && !flagged(iSequence)) {
	// not basic
	double distanceUp = abcUpper_[iSequence] - abcSolution_[iSequence];
	double distanceDown = abcSolution_[iSequence] - abcLower_[iSequence];
	double value = abcDj_[iSequence];
	if (distanceUp > primalTolerance_) {
	  // Check if "free"
	  if (distanceDown <= primalTolerance_) {
	    // should not be negative
	    if (value < 0.0) {
	      value = - value;
	      if (value > currentDualTolerance_) {
		bad=true;
	      }
	    }
	  } else {
	    // free
	    value=fabs(value);
	    if (value > currentDualTolerance_) {
	      bad=true;
	    }
	  }
	} else if (distanceDown > primalTolerance_) {
	  // should not be positive
	  if (value > 0.0) {
	    if (value > currentDualTolerance_) {
	      bad=true;
	    }
	  }
	}
      }
      if (changed||bad)
	printf("seq %d status %d current cost %g original %g dj %g %s\n",
	       iSequence,iStatus,saveCost[iSequence],abcCost_[iSequence],
	       abcDj_[iSequence],bad ? "(bad)" : "");
    }
    printf("TestB sumDual %g sumPrimal %g\n",sumDualInfeasibilities_,sumPrimalInfeasibilities_);
    if (numberDualInfeasibilities_) {
      makeNonFreeVariablesDualFeasible();
      moveToBasic();
      gutsOfSolution(3);
      printf("TestC sumDual %g sumPrimal %g\n",sumDualInfeasibilities_,sumPrimalInfeasibilities_);
    }
    CoinAbcMemcpy(internalStatus_,saveStatus,numberTotal_);
    CoinAbcMemcpy(abcSolution_,saveSolution,numberTotal_);
    CoinAbcMemcpy(abcCost_,saveCost,numberTotal_);
    delete [] saveStatus;
    delete [] saveSolution;
    delete [] saveCost;
    moveToBasic();
    gutsOfSolution(3);
    printf("TestD sumDual %g sumPrimal %g\n",sumDualInfeasibilities_,sumPrimalInfeasibilities_);
  }
#endif
#if 0
  {
    const double multiplier[] = { 1.0, -1.0}; // sign?????????????
    double dualT = - currentDualTolerance_;
    double largestCostDifference=0.1*currentDualTolerance_;
    int numberCostDifference=0;
    double largestBadDj=0.0;
    int numberBadDj=0;
    double sumBadDj=0.0;
    double sumCanMoveBad=0.0;
    int numberCanMoveBad=0;
    double sumCanMoveOthers=0.0;
    int numberCanMoveOthers=0;
    for (int iSequence = 0; iSequence < numberTotal_; iSequence++) {
      double costDifference=abcPerturbation_[iSequence]-abcCost_[iSequence];
      if (fabs(costDifference)>0.1*currentDualTolerance_) {
	if (fabs(costDifference)>largestCostDifference) 
	  largestCostDifference=fabs(costDifference);
	numberCostDifference++;
      }
      unsigned char iStatus = internalStatus_[iSequence] & 7;
      if (iStatus<4) {
	double mult = multiplier[iStatus];
	double dj = abcDj_[iSequence] * mult;
	if (dj < dualT) {
	  sumBadDj+=dualT-dj;
	  numberBadDj++;
	  if (dualT-dj>largestBadDj)
	    largestBadDj=dualT-dj;
	  if (costDifference*mult>0.0) {
	    sumCanMoveBad+=costDifference*mult;
	    numberCanMoveBad++;
	    //dj+=costDifference*mult;
	    abcDj_[iSequence]+=costDifference;
	    abcCost_[iSequence]=abcPerturbation_[iSequence];
	  }
	} else if (costDifference*mult>0.0) {
	  sumCanMoveOthers+=costDifference*mult;
	  numberCanMoveOthers++;
	  //dj+=costDifference*mult;
	  abcDj_[iSequence]+=costDifference;
	  abcCost_[iSequence]=abcPerturbation_[iSequence];
	}
      }
    }
    if (numberCostDifference+numberBadDj+numberCanMoveBad+numberCanMoveOthers) {
      printf("largest diff %g (%d), largest bad dj %g (%d - sum %g), can move bad %g (%d), good %g (%d) - %d at fake bound\n",largestCostDifference,numberCostDifference,largestBadDj,
	     numberBadDj, sumBadDj,sumCanMoveBad=0.0,numberCanMoveBad,
	     sumCanMoveOthers,numberCanMoveOthers,numberAtFakeBound());
    }
  }
#endif
}
// see if cutoff reached
bool
AbcSimplexDual::checkCutoff(bool computeObjective)
{
  double objValue=COIN_DBL_MAX;
  if (computeObjective)
    objValue = computeInternalObjectiveValue();
  else
    objValue = minimizationObjectiveValue();
  double limit = 0.0;
  getDblParam(ClpDualObjectiveLimit, limit);
  // Looks as if numberAtFakeBound() being computed too often
  if(fabs(limit) < 1.0e30 && objValue >
     limit && !numberAtFakeBound()) {
    bool looksInfeasible = !numberDualInfeasibilities_;
    if (objValue > limit + fabs(0.1 * limit) + 1.0e2 * sumDualInfeasibilities_ + 1.0e4 &&
	sumDualInfeasibilities_ < largestDualError_ && numberIterations_ > 0.5 * numberRows_ + 1000)
      looksInfeasible = true;
    if (looksInfeasible&&!computeObjective)
      objValue = computeInternalObjectiveValue();
    if (looksInfeasible) {
      // Even if not perturbed internal costs may have changed
      // be careful
      if(objValue > limit) {
	problemStatus_ = 1;
	secondaryStatus_ = 1; // and say was on cutoff
	return true;
      }
    }
  }
  return false;
}
#define CLEANUP_DJS 0
/* While updateDualsInDual sees what effect is of flip
   this does actual flipping.
   If change >0.0 then value in array >0.0 => from lower to upper
   returns 3 if skip this iteration and re-factorize
*/
int
AbcSimplexDual::flipBounds()
{
  CoinIndexedVector & array = usefulArray_[arrayForFlipBounds_];
  CoinIndexedVector & output = usefulArray_[arrayForFlipRhs_];
  output.clear();
  int numberFlipped=array.getNumElements();
  if (numberFlipped) {
#if CLP_CAN_HAVE_ZERO_OBJ>1
    if ((specialOptions_&2097152)==0) {
#endif
      // do actual flips
      // do in parallel once got spare space in factorization
#if ABC_PARALLEL==2
#endif
      int number=array.getNumElements();
      const int *  COIN_RESTRICT which=array.getIndices();
      double *  COIN_RESTRICT work = array.denseVector();
      
      double *  COIN_RESTRICT solution = abcSolution_;
      const double *  COIN_RESTRICT lower = abcLower_;
      const double *  COIN_RESTRICT upper = abcUpper_;
#if CLEANUP_DJS
      double *  COIN_RESTRICT cost = abcCost_;
      double *  COIN_RESTRICT dj = abcDj_;
      // see if we can clean up djs
      // may have perturbation
      const double * COIN_RESTRICT originalCost = abcPerturbation_;
#else
      const double *  COIN_RESTRICT cost = abcCost_;
      const double *  COIN_RESTRICT dj = abcDj_;
#endif
      const double multiplier[] = { 1.0, -1.0};
      for (int i = 0; i < number; i++) {
	double value=work[i]*theta_;
	work[i]=0.0;
	int iSequence = which[i];
	unsigned char iStatus = internalStatus_[iSequence]&3;
	assert ((internalStatus_[iSequence]&7)==0||
		(internalStatus_[iSequence]&7)==1);
	double mult = multiplier[iStatus];
	double djValue = dj[iSequence] * mult-value;
	//double perturbedTolerance = abcPerturbation_[iSequence];
	if (djValue<-currentDualTolerance_) {
	  // might just happen - if so just skip
	  assert (iSequence!=sequenceIn_);
	  double movement=(upper[iSequence]-lower[iSequence])*mult;
	  if (iStatus==0) {
	    // at lower bound
	    // to upper bound
	    setInternalStatus(iSequence, atUpperBound);
	    solution[iSequence] = upper[iSequence];
#if CLEANUP_DJS
	    if (cost[iSequence]<originalCost[iSequence]) {
	      double difference = CoinMax(cost[iSequence]-originalCost[iSequence],djValue);
	      dj[iSequence]-=difference;
	      cost[iSequence]-=difference;
	    }
#endif
	  } else {
	    // at upper bound
	    // to lower bound
	    setInternalStatus(iSequence, atLowerBound);
	    solution[iSequence] = lower[iSequence];
#if CLEANUP_DJS
	    if (cost[iSequence]>originalCost[iSequence]) {
	      double difference = CoinMin(cost[iSequence]-originalCost[iSequence],-djValue);
	      dj[iSequence]-=difference;
	      cost[iSequence]-=difference;
	    }
#endif
	  }
	  abcMatrix_->add(output, iSequence, movement);
	  objectiveChange_ += cost[iSequence]*movement;
	}
      }
      array.setNumElements(0);
      // double check something flipped
      if (output.getNumElements()) {
#if ABC_PARALLEL==0
	abcFactorization_->updateColumn(output);
#else
	assert (FACTOR_CPU>2);
	abcFactorization_->updateColumnCpu(output,1);
#endif
	abcDualRowPivot_->updatePrimalSolution(output,1.0);
      }
#if CLP_CAN_HAVE_ZERO_OBJ>1
    } else {
      clearArrays(3);
    }
#endif
  }
  // recompute dualOut_
  valueOut_ = solutionBasic_[pivotRow_];
  if (directionOut_ < 0) {
    dualOut_ = valueOut_ - upperOut_;
  } else {
    dualOut_ = lowerOut_ - valueOut_;
  }
#if 0
  // amount primal will move
  movement_ = -dualOut_ * directionOut_ / alpha_;
  double movementOld = oldDualOut * directionOut_ / alpha_;
  // so objective should increase by fabs(dj)*movement_
  // but we already have objective change - so check will be good
  if (objectiveChange_ + fabs(movementOld * dualIn_) < -CoinMax(1.0e-5, 1.0e-12 * fabs(rawObjectiveValue_))) {
#if ABC_NORMAL_DEBUG>3
    if (handler_->logLevel() & 32)
      printf("movement %g, movementOld %g swap change %g, rest %g  * %g\n",
	     objectiveChange_ + fabs(movement_ * dualIn_),
	     movementOld,objectiveChange_, movement_, dualIn_);
#endif
  }
  if (0) {
    if(abcFactorization_->pivots()) {
      // going backwards - factorize
      problemStatus_ = -2; // factorize now
      stateOfIteration_=2;
    }
  }
#endif
  return numberFlipped;
}
/* Undo a flip
 */
void 
AbcSimplexDual::flipBack(int number)
{
  CoinIndexedVector & array = usefulArray_[arrayForFlipBounds_];
  const int *  COIN_RESTRICT which=array.getIndices();
  double *  COIN_RESTRICT solution = abcSolution_;
  const double *  COIN_RESTRICT lower = abcLower_;
  const double *  COIN_RESTRICT upper = abcUpper_;
  for (int i = 0; i < number; i++) {
    int iSequence = which[i];
    unsigned char iStatus = internalStatus_[iSequence]&3;
    assert ((internalStatus_[iSequence]&7)==0||
	    (internalStatus_[iSequence]&7)==1);
    if (iStatus==0) {
      // at lower bound
      // to upper bound
      setInternalStatus(iSequence, atUpperBound);
      solution[iSequence] = upper[iSequence];
    } else {
      // at upper bound
      // to lower bound
      setInternalStatus(iSequence, atLowerBound);
      solution[iSequence] = lower[iSequence];
    }
  }
}
// Restores bound to original bound
void
AbcSimplexDual::originalBound( int iSequence)
{
  if (getFakeBound(iSequence) != noFake) {
    numberFake_--;;
    setFakeBound(iSequence, noFake);
    abcLower_[iSequence] = lowerSaved_[iSequence];
    abcUpper_[iSequence] = upperSaved_[iSequence];
  }
}
/* As changeBounds but just changes new bounds for a single variable.
   Returns true if change */
bool
AbcSimplexDual::changeBound( int iSequence)
{
  // old values
  double oldLower = abcLower_[iSequence];
  double oldUpper = abcUpper_[iSequence];
  double value = abcSolution_[iSequence];
  bool modified = false;
  // original values
  double lowerValue = lowerSaved_[iSequence];
  double upperValue = upperSaved_[iSequence];
  setFakeBound(iSequence,noFake);
  if (value == oldLower) {
    if (upperValue > oldLower + currentDualBound_) {
      abcUpper_[iSequence] = oldLower + currentDualBound_;
      setFakeBound(iSequence, upperFake);
      assert (abcLower_[iSequence]==lowerSaved_[iSequence]);
      assert (abcUpper_[iSequence]<upperSaved_[iSequence]);
      modified = true;
      numberFake_++;
    }
  } else if (value == oldUpper) {
    if (lowerValue < oldUpper - currentDualBound_) {
      abcLower_[iSequence] = oldUpper - currentDualBound_;
      setFakeBound(iSequence, lowerFake);
      assert (abcLower_[iSequence]>lowerSaved_[iSequence]);
      assert (abcUpper_[iSequence]==upperSaved_[iSequence]);
      modified = true;
      numberFake_++;
    }
  } else {
    assert(value == oldLower || value == oldUpper);
  }
  return modified;
}
/* Checks number of variables at fake bounds.  This is used by fastDual
   so can exit gracefully before end */
int
AbcSimplexDual::numberAtFakeBound()
{
  int numberFake = 0;

  if (numberFake_) {
    for (int iSequence = 0; iSequence < numberTotal_; iSequence++) {
      FakeBound bound = getFakeBound(iSequence);
      switch(getInternalStatus(iSequence)) {
	
      case basic:
	break;
      case isFree:
      case superBasic:
      case AbcSimplex::isFixed:
	//setFakeBound (iSequence, noFake);
	break;
      case atUpperBound:
	if (bound == upperFake || bound == bothFake)
	  numberFake++;
	break;
      case atLowerBound:
	if (bound == lowerFake || bound == bothFake)
	  numberFake++;
	break;
      }
    }
  }
  return numberFake;
}
int
AbcSimplexDual::resetFakeBounds(int type)
{
  if (type == 0||type==1) {
    // put back original bounds and then check
    //CoinAbcMemcpy(abcLower_,lowerSaved_,numberTotal_);
    //CoinAbcMemcpy(abcUpper_,upperSaved_,numberTotal_);
    double dummyChangeCost = 0.0;
    return changeBounds(3+type, dummyChangeCost);
  } else if (type < 0) {
#ifndef NDEBUG
    // just check
    int iSequence;
    int nFake = 0;
    int nErrors = 0;
    int nSuperBasic = 0;
    int nWarnings = 0;
    for (iSequence = 0; iSequence < numberTotal_; iSequence++) {
      FakeBound fakeStatus = getFakeBound(iSequence);
      Status status = getInternalStatus(iSequence);
      bool isFake = false;
#ifdef CLP_INVESTIGATE
      char RC = 'C';
      int jSequence = iSequence;
      if (jSequence >= numberColumns_) {
	RC = 'R';
	jSequence -= numberColumns_;
      }
#endif
      double lowerValue = lowerSaved_[iSequence];
      double upperValue = upperSaved_[iSequence];
      double value = abcSolution_[iSequence];
      CoinRelFltEq equal;
      if (status == atUpperBound ||
	  status == atLowerBound) {
	if (fakeStatus == AbcSimplexDual::upperFake) {
	  if(!equal(abcUpper_[iSequence], (lowerValue + currentDualBound_)) ||
	     !(equal(abcUpper_[iSequence], value) ||
	       equal(abcLower_[iSequence], value))) {
	    nErrors++;
#ifdef CLP_INVESTIGATE
	    printf("** upperFake %c%d %g <= %g <= %g true %g, %g\n",
		   RC, jSequence, abcLower_[iSequence], abcSolution_[iSequence],
		   abcUpper_[iSequence], lowerValue, upperValue);
#endif
	  }
	  isFake = true;;
	} else if (fakeStatus == AbcSimplexDual::lowerFake) {
	  if(!equal(abcLower_[iSequence], (upperValue - currentDualBound_)) ||
	     !(equal(abcUpper_[iSequence], value) ||
	       equal(abcLower_[iSequence], value))) {
	    nErrors++;
#ifdef CLP_INVESTIGATE
	    printf("** lowerFake %c%d %g <= %g <= %g true %g, %g\n",
		   RC, jSequence, abcLower_[iSequence], abcSolution_[iSequence],
		   abcUpper_[iSequence], lowerValue, upperValue);
#endif
	  }
	  isFake = true;;
	} else if (fakeStatus == AbcSimplexDual::bothFake) {
	  nWarnings++;
#ifdef CLP_INVESTIGATE
	  printf("** %d at bothFake?\n", iSequence);
#endif
	} else if (abcUpper_[iSequence] - abcLower_[iSequence] > 2.0 * currentDualBound_) {
	  nErrors++;
#ifdef CLP_INVESTIGATE
	  printf("** noFake! %c%d %g <= %g <= %g true %g, %g\n",
		 RC, jSequence, abcLower_[iSequence], abcSolution_[iSequence],
		 abcUpper_[iSequence], lowerValue, upperValue);
#endif
	}
      } else if (status == superBasic || status == isFree) {
	nSuperBasic++;
	//printf("** free or superbasic %c%d %g <= %g <= %g true %g, %g - status %d\n",
	//     RC,jSequence,abcLower_[iSequence],abcSolution_[iSequence],
	//     abcUpper_[iSequence],lowerValue,upperValue,status);
      } else if (status == basic) {
	bool odd = false;
	if (!equal(abcLower_[iSequence], lowerValue))
	  odd = true;
	if (!equal(abcUpper_[iSequence], upperValue))
	  odd = true;
	if (odd) {
#ifdef CLP_INVESTIGATE
	  printf("** basic %c%d %g <= %g <= %g true %g, %g\n",
		 RC, jSequence, abcLower_[iSequence], abcSolution_[iSequence],
		 abcUpper_[iSequence], lowerValue, upperValue);
#endif
	  nWarnings++;
	}
      } else if (status == isFixed) {
	if (!equal(abcUpper_[iSequence], abcLower_[iSequence])) {
	  nErrors++;
#ifdef CLP_INVESTIGATE
	  printf("** fixed! %c%d %g <= %g <= %g true %g, %g\n",
		 RC, jSequence, abcLower_[iSequence], abcSolution_[iSequence],
		 abcUpper_[iSequence], lowerValue, upperValue);
#endif
	}
      }
      if (isFake) {
	nFake++;
      } else {
	if (fakeStatus != AbcSimplexDual::noFake) {
	  nErrors++;
#ifdef CLP_INVESTIGATE
	  printf("** bad fake status %c%d %d\n",
		 RC, jSequence, fakeStatus);
#endif
	}
      }
    }
    if (nFake != numberFake_) {
#ifdef CLP_INVESTIGATE
      printf("nfake %d numberFake %d\n", nFake, numberFake_);
#endif
      nErrors++;
    }
    if (nErrors || type <= -1000) {
#ifdef CLP_INVESTIGATE
      printf("%d errors, %d warnings, %d free/superbasic, %d fake\n",
	     nErrors, nWarnings, nSuperBasic, numberFake_);
      printf("currentDualBound %g\n",
	     currentDualBound_);
#endif
      if (type <= -1000) {
	iSequence = -type;
	iSequence -= 1000;
#ifdef CLP_INVESTIGATE
	char RC = 'C';
	int jSequence = iSequence;
	if (jSequence >= numberColumns_) {
	  RC = 'R';
	  jSequence -= numberColumns_;
	}
	double lowerValue = lowerSaved_[iSequence];
	double upperValue = upperSaved_[iSequence];
	printf("*** movement>1.0e30 for  %c%d %g <= %g <= %g true %g, %g - status %d\n",
	       RC, jSequence, abcLower_[iSequence], abcSolution_[iSequence],
	       abcUpper_[iSequence], lowerValue, upperValue, internalStatus_[iSequence]);
#endif
	assert (nErrors); // should have been picked up
      }
      assert (!nErrors);
    }
#endif
  } else {
    CoinAbcMemcpy(abcLower_,lowerSaved_,numberTotal_);
    CoinAbcMemcpy(abcUpper_,upperSaved_,numberTotal_);
    // reset using status
    numberFake_ = 0;
    for (int iSequence = 0; iSequence < numberTotal_; iSequence++) {
      FakeBound fakeStatus = getFakeBound(iSequence);
      if (fakeStatus != AbcSimplexDual::noFake) {
	Status status = getInternalStatus(iSequence);
	if (status == basic) {
	  setFakeBound(iSequence, AbcSimplexDual::noFake);
	  continue;
	}
	double lowerValue = abcLower_[iSequence];
	double upperValue = abcUpper_[iSequence];
	double value = abcSolution_[iSequence];
	numberFake_++;
	if (fakeStatus == AbcSimplexDual::upperFake) {
	  abcUpper_[iSequence] = lowerValue + currentDualBound_;
	  if (status == AbcSimplex::atLowerBound) {
	    abcSolution_[iSequence] = lowerValue;
	  } else if (status == AbcSimplex::atUpperBound) {
	    abcSolution_[iSequence] = abcUpper_[iSequence];
	  } else {
	    abort();
	  }
	} else if (fakeStatus == AbcSimplexDual::lowerFake) {
	  abcLower_[iSequence] = upperValue - currentDualBound_;
	  if (status == AbcSimplex::atLowerBound) {
	    abcSolution_[iSequence] = abcLower_[iSequence];
	  } else if (status == AbcSimplex::atUpperBound) {
	    abcSolution_[iSequence] = upperValue;
	  } else {
	    abort();
	  }
	} else {
	  assert (fakeStatus == AbcSimplexDual::bothFake);
	  if (status == AbcSimplex::atLowerBound) {
	    abcLower_[iSequence] = value;
	    abcUpper_[iSequence] = value + currentDualBound_;
	  } else if (status == AbcSimplex::atUpperBound) {
	    abcUpper_[iSequence] = value;
	    abcLower_[iSequence] = value - currentDualBound_;
	  } else if (status == AbcSimplex::isFree ||
		     status == AbcSimplex::superBasic) {
	    abcLower_[iSequence] = value - 0.5 * currentDualBound_;
	    abcUpper_[iSequence] = value + 0.5 * currentDualBound_;
	  } else {
	    abort();
	  }
	}
      }
    }
  }
  return -1;
}
// maybe could JUST check against perturbationArray
void
AbcSimplex::checkDualSolutionPlusFake()
{
  
  sumDualInfeasibilities_ = 0.0;
  numberDualInfeasibilities_ = 0;
  sumFakeInfeasibilities_=0.0;
  int firstFreePrimal = -1;
  int firstFreeDual = -1;
  int numberSuperBasicWithDj = 0;
  bestPossibleImprovement_ = 0.0;
  // we can't really trust infeasibilities if there is dual error
  double error = CoinMin(1.0e-2, largestDualError_);
  // allow tolerance at least slightly bigger than standard
  double relaxedTolerance = currentDualTolerance_ +  error;
  // allow bigger tolerance for possible improvement
  double possTolerance = 5.0 * relaxedTolerance;
  sumOfRelaxedDualInfeasibilities_ = 0.0;
  //rawObjectiveValue_ -=sumNonBasicCosts_;
  sumNonBasicCosts_ = 0.0;
  const double *  COIN_RESTRICT abcLower = abcLower_;
  const double *  COIN_RESTRICT abcUpper = abcUpper_;
  const double *  COIN_RESTRICT abcSolution = abcSolution_;
#ifdef CLEANUP_DJS
  double *  COIN_RESTRICT abcDj = abcDj_;
  double *  COIN_RESTRICT abcCost = abcCost_;
  // see if we can clean up djs
  // may have perturbation
  const double * COIN_RESTRICT originalCost = abcPerturbation_;
#else
  const double *  COIN_RESTRICT abcDj = abcDj_;
  const double *  COIN_RESTRICT abcCost = abcCost_;
#endif
  //const double *  COIN_RESTRICT abcPerturbation = abcPerturbation_;
  int badDjSequence=-1;
  for (int iSequence = 0; iSequence < numberTotal_; iSequence++) {
    if (getInternalStatus(iSequence) != basic) {
      sumNonBasicCosts_ += abcSolution[iSequence]*abcCost[iSequence];
      // not basic
      double distanceUp = abcUpper[iSequence] - abcSolution[iSequence];
      double distanceDown = abcSolution[iSequence] - abcLower[iSequence];
      double value = abcDj[iSequence];
      if (distanceUp > primalTolerance_) {
	// Check if "free"
	if (distanceDown <= primalTolerance_) {
	  // should not be negative
	  if (value < 0.0) {
	    value = - value;
	    if (value > currentDualTolerance_) {
	      bool treatAsSuperBasic=false;
	      if (getInternalStatus(iSequence)==superBasic) {
#ifdef PAN
		if (fakeSuperBasic(iSequence)>=0) {
#endif
		  treatAsSuperBasic=true;
		  numberSuperBasicWithDj++;
		  if (firstFreeDual < 0)
		    firstFreeDual = iSequence;
#ifdef PAN
		}
#endif
	      }
	      if (!treatAsSuperBasic) {
		sumDualInfeasibilities_ += value - currentDualTolerance_;
		badDjSequence=iSequence;
		if (value > possTolerance)
		  bestPossibleImprovement_ += CoinMin(distanceUp, 1.0e10) * value;
		if (value > relaxedTolerance)
		  sumOfRelaxedDualInfeasibilities_ += value - relaxedTolerance;
		numberDualInfeasibilities_ ++;
	      }
	    }
#ifdef CLEANUP_DJS
	  } else {
	    // adjust cost etc
	    if (abcCost[iSequence]>originalCost[iSequence]) {
	      double difference = CoinMin(abcCost[iSequence]-originalCost[iSequence],value);
	      //printf("Lb %d changing cost from %g to %g, dj from %g to %g\n",
	      //     iSequence,abcCost[iSequence],abcCost[iSequence]-difference,
	      //     abcDj[iSequence],abcDj[iSequence]-difference);
	      abcDj[iSequence]=value-difference;
	      abcCost[iSequence]-=difference;
	    }
#endif
	  }
	} else {
	  // free
	  value=fabs(value);
	  if (value > 1.0 * relaxedTolerance) {
	    numberSuperBasicWithDj++;
	    if (firstFreeDual < 0)
	      firstFreeDual = iSequence;
	  }
	  if (value > currentDualTolerance_) {
	    sumDualInfeasibilities_ += value - currentDualTolerance_;
	    if (value > possTolerance)
	      bestPossibleImprovement_ += CoinMin(distanceUp, 1.0e10) * value;
	    if (value > relaxedTolerance)
	      sumOfRelaxedDualInfeasibilities_ += value - relaxedTolerance;
	    numberDualInfeasibilities_ ++;
	  }
	  if (firstFreePrimal < 0)
	    firstFreePrimal = iSequence;
	}
      } else if (distanceDown > primalTolerance_) {
	// should not be positive
	if (value > 0.0) {
	  if (value > currentDualTolerance_) {
	    bool treatAsSuperBasic=false;
	    if (getInternalStatus(iSequence)==superBasic) {
#ifdef PAN
	      if (fakeSuperBasic(iSequence)>=0) {
#endif
		treatAsSuperBasic=true;
		numberSuperBasicWithDj++;
		if (firstFreeDual < 0)
		  firstFreeDual = iSequence;
#ifdef PAN
	      }
#endif
	    }
	    if (!treatAsSuperBasic) {
	      sumDualInfeasibilities_ += value - currentDualTolerance_;
	      badDjSequence=iSequence;
	      if (value > possTolerance)
		bestPossibleImprovement_ += value * CoinMin(distanceDown, 1.0e10);
	      if (value > relaxedTolerance)
		sumOfRelaxedDualInfeasibilities_ += value - relaxedTolerance;
	      numberDualInfeasibilities_ ++;
	    }
	  }
#ifdef CLEANUP_DJS
	} else {
	  // adjust cost etc
	  if (abcCost[iSequence]<originalCost[iSequence]) {
	    double difference = CoinMax(abcCost[iSequence]-originalCost[iSequence],value);
	    //printf("Ub %d changing cost from %g to %g, dj from %g to %g\n",
	    //	     iSequence,abcCost[iSequence],abcCost[iSequence]-difference,
	    //	     abcDj[iSequence],abcDj[iSequence]-difference);
	    abcDj[iSequence]=value-difference;
	    abcCost[iSequence]-=difference;
	  }
#endif
	}
      }
    }
  }
#ifdef CLEANUP_DJS
  if (algorithm_<0&&numberDualInfeasibilities_==1&&firstFreeDual<0&&sumDualInfeasibilities_<1.0e-1) {
    // clean bad one
    assert (badDjSequence>=0);
    abcCost[badDjSequence]-=abcDj_[badDjSequence];
    abcDj_[badDjSequence]=0.0;
  }
#endif
  numberDualInfeasibilitiesWithoutFree_ = numberDualInfeasibilities_-numberSuperBasicWithDj;
  numberFreeNonBasic_=numberSuperBasicWithDj;
  firstFree_=-1;
  if (algorithm_ < 0 && firstFreeDual >= 0) {
    // dual
    firstFree_ = firstFreeDual;
  } else if ((numberSuperBasicWithDj ||
	      (abcProgress_.lastIterationNumber(0) <= 0))&&algorithm_>0) {
    firstFree_ = firstFreePrimal;
  }
}
// Perturbs problem
void 
AbcSimplexDual::perturb(double factor)
{
  const double * COIN_RESTRICT lower = lowerSaved_;
  const double * COIN_RESTRICT upper = upperSaved_;
  const double * COIN_RESTRICT perturbation = abcPerturbation_;
  double * COIN_RESTRICT cost = abcCost_;
  for (int i=0;i<numberTotal_;i++) {
    if (getInternalStatus(i)!=basic) {
      if (fabs(lower[i])<fabs(upper[i])) {
	cost[i]+=factor*perturbation[i];
      } else if (upper[i]!=COIN_DBL_MAX&&upper[i]!=lower[i]) {
	cost[i]-=factor*perturbation[i];
      } else {
	// free
	//cost[i]=costSaved[i];
      }
    }
  }
#ifdef CLEANUP_DJS
  // copy cost to perturbation
  CoinAbcMemcpy(abcPerturbation_,abcCost_,numberTotal_);
#endif
}
#if ABC_NORMAL_DEBUG>0
#define PERT_STATISTICS
#endif
#ifdef PERT_STATISTICS
static void breakdown(const char * name, int numberLook, const double * region)
{
     double range[] = {
          -COIN_DBL_MAX,
          -1.0e15, -1.0e11, -1.0e8, -1.0e5, -3.0e4, -1.0e4, -3.0e3, -1.0e3, -3.0e2, -1.0e2, -3.0e1, -1.0e1, -3.0,
          -1.0, -3.0e-1,
          -1.0e-1, -3.0e-1, -1.0e-2, -3.0e-2, -1.0e-3, -3.0e-3, -1.0e-4, -3.0e-4, -1.0e-5, -1.0e-8, -1.0e-11, -1.0e-15,
          0.0,
          1.0e-15, 1.0e-11, 1.0e-8, 1.0e-5, 3.0e-5, 1.0e-4, 3.0e-4, 1.0e-3, 3.0e-3, 1.0e-2, 3.0e-2, 1.0e-1, 3.0e-1,
          1.0, 3.0,
          1.0e1, 3.0e1, 1.0e2, 3.0e2, 1.0e3, 3.0e3, 1.0e4, 3.0e4, 1.0e5, 1.0e8, 1.0e11, 1.0e15,
          COIN_DBL_MAX
     };
     int nRanges = static_cast<int> (sizeof(range) / sizeof(double));
     int * number = new int[nRanges];
     memset(number, 0, nRanges * sizeof(int));
     int * numberExact = new int[nRanges];
     memset(numberExact, 0, nRanges * sizeof(int));
     int i;
     for ( i = 0; i < numberLook; i++) {
          double value = region[i];
          for (int j = 0; j < nRanges; j++) {
               if (value == range[j]) {
                    numberExact[j]++;
                    break;
               } else if (value < range[j]) {
                    number[j]++;
                    break;
               }
          }
     }
     printf("\n%s has %d entries\n", name, numberLook);
     for (i = 0; i < nRanges; i++) {
          if (number[i])
               printf("%d between %g and %g", number[i], range[i-1], range[i]);
          if (numberExact[i]) {
               if (number[i])
                    printf(", ");
               printf("%d exactly at %g", numberExact[i], range[i]);
          }
          if (number[i] + numberExact[i])
               printf("\n");
     }
     delete [] number;
     delete [] numberExact;
}
#endif
// Perturbs problem
void 
AbcSimplexDual::perturbB(double /*factorIn*/,int /*type*/)
{
  double overallMultiplier= (perturbation_==50||perturbation_>54) ? 1.0 : 0.1;
  // dual perturbation
  double perturbation = 1.0e-20;
  // maximum fraction of cost to perturb
  double maximumFraction = 1.0e-5;
  int maxLength = 0;
  int minLength = numberRows_;
  double averageCost = 0.0;
  int numberNonZero = 0;
  // See if we need to perturb
  double * COIN_RESTRICT sort = new double[numberColumns_];
  // Use objective BEFORE scaling ??
  const double * COIN_RESTRICT obj = objective();
  for (int i = 0; i < numberColumns_; i++) {
    double value = fabs(obj[i]);
    sort[i] = value;
    averageCost += fabs(abcCost_[i+maximumAbcNumberRows_]);
    if (value)
      numberNonZero++;
  }
  if (numberNonZero)
    averageCost /= static_cast<double> (numberNonZero);
  else
    averageCost = 1.0;
  // allow for cost scaling
  averageCost *= objectiveScale_;
  std::sort(sort, sort + numberColumns_);
  int number = 1;
  double last = sort[0];
  for (int i = 1; i < numberColumns_; i++) {
    if (last != sort[i])
      number++;
    last = sort[i];
  }
  delete [] sort;
#ifdef PERT_STATISTICS
  printf("%d different values\n",number);
#endif
#if 0
  printf("nnz %d percent %d", number, (number * 100) / numberColumns_);
  if (number * 4 > numberColumns_)
    printf(" - Would not perturb\n");
  else
    printf(" - Would perturb\n");
#endif
  // If small costs then more dangerous (better to scale)
  double numberMultiplier=1.25;
  if (averageCost<1.0e-3)
    numberMultiplier=20.0;
  else if (averageCost<1.0e-2)
    numberMultiplier=10.0;
  else if (averageCost<1.0e-1)
    numberMultiplier=3.0;
  else if (averageCost<1.0)
    numberMultiplier=2.0;
  numberMultiplier *= 2.0; // try
  if (number * numberMultiplier > numberColumns_||perturbation_>=100) {
    perturbation_=101;
#if ABC_NORMAL_DEBUG>0
    printf("Not perturbing - %d different costs, average %g\n",
	   number,averageCost);
#endif
#ifdef CLEANUP_DJS
    // copy cost to perturbation
    CoinAbcMemcpy(abcPerturbation_,abcCost_,numberTotal_);
#endif
    return ; // good enough
  }
  const int * COIN_RESTRICT columnLength = matrix_->getVectorLengths()-maximumAbcNumberRows_;
  const double * COIN_RESTRICT lower = lowerSaved_;
  const double * COIN_RESTRICT upper = upperSaved_;
  for (int iSequence = maximumAbcNumberRows_; iSequence < numberTotal_; iSequence++) {
    if (lower[iSequence] < upper[iSequence]) {
      int length = columnLength[iSequence];
      if (length > 2) {
	maxLength = CoinMax(maxLength, length);
	minLength = CoinMin(minLength, length);
      }
    }
  }
  bool uniformChange = false;
  bool inCbcOrOther = (specialOptions_ & 0x03000000) != 0;
  double constantPerturbation = 10.0 * dualTolerance_;
#ifdef PERT_STATISTICS
  breakdown("Objective before perturbation", numberColumns_, abcCost_+numberRows_);
#endif
  //#define PERTURB_OLD_WAY
#ifndef PERTURB_OLD_WAY
#if 1
#ifdef HEAVY_PERTURBATION
    if (perturbation_==50)
      perturbation_=HEAVY_PERTURBATION;
#endif
  if (perturbation_ >= 50) {
    // Experiment
    // maximumFraction could be 1.0e-10 to 1.0
    double m[] = {1.0e-10, 1.0e-9, 1.0e-8, 1.0e-7, 1.0e-6, 1.0e-5, 1.0e-4, 1.0e-3, 1.0e-2, 1.0e-1, 1.0};
    int whichOne = CoinMin(perturbation_ - 51,10);
    if (whichOne<0) {
      if (numberRows_<5000)
	whichOne=2; // treat 50 as if 53
      else
	whichOne=2; // treat 50 as if 52
    }
    if (inCbcOrOther&&whichOne>0)
      whichOne--;
    maximumFraction = m[whichOne];
    if (whichOne>7)
      constantPerturbation *= 10.0; 
    //if (whichOne<2)
    //constantPerturbation = maximumFraction*1.0e-10 * dualTolerance_;
  } else if (inCbcOrOther) {
    maximumFraction = 1.0e-6;
  }
#endif
  double smallestNonZero = 1.0e100;
  bool modifyRowCosts=false;
  numberNonZero = 0;
  //perturbation = 1.0e-10;
  perturbation = CoinMax(1.0e-10,maximumFraction);
  double * COIN_RESTRICT cost = abcCost_;
  bool allSame = true;
  double lastValue = 0.0;
  
  for (int iRow = 0; iRow < numberRows_; iRow++) {
    double lo = lower[iRow];
    double up = upper[iRow];
    if (lo < up) {
      double value = fabs(cost[iRow]);
      perturbation = CoinMax(perturbation, value);
      if (value) {
	modifyRowCosts = true;
	smallestNonZero = CoinMin(smallestNonZero, value);
      }
    }
    if (lo && lo > -1.0e10) {
      numberNonZero++;
      lo = fabs(lo);
      if (!lastValue)
	lastValue = lo;
      else if (fabs(lo - lastValue) > 1.0e-7)
	allSame = false;
    }
    if (up && up < 1.0e10) {
      numberNonZero++;
      up = fabs(up);
      if (!lastValue)
	lastValue = up;
      else if (fabs(up - lastValue) > 1.0e-7)
	allSame = false;
    }
  }
  double lastValue2 = 0.0;
  for (int iSequence = maximumAbcNumberRows_; iSequence < numberTotal_; iSequence++) {
    double lo = lower[iSequence];
    double up = upper[iSequence];
    if (lo < up) {
      double value =
	fabs(cost[iSequence]);
      perturbation = CoinMax(perturbation, value);
      if (value) {
	smallestNonZero = CoinMin(smallestNonZero, value);
      }
    }
    if (lo && lo > -1.0e10) {
      //numberNonZero++;
      lo = fabs(lo);
      if (!lastValue2)
	lastValue2 = lo;
      else if (fabs(lo - lastValue2) > 1.0e-7)
	allSame = false;
    }
    if (up && up < 1.0e10) {
      //numberNonZero++;
      up = fabs(up);
      if (!lastValue2)
	lastValue2 = up;
      else if (fabs(up - lastValue2) > 1.0e-7)
	allSame = false;
    }
  }
  if (allSame) {
    // Check elements
    double smallestNegative;
    double largestNegative;
    double smallestPositive;
    double largestPositive;
    matrix_->rangeOfElements(smallestNegative, largestNegative,
			     smallestPositive, largestPositive);
    if (smallestNegative == largestNegative &&
	smallestPositive == largestPositive) {
      // Really hit perturbation
      double adjust = CoinMin(100.0 * maximumFraction, 1.0e-3 * CoinMax(lastValue, lastValue2));
      maximumFraction = CoinMax(adjust, maximumFraction);
    }
  }
  perturbation = CoinMin(perturbation, smallestNonZero / maximumFraction);
  double largestZero = 0.0;
  double largest = 0.0;
  double largestPerCent = 0.0;
  // modify costs
  bool printOut = (handler_->logLevel() == 63);
  printOut = false;
  //assert (!modifyRowCosts);
  modifyRowCosts = false;
  const double * COIN_RESTRICT perturbationArray = perturbationSaved_;
  if (modifyRowCosts) {
    for (int iRow = 0; iRow < numberRows_; iRow++) {
      if (lower[iRow] < upper[iRow]) {
	double value = perturbation;
	double currentValue = cost[iRow];
	value = CoinMin(value, maximumFraction * (fabs(currentValue) + 1.0e-1 * perturbation + 1.0e-3));
	double perturbationValue=2.0*(perturbationArray[iRow]-0.5); // for now back to normal random
	if (lower[iRow] > -largeValue_) {
	  if (fabs(lower[iRow]) < fabs(upper[iRow]))
	    value *= perturbationValue;
	  else
	    value *= -perturbationValue;
	} else if (upper[iRow] < largeValue_) {
	  value *= -perturbationValue;
	} else {
	  value = 0.0;
	}
	if (currentValue) {
	  largest = CoinMax(largest, fabs(value));
	  if (fabs(value) > fabs(currentValue)*largestPerCent)
	    largestPerCent = fabs(value / currentValue);
	} else {
	  largestZero = CoinMax(largestZero, fabs(value));
	}
	if (printOut)
	  printf("row %d cost %g change %g\n", iRow, cost[iRow], value);
	cost[iRow] += value;
      }
    }
  }

  //double extraWeight = 10.0;
  // more its but faster double weight[]={1.0e-4,1.0e-2,1.0e-1,1.0,2.0,10.0,100.0,200.0,400.0,600.0,1000.0};
  // good its double weight[]={1.0e-4,1.0e-2,5.0e-1,1.0,2.0,5.0,10.0,20.0,30.0,40.0,100.0};
  double weight[] = {1.0e-4, 1.0e-2, 5.0e-1, 1.0, 2.0, 5.0, 10.0, 20.0, 30.0, 40.0, 100.0};
  //double weight[]={1.0e-4,1.0e-2,5.0e-1,1.0,20.0,50.0,100.0,120.0,130.0,140.0,200.0};
  // Scale back if wanted
  double weight2[] = {1.0e-4, 1.0e-2, 5.0e-1, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0};
  if (constantPerturbation < 99.0 * dualTolerance_&&false) {
    perturbation *= 0.1;
    //extraWeight = 0.5;
    memcpy(weight, weight2, sizeof(weight2));
  }
  // adjust weights if all columns long
  double factor = 1.0;
  if (maxLength) {
    factor = 3.0 / static_cast<double> (minLength);
  }
  // Make variables with more elements more expensive
  const double m1 = 0.5;
  double smallestAllowed = overallMultiplier*CoinMin(1.0e-2 * dualTolerance_, maximumFraction);
  double largestAllowed = overallMultiplier*CoinMax(1.0e3 * dualTolerance_, maximumFraction * averageCost);
  // smaller if in BAB
  //if (inCbcOrOther)
  //largestAllowed=CoinMin(largestAllowed,1.0e-5);
  //smallestAllowed = CoinMin(smallestAllowed,0.1*largestAllowed);
  randomNumberGenerator_.setSeed(1000000000);
#if ABC_NORMAL_DEBUG>0
  printf("perturbation %g constantPerturbation %g smallestNonZero %g maximumFraction %g smallestAllowed %g\n",
	 perturbation,constantPerturbation,smallestNonZero,maximumFraction,
	 smallestAllowed);
#endif
  for (int iSequence = maximumAbcNumberRows_; iSequence < numberTotal_; iSequence++) {
    if (lower[iSequence] < upper[iSequence] && getInternalStatus(iSequence) != basic) {
      double value = perturbation;
      double currentValue = cost[iSequence];
      double currentLargestAllowed=fabs(currentValue)*1.0e-3;
      if (!currentValue)
	currentLargestAllowed=1.0e-3;
      if (currentLargestAllowed<=10.0*smallestAllowed)
	continue; // don't perturb tiny value
      value = CoinMin(value, constantPerturbation + maximumFraction * (fabs(currentValue) + 1.0e-1 * perturbation + 1.0e-8));
      //value = CoinMin(value,constantPerturbation;+maximumFraction*fabs(currentValue));
      double value2 = constantPerturbation + 1.0e-1 * smallestNonZero;
      if (uniformChange) {
	value = maximumFraction;
	value2 = maximumFraction;
      }
      //double perturbationValue=2.0*(perturbationArray[iSequence]-0.5); // for now back to normal random
      double perturbationValue=randomNumberGenerator_.randomDouble();
      perturbationValue = 1.0-m1+m1*perturbationValue; // clean up
      if (lower[iSequence] > -largeValue_) {
	if (fabs(lower[iSequence]) <
	    fabs(upper[iSequence])) {
	  value *= perturbationValue;
	  value2 *= perturbationValue;
	} else {
	  //value *= -(1.0-m1+m1*randomNumberGenerator_.randomDouble());
	  //value2 *= -(1.0-m1+m1*randomNumberGenerator_.randomDouble());
	  value = 0.0;
	}
      } else if (upper[iSequence] < largeValue_) {
	value *= -perturbationValue;
	value2 *= -perturbationValue;
      } else {
	value = 0.0;
      }
      if (value) {
	int length = columnLength[iSequence];
	if (length > 3) {
	  length = static_cast<int> (static_cast<double> (length) * factor);
	  length = CoinMax(3, length);
	}
	double multiplier;
	if (length < 10)
	  multiplier = weight[length];
	else
	  multiplier = weight[10];
	value *= multiplier;
	value = CoinMin(value, value2);
	if (value) {
	  // get in range
	  if (fabs(value) <= smallestAllowed) {
	    value *= 10.0;
	    while (fabs(value) <= smallestAllowed)
	      value *= 10.0;
	  } else if (fabs(value) > currentLargestAllowed) {
	    value *= 0.1;
	    while (fabs(value) > currentLargestAllowed)
	      value *= 0.1;
	  }
	}
	if (currentValue) {
	  largest = CoinMax(largest, fabs(value));
	  if (fabs(value) > fabs(currentValue)*largestPerCent)
	    largestPerCent = fabs(value / currentValue);
	} else {
	  largestZero = CoinMax(largestZero, fabs(value));
	}
	// but negative if at ub
	if (getInternalStatus(iSequence) == atUpperBound)
	  value = -value;
	if (printOut)
	  printf("col %d cost %g change %g\n", iSequence, cost[iSequence], value);
	cost[iSequence] += value;
      }
    }
  }
#else
  // old way
     if (perturbation_ > 50) {
          // Experiment
          // maximumFraction could be 1.0e-10 to 1.0
          double m[] = {1.0e-10, 1.0e-9, 1.0e-8, 1.0e-7, 1.0e-6, 1.0e-5, 1.0e-4, 1.0e-3, 1.0e-2, 1.0e-1, 1.0};
          int whichOne = perturbation_ - 51;
          //if (inCbcOrOther&&whichOne>0)
          //whichOne--;
          maximumFraction = m[CoinMin(whichOne, 10)];
     } else if (inCbcOrOther) {
          //maximumFraction = 1.0e-6;
     }
     int iRow;
     double smallestNonZero = 1.0e100;
     numberNonZero = 0;
     if (perturbation_ >= 50) {
          perturbation = 1.0e-8;
	  if (perturbation_ > 50 && perturbation_ < 60) 
	    perturbation = CoinMax(1.0e-8,maximumFraction);
          bool allSame = true;
          double lastValue = 0.0;
          for (iRow = 0; iRow < numberRows_; iRow++) {
               double lo = abcLower_[iRow];
               double up = abcUpper_[iRow];
               if (lo && lo > -1.0e10) {
                    numberNonZero++;
                    lo = fabs(lo);
                    if (!lastValue)
                         lastValue = lo;
                    else if (fabs(lo - lastValue) > 1.0e-7)
                         allSame = false;
               }
               if (up && up < 1.0e10) {
                    numberNonZero++;
                    up = fabs(up);
                    if (!lastValue)
                         lastValue = up;
                    else if (fabs(up - lastValue) > 1.0e-7)
                         allSame = false;
               }
          }
          double lastValue2 = 0.0;
          for (int iColumn = maximumAbcNumberRows_; iColumn < numberTotal_; iColumn++) {
               double lo = abcLower_[iColumn];
               double up = abcUpper_[iColumn];
               if (lo < up) {
                    double value =
                         fabs(abcCost_[iColumn]);
                    perturbation = CoinMax(perturbation, value);
                    if (value) {
                         smallestNonZero = CoinMin(smallestNonZero, value);
                    }
               }
               if (lo && lo > -1.0e10) {
                    //numberNonZero++;
                    lo = fabs(lo);
                    if (!lastValue2)
                         lastValue2 = lo;
                    else if (fabs(lo - lastValue2) > 1.0e-7)
                         allSame = false;
               }
               if (up && up < 1.0e10) {
                    //numberNonZero++;
                    up = fabs(up);
                    if (!lastValue2)
                         lastValue2 = up;
                    else if (fabs(up - lastValue2) > 1.0e-7)
                         allSame = false;
               }
          }
          if (allSame) {
               // Check elements
               double smallestNegative;
               double largestNegative;
               double smallestPositive;
               double largestPositive;
               matrix_->rangeOfElements(smallestNegative, largestNegative,
                                        smallestPositive, largestPositive);
               if (smallestNegative == largestNegative &&
                         smallestPositive == largestPositive) {
                    // Really hit perturbation
                    double adjust = CoinMin(100.0 * maximumFraction, 1.0e-3 * CoinMax(lastValue, lastValue2));
                    maximumFraction = CoinMax(adjust, maximumFraction);
               }
          }
          perturbation = CoinMin(perturbation, smallestNonZero / maximumFraction);
     }
     double largestZero = 0.0;
     double largest = 0.0;
     double largestPerCent = 0.0;
     // modify costs
     bool printOut = (handler_->logLevel() == 63);
     printOut = false;
     // more its but faster double weight[]={1.0e-4,1.0e-2,1.0e-1,1.0,2.0,10.0,100.0,200.0,400.0,600.0,1000.0};
     // good its double weight[]={1.0e-4,1.0e-2,5.0e-1,1.0,2.0,5.0,10.0,20.0,30.0,40.0,100.0};
     double weight[] = {1.0e-4, 1.0e-2, 5.0e-1, 1.0, 2.0, 5.0, 10.0, 20.0, 30.0, 40.0, 100.0};
     //double weight[]={1.0e-4,1.0e-2,5.0e-1,1.0,20.0,50.0,100.0,120.0,130.0,140.0,200.0};
     //double extraWeight = 10.0;
     // Scale back if wanted
     double weight2[] = {1.0e-4, 1.0e-2, 5.0e-1, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0};
     if (constantPerturbation < 99.0 * dualTolerance_) {
          perturbation *= 0.1;
          //extraWeight = 0.5;
          memcpy(weight, weight2, sizeof(weight2));
     }
     // adjust weights if all columns long
     double factor = 1.0;
     if (maxLength) {
          factor = 3.0 / static_cast<double> (minLength);
     }
     // Make variables with more elements more expensive
     const double m1 = 0.5;
     double smallestAllowed = CoinMin(1.0e-2 * dualTolerance_, maximumFraction);
     double largestAllowed = CoinMax(1.0e3 * dualTolerance_, maximumFraction * averageCost);
     // smaller if in BAB
     //if (inCbcOrOther)
     //largestAllowed=CoinMin(largestAllowed,1.0e-5);
     //smallestAllowed = CoinMin(smallestAllowed,0.1*largestAllowed);
     for (int iColumn = maximumAbcNumberRows_; iColumn < numberTotal_; iColumn++) {
          if (abcLower_[iColumn] < abcUpper_[iColumn] 
	      && getInternalStatus(iColumn) != basic) {
               double value = perturbation;
               double currentValue = abcCost_[iColumn];
               value = CoinMin(value, constantPerturbation + maximumFraction * (fabs(currentValue) + 1.0e-1 * perturbation + 1.0e-8));
               //value = CoinMin(value,constantPerturbation;+maximumFraction*fabs(currentValue));
               double value2 = constantPerturbation + 1.0e-1 * smallestNonZero;
               if (uniformChange) {
                    value = maximumFraction;
                    value2 = maximumFraction;
               }
               if (abcLower_[iColumn] > -largeValue_) {
                    if (fabs(abcLower_[iColumn]) <
                              fabs(abcUpper_[iColumn])) {
                         value *= (1.0 - m1 + m1 * randomNumberGenerator_.randomDouble());
                         value2 *= (1.0 - m1 + m1 * randomNumberGenerator_.randomDouble());
                    } else {
                         //value *= -(1.0-m1+m1*randomNumberGenerator_.randomDouble());
                         //value2 *= -(1.0-m1+m1*randomNumberGenerator_.randomDouble());
                         value = 0.0;
                    }
               } else if (abcUpper_[iColumn] < largeValue_) {
                    value *= -(1.0 - m1 + m1 * randomNumberGenerator_.randomDouble());
                    value2 *= -(1.0 - m1 + m1 * randomNumberGenerator_.randomDouble());
               } else {
                    value = 0.0;
               }
               if (value) {
                    int length = columnLength[iColumn];
                    if (length > 3) {
                         length = static_cast<int> (static_cast<double> (length) * factor);
                         length = CoinMax(3, length);
                    }
                    double multiplier;
#if 1
                    if (length < 10)
                         multiplier = weight[length];
                    else
                         multiplier = weight[10];
#else
                    if (length < 10)
                         multiplier = weight[length];
                    else
                         multiplier = weight[10] + extraWeight * (length - 10);
                    multiplier *= 0.5;
#endif
                    value *= multiplier;
                    value = CoinMin(value, value2);
                    if (value) {
                         // get in range
                         if (fabs(value) <= smallestAllowed) {
                              value *= 10.0;
                              while (fabs(value) <= smallestAllowed)
                                   value *= 10.0;
                         } else if (fabs(value) > largestAllowed) {
                              value *= 0.1;
                              while (fabs(value) > largestAllowed)
                                   value *= 0.1;
                         }
                    }
                    if (currentValue) {
                         largest = CoinMax(largest, fabs(value));
                         if (fabs(value) > fabs(currentValue)*largestPerCent)
                              largestPerCent = fabs(value / currentValue);
                    } else {
                         largestZero = CoinMax(largestZero, fabs(value));
                    }
                    // but negative if at ub
                    if (getInternalStatus(iColumn) == atUpperBound)
                         value = -value;
                    if (printOut)
                         printf("col %d cost %g change %g\n", iColumn, objectiveWork_[iColumn], value);
                    abcCost_[iColumn] += value;
               }
          }
     }
#endif
#ifdef PERT_STATISTICS
  {
    double averageCost = 0.0;
    int numberNonZero = 0;
    double * COIN_RESTRICT sort = new double[numberColumns_];
    for (int i = 0; i < numberColumns_; i++) {
      double value = fabs(abcCost_[i+maximumAbcNumberRows_]);
      sort[i] = value;
      averageCost += value;
      if (value)
	numberNonZero++;
    }
    if (numberNonZero)
      averageCost /= static_cast<double> (numberNonZero);
    else
      averageCost = 1.0;
    std::sort(sort, sort + numberColumns_);
    int number = 1;
    double last = sort[0];
    for (int i = 1; i < numberColumns_; i++) {
      if (last != sort[i])
	number++;
    last = sort[i];
    }
    delete [] sort;
#if ABC_NORMAL_DEBUG>0
    printf("nnz %d percent %d", number, (number * 100) / numberColumns_);
    breakdown("Objective after perturbation", numberColumns_, abcCost_+numberRows_);
#endif
  }
#endif
  perturbation_=100;
  // copy cost to  perturbation
#ifdef CLEANUP_DJS
  CoinAbcMemcpy(abcPerturbation_,abcCost_,numberTotal_);
#endif
  handler_->message(CLP_SIMPLEX_PERTURB, messages_)
    << 100.0 * maximumFraction << perturbation << largest << 100.0 * largestPerCent << largestZero
    << CoinMessageEol;
}
/* Does something about fake tolerances
   -1 initializes
   1 might be optimal (back to original costs)
   2 after change currentDualBound
   3 might be optimal BUT change currentDualBound
*/
int 
AbcSimplexDual::bounceTolerances(int type)
{
  // for now turn off
  if (type==-1) {
    if (!perturbationFactor_)
      perturbationFactor_=0.001;
    CoinAbcMemcpy(abcCost_,costSaved_,numberTotal_);
    if (!perturbationFactor_) {
      //currentDualBound_=CoinMin(dualBound_,1.0e11);
      //CoinAbcMultiplyAdd(perturbationSaved_,numberTotal_,currentDualTolerance_,
      //		 abcPerturbation_,0.0);
    } else {
      //currentDualBound_=CoinMin(dualBound_,1.0e11);
      double factor=currentDualTolerance_*perturbationFactor_;
      perturbB(factor,0);
    }
#if ABC_NORMAL_DEBUG>0
    //printf("new dual bound %g (bounceTolerances)\n",currentDualBound_);
#endif
  } else {
    if (stateDualColumn_==-2) {
      double newTolerance=CoinMin(1.0e-1,dualTolerance_*100.0);
#if ABC_NORMAL_DEBUG>0
      printf("After %d iterations reducing dual tolerance from %g to %g\n",
	     numberIterations_,currentDualTolerance_,newTolerance);
#endif
      currentDualTolerance_=newTolerance;
      stateDualColumn_=-1;
    } else if (stateDualColumn_==-1) {
#if ABC_NORMAL_DEBUG>0
      printf("changing dual tolerance from %g to %g (vaguely optimal)\n",
	     currentDualTolerance_,dualTolerance_);
#endif
      currentDualTolerance_=dualTolerance_;
      stateDualColumn_=0;
    } else {
      if (stateDualColumn_>1) {
	normalDualColumnIteration_ = numberIterations_+CoinMax(10,numberRows_/4);
#if ABC_NORMAL_DEBUG>0
	printf("no cost modification until iteration %d\n",normalDualColumnIteration_);
#endif
      }
    }
    resetFakeBounds(0);
    CoinAbcMemcpy(abcCost_,abcPerturbation_,numberTotal_);
    numberChanged_ = 0; // Number of variables with changed costs
    moveToBasic();
    if (type!=1)
      return 0;
    // save status and solution
    CoinAbcMemcpy(status_,internalStatus_,numberTotal_);
    CoinAbcMemcpy(solutionSaved_,abcSolution_,numberTotal_);
#if ABC_NORMAL_DEBUG>0
    printf("A sumDual %g sumPrimal %g\n",sumDualInfeasibilities_,sumPrimalInfeasibilities_);
#endif
    gutsOfSolution(3);
#if ABC_NORMAL_DEBUG>0
    printf("B sumDual %g sumPrimal %g\n",sumDualInfeasibilities_,sumPrimalInfeasibilities_);
#endif
    double saveSum1=sumPrimalInfeasibilities_;
    double saveSumD1=sumDualInfeasibilities_;
    bool goToPrimal=false;
    if (!sumOfRelaxedDualInfeasibilities_) {
      if (perturbation_<101) {
	// try going back to original costs
	CoinAbcMemcpy(abcCost_,costSaved_,numberTotal_);
	perturbation_=101;
	numberChanged_ = 0; // Number of variables with changed costs
	moveToBasic();
	gutsOfSolution(3);
#if ABC_NORMAL_DEBUG>0
	printf("B2 sumDual %g sumPrimal %g\n",sumDualInfeasibilities_,sumPrimalInfeasibilities_);
#endif
	saveSumD1=sumDualInfeasibilities_;
      }
      if (sumOfRelaxedDualInfeasibilities_) {
	makeNonFreeVariablesDualFeasible();
	moveToBasic();
	abcProgress_.reset();
	gutsOfSolution(3);
#if ABC_NORMAL_DEBUG>0
	printf("C sumDual %g sumPrimal %g\n",sumDualInfeasibilities_,sumPrimalInfeasibilities_);
#endif
	if (sumPrimalInfeasibilities_>1.0e2*saveSum1+currentDualBound_*0.2
	  /*|| sumOfRelaxedDualInfeasibilities_<1.0e-4*sumPrimalInfeasibilities_*/) {
	  numberDisasters_++;
	  if (numberDisasters_>2)
	    goToPrimal=true;
	}
      } else {
	numberDualInfeasibilities_=0; 
	sumDualInfeasibilities_=0.0; 
      }
    } else {
      // carry on
      makeNonFreeVariablesDualFeasible();
      moveToBasic();
      abcProgress_.reset();
      gutsOfSolution(3);
#if ABC_NORMAL_DEBUG>0
      printf("C2 sumDual %g sumPrimal %g\n",sumDualInfeasibilities_,sumPrimalInfeasibilities_);
#endif
      numberDisasters_++;
      if (sumPrimalInfeasibilities_>1.0e2*saveSum1+currentDualBound_*0.2
	  ||(saveSumD1<1.0e-4*sumPrimalInfeasibilities_&&saveSumD1<1.0)) {
	numberDisasters_++;
	if (numberDisasters_>2||saveSumD1<1.0e-10*sumPrimalInfeasibilities_)
	  goToPrimal=true;
      }
    }
    if (goToPrimal) {
      // go to primal
      CoinAbcMemcpy(internalStatus_,status_,numberTotal_);
      CoinAbcMemcpy(abcSolution_,solutionSaved_,numberTotal_);
      int *  COIN_RESTRICT abcPivotVariable = abcPivotVariable_;
      // redo pivotVariable
      int numberBasic=0;
      for (int i=0;i<numberTotal_;i++) {
	if (getInternalStatus(i)==basic)
	  abcPivotVariable[numberBasic++]=i;
      }
      assert (numberBasic==numberRows_);
      moveToBasic();
      checkPrimalSolution(false);
#if ABC_NORMAL_DEBUG>0
      printf("D sumPrimal %g\n",sumPrimalInfeasibilities_);
#endif
      return 1;
    }
  }

  CoinAbcGatherFrom(abcCost_,costBasic_,abcPivotVariable_,numberRows_);
  return 0;
}
#if ABC_NORMAL_DEBUG>0
extern int cilk_conflict;
#endif
int 
AbcSimplexDual::noPivotRow()
{
#if ABC_NORMAL_DEBUG>3
  if (handler_->logLevel() & 32)
    printf("** no row pivot\n");
#endif
  int numberPivots = abcFactorization_->pivots();
  bool specialCase;
  int useNumberFake;
  int returnCode = 0;
  if (numberPivots <= CoinMax(dontFactorizePivots_, 20) &&
      (specialOptions_ & 2048) != 0 && currentDualBound_ >= 1.0e8) {
    specialCase = true;
    // as dual bound high - should be okay
    useNumberFake = 0;
  } else {
    specialCase = false;
    useNumberFake = numberAtFakeBound();
  }
  if (!numberPivots || specialCase) {
    // may have crept through - so may be optimal
    // check any flagged variables
    if (numberFlagged_ && numberPivots) {
      // try factorization
      returnCode = -2;
    }
    
    if (useNumberFake || numberDualInfeasibilities_) {
      // may be dual infeasible
      if ((specialOptions_ & 1024) == 0)
	problemStatus_ = -5;
      else if (!useNumberFake && numberPrimalInfeasibilities_
	       && !numberPivots)
	problemStatus_ = 1;
    } else {
      if (numberFlagged_) {
#if ABC_NORMAL_DEBUG>3
	std::cout << "Flagged variables at end - infeasible?" << std::endl;
	printf("Probably infeasible - pivot was %g\n", alpha_);
#endif
#if ABC_NORMAL_DEBUG>3
	abort();
#endif
	problemStatus_ = -5;
      } else {
	problemStatus_ = 0;
#ifndef CLP_CHECK_NUMBER_PIVOTS
#define CLP_CHECK_NUMBER_PIVOTS 10
#endif
#if CLP_CHECK_NUMBER_PIVOTS < 20
	if (numberPivots > CLP_CHECK_NUMBER_PIVOTS) {
	  gutsOfSolution(2);
	  rawObjectiveValue_ +=sumNonBasicCosts_;
	  setClpSimplexObjectiveValue();
	  if (numberPrimalInfeasibilities_) {
	    problemStatus_ = -1;
	    returnCode = -2;
	  }
	}
#endif
	if (!problemStatus_) {
	  // make it look OK
	  numberPrimalInfeasibilities_ = 0;
	  sumPrimalInfeasibilities_ = 0.0;
	  numberDualInfeasibilities_ = 0;
	  sumDualInfeasibilities_ = 0.0;
	  if (numberChanged_) {
	    numberChanged_ = 0; // Number of variables with changed costs
	    CoinAbcMemcpy(abcCost_,abcCost_+maximumNumberTotal_,numberTotal_);
	    CoinAbcGatherFrom(abcCost_,costBasic_,abcPivotVariable_,numberRows_);
		  // make sure duals are current
	    gutsOfSolution(1);
	    setClpSimplexObjectiveValue();
	    abcProgress_.modifyObjective(-COIN_DBL_MAX);
	    if (numberDualInfeasibilities_) {
	      problemStatus_ = 10; // was -3;
	      numberTimesOptimal_++;
	    } else {
	      computeObjectiveValue(true);
	    }
	  } else if (numberPivots) {
	    computeObjectiveValue(true);
	  }
	  sumPrimalInfeasibilities_ = 0.0;
	}
	if ((specialOptions_&(1024 + 16384)) != 0 && !problemStatus_&&abcFactorization_->pivots()) {
	  CoinIndexedVector * arrayVector = &usefulArray_[arrayForFtran_];
	  double * rhs = arrayVector->denseVector();
	  arrayVector->clear();
	  CoinAbcScatterTo(solutionBasic_,abcSolution_,abcPivotVariable_,numberRows_);
	  abcMatrix_->timesModifyExcludingSlacks(-1.0, abcSolution_,rhs);
	  //#define CHECK_ACCURACY
#ifdef CHECK_ACCURACY
	  bool bad = false;
#endif
	  bool bad2 = false;
	  int i;
	  for ( i = 0; i < numberRows_; i++) {
	    if (rhs[i] < abcLower_[i] - primalTolerance_ ||
		rhs[i] > abcUpper_[i] + primalTolerance_) {
	      bad2 = true;
#ifdef CHECK_ACCURACY
	      printf("row %d out of bounds %g, %g correct %g bad %g\n", i,
		     abcLower_[i], abcUpper_[i],
		     rhs[i], abcSolution_[i]);
#endif
	    } else if (fabs(rhs[i] - abcSolution_[i]) > 1.0e-3) {
#ifdef CHECK_ACCURACY
	      bad = true;
	      printf("row %d correct %g bad %g\n", i, rhs[i], abcSolution_[i]);
#endif
	    }
	    rhs[i] = 0.0;
	  }
	  for (int i = 0; i < numberTotal_; i++) {
	    if (abcSolution_[i] < abcLower_[i] - primalTolerance_ ||
		abcSolution_[i] > abcUpper_[i] + primalTolerance_) {
	      bad2 = true;
#ifdef CHECK_ACCURACY
	      printf("column %d out of bounds %g, %g value %g\n", i,
		     abcLower_[i], abcUpper_[i],
		     abcSolution_[i]);
#endif
	    }
	  }
	  if (bad2) {
	    problemStatus_ = -3;
	    returnCode = -2;
	    // Force to re-factorize early next time
	    int numberPivots = abcFactorization_->pivots();
	    if (forceFactorization_<0)
	      forceFactorization_=100000;
	    forceFactorization_ = CoinMin(forceFactorization_, (numberPivots + 1) >> 1);
	  }
	}
      }
    }
  } else {
    problemStatus_ = -3;
    returnCode = -2;
    // Force to re-factorize early next time
    int numberPivots = abcFactorization_->pivots();
    if (forceFactorization_<0)
      forceFactorization_=100000;
    forceFactorization_ = CoinMin(forceFactorization_, (numberPivots + 1) >> 1);
  }
  return returnCode;
}
void 
AbcSimplexDual::dualPivotColumn()
{
  double saveAcceptable=acceptablePivot_;
  if (largestPrimalError_>1.0e-5||largestDualError_>1.0e-5) {
    //if ((largestPrimalError_>1.0e-5||largestDualError_>1.0e-5)&&false) {
    if (!abcFactorization_->pivots())
      acceptablePivot_*=1.0e2;
    else if (abcFactorization_->pivots()<5)
      acceptablePivot_*=1.0e1;
  }
  dualColumn2();
  if (sequenceIn_<0&&acceptablePivot_>saveAcceptable) {
    acceptablePivot_=saveAcceptable;
#if ABC_NORMAL_DEBUG>0
    printf("No pivot!!!\n");
#endif
    // try again
    dualColumn1(true);
    dualColumn2();
  } else {
    acceptablePivot_=saveAcceptable;
  }
  if ((stateOfProblem_&VALUES_PASS)!=0) {
    // check no flips
    assert (!usefulArray_[arrayForFlipBounds_].getNumElements());
    // If no pivot - then try other way if plausible
    if (sequenceIn_<0) {
      // could use fake primal basic values
      if ((directionOut_<0&&lowerOut_>-1.0e30)||
	  (directionOut_>0&&upperOut_<1.30)) {
	directionOut_=-directionOut_;
	if (directionOut_<0&&abcDj_[sequenceOut_]<0.0)
	  upperTheta_=-abcDj_[sequenceOut_];
	else if (directionOut_>0&&abcDj_[sequenceOut_]>0.0)
	  upperTheta_=abcDj_[sequenceOut_];
	else
	  upperTheta_=1.0e30;
	CoinPartitionedVector & tableauRow = usefulArray_[arrayForTableauRow_];
	CoinPartitionedVector & candidateList = usefulArray_[arrayForDualColumn_];
	assert (!candidateList.getNumElements());
	tableauRow.compact();
	candidateList.compact();
	// redo candidate list
	int *  COIN_RESTRICT index = tableauRow.getIndices();
	double *  COIN_RESTRICT array = tableauRow.denseVector();
	double *  COIN_RESTRICT arrayCandidate=candidateList.denseVector();
	int *  COIN_RESTRICT indexCandidate = candidateList.getIndices();
	const double *  COIN_RESTRICT abcDj = abcDj_;
	const unsigned char *  COIN_RESTRICT internalStatus = internalStatus_;
	// do first pass to get possibles
	double bestPossible = 0.0;
	// We can also see if infeasible or pivoting on free
	double tentativeTheta = 1.0e25; // try with this much smaller as guess
	double acceptablePivot = currentAcceptablePivot_;
	double dualT=-currentDualTolerance_;
	// fixed will have been taken out by now
	const double multiplier[] = { 1.0, -1.0};
	int freeSequence=-1;
	double freeAlpha=0.0;
	int numberNonZero=tableauRow.getNumElements();
	int numberRemaining=0;
	if (ordinaryVariables()) {
	  for (int i = 0; i < numberNonZero; i++) {
	    int iSequence = index[i];
	    double tableauValue=array[i];
	    unsigned char iStatus=internalStatus[iSequence]&7;
	    double mult = multiplier[iStatus];
	    double alpha = tableauValue * mult;
	    double oldValue = abcDj[iSequence] * mult;
	    double value = oldValue - tentativeTheta * alpha;
	    if (value < dualT) {
	      bestPossible = CoinMax(bestPossible, alpha);
	      value = oldValue - upperTheta_ * alpha;
	      if (value < dualT && alpha >= acceptablePivot) {
		upperTheta_ = (oldValue - dualT) / alpha;
	      }
	      // add to list
	      arrayCandidate[numberRemaining] = alpha;
	      indexCandidate[numberRemaining++] = iSequence;
	    }
	  }
	} else {
	  double badFree = 0.0;
	  freeAlpha = currentAcceptablePivot_;
	  double currentDualTolerance = currentDualTolerance_;
	  for (int i = 0; i < numberNonZero; i++) {
	    int iSequence = index[i];
	    double tableauValue=array[i];
	    unsigned char iStatus=internalStatus[iSequence]&7;
	    if ((iStatus&4)==0) {
	      double mult = multiplier[iStatus];
	      double alpha = tableauValue * mult;
	      double oldValue = abcDj[iSequence] * mult;
	      double value = oldValue - tentativeTheta * alpha;
	      if (value < dualT) {
		bestPossible = CoinMax(bestPossible, alpha);
		value = oldValue - upperTheta_ * alpha;
		if (value < dualT && alpha >= acceptablePivot) {
		  upperTheta_ = (oldValue - dualT) / alpha;
		}
		// add to list
		arrayCandidate[numberRemaining] = alpha;
		indexCandidate[numberRemaining++] = iSequence;
	      }
	    } else {
	      bool keep;
	      bestPossible = CoinMax(bestPossible, fabs(tableauValue));
	      double oldValue = abcDj[iSequence];
	      // If free has to be very large - should come in via dualRow
	      //if (getInternalStatus(iSequence+addSequence)==isFree&&fabs(tableauValue)<1.0e-3)
	      //break;
	      if (oldValue > currentDualTolerance) {
		keep = true;
	      } else if (oldValue < -currentDualTolerance) {
		keep = true;
	      } else {
		if (fabs(tableauValue) > CoinMax(10.0 * acceptablePivot, 1.0e-5)) {
		  keep = true;
		} else {
		  keep = false;
		  badFree = CoinMax(badFree, fabs(tableauValue));
		}
	      }
	      if (keep) {
		// free - choose largest
		if (fabs(tableauValue) > fabs(freeAlpha)) {
		  freeAlpha = tableauValue;
		  freeSequence = iSequence;
		}
	      }
	    }
	  }
	}
	candidateList.setNumElements(numberRemaining);
	if (freeSequence>=0) {
	  sequenceIn_=freeSequence;
	} else if (fabs(upperTheta_-fabs(abcDj_[sequenceOut_]))<dualTolerance_) {
	  // can just move
	  stateOfIteration_=-1;
	  return;
	}
	dualColumn2();
      }
    }
    // redo dualOut_
    if (directionOut_<0) {
      dualOut_ = valueOut_ - upperOut_;
    } else {
      dualOut_ = lowerOut_ - valueOut_;
    }
  }
  usefulArray_[arrayForDualColumn_].clear();
  //clearArrays(arrayForDualColumn_);
  if (sequenceIn_ >= 0&&upperTheta_==COIN_DBL_MAX) {
    lowerIn_ = abcLower_[sequenceIn_];
    upperIn_ = abcUpper_[sequenceIn_];
    valueIn_ = abcSolution_[sequenceIn_];
    dualIn_ = abcDj_[sequenceIn_];
    if (valueIn_<lowerIn_+primalTolerance_) {
      directionIn_ = 1;
    } else if (valueIn_>upperIn_-primalTolerance_) {
      directionIn_ = -1;
    } else {
      if (alpha_ < 0.0) {
	// as if from upper bound
	directionIn_ = -1;
	//assert(upperIn_ == valueIn_);
      } else {
	// as if from lower bound
	directionIn_ = 1;
	//assert(lowerIn_ == valueIn_);
      }
    }
  }
#if ABC_DEBUG
  checkArrays(4);
#endif
#if CAN_HAVE_ZERO_OBJ>1
  if ((specialOptions_&2097152)!=0) 
    theta_=0.0;
#endif
  movement_=0.0;
  objectiveChange_=0.0;
  /*
    0 - take iteration
    1 - don't take but continue
    2 - don't take and break
  */
  btranAlpha_ = -alpha_ * directionOut_; // for check
}
void
AbcSimplexDual::getTableauColumnPart2()
{
#if ABC_PARALLEL
  if (parallelMode_!=0) {
    abcFactorization_->updateColumnFTPart2(usefulArray_[arrayForFtran_]);
    // pivot element
    alpha_ = usefulArray_[arrayForFtran_].denseVector()[pivotRow_];
  }
#endif
}
void 
AbcSimplexDual::replaceColumnPart3()
{
  abcFactorization_->replaceColumnPart3(this,
					&usefulArray_[arrayForReplaceColumn_],
					&usefulArray_[arrayForFtran_],
					lastPivotRow_,
					ftAlpha_?ftAlpha_:alpha_);
}
void
AbcSimplexDual::checkReplacePart1()
{
  //abcFactorization_->checkReplacePart1a(&usefulArray_[arrayForReplaceColumn_],pivotRow_);
  //usefulArray_[arrayForReplaceColumn_].print();
  ftAlpha_=abcFactorization_->checkReplacePart1(&usefulArray_[arrayForReplaceColumn_],pivotRow_);
}
#if 0
void
AbcSimplexDual::checkReplacePart1a()
{
  abcFactorization_->checkReplacePart1a(&usefulArray_[arrayForReplaceColumn_],pivotRow_);
}
void
AbcSimplexDual::checkReplacePart1b()
{
  //usefulArray_[arrayForReplaceColumn_].print();
  ftAlpha_=abcFactorization_->checkReplacePart1b(&usefulArray_[arrayForReplaceColumn_],pivotRow_);
}
#endif
/*
  returns 
  0 - OK
  1 - take iteration then re-factorize
  2 - flag something and skip
  3 - break and re-factorize
  5 - take iteration then re-factorize because of memory
 */
int 
AbcSimplexDual::checkReplace()
{
  int returnCode=0;
  if (!stateOfIteration_) {
    int saveStatus=problemStatus_;
    // check update
#if MOVE_REPLACE_PART1A < 0
    checkReplacePart1();
#endif
    int updateStatus=abcFactorization_->checkReplacePart2(pivotRow_,btranAlpha_,alpha_,ftAlpha_);
#if ABC_DEBUG
    checkArrays();
#endif
    // If looks like bad pivot - refactorize
    if (fabs(dualOut_) > 1.0e50)
      updateStatus = 2;
    // if no pivots, bad update but reasonable alpha - take and invert
    if (updateStatus == 2 &&
	!abcFactorization_->pivots() && fabs(alpha_) > 1.0e-5)
      updateStatus = 4;
    if (updateStatus == 1 || updateStatus == 4) {
      // slight error
      if (abcFactorization_->pivots() > 5 || updateStatus == 4) {
	problemStatus_ = -2; // factorize now
	returnCode = -3;
      }
    } else if (updateStatus == 2) {
      // major error
      // later we may need to unwind more e.g. fake bounds
      if (abcFactorization_->pivots() &&
	  ((moreSpecialOptions_ & 16) == 0 || abcFactorization_->pivots() > 4)) {
	problemStatus_ = -2; // factorize now
	returnCode = -2;
	moreSpecialOptions_ |= 16;
	stateOfIteration_=2;
      } else {
	assert (sequenceOut_>=0);
	// need to reject something
	char x = isColumn(sequenceOut_) ? 'C' : 'R';
	handler_->message(CLP_SIMPLEX_FLAG, messages_)
	  << x << sequenceWithin(sequenceOut_)
	  << CoinMessageEol;
#if ABC_NORMAL_DEBUG>0
	printf("BAD flag b %g pivotRow %d (seqout %d) sequenceIn %d\n", alpha_,pivotRow_,
	       sequenceOut_,sequenceIn_);
#endif
	setFlagged(sequenceOut_);
	// so can't happen immediately again
	sequenceOut_=-1;
	//abcProgress_.clearBadTimes();
	lastBadIteration_ = numberIterations_; // say be more cautious
	//clearArrays(-1); 
	//if(primalSolutionUpdated) 
	//gutsOfSolution(2);
	stateOfIteration_=1;
      }
    } else if (updateStatus == 3) {
      // out of memory
      // increase space if not many iterations
      if (abcFactorization_->pivots() <
	  0.5 * abcFactorization_->maximumPivots() &&
	  abcFactorization_->pivots() < 200)
	abcFactorization_->areaFactor(
				      abcFactorization_->areaFactor() * 1.1);
      problemStatus_ = -2; // factorize now
    } else if (updateStatus == 5) {
      problemStatus_ = -2; // factorize now
    }
    if (theta_ < 0.0) {
#if ABC_NORMAL_DEBUG>3
      if (handler_->logLevel() & 32)
	printf("negative theta %g\n", theta_);
#endif
      theta_ = 0.0;
    }
    //printf("check pstatus %d ustatus %d returncode %d nels %d\n",
    //	   problemStatus_,updateStatus,returnCode,usefulArray_[arrayForReplaceColumn_].getNumElements());
    if (saveStatus!=-1)
      problemStatus_=saveStatus;
  }
  return returnCode;
}
int 
AbcSimplexDual::noPivotColumn()
{
  // no incoming column is valid
  int returnCode=0;
  if (abcFactorization_->pivots() < 5 && acceptablePivot_ > 1.0e-8)
    acceptablePivot_ = 1.0e-8;
  returnCode = 1;
#if ABC_NORMAL_DEBUG>3
  if (handler_->logLevel() & 32)
    printf("** no column pivot\n");
#endif
  if (abcFactorization_->pivots() <=dontFactorizePivots_ && acceptablePivot_ <= 1.0e-8 &&
      lastFirstFree_<0) {
    // If not in branch and bound etc save ray
    delete [] ray_;
    if ((specialOptions_&(1024 | 4096)) == 0 || (specialOptions_ & 32) != 0) {
      // create ray anyway
      ray_ = new double [ numberRows_];
      setUsedArray(0);
      usefulArray_[arrayForBtran_].createOneUnpackedElement(pivotRow_, -directionOut_);
      abcFactorization_->updateColumnTranspose(usefulArray_[arrayForBtran_]);
      CoinMemcpyN(usefulArray_[arrayForBtran_].denseVector(), numberRows_, ray_);
      clearArrays(0);
    } else {
      ray_ = NULL;
    }
    // If we have just factorized and infeasibility reasonable say infeas
    double dualTest = ((specialOptions_ & 4096) != 0) ? 1.0e8 : 1.0e13;
    if (largestGap_)
      dualTest=CoinMin(largestGap_,dualTest);
    // but ignore if none at fake bound
    if (currentDualBound_<dualTest) {
      if (!numberAtFakeBound())
	dualTest=1.0e-12;
    }
    if (((specialOptions_ & 4096) != 0 || fabs(alpha_) < 1.0e-11) && currentDualBound_ >= dualTest) {
      double testValue = 1.0e-4;
      if (!abcFactorization_->pivots() && numberPrimalInfeasibilities_ == 1)
	testValue = 1.0e-6;
      if (valueOut_ > upperOut_ + testValue || valueOut_ < lowerOut_ - testValue
	  || (specialOptions_ & 64) == 0) {
	// say infeasible
	problemStatus_ = 1;
	// unless primal feasible!!!!
	//#define TEST_CLP_NODE
#ifndef TEST_CLP_NODE
	// Should be correct - but ...
	int numberFake = numberAtFakeBound();
	double sumPrimal =  (!numberFake) ? 2.0e5 : sumPrimalInfeasibilities_;
	if (sumPrimalInfeasibilities_ < 1.0e-3 || sumDualInfeasibilities_ > 1.0e-5 ||
	    (sumPrimal < 1.0e5 && (specialOptions_ & 1024) != 0 && abcFactorization_->pivots())) {
	  if (sumPrimal > 50.0 && abcFactorization_->pivots() > 2) {
	    problemStatus_ = -4;
	  } else {
	    problemStatus_ = 10;
	    // Get rid of objective
	    if ((specialOptions_ & 16384) == 0)
	      objective_ = new ClpLinearObjective(NULL, numberColumns_);
	  }
	}
#else
	if (sumPrimalInfeasibilities_ < 1.0e-3 || sumDualInfeasibilities_ > 1.0e-6) {
	  if ((specialOptions_ & 1024) != 0 && abcFactorization_->pivots()) {
	    problemStatus_ = 10;
	    // Get rid of objective
	    if ((specialOptions_ & 16384) == 0)
	      objective_ = new ClpLinearObjective(NULL, numberColumns_);
	  }
	}
#endif
	returnCode = 1;
	stateOfIteration_=2;
      }
    }
    if (abcFactorization_->pivots() != 0) {
      // If special option set - put off as long as possible
      if ((specialOptions_ & 64) == 0 || (moreSpecialOptions_ & 64) != 0) {
	if (numberTimesOptimal_<3&&abcFactorization_->pivots()>dontFactorizePivots_)
	  problemStatus_ = -4; //say looks infeasible
	else
	  problemStatus_ = 1; //say looks really infeasible
      } else {
	assert (sequenceOut_>=0);
	// flag
	char x = isColumn(sequenceOut_) ? 'C' : 'R';
	handler_->message(CLP_SIMPLEX_FLAG, messages_)
	  << x << sequenceWithin(sequenceOut_)
	  << CoinMessageEol;
#if ABC_NORMAL_DEBUG>3
	printf("flag c\n");
#endif
	setFlagged(sequenceOut_);
	lastBadIteration_ = numberIterations_; // say be more cautious
	// so can't happen immediately again
	sequenceOut_=-1;
	if (!abcFactorization_->pivots()) {
	  stateOfIteration_=1;
	}
      }
    }
  }
  pivotRow_ = -1;
  lastPivotRow_=-1;
  return returnCode;
}
#if 0
#include "CoinTime.hpp"
// Timed wait in nanoseconds - if negative then seconds
static int
timedWait(AbcSimplexDual * dual,int time, int which)
{
  pthread_mutex_lock(dual->mutexPointer(which));
  struct timespec absTime;
  clock_gettime(CLOCK_REALTIME, &absTime);
  if (time > 0) {
    absTime.tv_nsec += time;
    if (absTime.tv_nsec >= 1000000000) {
      absTime.tv_nsec -= 1000000000;
      absTime.tv_sec++;
    }
  } else {
    absTime.tv_sec -= time;
  }
  int rc = 0;
  while (! dual->threadInfoPointer()->status && rc == 0) {
    printf("waiting for signal on %d\n",which); 
    rc = pthread_cond_timedwait(dual->conditionPointer(which), dual->mutexPointer(which), &absTime);
  }
  if (rc == 0) 
    rc=dual->threadInfoPointer()->status;
  printf("got signal %d on %d\n",rc,which); 
  //pthread_mutex_unlock(dual->mutexPointer(which));
  return rc;
}
#endif
#if ABC_PARALLEL==1
void * abc_parallelManager(void * simplex)
{
  AbcSimplexDual * dual = reinterpret_cast<AbcSimplexDual *>(simplex);
  int whichThread=dual->whichThread();
  CoinThreadInfo * threadInfo = dual->threadInfoPointer(whichThread);
  pthread_mutex_lock(dual->mutexPointer(2,whichThread));
  pthread_barrier_wait(dual->barrierPointer());
#if 0
  int status=-1;
  while (status!=100)
    status=timedWait(dual,1000,2);
  pthread_cond_signal(dual->conditionPointer(1));
  pthread_mutex_unlock(dual->mutexPointer(1,whichThread));
#endif
  // so now mutex_ is locked
  int whichLocked=0;
  while (true) {
    pthread_mutex_t * mutexPointer = dual->mutexPointer(whichLocked,whichThread);
    // wait
    //printf("Child waiting for %d - status %d %d %d\n",
    //	   whichLocked,lockedX[0],lockedX[1],lockedX[2]);
    pthread_mutex_lock (mutexPointer);
    whichLocked++;
    if (whichLocked==3)
      whichLocked=0;
    int unLock=whichLocked+1;
    if (unLock==3)
      unLock=0;
    //printf("child pointer %x status %d\n",threadInfo,threadInfo->status);
    assert(threadInfo->status>=0);
    if (threadInfo->status==1000)
      pthread_exit(NULL);
    int type=threadInfo->status;
    int * which = threadInfo->stuff;
    int & returnCode=which[0];
    CoinIndexedVector * array;
    double dummy;
    switch(type) {
      // dummy
    case 0:
      break;
    case 1:
      returnCode=computeDualsAndCheck(dual,which);
      break;
    case 2:
      array=dual->usefulArray(dual->arrayForBtran()); // assuming not big overlap
      dual->dualRowPivot()->updateWeightsOnly(*array);
      //array->checkClean();
      break;
    case 3:
      //dual->replaceColumnPart3();
      dual->updateDualsInDual();
      break;
    case 4:
      which[2]=-1;
      dual->abcMatrix()->dualColumn1Part(which[1],which[2],threadInfo->result,
					 *dual->usefulArray(dual->arrayForBtran()),
					 *dual->usefulArray(dual->arrayForTableauRow()),
					 *dual->usefulArray(dual->arrayForDualColumn()));
      break;
    case 5:
      which[2]=-1;
      threadInfo->result=
	dual->abcMatrix()->dualColumn1Row(which[1],COIN_DBL_MAX,which[2],
					  *dual->usefulArray(dual->arrayForBtran()),
					  *dual->usefulArray(dual->arrayForTableauRow()),
					  *dual->usefulArray(dual->arrayForDualColumn()));
      break;
    case 6:// not used
      dual->getTableauColumnPart2();
      break;
    case 7: 
	dual->checkReplacePart1();
	//dual->checkReplacePart1a();
	//dual->checkReplacePart1b();
      break;
    case 8:
      which[2] = dual->flipBounds();
      break;
    case 9:
      dual->replaceColumnPart3();
      break;
      
    case 100:
      // initialization
      break;
    }
    threadInfo->status=-1;
    pthread_mutex_unlock (dual->mutexPointer(unLock,whichThread));
  }
}
void 
AbcSimplex::startParallelStuff(int type)
{
  /*
    first time 0,1 owned by main 2 by child
    at end of cycle should be 1,2 by main 0 by child then 2,0 by main 1 by child
  */
  int iStart=1;
  for (int i=0;i<NUMBER_THREADS;i++) {
    if ((stopStart_&iStart)!=0) {
      threadInfo_[i].status=type;
      pthread_mutex_unlock (&mutex_[locked_[i]+3*i]);
    }
    iStart = iStart<<1;
  }
}
#define NUMBER_PARALLEL_TASKS 10
//static int count_x[NUMBER_PARALLEL_TASKS]={0,0,0,0,0,0,0,0,0,0};
//static int count_y[NUMBER_PARALLEL_TASKS]={0,0,0,0,0,0,0,0,0,0};
int
AbcSimplex::stopParallelStuff(int type)
{
  //if (threadInfo_[0].status==-1)
  //count_y[type-1]++;
  //count_x[type-1]++;
  //printf("XXStop type %d iteration %d\n",type,numberIterations_);
  //if (threadInfo_[0].status!=-1) {
  //printf("Main waiting for %d - status %d\n",
  //	   locked,type);
  //pthread_mutex_lock(&mutex_[locked]);
  int iStop=32;
  for (int i=0;i<NUMBER_THREADS;i++) {
    if ((stopStart_&iStop)!=0) {
      int locked=locked_[i]+2;
      if (locked>=3)
	locked-=3;
      pthread_mutex_lock(&mutex_[locked+i*3]);
      locked_[i]++;
      if (locked_[i]==3)
	locked_[i]=0;
    }
    iStop = iStop<<1;
  }
  return threadInfo_[0].stuff[0];
}
#endif
//#define PRINT_WEIGHTS_FREQUENCY
#ifdef PRINT_WEIGHTS_FREQUENCY
extern int xweights1;
extern int xweights2;
extern int xweights3;
#endif
//static int whichModel=0;
int
AbcSimplexDual::dual()
{
  //handler_->setLogLevel(63);
#if 0
  whichModel++;
  printf("STARTing dual %d rows - model %d\n",numberRows_,whichModel);
  char modelName[20];
  sprintf(modelName,"model%d.mps",whichModel);
  writeMps(modelName,2);
  sprintf(modelName,"model%d.bas",whichModel);
  writeBasis(modelName,true,2);
#endif
  bestObjectiveValue_ = -COIN_DBL_MAX;
  algorithm_ = -1;
  moreSpecialOptions_ &= ~16; // clear check replaceColumn accuracy
  normalDualColumnIteration_=0;
  problemStatus_=-1;
  numberIterations_=baseIteration_;
  //baseIteration_=0;
  if (!lastDualBound_) {
    dualTolerance_ = dblParam_[ClpDualTolerance];
    primalTolerance_ = dblParam_[ClpPrimalTolerance];
    int tryType=moreSpecialOptions_/65536;
    if (tryType<5) {
      currentDualBound_=1.0e8;
    } else {
      currentDualBound_=1.0e4;
      tryType -=5;
    }
    currentDualBound_=CoinMin(currentDualBound_,dualBound_);
#if ABC_NORMAL_DEBUG>0
    printf("dual bound %g (initialize)\n",currentDualBound_);
#endif
    switch(tryType) {
    default:
      currentDualTolerance_=dualTolerance_;
      stateDualColumn_=0;
      break;
    case 1:
      currentDualTolerance_=CoinMin(1.0e-1,dualTolerance_*10.0);
      stateDualColumn_=-1;
      break;
    case 2:
      currentDualTolerance_=CoinMin(1.0e-1,dualTolerance_*100.0);
      stateDualColumn_=-1;
      break;
    case 3:
      currentDualTolerance_=CoinMin(1.0e-1,dualTolerance_*10000.0);
      stateDualColumn_=-1; // was -2 but that doesn't seem to work
      break;
    case 4:
      currentDualTolerance_=CoinMin(1.0e-1,dualTolerance_*1000000.0);
      stateDualColumn_=-1; // was -2 but that doesn't seem to work
      break;
    }
  } else {
    // done before
    currentDualBound_=1.1*lastDualBound_;
    currentDualTolerance_=dualTolerance_;
#if ABC_NORMAL_DEBUG>0
    printf("new dual bound %g (resolve)\n",currentDualBound_);
#endif
  }
  // save data
  saveData_ = saveData();
  // initialize 
  copyFromSaved();
  // temp
  if (fabs(primalTolerance()-1.001e-6)<1.0e-12&&false) {
    printf("trying idiot idea - need scaled matrix\n");
    primalTolerance_=1.0e-6;
    //for (int i=0;i<numberRows_;i++)
    //cost_[i]=-cost_[i];
    abcMatrix_->transposeTimesAll(cost_,abcCost_);
    delete [] cost_;
    cost_=NULL;
    CoinAbcMemcpy(costSaved_,abcCost_,numberTotal_);
    CoinAbcMemcpy(abcDj_,abcCost_,numberTotal_);
    static_cast<AbcSimplexDual *> (this)->makeNonFreeVariablesDualFeasible();
    const double multiplier[] = { 1.0, -1.0};
    double dualT = - currentDualTolerance_;
    double *  COIN_RESTRICT solution = abcSolution_;
    double *  COIN_RESTRICT lower = abcLower_;
    double *  COIN_RESTRICT upper = abcUpper_;
    for (int iSequence = 0; iSequence < numberTotal_; iSequence++) {
      int iStatus = internalStatus_[iSequence] & 7;
      if (iStatus<4) {
	double lowerValue=lower[iSequence];
	double upperValue=upper[iSequence];
	if (lowerValue>-1.0e10||upperValue<1.0e10) {
	  double mult = multiplier[iStatus];
	  double dj = abcDj_[iSequence] * mult;
	  if (dj < dualT) 
	    iStatus=1-iStatus;
	  if (lowerValue<=-1.0e10)
	    iStatus=1;
	  else if (upperValue>=1.0e10)
	    iStatus=0;
	  if (iStatus==0) {
	    setInternalStatus(iSequence, atLowerBound);
	    solution[iSequence] = lower[iSequence];
	  } else {
	    setInternalStatus(iSequence, atUpperBound);
	    solution[iSequence] = upper[iSequence];
	  }
	}
	assert (fabs(solution[iSequence])<1.0e10);
      }
    }
    CoinAbcMemcpy(solutionSaved_,abcSolution_,numberTotal_);
  }
  numberFlagged_=0;
#ifndef NDEBUG
  for (int iRow = 0; iRow < numberRows_; iRow++) {
    int iPivot = abcPivotVariable_[iRow];
    assert (!flagged(iPivot));
  }
#endif
#if ABC_PARALLEL==1
  // redo to test on parallelMode_
  if (parallelMode_!=0) {
    // For waking up thread
    memset(mutex_,0,sizeof(mutex_));
    for (int iThread=0;iThread<NUMBER_THREADS;iThread++) {
      for (int i=0;i<3;i++) {
	pthread_mutex_init(&mutex_[i+3*iThread], NULL);
	if (i<2)
	  pthread_mutex_lock(&mutex_[i+3*iThread]);
      }
      threadInfo_[iThread].status = 100;
    }
    //pthread_barrierattr_t attr;
    pthread_barrier_init(&barrier_, /*&attr*/ NULL, NUMBER_THREADS+1); 
    for (int iThread=0;iThread<NUMBER_THREADS;iThread++) {
      pthread_create(&abcThread_[iThread], NULL, abc_parallelManager, reinterpret_cast<void *>(this));
    }
    pthread_barrier_wait(&barrier_);
    pthread_barrier_destroy(&barrier_);
    for (int iThread=0;iThread<NUMBER_THREADS;iThread++) {
      threadInfo_[iThread].status = 0;
    }
    for (int i=0;i<NUMBER_THREADS;i++) {
      locked_[i]=0; 
    }
  }
#endif
#if ABC_PARALLEL==2
  abcFactorization_->setParallelMode(parallelMode_);
#endif
  static_cast<AbcSimplexDual *>(this)->bounceTolerances(-1);
  int saveDont = dontFactorizePivots_;
  if ((specialOptions_ & 2048) == 0)
    dontFactorizePivots_ = 0;
  else if(!dontFactorizePivots_)
    dontFactorizePivots_ = 20;
  if (alphaAccuracy_ != -1.0)
    alphaAccuracy_ = 1.0;
  startupSolve();
  lastPivotRow_=-1;
  pivotRow_=-1;
  // Save so can see if doing after primal
  swappedAlgorithm_ = (problemStatus_==10) ? 10 : 0;
  if (problemStatus_) {
#ifdef PRINT_WEIGHTS_FREQUENCY
    xweights1=0;
    xweights2=0;
    xweights3=0;
#endif
    numberFreeNonBasic_=0;
    gutsOfDual();
#ifdef PRINT_WEIGHTS_FREQUENCY
    if (dynamic_cast<AbcDualRowSteepest *>(abcDualRowPivot_)) {
      printf("ZZZZ %d iterations weights updated %d times\n",numberIterations_,xweights1+xweights2+xweights3);
      assert(numberIterations_==xweights1+xweights2+xweights3);
    }
#endif
  }
  if (!problemStatus_) {
    // see if cutoff reached
    double limit = 0.0;
    getDblParam(ClpDualObjectiveLimit, limit);
    if(fabs(limit) < 1.0e30 && minimizationObjectiveValue() >
       limit + 1.0e-7 + 1.0e-8 * fabs(limit)) {
      // actually infeasible on objective
      problemStatus_ = 1;
      secondaryStatus_ = 1;
    }
  }
  // If infeasible but primal errors - try dual
  if (problemStatus_==1 && numberPrimalInfeasibilities_) {
    bool inCbcOrOther = (specialOptions_ & 0x03000000) != 0;
    double factor = (!inCbcOrOther) ? 1.0 : 0.3;
    double averageInfeasibility = sumPrimalInfeasibilities_/
      static_cast<double>(numberPrimalInfeasibilities_);
    if (averageInfeasibility<factor*largestPrimalError_)
      problemStatus_= 10;
  }
  
  finishSolve();
  
  // Restore any saved stuff
  restoreData(saveData_);
  dontFactorizePivots_ = saveDont;
  if (problemStatus_ == 3) {
    rawObjectiveValue_=CoinMax(bestObjectiveValue_,rawObjectiveValue_-bestPossibleImprovement_);
    setClpSimplexObjectiveValue();
  }
#if ABC_PARALLEL==1
  if (parallelMode_!=0) {
    //for (int i=0;i<NUMBER_PARALLEL_TASKS;i++) {
    //if (count_x[i]||count_y[i])
    //printf("For parallel task %d spawned finished first %d times out of %d\n",
    //	     i+1,count_y[i],count_x[i]);
    //count_y[i]=count_x[i]=0;
    //}
    stopStart_=31+32*31; // all
    startParallelStuff(1000);
    for (int iThread=0;iThread<NUMBER_THREADS;iThread++) {
      pthread_join(abcThread_[iThread],NULL);
      for (int i=0;i<3;i++) {
	pthread_mutex_destroy (&mutex_[i+3*iThread]);
      }
    }
  }
#endif
  return problemStatus_;
}
