// Copyright (C) 2002, International Business Machines
// Corporation and others.  All Rights Reserved.
#include <cassert>
#ifdef CBC_STATISTICS
extern int osi_crunch;
extern int osi_primal;
extern int osi_dual;
extern int osi_hot;
#endif 
#include "CoinTime.hpp"
#include "CoinHelperFunctions.hpp"
#include "CoinIndexedVector.hpp"
#include "CoinModel.hpp"
#include "CoinMpsIO.hpp"
#include "CoinSort.hpp"
#include "ClpDualRowSteepest.hpp"
#include "ClpPrimalColumnSteepest.hpp"
#include "ClpPackedMatrix.hpp"
#include "ClpDualRowDantzig.hpp"
#include "ClpPrimalColumnDantzig.hpp"
#include "ClpFactorization.hpp"
#include "ClpObjective.hpp"
#include "ClpSimplex.hpp"
#include "ClpSimplexOther.hpp"
#include "ClpSimplexPrimal.hpp"
#include "ClpSimplexDual.hpp"
#include "ClpNonLinearCost.hpp"
#include "OsiClpSolverInterface.hpp"
#include "OsiBranchingObject.hpp"
#include "OsiCuts.hpp"
#include "OsiRowCut.hpp"
#include "OsiColCut.hpp"
#include "ClpPresolve.hpp"
#include "CoinLpIO.hpp"
static double totalTime=0.0;
//#define SAVE_MODEL 1
#ifdef SAVE_MODEL
static int resolveTry=0;
static int loResolveTry=0;
static int hiResolveTry=9999999;
#endif
//#############################################################################
// Solve methods
//#############################################################################
void OsiClpSolverInterface::initialSolve()
{
#define KEEP_SMALL
#ifdef KEEP_SMALL
  if (smallModel_) {
    delete [] spareArrays_;
    spareArrays_ = NULL;
    delete smallModel_;
    smallModel_=NULL;
  }
#endif
  bool deleteSolver;
  ClpSimplex * solver;
  double time1 = CoinCpuTime();
  int userFactorizationFrequency = modelPtr_->factorization()->maximumPivots();
  int totalIterations=0;
  bool abortSearch=false;
  ClpObjective * savedObjective=NULL;
  double savedDualLimit=modelPtr_->dblParam_[ClpDualObjectiveLimit];
  if (fakeObjective_) {
    // Clear (no objective, 0-1 and in B&B)
    modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~128));
    // See if all with costs fixed
    int numberColumns = modelPtr_->numberColumns_;
    const double * obj = modelPtr_->objective();
    const double * lower = modelPtr_->columnLower();
    const double * upper = modelPtr_->columnUpper();
    int i;
    for (i=0;i<numberColumns;i++) {
      double objValue = obj[i];
      if (objValue) {
	if (lower[i]!=upper[i])
	  break;
      }
    }
    if (i==numberColumns) {
      // Check (Clp fast dual)
      if ((specialOptions_&524288)==0) {
	// Set fake
	savedObjective=modelPtr_->objective_;
	modelPtr_->objective_=fakeObjective_;
	modelPtr_->dblParam_[ClpDualObjectiveLimit]=COIN_DBL_MAX;
      } else {
	// Set (no objective, 0-1 and in B&B)
	modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()|128);
      }
    }
  }
  // Check (in branch and bound)
  if ((specialOptions_&1024)==0) {
    solver = new ClpSimplex(true);
    deleteSolver=true;
    solver->borrowModel(*modelPtr_);
    // See if user set factorization frequency
    // borrowModel does not move
    solver->factorization()->maximumPivots(userFactorizationFrequency);
  } else {
    solver = modelPtr_;
    deleteSolver=false;
  }
  // Treat as if user simplex not enabled
  int saveSolveType=solver->solveType();
  bool doingPrimal = solver->algorithm()>0;
  if (saveSolveType==2) {
    disableSimplexInterface();
    solver->setSolveType(1);
  }
  int saveOptions = solver->specialOptions();
  solver->setSpecialOptions(saveOptions|64|32768); // go as far as possible
  // get original log levels
  int saveMessageLevel=modelPtr_->logLevel();
  int messageLevel=messageHandler()->logLevel();
  int saveMessageLevel2 = messageLevel;
  // Set message handler
  solver->passInMessageHandler(handler_);
  // But keep log level
  solver->messageHandler()->setLogLevel(saveMessageLevel);
  // set reasonable defaults
  bool takeHint;
  OsiHintStrength strength;
  // Switch off printing if asked to
  bool gotHint = (getHintParam(OsiDoReducePrint,takeHint,strength));
  assert (gotHint);
  if (strength!=OsiHintIgnore&&takeHint) {
    if (messageLevel>0)
      messageLevel--;
  }
  if (messageLevel<saveMessageLevel)
    solver->messageHandler()->setLogLevel(messageLevel);
  // Allow for specialOptions_==1+8 forcing saving factorization
  int startFinishOptions=0;
  if ((specialOptions_&9)==(1+8)) {
    startFinishOptions =1+2+4; // allow re-use of factorization
  }
  bool defaultHints=true;
  {
    int hint;
    for (hint=OsiDoPresolveInInitial;hint<OsiLastHintParam;hint++) {
      if (hint!=OsiDoReducePrint&&
          hint!=OsiDoInBranchAndCut) {
        bool yesNo;
        OsiHintStrength strength;
        getHintParam(static_cast<OsiHintParam> (hint),yesNo,strength);
        if (yesNo) {
          defaultHints=false;
          break;
        }
        if (strength != OsiHintIgnore) {
          defaultHints=false;
          break;
        }
      }
    }
  }
  /*
    If basis then do primal (as user could do dual with resolve)
    If not then see if dual feasible (and allow for gubs etc?)
  */
  bool doPrimal = (basis_.numberBasicStructurals()>0);
  setBasis(basis_,solver);
  bool inCbcOrOther = (modelPtr_->specialOptions()&0x03000000)!=0;
  if ((!defaultHints||doPrimal)&&!solveOptions_.getSpecialOption(6)) {
    // scaling
    // save initial state
    const double * rowScale1 = solver->rowScale();
    if (modelPtr_->solveType()==1) {
      gotHint = (getHintParam(OsiDoScale,takeHint,strength));
      assert (gotHint);
      if (strength==OsiHintIgnore||takeHint) {
        if (!solver->scalingFlag())
          solver->scaling(3);
      } else {
        solver->scaling(0);
      }
    } else {
      solver->scaling(0);
    }
    //solver->setDualBound(1.0e6);
    //solver->setDualTolerance(1.0e-7);
    
    //ClpDualRowSteepest steep;
    //solver->setDualRowPivotAlgorithm(steep);
    //solver->setPrimalTolerance(1.0e-8);
    //ClpPrimalColumnSteepest steepP;
    //solver->setPrimalColumnPivotAlgorithm(steepP);
    
    // sort out hints;
    // algorithm 0 whatever, -1 force dual, +1 force primal
    int algorithm = 0;
    gotHint = (getHintParam(OsiDoDualInInitial,takeHint,strength));
    assert (gotHint);
    if (strength!=OsiHintIgnore)
      algorithm = takeHint ? -1 : 1;
    // crash 0 do lightweight if all slack, 1 do, -1 don't
    int doCrash=0;
    gotHint = (getHintParam(OsiDoCrash,takeHint,strength));
    assert (gotHint);
    if (strength!=OsiHintIgnore)
      doCrash = takeHint ? 1 : -1;
    // doPrimal set true if any structurals in basis so switch off crash
    if (doPrimal)
      doCrash = -1;
    
    // presolve
    gotHint = (getHintParam(OsiDoPresolveInInitial,takeHint,strength));
    assert (gotHint);
    if (strength!=OsiHintIgnore&&takeHint) {
      ClpPresolve pinfo;
      ClpSimplex * model2 = pinfo.presolvedModel(*solver,1.0e-8);
      if (!model2) {
        // problem found to be infeasible - whats best?
        model2 = solver;
      } else {
	model2->setSpecialOptions(solver->specialOptions());
      }
      
      // change from 200 (unless changed)
      if (modelPtr_->factorization()->maximumPivots()==200)
        model2->factorization()->maximumPivots(100+model2->numberRows()/50);
      else
        model2->factorization()->maximumPivots(userFactorizationFrequency);
      int savePerturbation = model2->perturbation();
      if (savePerturbation==100)
        model2->setPerturbation(50);
      if (!doPrimal) {
        // faster if bounds tightened
        //int numberInfeasibilities = model2->tightenPrimalBounds();
        model2->tightenPrimalBounds();
        // look further
        bool crashResult=false;
        if (doCrash>0)
          crashResult =  (solver->crash(1000.0,1)>0);
        else if (doCrash==0&&algorithm>0)
          crashResult =  (solver->crash(1000.0,1)>0);
        doPrimal=crashResult;
      }
      if (algorithm<0)
        doPrimal=false;
      else if (algorithm>0)
        doPrimal=true;
      if (!doPrimal) {
        //if (numberInfeasibilities)
        //std::cout<<"** Analysis indicates model infeasible"
        //       <<std::endl;
        // up dual bound for safety
        //model2->setDualBound(1.0e11);
	disasterHandler_->setOsiModel(this);
	if (inCbcOrOther) {
	  disasterHandler_->setSimplex(model2);
	  disasterHandler_->setWhereFrom(4);
	  model2->setDisasterHandler(disasterHandler_);
	}
        model2->dual(0);
	totalIterations += model2->numberIterations();
	if (inCbcOrOther) {
	  if(disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
	    printf("dual trouble a\n");
#endif
	    if (disasterHandler_->typeOfDisaster()) {
	      // We want to abort 
	      abortSearch=true;
	      goto disaster;
	    }
	    // try just going back in
	    disasterHandler_->setPhase(1);
	    model2->dual();
	    totalIterations += model2->numberIterations();
	    if (disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
	      printf("dual trouble b\n");
#endif
	      if (disasterHandler_->typeOfDisaster()) {
		// We want to abort 
		abortSearch=true;
		goto disaster;
	      }
	      // try primal with original basis
	      disasterHandler_->setPhase(2);
	      setBasis(basis_,model2);
	      model2->primal();
	      totalIterations += model2->numberIterations();
	    }
	    if(disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
	      printf("disaster - treat as infeasible\n");
#endif
	      if (disasterHandler_->typeOfDisaster()) {
		// We want to abort 
		abortSearch=true;
		goto disaster;
	      }
	      model2->setProblemStatus(1);
	    }
	  }
	  // reset
	  model2->setDisasterHandler(NULL);
	}
        // check if clp thought it was in a loop
        if (model2->status()==3&&!model2->hitMaximumIterations()) {
          // switch algorithm
	  disasterHandler_->setOsiModel(this);
	  if (inCbcOrOther) {
	    disasterHandler_->setSimplex(model2);
	    disasterHandler_->setWhereFrom(6);
	    model2->setDisasterHandler(disasterHandler_);
	  }
          model2->primal();
	  totalIterations += model2->numberIterations();
	  if (inCbcOrOther) {
	    if(disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
	      printf("primal trouble a\n");
#endif
	      if (disasterHandler_->typeOfDisaster()) {
		// We want to abort 
		abortSearch=true;
		goto disaster;
	      }
	      // try just going back in (but with dual)
	      disasterHandler_->setPhase(1);
	      model2->dual();
	      totalIterations += model2->numberIterations();
	      if (disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
		printf("primal trouble b\n");
#endif
		if (disasterHandler_->typeOfDisaster()) {
		  // We want to abort 
		  abortSearch=true;
		  goto disaster;
		}
		// try primal with original basis
		disasterHandler_->setPhase(2);
		setBasis(basis_,model2);
		model2->dual();
		totalIterations += model2->numberIterations();
	      }
	      if(disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
		printf("disaster - treat as infeasible\n");
#endif
		if (disasterHandler_->typeOfDisaster()) {
		  // We want to abort 
		  abortSearch=true;
		  goto disaster;
		}
		model2->setProblemStatus(1);
	      }
	    }
	    // reset
	    model2->setDisasterHandler(NULL);
	  }
        }
      } else {
        // up infeasibility cost for safety
        //model2->setInfeasibilityCost(1.0e10);
	disasterHandler_->setOsiModel(this);
	if (inCbcOrOther) {
	  disasterHandler_->setSimplex(model2);
	  disasterHandler_->setWhereFrom(6);
	  model2->setDisasterHandler(disasterHandler_);
	}
        model2->primal(1);
	totalIterations += model2->numberIterations();
	if (inCbcOrOther) {
	  if(disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
	    printf("primal trouble a\n");
#endif
	    if (disasterHandler_->typeOfDisaster()) {
	      // We want to abort 
	      abortSearch=true;
	      goto disaster;
	    }
	    // try just going back in (but with dual)
	    disasterHandler_->setPhase(1);
	    model2->dual();
	    totalIterations += model2->numberIterations();
	    if (disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
	      printf("primal trouble b\n");
#endif
	      if (disasterHandler_->typeOfDisaster()) {
		// We want to abort 
		abortSearch=true;
		goto disaster;
	      }
	      // try primal with original basis
	      disasterHandler_->setPhase(2);
	      setBasis(basis_,model2);
	      model2->dual();
	      totalIterations += model2->numberIterations();
	    }
	    if(disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
	      printf("disaster - treat as infeasible\n");
#endif
	      if (disasterHandler_->typeOfDisaster()) {
		// We want to abort 
		abortSearch=true;
		goto disaster;
	      }
	      model2->setProblemStatus(1);
	    }
	  }
	  // reset
	  model2->setDisasterHandler(NULL);
	}
        // check if clp thought it was in a loop
        if (model2->status()==3&&!model2->hitMaximumIterations()) {
          // switch algorithm
	  disasterHandler_->setOsiModel(this);
	  if (inCbcOrOther) {
	    disasterHandler_->setSimplex(model2);
	    disasterHandler_->setWhereFrom(4);
	    model2->setDisasterHandler(disasterHandler_);
	  }
	  model2->dual(0);
	  totalIterations += model2->numberIterations();
	  if (inCbcOrOther) {
	    if(disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
	      printf("dual trouble a\n");
#endif
	      if (disasterHandler_->typeOfDisaster()) {
		// We want to abort 
		abortSearch=true;
		goto disaster;
	      }
	      // try just going back in
	      disasterHandler_->setPhase(1);
	      model2->dual();
	      totalIterations += model2->numberIterations();
	      if (disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
		printf("dual trouble b\n");
#endif
		if (disasterHandler_->typeOfDisaster()) {
		  // We want to abort 
		  abortSearch=true;
		goto disaster;
		}
		// try primal with original basis
		disasterHandler_->setPhase(2);
		setBasis(basis_,model2);
		model2->primal();
		totalIterations += model2->numberIterations();
	      }
	      if(disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
		printf("disaster - treat as infeasible\n");
#endif
		if (disasterHandler_->typeOfDisaster()) {
		  // We want to abort 
		  abortSearch=true;
		  goto disaster;
		}
		model2->setProblemStatus(1);
	      }
	    }
	    // reset
	    model2->setDisasterHandler(NULL);
	  }
        }
      }
      model2->setPerturbation(savePerturbation);
      if (model2!=solver) {
        int presolvedStatus = model2->status();
        pinfo.postsolve(true);
        
        delete model2;
        //printf("Resolving from postsolved model\n");
        // later try without (1) and check duals before solve
	if (presolvedStatus!=3) {
	  if (!inCbcOrOther||presolvedStatus!=1) {
	    disasterHandler_->setOsiModel(this);
	    if (inCbcOrOther) {
	      disasterHandler_->setSimplex(solver); // as "borrowed"
	      disasterHandler_->setWhereFrom(6);
	      solver->setDisasterHandler(disasterHandler_);
	    }
	    solver->primal(1);
	    totalIterations += solver->numberIterations();
	    if (inCbcOrOther) {
	      if(disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
		printf("primal trouble a\n");
#endif
		if (disasterHandler_->typeOfDisaster()) {
		  // We want to abort 
		  abortSearch=true;
		  goto disaster;
		}
		// try just going back in (but with dual)
		disasterHandler_->setPhase(1);
		solver->dual();
		totalIterations += solver->numberIterations();
		if (disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
		  printf("primal trouble b\n");
#endif
		  if (disasterHandler_->typeOfDisaster()) {
		    // We want to abort 
		    abortSearch=true;
		    goto disaster;
		  }
		  // try primal with original basis
		  disasterHandler_->setPhase(2);
		  setBasis(basis_,solver);
		  solver->dual();
		  totalIterations += solver->numberIterations();
		}
		if(disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
		  printf("disaster - treat as infeasible\n");
#endif
		  if (disasterHandler_->typeOfDisaster()) {
		    // We want to abort 
		    abortSearch=true;
		    goto disaster;
		  }
		  solver->setProblemStatus(1);
		}
	      }
	      // reset
	      solver->setDisasterHandler(NULL);
	    }
	  }
	}
      }
      lastAlgorithm_=1; // primal
      //if (solver->numberIterations())
      //printf("****** iterated %d\n",solver->numberIterations());
    } else {
      // do we want crash
      if (doCrash>0)
        solver->crash(1000.0,2);
      else if (doCrash==0)
        solver->crash(1000.0,0);
      if (algorithm<0)
        doPrimal=false;
      else if (algorithm>0)
        doPrimal=true;
      disasterHandler_->setOsiModel(this);
      disasterHandler_->setSimplex(solver); // as "borrowed"
      bool inCbcOrOther = (modelPtr_->specialOptions()&0x03000000)!=0;
      if (!doPrimal) 
	disasterHandler_->setWhereFrom(4);
      else
	disasterHandler_->setWhereFrom(6);
      if (inCbcOrOther)
	solver->setDisasterHandler(disasterHandler_);
      if (!doPrimal) {
        //printf("doing dual\n");
        solver->dual(0);
	totalIterations += solver->numberIterations();
	if (inCbcOrOther) {
	  if(disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
	    printf("dual trouble a\n");
#endif
	    if (disasterHandler_->typeOfDisaster()) {
	      // We want to abort 
	      abortSearch=true;
	      goto disaster;
	    }
	    // try just going back in
	    disasterHandler_->setPhase(1);
	    solver->dual();
	    totalIterations += solver->numberIterations();
	    if (disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
	      printf("dual trouble b\n");
#endif
	      if (disasterHandler_->typeOfDisaster()) {
		// We want to abort 
		abortSearch=true;
		goto disaster;
	      }
	      // try primal with original basis
	      disasterHandler_->setPhase(2);
	      setBasis(basis_,solver);
	      solver->primal();
	      totalIterations += solver->numberIterations();
	    }
	    if(disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
	      printf("disaster - treat as infeasible\n");
#endif
	      if (disasterHandler_->typeOfDisaster()) {
		// We want to abort 
		abortSearch=true;
		goto disaster;
	      }
	      solver->setProblemStatus(1);
	    }
	  }
	  // reset
	  solver->setDisasterHandler(NULL);
	}
        lastAlgorithm_=2; // dual
        // check if clp thought it was in a loop
        if (solver->status()==3&&!solver->hitMaximumIterations()) {
          // switch algorithm
          solver->primal(0);
	  totalIterations += solver->numberIterations();
          lastAlgorithm_=1; // primal
        }
      } else {
        //printf("doing primal\n");
        solver->primal(1);
	totalIterations += solver->numberIterations();
	if (inCbcOrOther) {
	  if(disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
	    printf("primal trouble a\n");
#endif
	    if (disasterHandler_->typeOfDisaster()) {
	      // We want to abort 
	      abortSearch=true;
	      goto disaster;
	    }
	    // try just going back in (but with dual)
	    disasterHandler_->setPhase(1);
	    solver->dual();
	    totalIterations += solver->numberIterations();
	    if (disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
	      printf("primal trouble b\n");
#endif
	      if (disasterHandler_->typeOfDisaster()) {
		// We want to abort 
		abortSearch=true;
		goto disaster;
	      }
	      // try primal with original basis
	      disasterHandler_->setPhase(2);
	      setBasis(basis_,solver);
	      solver->dual();
	      totalIterations += solver->numberIterations();
	    }
	    if(disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
	      printf("disaster - treat as infeasible\n");
#endif
	      if (disasterHandler_->typeOfDisaster()) {
		// We want to abort 
		abortSearch=true;
		goto disaster;
	      }
	      solver->setProblemStatus(1);
	    }
	  }
	  // reset
	  solver->setDisasterHandler(NULL);
	}
        lastAlgorithm_=1; // primal
        // check if clp thought it was in a loop
        if (solver->status()==3&&!solver->hitMaximumIterations()) {
          // switch algorithm
          solver->dual(0);
	  totalIterations += solver->numberIterations();
          lastAlgorithm_=2; // dual
        }
      }
    }
    // If scaled feasible but unscaled infeasible take action
    if (!solver->status()&&cleanupScaling_) {
      solver->cleanup(cleanupScaling_);
    }
    basis_ = getBasis(solver);
    //basis_.print();
    const double * rowScale2 = solver->rowScale();
    solver->setSpecialOptions(saveOptions);
    if (!rowScale1&&rowScale2) {
      // need to release memory
      if (!solver->savedRowScale_) {
	solver->setRowScale(NULL);
	solver->setColumnScale(NULL);
      } else {
	solver->rowScale_=NULL;
	solver->columnScale_=NULL;
      }
    }
  } else {
    // User doing nothing and all slack basis
    ClpSolve options=solveOptions_;
    bool yesNo;
    OsiHintStrength strength;
    getHintParam(OsiDoInBranchAndCut,yesNo,strength);
    if (yesNo) {
      solver->setSpecialOptions(solver->specialOptions()|1024);
    }
    solver->initialSolve(options);
    totalIterations += solver->numberIterations();
    lastAlgorithm_ = 2; // say dual
    // If scaled feasible but unscaled infeasible take action
    if (!solver->status()&&cleanupScaling_) {
      solver->cleanup(cleanupScaling_);
    }
    basis_ = getBasis(solver);
    //basis_.print();
  }
  solver->messageHandler()->setLogLevel(saveMessageLevel);
 disaster:
  if (deleteSolver) {
    solver->returnModel(*modelPtr_);
    delete solver;
  }
  if (startFinishOptions) {
    int save = modelPtr_->logLevel();
    if (save<2) modelPtr_->setLogLevel(0);
    modelPtr_->dual(0,startFinishOptions);
    totalIterations += modelPtr_->numberIterations();
    modelPtr_->setLogLevel(save);
  }
  if (saveSolveType==2) {
    enableSimplexInterface(doingPrimal);
  }
  if (savedObjective) {
    // fix up
    modelPtr_->dblParam_[ClpDualObjectiveLimit]=savedDualLimit;
    //modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~32));
    modelPtr_->objective_=savedObjective;
    if (!modelPtr_->problemStatus_) {
      CoinZeroN(modelPtr_->dual_,modelPtr_->numberRows_);
      CoinZeroN(modelPtr_->reducedCost_,modelPtr_->numberColumns_);
      if (modelPtr_->dj_&&(modelPtr_->whatsChanged_&1)!=0)
	CoinZeroN(modelPtr_->dj_,modelPtr_->numberColumns_+modelPtr_->numberRows_);
      modelPtr_->computeObjectiveValue();
    }
  }
  modelPtr_->setNumberIterations(totalIterations);
  handler_->setLogLevel(saveMessageLevel2);
  if (modelPtr_->problemStatus_==3&&lastAlgorithm_==2)
    modelPtr_->computeObjectiveValue();
  // mark so we can pick up objective value quickly
  modelPtr_->upperIn_=0.0;
  time1 = CoinCpuTime()-time1;
  totalTime += time1;
  assert (!modelPtr_->disasterHandler());
  if (lastAlgorithm_<1||lastAlgorithm_>2)
    lastAlgorithm_=1;
  if (abortSearch) {
    lastAlgorithm_=-911;
    modelPtr_->setProblemStatus(4);
  }
  modelPtr_->whatsChanged_ |= 0x30000;
  //std::cout<<time1<<" seconds - total "<<totalTime<<std::endl;
}
//-----------------------------------------------------------------------------
void OsiClpSolverInterface::resolve()
{
#ifdef COIN_DEVELOP
  {
    int i;
    int n = getNumCols();
    const double *lower = getColLower() ;
    const double *upper = getColUpper() ;
    for (i=0;i<n;i++) {
      assert (lower[i]<1.0e12);
      assert (upper[i]>-1.0e12);
    }
    n = getNumRows();
    lower = getRowLower() ;
    upper = getRowUpper() ;
    for (i=0;i<n;i++) {
      assert (lower[i]<1.0e12);
      assert (upper[i]>-1.0e12);
    }
  }
#endif
  if ((stuff_.solverOptions_&65536)!=0) {
    modelPtr_->fastDual2(&stuff_);
    return;
  }
  //void pclp(char *);
  //pclp("res");
  bool takeHint;
  OsiHintStrength strength;
  bool gotHint = (getHintParam(OsiDoInBranchAndCut,takeHint,strength));
  assert (gotHint);
  // mark so we can pick up objective value quickly
  modelPtr_->upperIn_=0.0;
  if ((specialOptions_&4096)!=0) {
    // Quick check to see if optimal
    modelPtr_->checkSolutionInternal();
    if (modelPtr_->problemStatus()==0) {
      modelPtr_->setNumberIterations(0);
      return;
    }
  }
  int totalIterations=0;
  bool abortSearch=false;
  ClpObjective * savedObjective=NULL;
  double savedDualLimit=modelPtr_->dblParam_[ClpDualObjectiveLimit];
  if (fakeObjective_) {
    modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~128));
    // See if all with costs fixed
    int numberColumns = modelPtr_->numberColumns_;
    const double * obj = modelPtr_->objective();
    const double * lower = modelPtr_->columnLower();
    const double * upper = modelPtr_->columnUpper();
    int i;
    for (i=0;i<numberColumns;i++) {
      double objValue = obj[i];
      if (objValue) {
	if (lower[i]!=upper[i])
	  break;
      }
    }
    if (i==numberColumns) {
      if ((specialOptions_&524288)==0) {
	// Set fake
	savedObjective=modelPtr_->objective_;
	modelPtr_->objective_=fakeObjective_;
	modelPtr_->dblParam_[ClpDualObjectiveLimit]=COIN_DBL_MAX;
      } else {
	modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()|128);
      }
    }
  }
  // If using Clp initialSolve and primal - just do here
  gotHint = (getHintParam(OsiDoDualInResolve,takeHint,strength));
  assert (gotHint);
  if (strength!=OsiHintIgnore&&!takeHint&&solveOptions_.getSpecialOption(6)) {
    ClpSolve options=solveOptions_;
    // presolve
    getHintParam(OsiDoPresolveInResolve,takeHint,strength);
    if (strength!=OsiHintIgnore&&!takeHint)
      options.setPresolveType(ClpSolve::presolveOff);
    int saveOptions = modelPtr_->specialOptions();
    getHintParam(OsiDoInBranchAndCut,takeHint,strength);
    if (takeHint) {
      modelPtr_->setSpecialOptions(modelPtr_->specialOptions()|1024);
    }
    setBasis(basis_,modelPtr_);
    modelPtr_->initialSolve(options);
    lastAlgorithm_ = 1; // say primal
    // If scaled feasible but unscaled infeasible take action
    if (!modelPtr_->status()&&cleanupScaling_) {
      modelPtr_->cleanup(cleanupScaling_);
    }
    modelPtr_->setSpecialOptions(saveOptions); // restore
    basis_ = getBasis(modelPtr_);
  }
  int saveSolveType=modelPtr_->solveType();
  bool doingPrimal = modelPtr_->algorithm()>0;
  if (saveSolveType==2) {
    disableSimplexInterface();
  }
  int saveOptions = modelPtr_->specialOptions();
  int startFinishOptions=0;
  if (specialOptions_!=0x80000000) {
    if((specialOptions_&1)==0) {
      startFinishOptions=0;
      modelPtr_->setSpecialOptions(saveOptions|(64|1024|32768));
    } else {
      startFinishOptions=1+4;
      if ((specialOptions_&8)!=0)
        startFinishOptions +=2; // allow re-use of factorization
      if((specialOptions_&4)==0||!takeHint) 
        modelPtr_->setSpecialOptions(saveOptions|(64|128|512|1024|4096|32768));
      else
        modelPtr_->setSpecialOptions(saveOptions|(64|128|512|1024|2048|4096|32768));
    }
  } else {
    modelPtr_->setSpecialOptions(saveOptions|64|32768);
  }
  //printf("options %d size %d\n",modelPtr_->specialOptions(),modelPtr_->numberColumns());
  //modelPtr_->setSolveType(1);
  // Set message handler to have same levels etc
  int saveMessageLevel=modelPtr_->logLevel();
  int messageLevel=messageHandler()->logLevel();
  bool oldDefault;
  CoinMessageHandler * saveHandler = modelPtr_->pushMessageHandler(handler_,oldDefault);
  //printf("basis before dual\n");
  //basis_.print();
  setBasis(basis_,modelPtr_);
#ifdef SAVE_MODEL
  resolveTry++;
#if SAVE_MODEL > 1
  if (resolveTry>=loResolveTry&&
      resolveTry<=hiResolveTry) {
    char fileName[20];
    sprintf(fileName,"save%d.mod",resolveTry);
    modelPtr_->saveModel(fileName);
  }
#endif
#endif
  // set reasonable defaults
  // Switch off printing if asked to
  gotHint = (getHintParam(OsiDoReducePrint,takeHint,strength));
  assert (gotHint);
  if (strength!=OsiHintIgnore&&takeHint) {
    if (messageLevel>0)
      messageLevel--;
  }
  if (messageLevel<modelPtr_->messageHandler()->logLevel())
    modelPtr_->messageHandler()->setLogLevel(messageLevel);
  // See if user set factorization frequency
  int userFactorizationFrequency = modelPtr_->factorization()->maximumPivots();
  // scaling
  if (modelPtr_->solveType()==1) {
    gotHint = (getHintParam(OsiDoScale,takeHint,strength));
    assert (gotHint);
    if (strength==OsiHintIgnore||takeHint) {
      if (!modelPtr_->scalingFlag())
	modelPtr_->scaling(3);
    } else {
      modelPtr_->scaling(0);
    }
  } else {
    modelPtr_->scaling(0);
  }
  // sort out hints;
  // algorithm -1 force dual, +1 force primal
  int algorithm = -1;
  gotHint = (getHintParam(OsiDoDualInResolve,takeHint,strength));
  assert (gotHint);
  if (strength!=OsiHintIgnore)
    algorithm = takeHint ? -1 : 1;
  //modelPtr_->saveModel("save.bad");
  // presolve
  gotHint = (getHintParam(OsiDoPresolveInResolve,takeHint,strength));
  assert (gotHint);
  if (strength!=OsiHintIgnore&&takeHint) {
#ifdef KEEP_SMALL
    if (smallModel_) {
      delete [] spareArrays_;
      spareArrays_ = NULL;
      delete smallModel_;
      smallModel_=NULL;
    }
#endif
    ClpPresolve pinfo;
    if ((specialOptions_&128)!=0) {
      specialOptions_ &= ~128;
    }
    if ((modelPtr_->specialOptions()&1024)!=0) {
      pinfo.setDoDual(false);
      pinfo.setDoTripleton(false);
      pinfo.setDoDupcol(false);
      pinfo.setDoDuprow(false);
      pinfo.setDoSingletonColumn(false);
    }
    ClpSimplex * model2 = pinfo.presolvedModel(*modelPtr_,1.0e-8);
    if (!model2) {
      // problem found to be infeasible - whats best?
      model2 = modelPtr_;
    }
    // return number of rows
    int * stats = reinterpret_cast<int *> (getApplicationData());
    if (stats) {
      stats[0]=model2->numberRows();
      stats[1]=model2->numberColumns();
    }
    //printf("rows %d -> %d, columns %d -> %d\n",
    //     modelPtr_->numberRows(),model2->numberRows(),
    //     modelPtr_->numberColumns(),model2->numberColumns());
    // change from 200
    if (modelPtr_->factorization()->maximumPivots()==200)
      model2->factorization()->maximumPivots(100+model2->numberRows()/50);
    else
      model2->factorization()->maximumPivots(userFactorizationFrequency);
    if (algorithm<0) {
      model2->dual();
      totalIterations += model2->numberIterations();
      // check if clp thought it was in a loop
      if (model2->status()==3&&!model2->hitMaximumIterations()) {
	// switch algorithm
	model2->primal();
	totalIterations += model2->numberIterations();
      }
    } else {
      model2->primal(1);
      totalIterations += model2->numberIterations();
      // check if clp thought it was in a loop
      if (model2->status()==3&&!model2->hitMaximumIterations()) {
	// switch algorithm
	model2->dual();
	totalIterations += model2->numberIterations();
      }
    }
    if (model2!=modelPtr_) {
      int finalStatus=model2->status();
      pinfo.postsolve(true);
    
      delete model2;
      // later try without (1) and check duals before solve
      if (finalStatus!=3&&(finalStatus||modelPtr_->status()==-1)) {
        modelPtr_->primal(1);
	totalIterations += modelPtr_->numberIterations();
        lastAlgorithm_=1; // primal
        //if (modelPtr_->numberIterations())
        //printf("****** iterated %d\n",modelPtr_->numberIterations());
      }
    }
  } else {
    //modelPtr_->setLogLevel(63);
    //modelPtr_->setDualTolerance(1.0e-7);
    if (false&&modelPtr_->scalingFlag_>0&&!modelPtr_->rowScale_&&
	!modelPtr_->rowCopy_&&matrixByRow_) {
      assert (matrixByRow_->getNumElements()==modelPtr_->clpMatrix()->getNumElements());
      modelPtr_->setNewRowCopy(new ClpPackedMatrix(*matrixByRow_));
    }
    if (algorithm<0) {
      //writeMps("try1");
      int savePerturbation = modelPtr_->perturbation();
      if ((specialOptions_&2)!=0)
	modelPtr_->setPerturbation(100);
      //modelPtr_->messageHandler()->setLogLevel(1);
      //writeMpsNative("bad",NULL,NULL,2,1,1.0);
      disasterHandler_->setOsiModel(this);
      bool inCbcOrOther = (modelPtr_->specialOptions()&0x03000000)!=0;
#if 0
      // See how many integers fixed
      bool skipCrunch=true;
      const char * integerInformation = modelPtr_->integerType_;
      if (integerInformation) {
	int numberColumns = modelPtr_->numberColumns_;
	const double * lower = modelPtr_->columnLower();
	const double * upper = modelPtr_->columnUpper();
	int target=CoinMax(1,numberColumns/10000);
	for (int i=0;i<numberColumns;i++) {
	  if (integerInformation[i]) {
	    if (lower[i]==upper[i]) {
	      target--;
	      if (!target) {
		skipCrunch=false;
		break;
	      }
	    }
	  }
	}
      }
#endif
      if((specialOptions_&1)==0||(specialOptions_&2048)!=0/*||skipCrunch*/) {
	disasterHandler_->setWhereFrom(0); // dual
	if (inCbcOrOther)
	  modelPtr_->setDisasterHandler(disasterHandler_);
	bool specialScale;
	if ((specialOptions_&131072)!=0&&!modelPtr_->rowScale_) {
	  modelPtr_->rowScale_ = rowScale_.array();
	  modelPtr_->columnScale_ = columnScale_.array();
	  specialScale=true;
	} else {
	  specialScale=false;
	}
#ifdef KEEP_SMALL
	if (smallModel_) {
	  delete [] spareArrays_;
	  spareArrays_ = NULL;
	  delete smallModel_;
	  smallModel_=NULL;
	}
#endif
#ifdef CBC_STATISTICS
	osi_dual++;
#endif 
	modelPtr_->dual(0,startFinishOptions);
	totalIterations += modelPtr_->numberIterations();
	if (specialScale) {
	  modelPtr_->rowScale_ = NULL;
	  modelPtr_->columnScale_ = NULL;
	}
      } else {
#ifdef CBC_STATISTICS
	osi_crunch++;
#endif 
	crunch();
	totalIterations += modelPtr_->numberIterations();
	if (modelPtr_->problemStatus()==4)
	  goto disaster;
	// should have already been fixed if problems
	inCbcOrOther=false;
      }
      if (inCbcOrOther) {
	if(disasterHandler_->inTrouble()) {
	  if (disasterHandler_->typeOfDisaster()) {
	    // We want to abort 
	    abortSearch=true;
	    goto disaster;
	  }
	  // try just going back in
	  disasterHandler_->setPhase(1);
	  modelPtr_->dual();
	  totalIterations += modelPtr_->numberIterations();
	  if (disasterHandler_->inTrouble()) {
	    if (disasterHandler_->typeOfDisaster()) {
	      // We want to abort 
	      abortSearch=true;
	      goto disaster;
	    }
	    // try primal with original basis
	    disasterHandler_->setPhase(2);
	    setBasis(basis_,modelPtr_);
	    modelPtr_->primal();
	    totalIterations += modelPtr_->numberIterations();
	  }
	  if(disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
	    printf("disaster - treat as infeasible\n");
#endif
	    if (disasterHandler_->typeOfDisaster()) {
	      // We want to abort 
	      abortSearch=true;
	      goto disaster;
	    }
	    modelPtr_->setProblemStatus(1);
	  }
	}
	// reset
	modelPtr_->setDisasterHandler(NULL);
      }
      if (modelPtr_->problemStatus()==4) {
	// bad bounds?
	modelPtr_->setProblemStatus(1);
      }
      if (!modelPtr_->problemStatus()&&0) {
        int numberColumns = modelPtr_->numberColumns();
        const double * columnLower = modelPtr_->columnLower();
        const double * columnUpper = modelPtr_->columnUpper();
        int nBad=0;
        for (int i=0;i<numberColumns;i++) {
          if (columnLower[i]==columnUpper[i]&&modelPtr_->getColumnStatus(i)==ClpSimplex::basic) {
            nBad++;
            modelPtr_->setColumnStatus(i,ClpSimplex::isFixed);
          }
        }
        if (nBad) {
          modelPtr_->primal(1);
    totalIterations += modelPtr_->numberIterations();
          printf("%d fixed basic - %d iterations\n",nBad,modelPtr_->numberIterations());
        }
      }
      assert (modelPtr_->objectiveValue()<1.0e100);
      modelPtr_->setPerturbation(savePerturbation);
      lastAlgorithm_=2; // dual
      // check if clp thought it was in a loop
      if (modelPtr_->status()==3&&!modelPtr_->hitMaximumIterations()) {
	modelPtr_->setSpecialOptions(saveOptions);
	// switch algorithm
	//modelPtr_->messageHandler()->setLogLevel(63);
	// Allow for catastrophe
	int saveMax = modelPtr_->maximumIterations();
	int numberIterations = modelPtr_->numberIterations();
	int numberRows = modelPtr_->numberRows();
	int numberColumns = modelPtr_->numberColumns();
	if (modelPtr_->maximumIterations()>100000+numberIterations)
	  modelPtr_->setMaximumIterations(numberIterations + 1000 + 2*numberRows+numberColumns);
	modelPtr_->primal(0,startFinishOptions);
	totalIterations += modelPtr_->numberIterations();
	modelPtr_->setMaximumIterations(saveMax);
	lastAlgorithm_=1; // primal
        if (modelPtr_->status()==3&&!modelPtr_->hitMaximumIterations()) {
#ifdef COIN_DEVELOP
	  printf("in trouble - try all slack\n");
#endif
	  CoinWarmStartBasis allSlack;
	  setBasis(allSlack,modelPtr_);
	  modelPtr_->dual();
	  totalIterations += modelPtr_->numberIterations();
          if (modelPtr_->status()==3&&!modelPtr_->hitMaximumIterations()) {
	    if (modelPtr_->numberPrimalInfeasibilities()) {
#ifdef COIN_DEVELOP
	      printf("Real real trouble - treat as infeasible\n");
#endif
	      modelPtr_->setProblemStatus(1);
	    } else {
#ifdef COIN_DEVELOP
	      printf("Real real trouble - treat as optimal\n");
#endif
	      modelPtr_->setProblemStatus(0);
	    }
	  }
	}
      }
      assert (modelPtr_->objectiveValue()<1.0e100);
    } else {
#ifdef KEEP_SMALL
      if (smallModel_) {
	delete [] spareArrays_;
	spareArrays_ = NULL;
	delete smallModel_;
	smallModel_=NULL;
      }
#endif
      //printf("doing primal\n");
#ifdef CBC_STATISTICS
      osi_primal++;
#endif 
      modelPtr_->primal(1,startFinishOptions);
      totalIterations += modelPtr_->numberIterations();
      lastAlgorithm_=1; // primal
      // check if clp thought it was in a loop
      if (modelPtr_->status()==3&&!modelPtr_->hitMaximumIterations()) {
	// switch algorithm
	modelPtr_->dual();
	totalIterations += modelPtr_->numberIterations();
	lastAlgorithm_=2; // dual
      }
    }
  }
  // If scaled feasible but unscaled infeasible take action
  //if (!modelPtr_->status()&&cleanupScaling_) {
  if (cleanupScaling_) {
    modelPtr_->cleanup(cleanupScaling_);
  }
  basis_ = getBasis(modelPtr_);
 disaster:
  //printf("basis after dual\n");
  //basis_.print();
  modelPtr_->popMessageHandler(saveHandler,oldDefault);
  modelPtr_->messageHandler()->setLogLevel(saveMessageLevel);
  if (saveSolveType==2) {
    int saveStatus = modelPtr_->problemStatus_;
    enableSimplexInterface(doingPrimal);
    modelPtr_->problemStatus_=saveStatus;
  }
#ifdef COIN_DEVELOP_x
  extern bool doingDoneBranch;
  if (doingDoneBranch) {
    if (modelPtr_->numberIterations())
      printf("***** done %d iterations after general\n",modelPtr_->numberIterations());
    doingDoneBranch=false;
  }
#endif
  modelPtr_->setNumberIterations(totalIterations);
  //modelPtr_->setSolveType(saveSolveType);
  if (abortSearch) {
    lastAlgorithm_=-911;
    modelPtr_->setProblemStatus(4);
  }
  if (savedObjective) {
    // fix up
    modelPtr_->dblParam_[ClpDualObjectiveLimit]=savedDualLimit;
    //modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~32));
    modelPtr_->objective_=savedObjective;
    if (!modelPtr_->problemStatus_) {
      CoinZeroN(modelPtr_->dual_,modelPtr_->numberRows_);
      CoinZeroN(modelPtr_->reducedCost_,modelPtr_->numberColumns_);
      if (modelPtr_->dj_&&(modelPtr_->whatsChanged_&1)!=0)
	CoinZeroN(modelPtr_->dj_,modelPtr_->numberColumns_+modelPtr_->numberRows_);
      modelPtr_->computeObjectiveValue();
    }
  }
  modelPtr_->setSpecialOptions(saveOptions); // restore
  if (modelPtr_->problemStatus_==3&&lastAlgorithm_==2)
    modelPtr_->computeObjectiveValue();
  if (lastAlgorithm_<1||lastAlgorithm_>2)
    lastAlgorithm_=1;
#ifdef SAVE_MODEL
  if (resolveTry>=loResolveTry&&
      resolveTry<=hiResolveTry) {
    printf("resolve %d took %d iterations - algorithm %d\n",resolveTry,modelPtr_->numberIterations(),lastAlgorithm_);
  }
#endif
  // Make sure whatsChanged not out of sync
  if (!modelPtr_->columnUpperWork_)
    modelPtr_->whatsChanged_ &= ~0xffff;
  modelPtr_->whatsChanged_ |= 0x30000;
}
// Sort of lexicographic resolve
void 
OsiClpSolverInterface::lexSolve()
{
#if 1
  abort();
#else
  ((ClpSimplexPrimal *) modelPtr_)->lexSolve();
  printf("itA %d\n",modelPtr_->numberIterations());
  modelPtr_->primal();
  printf("itB %d\n",modelPtr_->numberIterations());
  basis_ = getBasis(modelPtr_);
#endif
}

/* Sets up solver for repeated use by Osi interface.
   The normal usage does things like keeping factorization around so can be used.
   Will also do things like keep scaling and row copy of matrix if
   matrix does not change.
   adventure:
   0 - safe stuff as above
   1 - will take more risks - if it does not work then bug which will be fixed
   2 - don't bother doing most extreme termination checks e.g. don't bother
       re-factorizing if less than 20 iterations.
   3 - Actually safer than 1 (mainly just keeps factorization)

   printOut - -1 always skip round common messages instead of doing some work
               0 skip if normal defaults
               1 leaves
  */
void 
OsiClpSolverInterface::setupForRepeatedUse(int senseOfAdventure, int printOut)
{
  // First try
  switch (senseOfAdventure) {
  case 0:
    specialOptions_=8;
    break;
  case 1:
    specialOptions_=1+2+8;
    break;
  case 2:
    specialOptions_=1+2+4+8;
    break;
  case 3:
    specialOptions_=1+8;
    break;
  }
  bool stopPrinting=false;
  if (printOut<0) {
    stopPrinting=true;
  } else if (!printOut) {
    bool takeHint;
    OsiHintStrength strength;
    getHintParam(OsiDoReducePrint,takeHint,strength);
    int messageLevel=messageHandler()->logLevel();
    if (strength!=OsiHintIgnore&&takeHint) 
      messageLevel--;
    stopPrinting = (messageLevel<=0);
  }
#ifndef COIN_DEVELOP
  if (stopPrinting) {
    CoinMessages * messagesPointer = modelPtr_->messagesPointer();
    // won't even build messages 
    messagesPointer->setDetailMessages(100,10000,reinterpret_cast<int *> (NULL));
  }
#endif
}
#ifndef NDEBUG
// For errors to make sure print to screen
// only called in debug mode
static void indexError(int index,
			std::string methodName)
{
  std::cerr<<"Illegal index "<<index<<" in OsiClpSolverInterface::"<<methodName<<std::endl;
  throw CoinError("Illegal index",methodName,"OsiClpSolverInterface");
}
#endif
//#############################################################################
// Parameter related methods
//#############################################################################

bool
OsiClpSolverInterface::setIntParam(OsiIntParam key, int value)
{
  return modelPtr_->setIntParam(static_cast<ClpIntParam> (key), value);
}

//-----------------------------------------------------------------------------

bool
OsiClpSolverInterface::setDblParam(OsiDblParam key, double value)
{
  if (key != OsiLastDblParam ) {
    if (key==OsiDualObjectiveLimit||key==OsiPrimalObjectiveLimit)
      value *= modelPtr_->optimizationDirection();
    return modelPtr_->setDblParam(static_cast<ClpDblParam> (key), value);
  } else {
    return false;
  }
}

//-----------------------------------------------------------------------------

bool
OsiClpSolverInterface::setStrParam(OsiStrParam key, const std::string & value)
{
  assert (key!=OsiSolverName);
  if (key != OsiLastStrParam ) {
    return modelPtr_->setStrParam(static_cast<ClpStrParam> (key), value);
  } else {
    return false;
  }
}


//-----------------------------------------------------------------------------

bool
OsiClpSolverInterface::getIntParam(OsiIntParam key, int& value) const 
{
  return modelPtr_->getIntParam(static_cast<ClpIntParam> (key), value);
}

//-----------------------------------------------------------------------------

bool
OsiClpSolverInterface::getDblParam(OsiDblParam key, double& value) const
{
  if (key != OsiLastDblParam ) {
    bool condition =  modelPtr_->getDblParam(static_cast<ClpDblParam> (key), value);
    if (key==OsiDualObjectiveLimit||key==OsiPrimalObjectiveLimit)
      value *= modelPtr_->optimizationDirection();
    return condition;
  } else {
    return false;
  }
}

//-----------------------------------------------------------------------------

bool
OsiClpSolverInterface::getStrParam(OsiStrParam key, std::string & value) const
{
  if ( key==OsiSolverName ) {
    value = "clp";
    return true;
  }
  if (key != OsiLastStrParam ) {
    return modelPtr_->getStrParam(static_cast<ClpStrParam> (key), value);
  } else {
    return false;
  }
}


//#############################################################################
// Methods returning info on how the solution process terminated
//#############################################################################

bool OsiClpSolverInterface::isAbandoned() const
{
  // not sure about -1 (should not happen)
  return (modelPtr_->status()==4||modelPtr_->status()==-1||
	  (modelPtr_->status()==1&&modelPtr_->secondaryStatus()==8));
}

bool OsiClpSolverInterface::isProvenOptimal() const
{

  const int stat = modelPtr_->status();
  return (stat == 0);
}

bool OsiClpSolverInterface::isProvenPrimalInfeasible() const
{

  const int stat = modelPtr_->status();
  if (stat != 1)
     return false;
  return true;
}

bool OsiClpSolverInterface::isProvenDualInfeasible() const
{
  const int stat = modelPtr_->status();
  return stat == 2;
}
/* 
   NOTE - Coding if limit > 1.0e30 says that 1.0e29 is loose bound
   so all maximization tests are changed 
*/
bool OsiClpSolverInterface::isPrimalObjectiveLimitReached() const
{
  double limit = 0.0;
  modelPtr_->getDblParam(ClpPrimalObjectiveLimit, limit);
  if (fabs(limit) > 1e30) {
    // was not ever set
    return false;
  }
   
  const double obj = modelPtr_->objectiveValue();
  int maxmin = static_cast<int> (modelPtr_->optimizationDirection());

  switch (lastAlgorithm_) {
   case 0: // no simplex was needed
     return maxmin > 0 ? (obj < limit) /*minim*/ : (-obj < limit) /*maxim*/;
   case 2: // dual simplex
     if (modelPtr_->status() == 0) // optimal
	return maxmin > 0 ? (obj < limit) /*minim*/ : (-obj < limit) /*maxim*/;
     return false;
   case 1: // primal simplex
     return maxmin > 0 ? (obj < limit) /*minim*/ : (-obj < limit) /*maxim*/;
  }
  return false; // fake return
}

bool OsiClpSolverInterface::isDualObjectiveLimitReached() const
{

  const int stat = modelPtr_->status();
  if (stat == 1)
  return true;
  double limit = 0.0;
  modelPtr_->getDblParam(ClpDualObjectiveLimit, limit);
  if (fabs(limit) > 1e30) {
    // was not ever set
    return false;
  }
   
  const double obj = modelPtr_->objectiveValue();
  int maxmin = static_cast<int> (modelPtr_->optimizationDirection());

  switch (lastAlgorithm_) {
   case 0: // no simplex was needed
     return maxmin > 0 ? (obj > limit) /*minim*/ : (-obj > limit) /*maxim*/;
   case 1: // primal simplex
     if (stat == 0) // optimal
	return maxmin > 0 ? (obj > limit) /*minim*/ : (-obj > limit) /*maxim*/;
     return false;
   case 2: // dual simplex
     if (stat != 0 && stat != 3)
	// over dual limit
	return true;
     return maxmin > 0 ? (obj > limit) /*minim*/ : (-obj > limit) /*maxim*/;
  }
  return false; // fake return
}

bool OsiClpSolverInterface::isIterationLimitReached() const
{
  const int stat = modelPtr_->status();
  return (stat == 3);
}

//#############################################################################
// WarmStart related methods
//#############################################################################
CoinWarmStart *OsiClpSolverInterface::getEmptyWarmStart () const
  { return (static_cast<CoinWarmStart *>(new CoinWarmStartBasis())) ; }

CoinWarmStart* OsiClpSolverInterface::getWarmStart() const
{

  return new CoinWarmStartBasis(basis_);
}
/* Get warm start information.
   Return warm start information for the current state of the solver
   interface. If there is no valid warm start information, an empty warm
   start object wil be returned.  This does not necessarily create an 
   object - may just point to one.  must Delete set true if user
   should delete returned object.
   OsiClp version always returns pointer and false.
*/
CoinWarmStart* 
OsiClpSolverInterface::getPointerToWarmStart(bool & mustDelete) 
{
  mustDelete = false;
  return &basis_;
}

//-----------------------------------------------------------------------------

bool OsiClpSolverInterface::setWarmStart(const CoinWarmStart* warmstart)
{
  modelPtr_->whatsChanged_ &= 0xffff;
  const CoinWarmStartBasis* ws =
    dynamic_cast<const CoinWarmStartBasis*>(warmstart);
  if (ws) {
    basis_ = CoinWarmStartBasis(*ws);
    return true;
  } else if (!warmstart) {
    // create from current basis
    basis_ = getBasis(modelPtr_);
    return true;
  } else {
    return false;
  }
}

//#############################################################################
// Hotstart related methods (primarily used in strong branching)
//#############################################################################
void OsiClpSolverInterface::markHotStart()
{
#ifdef CBC_STATISTICS
  osi_hot++;
#endif 
  //printf("HotStart options %x changed %x, small %x spare %x\n",
  // specialOptions_,modelPtr_->whatsChanged_,
  // smallModel_,spareArrays_);
  modelPtr_->setProblemStatus(0);
  saveData_.perturbation_=0;
  saveData_.specialOptions_ = modelPtr_->specialOptions_;
  modelPtr_->specialOptions_ |= 0x1000000;
  modelPtr_->specialOptions_ = saveData_.specialOptions_; 
  ClpObjective * savedObjective=NULL;
  double savedDualLimit=modelPtr_->dblParam_[ClpDualObjectiveLimit];
  if (fakeObjective_) {
    modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~128));
    // See if all with costs fixed
    int numberColumns = modelPtr_->numberColumns_;
    const double * obj = modelPtr_->objective();
    const double * lower = modelPtr_->columnLower();
    const double * upper = modelPtr_->columnUpper();
    int i;
    for (i=0;i<numberColumns;i++) {
      double objValue = obj[i];
      if (objValue) {
	if (lower[i]!=upper[i])
	  break;
      }
    }
    if (i==numberColumns) {
      if ((specialOptions_&524288)==0) {
	// Set fake
	savedObjective=modelPtr_->objective_;
	modelPtr_->objective_=fakeObjective_;
	modelPtr_->dblParam_[ClpDualObjectiveLimit]=COIN_DBL_MAX;
	saveData_.perturbation_=1;
      } else {
	modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()|128);
      }
    }
  }
#define CLEAN_HOT_START
#ifdef CLEAN_HOT_START
  if ((specialOptions_&65536)!=0) {
    //specialOptions_ |= 65536;
    saveData_.scalingFlag_=modelPtr_->logLevel();
    if (modelPtr_->logLevel()<2)
      modelPtr_->setLogLevel(0);
    assert ((specialOptions_&128)==0);
    // space for save arrays
    int numberColumns = modelPtr_->numberColumns();
    int numberRows = modelPtr_->numberRows();
    // Get space for strong branching 
    int size = static_cast<int>((1+4*(numberRows+numberColumns))*sizeof(double));
    // and for save of original column bounds
    size += static_cast<int>(2*numberColumns*sizeof(double));
    size += static_cast<int>((1+4*numberRows+2*numberColumns)*sizeof(int));
    size += numberRows+numberColumns;
    assert (spareArrays_==NULL);
    spareArrays_ = new char[size];
    //memset(spareArrays_,0x20,size);
    // Setup for strong branching
    assert (factorization_==NULL);
    if ((specialOptions_&131072)!=0) {
      assert (lastNumberRows_>=0);
      if (modelPtr_->rowScale_!=rowScale_.array()) {
	assert(modelPtr_->columnScale_!=columnScale_.array());
	delete [] modelPtr_->rowScale_;
	modelPtr_->rowScale_=NULL;
	delete [] modelPtr_->columnScale_;
	modelPtr_->columnScale_=NULL;
	if (lastNumberRows_==modelPtr_->numberRows()) {
	  // use scaling
	  modelPtr_->rowScale_ = rowScale_.array();
	  modelPtr_->columnScale_ = columnScale_.array();
	} else {
	  specialOptions_ &= ~131072;
	}
      }
      lastNumberRows_ = -1 -lastNumberRows_;
    }
    factorization_ = static_cast<ClpSimplexDual *>(modelPtr_)->setupForStrongBranching(spareArrays_,numberRows,
										       numberColumns,true);
    double * arrayD = reinterpret_cast<double *> (spareArrays_);
    arrayD[0]=modelPtr_->objectiveValue()* modelPtr_->optimizationDirection();
    double * saveSolution = arrayD+1;
    double * saveLower = saveSolution + (numberRows+numberColumns);
    double * saveUpper = saveLower + (numberRows+numberColumns);
    double * saveObjective = saveUpper + (numberRows+numberColumns);
    double * saveLowerOriginal = saveObjective + (numberRows+numberColumns);
    double * saveUpperOriginal = saveLowerOriginal + numberColumns;
    CoinMemcpyN( modelPtr_->columnLower(),numberColumns, saveLowerOriginal);
    CoinMemcpyN( modelPtr_->columnUpper(),numberColumns, saveUpperOriginal);
#if 0
    if (whichRange_&&whichRange_[0]) {
      // get ranging information
      int numberToDo = whichRange_[0];
      int * which = new int [numberToDo];
      // Convert column numbers
      int * backColumn = whichColumn+numberColumns;
      for (int i=0;i<numberToDo;i++) {
	int iColumn = whichRange_[i+1];
	which[i]=backColumn[iColumn];
      }
      double * downRange=new double [numberToDo];
      double * upRange=new double [numberToDo];
      int * whichDown = new int [numberToDo];
      int * whichUp = new int [numberToDo];
      modelPtr_->gutsOfSolution(NULL,NULL,false);
      // Tell code we can increase costs in some cases
      modelPtr_->setCurrentDualTolerance(0.0);
      ((ClpSimplexOther *) modelPtr_)->dualRanging(numberToDo,which,
						   upRange, whichUp, downRange, whichDown);
      delete [] whichDown;
      delete [] whichUp;
      delete [] which;
      rowActivity_=upRange;
      columnActivity_=downRange;
    }
#endif 
    if (savedObjective) {
      // fix up
      modelPtr_->dblParam_[ClpDualObjectiveLimit]=savedDualLimit;
      //modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~32));
      modelPtr_->objective_=savedObjective;
      if (!modelPtr_->problemStatus_) {
	CoinZeroN(modelPtr_->dual_,modelPtr_->numberRows_);
	CoinZeroN(modelPtr_->reducedCost_,modelPtr_->numberColumns_);
	if (modelPtr_->dj_&&(modelPtr_->whatsChanged_&1)!=0)
	  CoinZeroN(modelPtr_->dj_,modelPtr_->numberColumns_+modelPtr_->numberRows_);
	modelPtr_->computeObjectiveValue();
      }
    }
    return;
  }
#endif
  if ((specialOptions_&8192)==0&&false) { // ||(specialOptions_&65536)!=0) {
    delete ws_;
    ws_ = dynamic_cast<CoinWarmStartBasis*>(getWarmStart());
    int numberRows = modelPtr_->numberRows();
    rowActivity_= new double[numberRows];
    CoinMemcpyN(modelPtr_->primalRowSolution(),numberRows,rowActivity_);
    int numberColumns = modelPtr_->numberColumns();
    columnActivity_= new double[numberColumns];
    CoinMemcpyN(modelPtr_->primalColumnSolution(),numberColumns,columnActivity_);
  } else {
#if 0
    int saveLevel = modelPtr_->logLevel();
    modelPtr_->setLogLevel(0);
    //modelPtr_->dual();
    OsiClpSolverInterface::resolve();
    if (modelPtr_->numberIterations()>0)
      printf("**** iterated large %d\n",modelPtr_->numberIterations());
    //else
    //printf("no iterations\n");
    modelPtr_->setLogLevel(saveLevel);
#endif
    // called from CbcNode
    int numberColumns = modelPtr_->numberColumns();
    int numberRows = modelPtr_->numberRows();
    // Get space for crunch and strong branching (too much)
    int size = static_cast<int>((1+4*(numberRows+numberColumns))*sizeof(double));
    // and for save of original column bounds
    size += static_cast<int>(2*numberColumns*sizeof(double));
    size += static_cast<int>((1+4*numberRows+2*numberColumns)*sizeof(int));
    size += numberRows+numberColumns;
#ifdef KEEP_SMALL
    if(smallModel_&&(modelPtr_->whatsChanged_&0x30000)!=0x30000) {
      //printf("Bounds changed ? %x\n",modelPtr_->whatsChanged_);
      delete smallModel_;
      smallModel_=NULL;
    }
    if (!smallModel_) {
      delete [] spareArrays_;
      spareArrays_ = NULL;
    }
#endif
    if (spareArrays_==NULL) {
      //if (smallModel_)
      //printf("small model %x\n",smallModel_);
      delete smallModel_;
      smallModel_=NULL;
      spareArrays_ = new char[size];
      //memset(spareArrays_,0x20,size);
    } else {
      double * arrayD = reinterpret_cast<double *> (spareArrays_);
      double * saveSolution = arrayD+1;
      double * saveLower = saveSolution + (numberRows+numberColumns);
      double * saveUpper = saveLower + (numberRows+numberColumns);
      double * saveObjective = saveUpper + (numberRows+numberColumns);
      double * saveLowerOriginal = saveObjective + (numberRows+numberColumns);
      double * saveUpperOriginal = saveLowerOriginal + numberColumns;
      double * lowerOriginal = modelPtr_->columnLower();
      double * upperOriginal = modelPtr_->columnUpper();
      arrayD = saveUpperOriginal + numberColumns;
      int * savePivot = reinterpret_cast<int *> (arrayD);
      int * whichRow = savePivot+numberRows;
      int * whichColumn = whichRow + 3*numberRows;
      int nSame=0;
      int nSub=0;
      for (int i=0;i<numberColumns;i++) {
	double lo = lowerOriginal[i];
	//char * xx = (char *) (saveLowerOriginal+i);
	//assert (xx[0]!=0x20||xx[1]!=0x20);
	//xx = (char *) (saveUpperOriginal+i);
	//assert (xx[0]!=0x20||xx[1]!=0x20);
	double loOld = saveLowerOriginal[i];
	//assert (!loOld||fabs(loOld)>1.0e-30);
	double up = upperOriginal[i];
	double upOld = saveUpperOriginal[i];
	if (lo>=loOld&&up<=upOld) {
	  if (lo==loOld&&up==upOld) {
	    nSame++;
	  } else {
	    nSub++;
	    //if (!isInteger(i))
	    //nSub+=10;
	  }
	}
      }
      //printf("Mark Hot %d bounds same, %d interior, %d bad\n",
      //     nSame,nSub,numberColumns-nSame-nSub);
      if (nSame<numberColumns) {
	if (nSame+nSub<numberColumns) {
	  delete smallModel_;
	  smallModel_=NULL;
	} else {
	  // we can fix up (but should we if large number fixed?)
	  assert (smallModel_);
	  double * lowerSmall = smallModel_->columnLower();
	  double * upperSmall = smallModel_->columnUpper();
	  int numberColumns2 = smallModel_->numberColumns();
	  for (int i=0;i<numberColumns2;i++) {
	    int iColumn = whichColumn[i];
	    lowerSmall[i]=lowerOriginal[iColumn];
	    upperSmall[i]=upperOriginal[iColumn];
	  }
	}
      }
    }
    double * arrayD = reinterpret_cast<double *> (spareArrays_);
    arrayD[0]=modelPtr_->objectiveValue()* modelPtr_->optimizationDirection();
    double * saveSolution = arrayD+1;
    double * saveLower = saveSolution + (numberRows+numberColumns);
    double * saveUpper = saveLower + (numberRows+numberColumns);
    double * saveObjective = saveUpper + (numberRows+numberColumns);
    double * saveLowerOriginal = saveObjective + (numberRows+numberColumns);
    double * saveUpperOriginal = saveLowerOriginal + numberColumns;
    arrayD = saveUpperOriginal + numberColumns;
    int * savePivot = reinterpret_cast<int *> (arrayD);
    int * whichRow = savePivot+numberRows;
    int * whichColumn = whichRow + 3*numberRows;
    int * arrayI = whichColumn + 2*numberColumns;
    //unsigned char * saveStatus = (unsigned char *) (arrayI+1);
    // Use dual region
    double * rhs = modelPtr_->dualRowSolution();
    int nBound=0;
    ClpSimplex * small;
#ifndef KEEP_SMALL
    assert (!smallModel_);
    small = static_cast<ClpSimplexOther *> (modelPtr_)->crunch(rhs,whichRow,whichColumn,nBound,true);
    bool needSolveInSetupHotStart=true;
#else
    bool needSolveInSetupHotStart=true;
    if (!smallModel_) {
#ifndef NDEBUG
      CoinFillN(whichRow,3*numberRows+2*numberColumns,-1);
#endif
      small = static_cast<ClpSimplexOther *> (modelPtr_)->crunch(rhs,whichRow,whichColumn,nBound,true);
#ifndef NDEBUG
      int nCopy = 3*numberRows+2*numberColumns;
      for (int i=0;i<nCopy;i++)
	assert (whichRow[i]>=-CoinMax(numberRows,numberColumns)&&whichRow[i]<CoinMax(numberRows,numberColumns));
#endif
      smallModel_=small;
      //int hotIts = small->intParam_[ClpMaxNumIterationHotStart];
      //if (5*small->factorization_->maximumPivots()>
      //  4*hotIts)
      //small->factorization_->maximumPivots(hotIts+1);
    } else {
      assert((modelPtr_->whatsChanged_&0x30000)==0x30000);
      //delete [] spareArrays_;
      //spareArrays_ = NULL;
      assert (spareArrays_);
      int nCopy = 3*numberRows+2*numberColumns;
      nBound = whichRow[nCopy];
#ifndef NDEBUG
      for (int i=0;i<nCopy;i++)
	assert (whichRow[i]>=-CoinMax(numberRows,numberColumns)&&whichRow[i]<CoinMax(numberRows,numberColumns));
#endif
      needSolveInSetupHotStart=false;
      small = smallModel_;
    }
#endif
    if (small) {
      small->specialOptions_ |= 262144;
      small->specialOptions_ &= ~65536;
    }
    if (small&&(specialOptions_&131072)!=0) {
      assert (lastNumberRows_>=0);
      int numberRows2 = small->numberRows();
      int numberColumns2 = small->numberColumns();
      double * rowScale2 = new double [2*numberRows2];
      const double * rowScale = rowScale_.array();
      double * inverseScale2 = rowScale2+numberRows2;
      const double * inverseScale = rowScale+modelPtr_->numberRows_;
      int i;
      for (i=0;i<numberRows2;i++) {
	int iRow = whichRow[i];
	rowScale2[i]=rowScale[iRow];
	inverseScale2[i]=inverseScale[iRow];
      }
      small->setRowScale(rowScale2);
      double * columnScale2 = new double [2*numberColumns2];
      const double * columnScale = columnScale_.array();
      inverseScale2 = columnScale2+numberColumns2;
      inverseScale = columnScale+modelPtr_->numberColumns_;
      for (i=0;i<numberColumns2;i++) {
	int iColumn = whichColumn[i];
	columnScale2[i]=columnScale[iColumn];
	inverseScale2[i]=inverseScale[iColumn];
      }
      small->setColumnScale(columnScale2);
    }
    if (!small) {
      // should never be infeasible .... but
      delete [] spareArrays_;
      spareArrays_=NULL;
      delete ws_;
      ws_ = dynamic_cast<CoinWarmStartBasis*>(getWarmStart());
      int numberRows = modelPtr_->numberRows();
      rowActivity_= new double[numberRows];
      CoinMemcpyN(modelPtr_->primalRowSolution(),numberRows,rowActivity_);
      int numberColumns = modelPtr_->numberColumns();
      columnActivity_= new double[numberColumns];
      CoinMemcpyN(modelPtr_->primalColumnSolution(),numberColumns,columnActivity_);
      modelPtr_->setProblemStatus(1);
      if (savedObjective) {
	// fix up
	modelPtr_->dblParam_[ClpDualObjectiveLimit]=savedDualLimit;
	//modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~32));
	modelPtr_->objective_=savedObjective;
      }
      return;
    }
    int clpOptions = modelPtr_->specialOptions();
    clpOptions &= ~65536;
    if((specialOptions_&1)==0) {
      small->setSpecialOptions(clpOptions|(64|1024));
    } else {
      if((specialOptions_&4)==0) 
        small->setSpecialOptions(clpOptions|(64|128|512|1024|4096));
      else
        small->setSpecialOptions(clpOptions|(64|128|512|1024|2048|4096));
    }
    arrayI[0]=nBound;
    assert (smallModel_==NULL||small==smallModel_);
    if ((specialOptions_&256)!=0||1) {
      // only need to do this on second pass in CbcNode
      if (modelPtr_->logLevel()<2) small->setLogLevel(0);
      small->specialOptions_ |= 262144;
      small->moreSpecialOptions_ = modelPtr_->moreSpecialOptions_;
#define SETUP_HOT
#ifndef SETUP_HOT
      small->dual();
#else
      assert (factorization_==NULL);
      //needSolveInSetupHotStart=true;
      ClpFactorization * factorization = static_cast<ClpSimplexDual *>(small)->setupForStrongBranching(spareArrays_,
		       numberRows,numberColumns,
												       needSolveInSetupHotStart);
#endif
      if (small->numberIterations()>0&&small->logLevel()>2)
	printf("**** iterated small %d\n",small->numberIterations());
      //small->setLogLevel(0);
      // Could be infeasible if forced one way (and other way stopped on iterations)
      if (small->status()==1) {
#ifndef KEEP_SMALL
	if (small!=modelPtr_)
	  delete small;
	//delete smallModel_;
	//smallModel_=NULL;
	assert (!smallModel_);
#else
	assert (small==smallModel_);
	if (smallModel_!=modelPtr_) {
	  delete smallModel_;
	}
	smallModel_=NULL;
#endif
	delete [] spareArrays_;
	spareArrays_=NULL;
	delete ws_;
	ws_ = dynamic_cast<CoinWarmStartBasis*>(getWarmStart());
	int numberRows = modelPtr_->numberRows();
	rowActivity_= new double[numberRows];
 CoinMemcpyN(modelPtr_->primalRowSolution(),	numberRows,rowActivity_);
	int numberColumns = modelPtr_->numberColumns();
	columnActivity_= new double[numberColumns];
 CoinMemcpyN(modelPtr_->primalColumnSolution(),	numberColumns,columnActivity_);
	modelPtr_->setProblemStatus(1);
	if (savedObjective) {
	  // fix up
	  modelPtr_->dblParam_[ClpDualObjectiveLimit]=savedDualLimit;
	  //modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~32));
	  modelPtr_->objective_=savedObjective;
	}
	return;
      } else {
	// update model
	static_cast<ClpSimplexOther *> (modelPtr_)->afterCrunch(*small,whichRow,whichColumn,nBound);
      } 
#ifndef SETUP_HOT
      assert (factorization_==NULL);
      factorization_ = static_cast<ClpSimplexDual *>(small)->setupForStrongBranching(spareArrays_,numberRows,
			     numberColumns,false);
#else
      assert (factorization!=NULL);
      factorization_ = factorization;
#endif
    } else {
      assert (factorization_==NULL);
      factorization_ = static_cast<ClpSimplexDual *>(small)->setupForStrongBranching(spareArrays_,numberRows,
										     numberColumns,false);
    }
    smallModel_=small;
    if (modelPtr_->logLevel()<2) smallModel_->setLogLevel(0);
    // Setup for strong branching
    int numberColumns2 = smallModel_->numberColumns();
    CoinMemcpyN( modelPtr_->columnLower(),numberColumns, saveLowerOriginal);
    CoinMemcpyN( modelPtr_->columnUpper(),numberColumns, saveUpperOriginal);
    const double * smallLower = smallModel_->columnLower();
    const double * smallUpper = smallModel_->columnUpper();
    // But modify if bounds changed in small
    for (int i=0;i<numberColumns2;i++) {
      int iColumn = whichColumn[i];
      saveLowerOriginal[iColumn] = CoinMax(saveLowerOriginal[iColumn],
					   smallLower[i]);
      saveUpperOriginal[iColumn] = CoinMin(saveUpperOriginal[iColumn],
					   smallUpper[i]);
    }
    if (whichRange_&&whichRange_[0]) {
      // get ranging information
      int numberToDo = whichRange_[0];
      int * which = new int [numberToDo];
      // Convert column numbers
      int * backColumn = whichColumn+numberColumns;
      for (int i=0;i<numberToDo;i++) {
        int iColumn = whichRange_[i+1];
        which[i]=backColumn[iColumn];
      }
      double * downRange=new double [numberToDo];
      double * upRange=new double [numberToDo];
      int * whichDown = new int [numberToDo];
      int * whichUp = new int [numberToDo];
      smallModel_->setFactorization(*factorization_);
      smallModel_->gutsOfSolution(NULL,NULL,false);
      // Tell code we can increase costs in some cases
      smallModel_->setCurrentDualTolerance(0.0);
      static_cast<ClpSimplexOther *> (smallModel_)->dualRanging(numberToDo,which,
                         upRange, whichUp, downRange, whichDown);
      delete [] whichDown;
      delete [] whichUp;
      delete [] which;
      rowActivity_=upRange;
      columnActivity_=downRange;
    }
  }
    if (savedObjective) {
      // fix up
      modelPtr_->dblParam_[ClpDualObjectiveLimit]=savedDualLimit;
      //modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~32));
      modelPtr_->objective_=savedObjective;
      if (!modelPtr_->problemStatus_) {
	CoinZeroN(modelPtr_->dual_,modelPtr_->numberRows_);
	CoinZeroN(modelPtr_->reducedCost_,modelPtr_->numberColumns_);
	if (modelPtr_->dj_&&(modelPtr_->whatsChanged_&1)!=0)
	  CoinZeroN(modelPtr_->dj_,modelPtr_->numberColumns_+modelPtr_->numberRows_);
	modelPtr_->computeObjectiveValue();
      }
    }
}

void OsiClpSolverInterface::solveFromHotStart()
{
#ifdef KEEP_SMALL
  if (!spareArrays_) {
    assert (!smallModel_);
    assert (modelPtr_->problemStatus_==1);
    return;
  }
#endif
  ClpObjective * savedObjective=NULL;
  double savedDualLimit=modelPtr_->dblParam_[ClpDualObjectiveLimit];
  if (saveData_.perturbation_) {
    // Set fake
    savedObjective=modelPtr_->objective_;
    modelPtr_->objective_=fakeObjective_;
    modelPtr_->dblParam_[ClpDualObjectiveLimit]=COIN_DBL_MAX;
  }
  int numberRows = modelPtr_->numberRows();
  int numberColumns = modelPtr_->numberColumns();
  modelPtr_->getIntParam(ClpMaxNumIteration,itlimOrig_);
  int itlim;
  modelPtr_->getIntParam(ClpMaxNumIterationHotStart, itlim);
  // Is there an extra copy of scaled bounds
  int extraCopy = (modelPtr_->maximumRows_>0) ? modelPtr_->maximumRows_+modelPtr_->maximumColumns_ : 0; 
#ifdef CLEAN_HOT_START
  if ((specialOptions_&65536)!=0) {
    double * arrayD = reinterpret_cast<double *> (spareArrays_);
    double saveObjectiveValue = arrayD[0];
    double * saveSolution = arrayD+1;
    int number = numberRows+numberColumns;
    CoinMemcpyN(saveSolution,number,modelPtr_->solutionRegion());
    double * saveLower = saveSolution + (numberRows+numberColumns);
    CoinMemcpyN(saveLower,number,modelPtr_->lowerRegion());
    double * saveUpper = saveLower + (numberRows+numberColumns);
    CoinMemcpyN(saveUpper,number,modelPtr_->upperRegion());
    double * saveObjective = saveUpper + (numberRows+numberColumns);
    CoinMemcpyN(saveObjective,number,modelPtr_->costRegion());
    double * saveLowerOriginal = saveObjective + (numberRows+numberColumns);
    double * saveUpperOriginal = saveLowerOriginal + numberColumns;
    arrayD = saveUpperOriginal + numberColumns;
    int * savePivot = reinterpret_cast<int *> (arrayD);
    CoinMemcpyN(savePivot,numberRows,modelPtr_->pivotVariable());
    int * whichRow = savePivot+numberRows;
    int * whichColumn = whichRow + 3*numberRows;
    int * arrayI = whichColumn + 2*numberColumns;
    unsigned char * saveStatus = reinterpret_cast<unsigned char *> (arrayI+1);
    CoinMemcpyN(saveStatus,number,modelPtr_->statusArray());
    modelPtr_->setFactorization(*factorization_);
    double * columnLower = modelPtr_->columnLower();
    double * columnUpper = modelPtr_->columnUpper();
    // make sure whatsChanged_ has 1 set
    modelPtr_->setWhatsChanged(511);
    double * lowerInternal = modelPtr_->lowerRegion();
    double * upperInternal = modelPtr_->upperRegion();
    double rhsScale = modelPtr_->rhsScale();
    const double * columnScale = NULL;
    if (modelPtr_->scalingFlag()>0) 
      columnScale = modelPtr_->columnScale() ;
    // and do bounds in case dual needs them
    int iColumn;
    for (iColumn=0;iColumn<numberColumns;iColumn++) {
      if (columnLower[iColumn]>saveLowerOriginal[iColumn]) {
	double value = columnLower[iColumn];
	value *= rhsScale;
	if (columnScale)
	  value /= columnScale[iColumn];
	lowerInternal[iColumn]=value;
	if (extraCopy)
	  lowerInternal[iColumn+extraCopy]=value;
      }
      if (columnUpper[iColumn]<saveUpperOriginal[iColumn]) {
	double value = columnUpper[iColumn];
	value *= rhsScale;
	if (columnScale)
	  value /= columnScale[iColumn];
	upperInternal[iColumn]=value;
	if (extraCopy)
	  upperInternal[iColumn+extraCopy]=value;
      }
    }
    // Start of fast iterations
    bool alwaysFinish= ((specialOptions_&32)==0) ? true : false;
    //modelPtr_->setLogLevel(1);
    modelPtr_->setIntParam(ClpMaxNumIteration,itlim);
    int saveNumberFake = (static_cast<ClpSimplexDual *>(modelPtr_))->numberFake_;
    int status = (static_cast<ClpSimplexDual *>(modelPtr_))->fastDual(alwaysFinish);
    (static_cast<ClpSimplexDual *>(modelPtr_))->numberFake_ = saveNumberFake;
    
    int problemStatus = modelPtr_->problemStatus();
    double objectiveValue =modelPtr_->objectiveValue() * modelPtr_->optimizationDirection();
    CoinAssert (modelPtr_->problemStatus()||modelPtr_->objectiveValue()<1.0e50);
    // make sure plausible
    double obj = CoinMax(objectiveValue,saveObjectiveValue);
    if (problemStatus==10||problemStatus<0) {
      // was trying to clean up or something odd
      if (problemStatus==10)
	lastAlgorithm_=1; // so won't fail on cutoff (in CbcNode)
      status=1;
    }
    if (status) {
      // not finished - might be optimal
      modelPtr_->checkPrimalSolution(modelPtr_->solutionRegion(0),
                                     modelPtr_->solutionRegion(1));
      //modelPtr_->gutsOfSolution(NULL,NULL,0);
      //if (problemStatus==3)
      //modelPtr_->computeObjectiveValue();
      objectiveValue =modelPtr_->objectiveValue() *
	modelPtr_->optimizationDirection();
      obj = CoinMax(objectiveValue,saveObjectiveValue);
      if (!modelPtr_->numberDualInfeasibilities()) { 
	double limit = 0.0;
	modelPtr_->getDblParam(ClpDualObjectiveLimit, limit);
	if (modelPtr_->secondaryStatus()==1&&!problemStatus&&obj<limit) {
	  obj=limit;
	  problemStatus=3;
	}
	if (!modelPtr_->numberPrimalInfeasibilities()&&obj<limit) { 
	  problemStatus=0;
	} else if (problemStatus==10) {
	  problemStatus=3;
	} else if (!modelPtr_->numberPrimalInfeasibilities()) {
	  problemStatus=1; // infeasible
	} 
      } else {
	// can't say much
	//if (problemStatus==3)
	//modelPtr_->computeObjectiveValue();
	lastAlgorithm_=1; // so won't fail on cutoff (in CbcNode)
	problemStatus=3;
      }
    } else if (!problemStatus) {
      if (modelPtr_->isDualObjectiveLimitReached()) 
	problemStatus=1; // infeasible
    }
    if (status&&!problemStatus) {
      problemStatus=3; // can't be sure
      lastAlgorithm_=1;
    }
    if (problemStatus<0)
      problemStatus=3;
    modelPtr_->setProblemStatus(problemStatus);
    modelPtr_->setObjectiveValue(obj*modelPtr_->optimizationDirection());
    double * solution = modelPtr_->primalColumnSolution();
    const double * solution2 = modelPtr_->solutionRegion();
    // could just do changed bounds - also try double size scale so can use * not /
    if (!columnScale) {
      for (iColumn=0;iColumn<numberColumns;iColumn++) {
	solution[iColumn]= solution2[iColumn];
      }
    } else {
      for (iColumn=0;iColumn<numberColumns;iColumn++) {
	solution[iColumn]= solution2[iColumn]*columnScale[iColumn];
      }
    }
    CoinMemcpyN(saveLowerOriginal,numberColumns,columnLower);
    CoinMemcpyN(saveUpperOriginal,numberColumns,columnUpper);
#if 0
    // could combine with loop above
    if (modelPtr_==modelPtr_)
      modelPtr_->computeObjectiveValue();
    if (status&&!problemStatus) {
      memset(modelPtr_->primalRowSolution(),0,numberRows*sizeof(double));
      modelPtr_->clpMatrix()->times(1.0,solution,modelPtr_->primalRowSolution());
      modelPtr_->checkSolutionInternal();
      //modelPtr_->setLogLevel(1);
      //modelPtr_->allSlackBasis();
      //modelPtr_->primal(1);
      //memset(modelPtr_->primalRowSolution(),0,numberRows*sizeof(double));
      //modelPtr_->clpMatrix()->times(1.0,solution,modelPtr_->primalRowSolution());
      //modelPtr_->checkSolutionInternal();
      assert (!modelPtr_->problemStatus());
    }
#endif
    // and back bounds
    CoinMemcpyN(saveLower,number,modelPtr_->lowerRegion());
    CoinMemcpyN(saveUpper,number,modelPtr_->upperRegion());
    if (extraCopy) {
      CoinMemcpyN(saveLower,number,modelPtr_->lowerRegion()+extraCopy);
      CoinMemcpyN(saveUpper,number,modelPtr_->upperRegion()+extraCopy);
    }
    modelPtr_->setIntParam(ClpMaxNumIteration,itlimOrig_);
    if (savedObjective) {
      // fix up
      modelPtr_->dblParam_[ClpDualObjectiveLimit]=savedDualLimit;
      //modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~32));
      modelPtr_->objective_=savedObjective;
      if (!modelPtr_->problemStatus_) {
	CoinZeroN(modelPtr_->dual_,modelPtr_->numberRows_);
	CoinZeroN(modelPtr_->reducedCost_,modelPtr_->numberColumns_);
	if (modelPtr_->dj_&&(modelPtr_->whatsChanged_&1)!=0)
	  CoinZeroN(modelPtr_->dj_,modelPtr_->numberColumns_+modelPtr_->numberRows_);
	modelPtr_->computeObjectiveValue();
      }
    }
    return;
  }
#endif
  if (smallModel_==NULL) {
    setWarmStart(ws_);
    CoinMemcpyN(           rowActivity_,numberRows,modelPtr_->primalRowSolution());
    CoinMemcpyN(columnActivity_,numberColumns,modelPtr_->primalColumnSolution());
    modelPtr_->setIntParam(ClpMaxNumIteration,CoinMin(itlim,9999));
    resolve();
  } else {
    assert (spareArrays_);
    double * arrayD = reinterpret_cast<double *> (spareArrays_);
    double saveObjectiveValue = arrayD[0];
    double * saveSolution = arrayD+1;
    int numberRows2 = smallModel_->numberRows();
    int numberColumns2 = smallModel_->numberColumns();
    int number = numberRows2+numberColumns2;
    CoinMemcpyN(saveSolution,number,smallModel_->solutionRegion());
    double * saveLower = saveSolution + (numberRows+numberColumns);
    CoinMemcpyN(saveLower,number,smallModel_->lowerRegion());
    double * saveUpper = saveLower + (numberRows+numberColumns);
    CoinMemcpyN(saveUpper,number,smallModel_->upperRegion());
    double * saveObjective = saveUpper + (numberRows+numberColumns);
    CoinMemcpyN(saveObjective,number,smallModel_->costRegion());
    double * saveLowerOriginal = saveObjective + (numberRows+numberColumns);
    double * saveUpperOriginal = saveLowerOriginal + numberColumns;
    arrayD = saveUpperOriginal + numberColumns;
    int * savePivot = reinterpret_cast<int *> (arrayD);
    CoinMemcpyN(savePivot,numberRows2,smallModel_->pivotVariable());
    int * whichRow = savePivot+numberRows;
    int * whichColumn = whichRow + 3*numberRows;
    int * arrayI = whichColumn + 2*numberColumns;
    unsigned char * saveStatus = reinterpret_cast<unsigned char *> (arrayI+1);
    CoinMemcpyN(saveStatus,number,smallModel_->statusArray());
    smallModel_->setFactorization(*factorization_);
    //int * backColumn = whichColumn+numberColumns;
    const double * lowerBig = modelPtr_->columnLower();
    const double * upperBig = modelPtr_->columnUpper();
    // make sure whatsChanged_ has 1 set
    smallModel_->setWhatsChanged(511);
    double * lowerSmall = smallModel_->lowerRegion();
    double * upperSmall = smallModel_->upperRegion();
    double * lowerSmallReal = smallModel_->columnLower();
    double * upperSmallReal = smallModel_->columnUpper();
    int i;
    double rhsScale = smallModel_->rhsScale();
    const double * columnScale = NULL;
    if (smallModel_->scalingFlag()>0) {
      columnScale = smallModel_->columnScale();
    }
    // and do bounds in case dual needs them
    // may be infeasible
    for (i=0;i<numberColumns2;i++) {
      int iColumn = whichColumn[i];
      if (lowerBig[iColumn]>saveLowerOriginal[iColumn]) {
        double value = lowerBig[iColumn];
        lowerSmallReal[i]=value;
        value *= rhsScale;
        if (columnScale)
          value /= columnScale[i];
        lowerSmall[i]=value;
      }
      if (upperBig[iColumn]<saveUpperOriginal[iColumn]) {
        double value = upperBig[iColumn];
        upperSmallReal[i]=value;
        value *= rhsScale;
        if (columnScale)
          value /= columnScale[i];
        upperSmall[i]=value;
      }
      if (upperSmall[i]<lowerSmall[i]-1.0e-8)
	break;
    }
    bool infeasible = (i<numberColumns2);
    // Start of fast iterations
    bool alwaysFinish= ((specialOptions_&32)==0) ? true : false;
    //smallModel_->setLogLevel(1);
    smallModel_->setIntParam(ClpMaxNumIteration,itlim);
    int saveNumberFake = (static_cast<ClpSimplexDual *>(smallModel_))->numberFake_;
    int status;
    if (!infeasible) {
      status = static_cast<ClpSimplexDual *>(smallModel_)->fastDual(alwaysFinish);
    } else {
      status=0;
      smallModel_->setProblemStatus(1);
    }
    (static_cast<ClpSimplexDual *>(smallModel_))->numberFake_ = saveNumberFake;
    if (smallModel_->numberIterations()==-98) {
      printf("rrrrrrrrrrrr\n");
      smallModel_->checkPrimalSolution(smallModel_->solutionRegion(0),
                                     smallModel_->solutionRegion(1));
      //smallModel_->gutsOfSolution(NULL,NULL,0);
      //if (problemStatus==3)
      //smallModel_->computeObjectiveValue();
      printf("robj %g\n",smallModel_->objectiveValue() *
	     modelPtr_->optimizationDirection());
      writeMps("rr.mps");
      smallModel_->writeMps("rr_small.mps");
      ClpSimplex temp = *smallModel_;
      printf("small\n");
      temp.setLogLevel(63);
      temp.dual();
      double limit = 0.0;
      modelPtr_->getDblParam(ClpDualObjectiveLimit, limit);
      if (temp.problemStatus()==0&&temp.objectiveValue()<limit) {
	printf("inf obj %g, true %g - offsets %g %g\n",smallModel_->objectiveValue(),
	       temp.objectiveValue(),
	       smallModel_->objectiveOffset(),temp.objectiveOffset());
      }
      printf("big\n");
      temp = *modelPtr_;
      temp.dual();
      if (temp.problemStatus()==0&&temp.objectiveValue()<limit) {
	printf("inf obj %g, true %g - offsets %g %g\n",smallModel_->objectiveValue(),
	       temp.objectiveValue(),
	       smallModel_->objectiveOffset(),temp.objectiveOffset());
      }
    }
    int problemStatus = smallModel_->problemStatus();
    double objectiveValue =smallModel_->objectiveValue() * modelPtr_->optimizationDirection();
    CoinAssert (smallModel_->problemStatus()||smallModel_->objectiveValue()<1.0e50);
    // make sure plausible
    double obj = CoinMax(objectiveValue,saveObjectiveValue);
    if (problemStatus==10||problemStatus<0) {
      // was trying to clean up or something odd
      if (problemStatus==10)
        lastAlgorithm_=1; // so won't fail on cutoff (in CbcNode)
      status=1;
    }
    if (status) {
      // not finished - might be optimal
      smallModel_->checkPrimalSolution(smallModel_->solutionRegion(0),
                                     smallModel_->solutionRegion(1));
      //smallModel_->gutsOfSolution(NULL,NULL,0);
      //if (problemStatus==3)
      //smallModel_->computeObjectiveValue();
      objectiveValue =smallModel_->objectiveValue() *
        modelPtr_->optimizationDirection();
      if (problemStatus!=10)
	obj = CoinMax(objectiveValue,saveObjectiveValue);
      if (!smallModel_->numberDualInfeasibilities()) { 
        double limit = 0.0;
        modelPtr_->getDblParam(ClpDualObjectiveLimit, limit);
        if (smallModel_->secondaryStatus()==1&&!problemStatus&&obj<limit) {
#if 0
          // switch off
          ClpSimplex temp = *smallModel_;
          temp.dual();
          if (temp.problemStatus()==0&&temp.objectiveValue()<limit) {
            printf("inf obj %g, true %g - offsets %g %g\n",smallModel_->objectiveValue(),
                   temp.objectiveValue(),
                   smallModel_->objectiveOffset(),temp.objectiveOffset());
          }
          lastAlgorithm_=1;
          obj=limit;
          problemStatus=10;
#else
          obj=limit;
          problemStatus=3;
#endif
        }
        if (!smallModel_->numberPrimalInfeasibilities()&&obj<limit) { 
          problemStatus=0;
#if 0
          ClpSimplex temp = *smallModel_;
          temp.dual();
          if (temp.numberIterations())
            printf("temp iterated\n");
          assert (temp.problemStatus()==0&&temp.objectiveValue()<limit);
#endif
        } else if (problemStatus==10) {
          problemStatus=3;
        } else if (!smallModel_->numberPrimalInfeasibilities()) {
          problemStatus=1; // infeasible
        } 
      } else {
        // can't say much
        //if (problemStatus==3)
        //smallModel_->computeObjectiveValue();
        lastAlgorithm_=1; // so won't fail on cutoff (in CbcNode)
        problemStatus=3;
      }
    } else if (!problemStatus) {
      if (smallModel_->isDualObjectiveLimitReached()) 
        problemStatus=1; // infeasible
    }
    if (status&&!problemStatus) {
      problemStatus=3; // can't be sure
      lastAlgorithm_=1;
    }
    if (problemStatus<0)
      problemStatus=3;
    modelPtr_->setProblemStatus(problemStatus);
    modelPtr_->setObjectiveValue(obj*modelPtr_->optimizationDirection());
    modelPtr_->setSumDualInfeasibilities(smallModel_->sumDualInfeasibilities());
    modelPtr_->setNumberDualInfeasibilities(smallModel_->numberDualInfeasibilities());
    modelPtr_->setSumPrimalInfeasibilities(smallModel_->sumPrimalInfeasibilities());
    modelPtr_->setNumberPrimalInfeasibilities(smallModel_->numberPrimalInfeasibilities());
    double * solution = modelPtr_->primalColumnSolution();
    const double * solution2 = smallModel_->solutionRegion();
    if (!columnScale) {
      for (i=0;i<numberColumns2;i++) {
        int iColumn = whichColumn[i];
        solution[iColumn]= solution2[i];
        lowerSmallReal[i]=saveLowerOriginal[iColumn];
        upperSmallReal[i]=saveUpperOriginal[iColumn];
      }
    } else {
      for (i=0;i<numberColumns2;i++) {
        int iColumn = whichColumn[i];
        solution[iColumn]= solution2[i]*columnScale[i];
        lowerSmallReal[i]=saveLowerOriginal[iColumn];
        upperSmallReal[i]=saveUpperOriginal[iColumn];
      }
    }
    // could combine with loop above
    if (modelPtr_==smallModel_)
      modelPtr_->computeObjectiveValue();
#if 1
    if (status&&!problemStatus) {
      memset(modelPtr_->primalRowSolution(),0,numberRows*sizeof(double));
      modelPtr_->clpMatrix()->times(1.0,solution,modelPtr_->primalRowSolution());
      modelPtr_->checkSolutionInternal();
      //modelPtr_->setLogLevel(1);
      //modelPtr_->allSlackBasis();
      //modelPtr_->primal(1);
      //memset(modelPtr_->primalRowSolution(),0,numberRows*sizeof(double));
      //modelPtr_->clpMatrix()->times(1.0,solution,modelPtr_->primalRowSolution());
      //modelPtr_->checkSolutionInternal();
      assert (!modelPtr_->problemStatus());
    }
#endif
    modelPtr_->setNumberIterations(smallModel_->numberIterations());
    // and back bounds
    CoinMemcpyN(saveLower,number,smallModel_->lowerRegion());
    CoinMemcpyN(saveUpper,number,smallModel_->upperRegion());
  }
  if (savedObjective) {
    // fix up
    modelPtr_->dblParam_[ClpDualObjectiveLimit]=savedDualLimit;
    //modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~32));
    modelPtr_->objective_=savedObjective;
    if (!modelPtr_->problemStatus_) {
      CoinZeroN(modelPtr_->dual_,modelPtr_->numberRows_);
      CoinZeroN(modelPtr_->reducedCost_,modelPtr_->numberColumns_);
      if (modelPtr_->dj_&&(modelPtr_->whatsChanged_&1)!=0)
	CoinZeroN(modelPtr_->dj_,modelPtr_->numberColumns_+modelPtr_->numberRows_);
      modelPtr_->computeObjectiveValue();
    }
  }
  modelPtr_->setIntParam(ClpMaxNumIteration,itlimOrig_);
}

void OsiClpSolverInterface::unmarkHotStart()
{
#ifdef CLEAN_HOT_START
  if ((specialOptions_&65536)!=0) {
    modelPtr_->setLogLevel(saveData_.scalingFlag_);
    modelPtr_->deleteRim(0);
    if (lastNumberRows_<0) {
      specialOptions_ |= 131072;
      lastNumberRows_ = -1 -lastNumberRows_;
      if (modelPtr_->rowScale_) {
	if (modelPtr_->rowScale_!=rowScale_.array()) {
	  delete [] modelPtr_->rowScale_;
	  delete [] modelPtr_->columnScale_;
	}
	modelPtr_->rowScale_=NULL;
	modelPtr_->columnScale_=NULL;
      }
    }
    delete factorization_;
    delete [] spareArrays_;
    smallModel_=NULL;
    spareArrays_=NULL;
    factorization_=NULL;
    delete [] rowActivity_;
    delete [] columnActivity_;
    rowActivity_=NULL;
    columnActivity_=NULL;
    return;
  }
#endif
  if (smallModel_==NULL) {
    setWarmStart(ws_);
    int numberRows = modelPtr_->numberRows();
    int numberColumns = modelPtr_->numberColumns();
    CoinMemcpyN(           rowActivity_,numberRows,modelPtr_->primalRowSolution());
    CoinMemcpyN(columnActivity_,numberColumns,modelPtr_->primalColumnSolution());
    delete ws_;
    ws_ = NULL;
  } else {
#ifndef KEEP_SMALL
    if (smallModel_!=modelPtr_)
      delete smallModel_;
    smallModel_=NULL;
#else
    if (smallModel_==modelPtr_) {
      smallModel_=NULL;
    } else if (smallModel_) {
      if(!spareArrays_) {
	delete smallModel_;
	smallModel_=NULL;
	delete factorization_;
	factorization_=NULL;
      } else {
	static_cast<ClpSimplexDual *> (smallModel_)->cleanupAfterStrongBranching( factorization_);
	if ((smallModel_->specialOptions_&4096)==0) {
	  delete factorization_;
	}
      }
    }
#endif
    //delete [] spareArrays_;
    //spareArrays_=NULL;
    factorization_=NULL;
  }
  delete [] rowActivity_;
  delete [] columnActivity_;
  rowActivity_=NULL;
  columnActivity_=NULL;
  // Make sure whatsChanged not out of sync
  if (!modelPtr_->columnUpperWork_)
    modelPtr_->whatsChanged_ &= ~0xffff;
  modelPtr_->specialOptions_ = saveData_.specialOptions_; 
}

//#############################################################################
// Problem information methods (original data)
//#############################################################################

//------------------------------------------------------------------
const char * OsiClpSolverInterface::getRowSense() const
{
  extractSenseRhsRange();
  return rowsense_;
}
//------------------------------------------------------------------
const double * OsiClpSolverInterface::getRightHandSide() const
{
  extractSenseRhsRange();
  return rhs_;
}
//------------------------------------------------------------------
const double * OsiClpSolverInterface::getRowRange() const
{
  extractSenseRhsRange();
  return rowrange_;
}
//------------------------------------------------------------------
// Return information on integrality
//------------------------------------------------------------------
bool OsiClpSolverInterface::isContinuous(int colNumber) const
{
  if ( integerInformation_==NULL ) return true;
#ifndef NDEBUG
  int n = modelPtr_->numberColumns();
  if (colNumber<0||colNumber>=n) {
    indexError(colNumber,"isContinuous");
  }
#endif
  if ( integerInformation_[colNumber]==0 ) return true;
  return false;
}
bool 
OsiClpSolverInterface::isBinary(int colNumber) const
{
#ifndef NDEBUG
  int n = modelPtr_->numberColumns();
  if (colNumber<0||colNumber>=n) {
    indexError(colNumber,"isBinary");
  }
#endif
  if ( integerInformation_==NULL || integerInformation_[colNumber]==0 ) {
    return false;
  } else {
    const double * cu = getColUpper();
    const double * cl = getColLower();
    if ((cu[colNumber]== 1 || cu[colNumber]== 0) && 
	(cl[colNumber]== 0 || cl[colNumber]==1))
      return true;
    else 
      return false;
  }
}
//-----------------------------------------------------------------------------
bool 
OsiClpSolverInterface::isInteger(int colNumber) const
{
#ifndef NDEBUG
  int n = modelPtr_->numberColumns();
  if (colNumber<0||colNumber>=n) {
    indexError(colNumber,"isInteger");
  }
#endif
  if ( integerInformation_==NULL || integerInformation_[colNumber]==0 ) 
    return false;
  else
    return true;
}
//-----------------------------------------------------------------------------
bool 
OsiClpSolverInterface::isIntegerNonBinary(int colNumber) const
{
#ifndef NDEBUG
  int n = modelPtr_->numberColumns();
  if (colNumber<0||colNumber>=n) {
    indexError(colNumber,"isIntegerNonBinary");
  }
#endif
  if ( integerInformation_==NULL || integerInformation_[colNumber]==0 ) {
    return false;
  } else {
    return !isBinary(colNumber);
  }
}
//-----------------------------------------------------------------------------
bool 
OsiClpSolverInterface::isFreeBinary(int colNumber) const
{
#ifndef NDEBUG
  int n = modelPtr_->numberColumns();
  if (colNumber<0||colNumber>=n) {
    indexError(colNumber,"isFreeBinary");
  }
#endif
  if ( integerInformation_==NULL || integerInformation_[colNumber]==0 ) {
    return false;
  } else {
    const double * cu = getColUpper();
    const double * cl = getColLower();
    if ((cu[colNumber]== 1) && (cl[colNumber]== 0))
      return true;
    else 
      return false;
  }
}
/*  Return array of column length
    0 - continuous
    1 - binary (may get fixed later)
    2 - general integer (may get fixed later)
*/
const char * 
OsiClpSolverInterface::getColType(bool refresh) const
{
  if (!columnType_||refresh) {
    const int numCols = getNumCols() ;
    if (!columnType_)
      columnType_ = new char [numCols];
    if ( integerInformation_==NULL ) {
      memset(columnType_,0,numCols);
    } else {
      const double * cu = getColUpper();
      const double * cl = getColLower();
      for (int i = 0 ; i < numCols ; ++i) {
	if (integerInformation_[i]) {
	  if ((cu[i]== 1 || cu[i]== 0) && 
	      (cl[i]== 0 || cl[i]==1))
	    columnType_[i]=1;
	  else
	    columnType_[i]=2;
	} else {
	  columnType_[i]=0;
	}
      }
    }
  }
  return columnType_;
}

/* Return true if column is integer but does not have to
   be declared as such.
   Note: This function returns true if the the column
   is binary or a general integer.
*/
bool 
OsiClpSolverInterface::isOptionalInteger(int colNumber) const
{
#ifndef NDEBUG
  int n = modelPtr_->numberColumns();
  if (colNumber<0||colNumber>=n) {
    indexError(colNumber,"isInteger");
  }
#endif
  if ( integerInformation_==NULL || integerInformation_[colNumber]!=2 ) 
    return false;
  else
    return true;
}
/* Set the index-th variable to be an optional integer variable */
void 
OsiClpSolverInterface::setOptionalInteger(int index)
{
  if (!integerInformation_) {
    integerInformation_ = new char[modelPtr_->numberColumns()];
    CoinFillN ( integerInformation_, modelPtr_->numberColumns(),static_cast<char> (0));
  }
#ifndef NDEBUG
  int n = modelPtr_->numberColumns();
  if (index<0||index>=n) {
    indexError(index,"setInteger");
  }
#endif
  integerInformation_[index]=2;
  modelPtr_->setInteger(index);
}

//------------------------------------------------------------------
// Row and column copies of the matrix ...
//------------------------------------------------------------------
const CoinPackedMatrix * OsiClpSolverInterface::getMatrixByRow() const
{
  if ( matrixByRow_ == NULL ) {
    matrixByRow_ = new CoinPackedMatrix();
    matrixByRow_->setExtraGap(0.0);
    matrixByRow_->setExtraMajor(0.0);
    matrixByRow_->reverseOrderedCopyOf(*modelPtr_->matrix());
    //matrixByRow_->removeGaps();
#if 0
    CoinPackedMatrix back;
    std::cout<<"start check"<<std::endl;
    back.reverseOrderedCopyOf(*matrixByRow_);
    modelPtr_->matrix()->isEquivalent2(back);
    std::cout<<"stop check"<<std::endl;
#endif
  }
  assert (matrixByRow_->getNumElements()==modelPtr_->clpMatrix()->getNumElements());
  return matrixByRow_;
}

const CoinPackedMatrix * OsiClpSolverInterface::getMatrixByCol() const
{
  return modelPtr_->matrix();
}
  
// Get pointer to mutable column-wise copy of matrix (returns NULL if not meaningful)
CoinPackedMatrix * 
OsiClpSolverInterface::getMutableMatrixByCol() const 
{
  ClpPackedMatrix * matrix = dynamic_cast<ClpPackedMatrix *>(modelPtr_->matrix_) ;
  if (matrix)
    return matrix->getPackedMatrix();
  else
    return NULL;
}

//------------------------------------------------------------------
std::vector<double*> OsiClpSolverInterface::getDualRays(int /*maxNumRays*/,
							bool fullRay) const
{
  if (fullRay == true) {
    throw CoinError("Full dual rays not yet implemented.","getDualRays",
		    "OsiClpSolverInterface");
  }
  return std::vector<double*>(1, modelPtr_->infeasibilityRay());
}
//------------------------------------------------------------------
std::vector<double*> OsiClpSolverInterface::getPrimalRays(int /*maxNumRays*/) const
{
  return std::vector<double*>(1, modelPtr_->unboundedRay());
}
//#############################################################################
void
OsiClpSolverInterface::setContinuous(int index)
{

  if (integerInformation_) {
#ifndef NDEBUG
    int n = modelPtr_->numberColumns();
    if (index<0||index>=n) {
      indexError(index,"setContinuous");
    }
#endif
    integerInformation_[index]=0;
  }
  modelPtr_->setContinuous(index);
}
//-----------------------------------------------------------------------------
void
OsiClpSolverInterface::setInteger(int index)
{
  if (!integerInformation_) {
    integerInformation_ = new char[modelPtr_->numberColumns()];
    CoinFillN ( integerInformation_, modelPtr_->numberColumns(),static_cast<char> (0));
  }
#ifndef NDEBUG
  int n = modelPtr_->numberColumns();
  if (index<0||index>=n) {
    indexError(index,"setInteger");
  }
#endif
  integerInformation_[index]=1;
  modelPtr_->setInteger(index);
}
//-----------------------------------------------------------------------------
void
OsiClpSolverInterface::setContinuous(const int* indices, int len)
{
  if (integerInformation_) {
#ifndef NDEBUG
    int n = modelPtr_->numberColumns();
#endif
    int i;
    for (i=0; i<len;i++) {
      int colNumber = indices[i];
#ifndef NDEBUG
      if (colNumber<0||colNumber>=n) {
	indexError(colNumber,"setContinuous");
      }
#endif
      integerInformation_[colNumber]=0;
      modelPtr_->setContinuous(colNumber);
    }
  }
}
//-----------------------------------------------------------------------------
void
OsiClpSolverInterface::setInteger(const int* indices, int len)
{
  if (!integerInformation_) {
    integerInformation_ = new char[modelPtr_->numberColumns()];
    CoinFillN ( integerInformation_, modelPtr_->numberColumns(),static_cast<char> (0));
  }
#ifndef NDEBUG
  int n = modelPtr_->numberColumns();
#endif
  int i;
  for (i=0; i<len;i++) {
    int colNumber = indices[i];
#ifndef NDEBUG
    if (colNumber<0||colNumber>=n) {
      indexError(colNumber,"setInteger");
    }
#endif
    integerInformation_[colNumber]=1;
    modelPtr_->setInteger(colNumber);
  }
}
/* Set the objective coefficients for all columns
    array [getNumCols()] is an array of values for the objective.
    This defaults to a series of set operations and is here for speed.
*/
void 
OsiClpSolverInterface::setObjective(const double * array)
{
  // Say can't gurantee optimal basis etc
  lastAlgorithm_=999;
  modelPtr_->whatsChanged_ &= (0xffff&~64);
  int n = modelPtr_->numberColumns() ;
  if (fakeMinInSimplex_) {
    std::transform(array,array+n,
  		   modelPtr_->objective(),std::negate<double>()) ;
  } else {
    CoinMemcpyN(array,n,modelPtr_->objective());
  }
}
/* Set the lower bounds for all columns
    array [getNumCols()] is an array of values for the objective.
    This defaults to a series of set operations and is here for speed.
*/
void 
OsiClpSolverInterface::setColLower(const double * array)
{
  // Say can't gurantee optimal basis etc
  lastAlgorithm_=999;
  modelPtr_->whatsChanged_ &= (0x1ffff&128);
  CoinMemcpyN(array,modelPtr_->numberColumns(),
		    modelPtr_->columnLower());
}
/* Set the upper bounds for all columns
    array [getNumCols()] is an array of values for the objective.
    This defaults to a series of set operations and is here for speed.
*/
void 
OsiClpSolverInterface::setColUpper(const double * array)
{
  // Say can't gurantee optimal basis etc
  lastAlgorithm_=999;
  modelPtr_->whatsChanged_ &= (0x1ffff&256);
  CoinMemcpyN(array,modelPtr_->numberColumns(),
		    modelPtr_->columnUpper());
}
//-----------------------------------------------------------------------------
void OsiClpSolverInterface::setColSolution(const double * cs) 
{
  // Say can't gurantee optimal basis etc
  lastAlgorithm_=999;
  CoinDisjointCopyN(cs,modelPtr_->numberColumns(),
		    modelPtr_->primalColumnSolution());
  if (modelPtr_->solveType()==2) {
    // directly into code as well
    CoinDisjointCopyN(cs,modelPtr_->numberColumns(),
		      modelPtr_->solutionRegion(1));
  }
}
//-----------------------------------------------------------------------------
void OsiClpSolverInterface::setRowPrice(const double * rs) 
{
  CoinDisjointCopyN(rs,modelPtr_->numberRows(),
		    modelPtr_->dualRowSolution());
  if (modelPtr_->solveType()==2) {
    // directly into code as well (? sign )
    CoinDisjointCopyN(rs,modelPtr_->numberRows(),
		      modelPtr_->djRegion(0));
  }
}

//#############################################################################
// Problem modifying methods (matrix)
//#############################################################################
void 
OsiClpSolverInterface::addCol(const CoinPackedVectorBase& vec,
			      const double collb, const double colub,   
			      const double obj)
{
  int numberColumns = modelPtr_->numberColumns();
  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|8|64|128|256));
  modelPtr_->resize(modelPtr_->numberRows(),numberColumns+1);
  linearObjective_ = modelPtr_->objective();
  basis_.resize(modelPtr_->numberRows(),numberColumns+1);
  setColBounds(numberColumns,collb,colub);
  setObjCoeff(numberColumns,obj);
  if (!modelPtr_->clpMatrix())
    modelPtr_->createEmptyMatrix();
  modelPtr_->matrix()->appendCol(vec);
  if (integerInformation_) {
    char * temp = new char[numberColumns+1];
    CoinMemcpyN(integerInformation_,numberColumns,temp);
    delete [] integerInformation_;
    integerInformation_ = temp;
    integerInformation_[numberColumns]=0;
  }
  freeCachedResults();
}
//-----------------------------------------------------------------------------
/* Add a column (primal variable) to the problem. */
void 
OsiClpSolverInterface::addCol(int numberElements, const int * rows, const double * elements,
			   const double collb, const double colub,   
			   const double obj) 
{
  CoinPackedVector column(numberElements, rows, elements);
  addCol(column,collb,colub,obj);
}
// Add a named column (primal variable) to the problem.
void 
OsiClpSolverInterface::addCol(const CoinPackedVectorBase& vec,
		      const double collb, const double colub,   
		      const double obj, std::string name) 
{
  int ndx = getNumCols() ;
  addCol(vec,collb,colub,obj) ;
  setColName(ndx,name) ;
}
//-----------------------------------------------------------------------------
void 
OsiClpSolverInterface::addCols(const int numcols,
			       const CoinPackedVectorBase * const * cols,
			       const double* collb, const double* colub,   
			       const double* obj)
{
  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|8|64|128|256));
  int numberColumns = modelPtr_->numberColumns();
  modelPtr_->resize(modelPtr_->numberRows(),numberColumns+numcols);
  linearObjective_ = modelPtr_->objective();
  basis_.resize(modelPtr_->numberRows(),numberColumns+numcols);
  double * lower = modelPtr_->columnLower()+numberColumns;
  double * upper = modelPtr_->columnUpper()+numberColumns;
  double * objective = modelPtr_->objective()+numberColumns;
  int iCol;
  if (collb) {
    for (iCol = 0; iCol < numcols; iCol++) {
      lower[iCol]= forceIntoRange(collb[iCol], -OsiClpInfinity, OsiClpInfinity);
      if (lower[iCol]<-1.0e27)
	lower[iCol]=-COIN_DBL_MAX;
    }
  } else {
    CoinFillN ( lower, numcols,0.0);
  }
  if (colub) {
    for (iCol = 0; iCol < numcols; iCol++) {
      upper[iCol]= forceIntoRange(colub[iCol], -OsiClpInfinity, OsiClpInfinity);
      if (upper[iCol]>1.0e27)
	upper[iCol]=COIN_DBL_MAX;
    }
  } else {
    CoinFillN ( upper, numcols,COIN_DBL_MAX);
  }
  if (obj) {
    for (iCol = 0; iCol < numcols; iCol++) {
      objective[iCol] = obj[iCol];
    }
  } else {
    CoinFillN ( objective, numcols,0.0);
  }
  if (!modelPtr_->clpMatrix())
    modelPtr_->createEmptyMatrix();
  modelPtr_->matrix()->appendCols(numcols,cols);
  if (integerInformation_) {
    char * temp = new char[numberColumns+numcols];
    CoinMemcpyN(integerInformation_,numberColumns,temp);
    delete [] integerInformation_;
    integerInformation_ = temp;
    for (iCol = 0; iCol < numcols; iCol++) 
      integerInformation_[numberColumns+iCol]=0;
  }
  freeCachedResults();
}
void 
OsiClpSolverInterface::addCols(const int numcols,
			       const int * columnStarts, const int * rows, const double * elements,
			       const double* collb, const double* colub,   
			       const double* obj)
{
  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|8|64|128|256));
  int numberColumns = modelPtr_->numberColumns();
  modelPtr_->resize(modelPtr_->numberRows(),numberColumns+numcols);
  linearObjective_ = modelPtr_->objective();
  basis_.resize(modelPtr_->numberRows(),numberColumns+numcols);
  double * lower = modelPtr_->columnLower()+numberColumns;
  double * upper = modelPtr_->columnUpper()+numberColumns;
  double * objective = modelPtr_->objective()+numberColumns;
  int iCol;
  if (collb) {
    for (iCol = 0; iCol < numcols; iCol++) {
      lower[iCol]= forceIntoRange(collb[iCol], -OsiClpInfinity, OsiClpInfinity);
      if (lower[iCol]<-1.0e27)
	lower[iCol]=-COIN_DBL_MAX;
    }
  } else {
    CoinFillN ( lower, numcols,0.0);
  }
  if (colub) {
    for (iCol = 0; iCol < numcols; iCol++) {
      upper[iCol]= forceIntoRange(colub[iCol], -OsiClpInfinity, OsiClpInfinity);
      if (upper[iCol]>1.0e27)
	upper[iCol]=COIN_DBL_MAX;
    }
  } else {
    CoinFillN ( upper, numcols,COIN_DBL_MAX);
  }
  if (obj) {
    for (iCol = 0; iCol < numcols; iCol++) {
      objective[iCol] = obj[iCol];
    }
  } else {
    CoinFillN ( objective, numcols,0.0);
  }
  if (!modelPtr_->clpMatrix())
    modelPtr_->createEmptyMatrix();
  modelPtr_->matrix()->appendCols(numcols,columnStarts,rows,elements);
  if (integerInformation_) {
    char * temp = new char[numberColumns+numcols];
    CoinMemcpyN(integerInformation_,numberColumns,temp);
    delete [] integerInformation_;
    integerInformation_ = temp;
    for (iCol = 0; iCol < numcols; iCol++) 
      integerInformation_[numberColumns+iCol]=0;
  }
  freeCachedResults();
}
//-----------------------------------------------------------------------------
void 
OsiClpSolverInterface::deleteCols(const int num, const int * columnIndices)
{
  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|8|64|128|256));
  findIntegers(false);
  deleteBranchingInfo(num,columnIndices);
  modelPtr_->deleteColumns(num,columnIndices);
  int nameDiscipline;
  getIntParam(OsiNameDiscipline,nameDiscipline) ;
  if (num&&nameDiscipline) {
    // Very clumsy (and inefficient) - need to sort and then go backwards in ? chunks
    int * indices = CoinCopyOfArray(columnIndices,num);
    std::sort(indices,indices+num);
    int num2=num;
    while(num2) {
      int next = indices[num2-1];
      int firstDelete = num2-1;
      int i;
      for (i=num2-2;i>=0;i--) {
	if (indices[i]+1==next) {
	  next --;
	  firstDelete=i;
	} else {
	  break;
	}
      }
      OsiSolverInterface::deleteColNames(indices[firstDelete],num2-firstDelete);
      num2 = firstDelete;
      assert (num2>=0);
    }
    delete [] indices;
  }
  // synchronize integers (again)
  if (integerInformation_) {
    int numberColumns = modelPtr_->numberColumns();
    for (int i=0;i<numberColumns;i++) {
      if (modelPtr_->isInteger(i))
	integerInformation_[i]=1;
      else
	integerInformation_[i]=0;
    }
  }
  basis_.deleteColumns(num,columnIndices);
  linearObjective_ = modelPtr_->objective();
  freeCachedResults();
}
//-----------------------------------------------------------------------------
void 
OsiClpSolverInterface::addRow(const CoinPackedVectorBase& vec,
			      const double rowlb, const double rowub)
{
  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|4|16|32));
  freeCachedResults0();
  int numberRows = modelPtr_->numberRows();
  modelPtr_->resize(numberRows+1,modelPtr_->numberColumns());
  basis_.resize(numberRows+1,modelPtr_->numberColumns());
  setRowBounds(numberRows,rowlb,rowub);
  if (!modelPtr_->clpMatrix())
    modelPtr_->createEmptyMatrix();
  modelPtr_->matrix()->appendRow(vec);
  freeCachedResults1();
}
//-----------------------------------------------------------------------------
void OsiClpSolverInterface::addRow(const CoinPackedVectorBase& vec,
				const double rowlb, const double rowub,
				std::string name)
{
  int ndx = getNumRows() ;
  addRow(vec,rowlb,rowub) ;
  setRowName(ndx,name) ;
}
//-----------------------------------------------------------------------------
void 
OsiClpSolverInterface::addRow(const CoinPackedVectorBase& vec,
			      const char rowsen, const double rowrhs,   
			      const double rowrng)
{
  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|4|16|32));
  freeCachedResults0();
  int numberRows = modelPtr_->numberRows();
  modelPtr_->resize(numberRows+1,modelPtr_->numberColumns());
  basis_.resize(numberRows+1,modelPtr_->numberColumns());
  double rowlb = 0, rowub = 0;
  convertSenseToBound(rowsen, rowrhs, rowrng, rowlb, rowub);
  setRowBounds(numberRows,rowlb,rowub);
  if (!modelPtr_->clpMatrix())
    modelPtr_->createEmptyMatrix();
  modelPtr_->matrix()->appendRow(vec);
  freeCachedResults1();
}
//-----------------------------------------------------------------------------
void 
OsiClpSolverInterface::addRow(int numberElements, const int * columns, const double * elements,
			   const double rowlb, const double rowub) 
{
  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|4|16|32));
  freeCachedResults0();
  int numberRows = modelPtr_->numberRows();
  modelPtr_->resize(numberRows+1,modelPtr_->numberColumns());
  basis_.resize(numberRows+1,modelPtr_->numberColumns());
  setRowBounds(numberRows,rowlb,rowub);
  if (!modelPtr_->clpMatrix())
    modelPtr_->createEmptyMatrix();
  modelPtr_->matrix()->appendRow(numberElements, columns, elements);
  CoinBigIndex starts[2];
  starts[0]=0;
  starts[1]=numberElements;
  redoScaleFactors( 1,starts, columns, elements);
  freeCachedResults1();
}
//-----------------------------------------------------------------------------
void 
OsiClpSolverInterface::addRows(const int numrows,
			       const CoinPackedVectorBase * const * rows,
			       const double* rowlb, const double* rowub)
{
  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|4|16|32));
  freeCachedResults0();
  int numberRows = modelPtr_->numberRows();
  modelPtr_->resize(numberRows+numrows,modelPtr_->numberColumns());
  basis_.resize(numberRows+numrows,modelPtr_->numberColumns());
  double * lower = modelPtr_->rowLower()+numberRows;
  double * upper = modelPtr_->rowUpper()+numberRows;
  int iRow;
  for (iRow = 0; iRow < numrows; iRow++) {
    if (rowlb) 
      lower[iRow]= forceIntoRange(rowlb[iRow], -OsiClpInfinity, OsiClpInfinity);
    else 
      lower[iRow]=-OsiClpInfinity;
    if (rowub) 
      upper[iRow]= forceIntoRange(rowub[iRow], -OsiClpInfinity, OsiClpInfinity);
    else 
      upper[iRow]=OsiClpInfinity;
    if (lower[iRow]<-1.0e27)
      lower[iRow]=-COIN_DBL_MAX;
    if (upper[iRow]>1.0e27)
      upper[iRow]=COIN_DBL_MAX;
  }
  if (!modelPtr_->clpMatrix())
    modelPtr_->createEmptyMatrix();
  modelPtr_->matrix()->appendRows(numrows,rows);
  freeCachedResults1();
}
//-----------------------------------------------------------------------------
void 
OsiClpSolverInterface::addRows(const int numrows,
			       const CoinPackedVectorBase * const * rows,
			       const char* rowsen, const double* rowrhs,   
			       const double* rowrng)
{
  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|4|16|32));
  freeCachedResults0();
  int numberRows = modelPtr_->numberRows();
  modelPtr_->resize(numberRows+numrows,modelPtr_->numberColumns());
  basis_.resize(numberRows+numrows,modelPtr_->numberColumns());
  double * lower = modelPtr_->rowLower()+numberRows;
  double * upper = modelPtr_->rowUpper()+numberRows;
  int iRow;
  for (iRow = 0; iRow < numrows; iRow++) {
    double rowlb = 0, rowub = 0;
    convertSenseToBound(rowsen[iRow], rowrhs[iRow], rowrng[iRow], 
			rowlb, rowub);
    lower[iRow]= forceIntoRange(rowlb, -OsiClpInfinity, OsiClpInfinity);
    upper[iRow]= forceIntoRange(rowub, -OsiClpInfinity, OsiClpInfinity);
    if (lower[iRow]<-1.0e27)
      lower[iRow]=-COIN_DBL_MAX;
    if (upper[iRow]>1.0e27)
      upper[iRow]=COIN_DBL_MAX;
  }
  if (!modelPtr_->clpMatrix())
    modelPtr_->createEmptyMatrix();
  modelPtr_->matrix()->appendRows(numrows,rows);
  freeCachedResults1();
}
void 
OsiClpSolverInterface::addRows(const int numrows,
			       const int * rowStarts, const int * columns, const double * element,
			       const double* rowlb, const double* rowub)
{
  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|4|16|32));
  freeCachedResults0();
  int numberRows = modelPtr_->numberRows();
  modelPtr_->resize(numberRows+numrows,modelPtr_->numberColumns());
  basis_.resize(numberRows+numrows,modelPtr_->numberColumns());
  double * lower = modelPtr_->rowLower()+numberRows;
  double * upper = modelPtr_->rowUpper()+numberRows;
  int iRow;
  for (iRow = 0; iRow < numrows; iRow++) {
    if (rowlb) 
      lower[iRow]= forceIntoRange(rowlb[iRow], -OsiClpInfinity, OsiClpInfinity);
    else 
      lower[iRow]=-OsiClpInfinity;
    if (rowub) 
      upper[iRow]= forceIntoRange(rowub[iRow], -OsiClpInfinity, OsiClpInfinity);
    else 
      upper[iRow]=OsiClpInfinity;
    if (lower[iRow]<-1.0e27)
      lower[iRow]=-COIN_DBL_MAX;
    if (upper[iRow]>1.0e27)
      upper[iRow]=COIN_DBL_MAX;
  }
  if (!modelPtr_->clpMatrix())
    modelPtr_->createEmptyMatrix();
  modelPtr_->matrix()->appendRows(numrows,rowStarts,columns,element);
  redoScaleFactors( numrows,rowStarts, columns, element);
  freeCachedResults1();
}
//-----------------------------------------------------------------------------
void 
OsiClpSolverInterface::deleteRows(const int num, const int * rowIndices)
{
  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|4|16|32));
  // will still be optimal if all rows basic
  bool allBasic=true;
  int numBasis = basis_.getNumArtificial();
  for (int i=0;i<num;i++) {
    int iRow = rowIndices[i];
    if (iRow<numBasis) {
      if (basis_.getArtifStatus(iRow)!=CoinWarmStartBasis::basic) {
	allBasic=false;
	break;
      }
    }
  }
  int saveAlgorithm = allBasic ? lastAlgorithm_ : 999;
  modelPtr_->deleteRows(num,rowIndices);
  int nameDiscipline;
  getIntParam(OsiNameDiscipline,nameDiscipline) ;
  if (num&&nameDiscipline) {
    // Very clumsy (and inefficient) - need to sort and then go backwards in ? chunks
    int * indices = CoinCopyOfArray(rowIndices,num);
    std::sort(indices,indices+num);
    int num2=num;
    while(num2) {
      int next = indices[num2-1];
      int firstDelete = num2-1;
      int i;
      for (i=num2-2;i>=0;i--) {
	if (indices[i]+1==next) {
	  next --;
	  firstDelete=i;
	} else {
	  break;
	}
      }
      OsiSolverInterface::deleteRowNames(indices[firstDelete],num2-firstDelete);
      num2 = firstDelete;
      assert (num2>=0);
    }
    delete [] indices;
  }
  basis_.deleteRows(num,rowIndices);
  CoinPackedMatrix * saveRowCopy = matrixByRow_;
  matrixByRow_=NULL;
  freeCachedResults();
  modelPtr_->setNewRowCopy(NULL);
  delete modelPtr_->scaledMatrix_;
  modelPtr_->scaledMatrix_=NULL;
  if (saveRowCopy) {
#if 1
    matrixByRow_=saveRowCopy;
    matrixByRow_->deleteRows(num,rowIndices);
    assert (matrixByRow_->getNumElements()==modelPtr_->clpMatrix()->getNumElements());
#else
    delete saveRowCopy;
#endif
  }
  lastAlgorithm_ = saveAlgorithm;
  if ((specialOptions_&131072)!=0) 
    lastNumberRows_=modelPtr_->numberRows();
}

//#############################################################################
// Methods to input a problem
//#############################################################################

void
OsiClpSolverInterface::loadProblem(const CoinPackedMatrix& matrix,
				   const double* collb, const double* colub,   
				   const double* obj,
				   const double* rowlb, const double* rowub)
{
  modelPtr_->whatsChanged_ = 0;
  // Get rid of integer information (modelPtr will get rid of its copy)
  delete [] integerInformation_;
  integerInformation_=NULL;
  modelPtr_->loadProblem(matrix, collb, colub, obj, rowlb, rowub);
  linearObjective_ = modelPtr_->objective();
  freeCachedResults();
  basis_=CoinWarmStartBasis();
  if (ws_) {
     delete ws_;
     ws_ = 0;
  }
}

//-----------------------------------------------------------------------------

void
OsiClpSolverInterface::assignProblem(CoinPackedMatrix*& matrix,
				     double*& collb, double*& colub,
				     double*& obj,
				     double*& rowlb, double*& rowub)
{
  modelPtr_->whatsChanged_ = 0;
  // Get rid of integer information (modelPtr will get rid of its copy)
  loadProblem(*matrix, collb, colub, obj, rowlb, rowub);
  delete matrix;   matrix = NULL;
  delete[] collb;  collb = NULL;
  delete[] colub;  colub = NULL;
  delete[] obj;    obj = NULL;
  delete[] rowlb;  rowlb = NULL;
  delete[] rowub;  rowub = NULL;
}

//-----------------------------------------------------------------------------

void
OsiClpSolverInterface::loadProblem(const CoinPackedMatrix& matrix,
				   const double* collb, const double* colub,
				   const double* obj,
				   const char* rowsen, const double* rowrhs,   
				   const double* rowrng)
{
  modelPtr_->whatsChanged_ = 0;
  // Get rid of integer information (modelPtr will get rid of its copy)
  // assert( rowsen != NULL );
  // assert( rowrhs != NULL );
  // If any of Rhs NULLs then create arrays
  int numrows = matrix.getNumRows();
  const char * rowsenUse = rowsen;
  if (!rowsen) {
    char * rowsen = new char [numrows];
    for (int i=0;i<numrows;i++)
      rowsen[i]='G';
    rowsenUse = rowsen;
  } 
  const double * rowrhsUse = rowrhs;
  if (!rowrhs) {
    double * rowrhs = new double [numrows];
    for (int i=0;i<numrows;i++)
      rowrhs[i]=0.0;
    rowrhsUse = rowrhs;
  }
  const double * rowrngUse = rowrng;
  if (!rowrng) {
    double * rowrng = new double [numrows];
    for (int i=0;i<numrows;i++)
      rowrng[i]=0.0;
    rowrngUse = rowrng;
  }
  double * rowlb = new double[numrows];
  double * rowub = new double[numrows];
  for (int i = numrows-1; i >= 0; --i) {   
    convertSenseToBound(rowsenUse[i],rowrhsUse[i],rowrngUse[i],rowlb[i],rowub[i]);
  }
  if (rowsen!=rowsenUse)
    delete [] rowsenUse;
  if (rowrhs!=rowrhsUse)
    delete [] rowrhsUse;
  if (rowrng!=rowrngUse)
    delete [] rowrngUse;
  loadProblem(matrix, collb, colub, obj, rowlb, rowub);
  delete [] rowlb;
  delete [] rowub;
}

//-----------------------------------------------------------------------------

void
OsiClpSolverInterface::assignProblem(CoinPackedMatrix*& matrix,
				     double*& collb, double*& colub,
				     double*& obj,
				     char*& rowsen, double*& rowrhs,
				     double*& rowrng)
{
  modelPtr_->whatsChanged_ = 0;
  // Get rid of integer information (modelPtr will get rid of its copy)
  loadProblem(*matrix, collb, colub, obj, rowsen, rowrhs, rowrng);
  delete matrix;   matrix = NULL;
  delete[] collb;  collb = NULL;
  delete[] colub;  colub = NULL;
  delete[] obj;    obj = NULL;
  delete[] rowsen; rowsen = NULL;
  delete[] rowrhs; rowrhs = NULL;
  delete[] rowrng; rowrng = NULL;
}

//-----------------------------------------------------------------------------

void
OsiClpSolverInterface::loadProblem(const int numcols, const int numrows,
				   const CoinBigIndex * start, const int* index,
				   const double* value,
				   const double* collb, const double* colub,
				   const double* obj,
				   const double* rowlb, const double* rowub)
{
  modelPtr_->whatsChanged_ = 0;
  // Get rid of integer information (modelPtr will get rid of its copy)
  delete [] integerInformation_;
  integerInformation_=NULL;
  modelPtr_->loadProblem(numcols, numrows, start,  index,
	    value, collb, colub, obj,
	    rowlb,  rowub);
  linearObjective_ = modelPtr_->objective();
  freeCachedResults();
  basis_=CoinWarmStartBasis();
  if (ws_) {
     delete ws_;
     ws_ = 0;
  }
}
//-----------------------------------------------------------------------------

void
OsiClpSolverInterface::loadProblem(const int numcols, const int numrows,
				   const CoinBigIndex * start, const int* index,
				   const double* value,
				   const double* collb, const double* colub,
				   const double* obj,
				   const char* rowsen, const double* rowrhs,   
				   const double* rowrng)
{
  modelPtr_->whatsChanged_ = 0;
  // Get rid of integer information (modelPtr will get rid of its copy)
  // If any of Rhs NULLs then create arrays
  const char * rowsenUse = rowsen;
  if (!rowsen) {
    char * rowsen = new char [numrows];
    for (int i=0;i<numrows;i++)
      rowsen[i]='G';
    rowsenUse = rowsen;
  } 
  const double * rowrhsUse = rowrhs;
  if (!rowrhs) {
    double * rowrhs = new double [numrows];
    for (int i=0;i<numrows;i++)
      rowrhs[i]=0.0;
    rowrhsUse = rowrhs;
  }
  const double * rowrngUse = rowrng;
  if (!rowrng) {
    double * rowrng = new double [numrows];
    for (int i=0;i<numrows;i++)
      rowrng[i]=0.0;
    rowrngUse = rowrng;
  }
  double * rowlb = new double[numrows];
  double * rowub = new double[numrows];
  for (int i = numrows-1; i >= 0; --i) {   
    convertSenseToBound(rowsenUse[i],rowrhsUse[i],rowrngUse[i],rowlb[i],rowub[i]);
  }
  if (rowsen!=rowsenUse)
    delete [] rowsenUse;
  if (rowrhs!=rowrhsUse)
    delete [] rowrhsUse;
  if (rowrng!=rowrngUse)
    delete [] rowrngUse;
  loadProblem(numcols, numrows, start,  index, value, collb, colub, obj,
	      rowlb,  rowub);
  delete[] rowlb;
  delete[] rowub;
}
// This loads a model from a coinModel object - returns number of errors
int 
OsiClpSolverInterface::loadFromCoinModel (  CoinModel & modelObject, bool keepSolution)
{
  modelPtr_->whatsChanged_ = 0;
  int numberErrors = 0;
  // Set arrays for normal use
  double * rowLower = modelObject.rowLowerArray();
  double * rowUpper = modelObject.rowUpperArray();
  double * columnLower = modelObject.columnLowerArray();
  double * columnUpper = modelObject.columnUpperArray();
  double * objective = modelObject.objectiveArray();
  int * integerType = modelObject.integerTypeArray();
  double * associated = modelObject.associatedArray();
  // If strings then do copies
  if (modelObject.stringsExist()) {
    numberErrors = modelObject.createArrays(rowLower, rowUpper, columnLower, columnUpper,
                                            objective, integerType,associated);
  }
  CoinPackedMatrix matrix;
  modelObject.createPackedMatrix(matrix,associated);
  int numberRows = modelObject.numberRows();
  int numberColumns = modelObject.numberColumns();
  CoinWarmStart * ws = getWarmStart();
  bool restoreBasis = keepSolution && numberRows&&numberRows==getNumRows()&&
    numberColumns==getNumCols();
  loadProblem(matrix, 
              columnLower, columnUpper, objective, rowLower, rowUpper);
  if (restoreBasis)
    setWarmStart(ws);
  delete ws;
  // Do names if wanted
  int numberItems;
  numberItems = modelObject.rowNames()->numberItems();
  if (numberItems) {
    const char *const * rowNames=modelObject.rowNames()->names();
    modelPtr_->copyRowNames(rowNames,0,numberItems);
  }
  numberItems = modelObject.columnNames()->numberItems();
  if (numberItems) {
    const char *const * columnNames=modelObject.columnNames()->names();
    modelPtr_->copyColumnNames(columnNames,0,numberItems);
  }
  // Do integers if wanted
  assert(integerType);
  for (int iColumn=0;iColumn<numberColumns;iColumn++) {
    if (integerType[iColumn])
      setInteger(iColumn);
  }
  if (rowLower!=modelObject.rowLowerArray()||
      columnLower!=modelObject.columnLowerArray()) {
    delete [] rowLower;
    delete [] rowUpper;
    delete [] columnLower;
    delete [] columnUpper;
    delete [] objective;
    delete [] integerType;
    delete [] associated;
    //if (numberErrors)
    //  handler_->message(CLP_BAD_STRING_VALUES,messages_)
    //    <<numberErrors
    //    <<CoinMessageEol;
  }
  modelPtr_->optimizationDirection_ = modelObject.optimizationDirection();  
  return numberErrors;
}

//-----------------------------------------------------------------------------
// Write mps files
//-----------------------------------------------------------------------------

void OsiClpSolverInterface::writeMps(const char * filename,
				     const char * extension,
				     double objSense) const
{
  std::string f(filename);
  std::string e(extension);
  std::string fullname;
  if (e!="") {
    fullname = f + "." + e;
  } else {
    // no extension so no trailing period
    fullname = f;
  }
  // get names
  const char * const * const rowNames = modelPtr_->rowNamesAsChar();
  const char * const * const columnNames = modelPtr_->columnNamesAsChar();
  // Fall back on Osi version - possibly with names
  OsiSolverInterface::writeMpsNative(fullname.c_str(), 
				     const_cast<const char **>(rowNames),
                                     const_cast<const char **>(columnNames),0,2,objSense,
				     numberSOS_,setInfo_);
  if (rowNames) {
    modelPtr_->deleteNamesAsChar(rowNames, modelPtr_->numberRows_+1);
    modelPtr_->deleteNamesAsChar(columnNames, modelPtr_->numberColumns_);
  }
}

int 
OsiClpSolverInterface::writeMpsNative(const char *filename, 
		  const char ** rowNames, const char ** columnNames,
		  int formatType,int numberAcross,double objSense) const 
{
  return OsiSolverInterface::writeMpsNative(filename, rowNames, columnNames,
			       formatType, numberAcross,objSense,
					    numberSOS_,setInfo_);
}

//#############################################################################
// CLP specific public interfaces
//#############################################################################

ClpSimplex * OsiClpSolverInterface::getModelPtr() const
{
  int saveAlgorithm = lastAlgorithm_;
  //freeCachedResults();
  lastAlgorithm_ = saveAlgorithm;
  //bool inCbcOrOther = (modelPtr_->specialOptions()&0x03000000)!=0;
  return modelPtr_;
}

//------------------------------------------------------------------- 

//#############################################################################
// Constructors, destructors clone and assignment
//#############################################################################
//-------------------------------------------------------------------
// Default Constructor 
//-------------------------------------------------------------------
OsiClpSolverInterface::OsiClpSolverInterface ()
:
OsiSolverInterface(),
rowsense_(NULL),
rhs_(NULL),
rowrange_(NULL),
ws_(NULL),
rowActivity_(NULL),
columnActivity_(NULL),
numberSOS_(0),
setInfo_(NULL),
smallModel_(NULL),
factorization_(NULL),
smallestElementInCut_(1.0e-15),
smallestChangeInCut_(1.0e-10),
largestAway_(-1.0),
spareArrays_(NULL),
matrixByRow_(NULL),
matrixByRowAtContinuous_(NULL),  
integerInformation_(NULL),
whichRange_(NULL),
fakeMinInSimplex_(false),
linearObjective_(NULL),
cleanupScaling_(0),
specialOptions_(0x80000000),
baseModel_(NULL),
lastNumberRows_(0),
continuousModel_(NULL),
fakeObjective_(NULL)
{
  //printf("in default %x\n",this);
  modelPtr_=NULL;
  notOwned_=false;
  disasterHandler_ = new OsiClpDisasterHandler();
  reset();
}

//-------------------------------------------------------------------
// Clone
//-------------------------------------------------------------------
OsiSolverInterface * OsiClpSolverInterface::clone(bool CopyData) const
{
  //printf("in clone %x\n",this);
  OsiClpSolverInterface * newSolver;
  if (CopyData) {
    newSolver = new OsiClpSolverInterface(*this);
  } else {
    newSolver = new OsiClpSolverInterface();
  }
#if 0
  const double * obj = newSolver->getObjCoefficients();
  const double * oldObj = getObjCoefficients();
  if(newSolver->getNumCols()>3787)
    printf("%x - obj %x (from %x) val %g\n",newSolver,obj,oldObj,obj[3787]);
#endif
  return newSolver;
}


//-------------------------------------------------------------------
// Copy constructor 
//-------------------------------------------------------------------
OsiClpSolverInterface::OsiClpSolverInterface (
                  const OsiClpSolverInterface & rhs)
: OsiSolverInterface(rhs),
rowsense_(NULL),
rhs_(NULL),
rowrange_(NULL),
ws_(NULL),
rowActivity_(NULL),
columnActivity_(NULL),
  stuff_(rhs.stuff_),
numberSOS_(rhs.numberSOS_),
setInfo_(NULL),
smallModel_(NULL),
factorization_(NULL),
smallestElementInCut_(rhs.smallestElementInCut_),
smallestChangeInCut_(rhs.smallestChangeInCut_),
largestAway_(-1.0),
spareArrays_(NULL),
basis_(),
itlimOrig_(9999999),
lastAlgorithm_(0),
notOwned_(false),
matrixByRow_(NULL),
matrixByRowAtContinuous_(NULL),  
integerInformation_(NULL),
whichRange_(NULL),
fakeMinInSimplex_(rhs.fakeMinInSimplex_)
{
  //printf("in copy %x - > %x\n",&rhs,this);
  if ( rhs.modelPtr_  ) 
    modelPtr_ = new ClpSimplex(*rhs.modelPtr_);
  else
    modelPtr_ = new ClpSimplex();
  if ( rhs.baseModel_  ) 
    baseModel_ = new ClpSimplex(*rhs.baseModel_);
  else
    baseModel_ = NULL;
  if ( rhs.continuousModel_  ) 
    continuousModel_ = new ClpSimplex(*rhs.continuousModel_);
  else
    continuousModel_ = NULL;
  if (rhs.matrixByRowAtContinuous_)
    matrixByRowAtContinuous_ = new CoinPackedMatrix(*rhs.matrixByRowAtContinuous_);
  if ( rhs.disasterHandler_  ) 
    disasterHandler_ = dynamic_cast<OsiClpDisasterHandler *>(rhs.disasterHandler_->clone());
  else
    disasterHandler_ = NULL;
  if (rhs.fakeObjective_)
    fakeObjective_ = new ClpLinearObjective(*rhs.fakeObjective_);
  else
    fakeObjective_ = NULL;
  linearObjective_ = modelPtr_->objective();
  if ( rhs.ws_ ) 
    ws_ = new CoinWarmStartBasis(*rhs.ws_);
  basis_ = rhs.basis_;
  if (rhs.integerInformation_) {
    int numberColumns = modelPtr_->numberColumns();
    integerInformation_ = new char[numberColumns];
    CoinMemcpyN(rhs.integerInformation_,	numberColumns,integerInformation_);
  }
  saveData_ = rhs.saveData_;
  solveOptions_  = rhs.solveOptions_;
  cleanupScaling_ = rhs.cleanupScaling_;
  specialOptions_ = rhs.specialOptions_;
  lastNumberRows_ = rhs.lastNumberRows_;
  rowScale_ = rhs.rowScale_;
  columnScale_ = rhs.columnScale_;
  fillParamMaps();
  messageHandler()->setLogLevel(rhs.messageHandler()->logLevel());
  if (numberSOS_) {
    setInfo_ = new CoinSet[numberSOS_];
    for (int i=0;i<numberSOS_;i++)
      setInfo_[i]=rhs.setInfo_[i];
  }
}

// Borrow constructor - only delete one copy
OsiClpSolverInterface::OsiClpSolverInterface (ClpSimplex * rhs,
					      bool reallyOwn)
:
OsiSolverInterface(),
rowsense_(NULL),
rhs_(NULL),
rowrange_(NULL),
ws_(NULL),
rowActivity_(NULL),
columnActivity_(NULL),
numberSOS_(0),
setInfo_(NULL),
smallModel_(NULL),
factorization_(NULL),
smallestElementInCut_(1.0e-15),
smallestChangeInCut_(1.0e-10),
largestAway_(-1.0),
spareArrays_(NULL),
basis_(),
itlimOrig_(9999999),
lastAlgorithm_(0),
notOwned_(false),
matrixByRow_(NULL),
matrixByRowAtContinuous_(NULL),  
integerInformation_(NULL),
whichRange_(NULL),
fakeMinInSimplex_(false),
cleanupScaling_(0),
specialOptions_(0x80000000),
baseModel_(NULL),
lastNumberRows_(0),
continuousModel_(NULL),
fakeObjective_(NULL)
{
  disasterHandler_ = new OsiClpDisasterHandler();
  //printf("in borrow %x - > %x\n",&rhs,this);
  modelPtr_ = rhs;
  basis_.resize(modelPtr_->numberRows(),modelPtr_->numberColumns());
  linearObjective_ = modelPtr_->objective();
  if (rhs) {
    notOwned_=!reallyOwn;

    if (rhs->integerInformation()) {
      int numberColumns = modelPtr_->numberColumns();
      integerInformation_ = new char[numberColumns];
      CoinMemcpyN(rhs->integerInformation(),	numberColumns,integerInformation_);
    }
  }
  fillParamMaps();
}
    
// Releases so won't error
void 
OsiClpSolverInterface::releaseClp()
{
  modelPtr_=NULL;
  notOwned_=false;
}
    
//-------------------------------------------------------------------
// Destructor 
//-------------------------------------------------------------------
OsiClpSolverInterface::~OsiClpSolverInterface ()
{
  //printf("in destructor %x\n",this);
  freeCachedResults();
  if (!notOwned_)
    delete modelPtr_;
  delete baseModel_;
  delete continuousModel_;
  delete disasterHandler_;
  delete fakeObjective_;
  delete ws_;
  delete [] rowActivity_;
  delete [] columnActivity_;
  delete [] setInfo_;
#ifdef KEEP_SMALL
  if (smallModel_) {
    delete [] spareArrays_;
    spareArrays_ = NULL;
    delete smallModel_;
    smallModel_=NULL;
  }
#endif
  assert(smallModel_==NULL);
  assert(factorization_==NULL);
  assert(spareArrays_==NULL);
  delete [] integerInformation_;
  delete matrixByRowAtContinuous_;
  delete matrixByRow_;
}

//-------------------------------------------------------------------
// Assignment operator 
//-------------------------------------------------------------------
OsiClpSolverInterface &
OsiClpSolverInterface::operator=(const OsiClpSolverInterface& rhs)
{
  if (this != &rhs) {    
    //printf("in = %x - > %x\n",&rhs,this);
    OsiSolverInterface::operator=(rhs);
    freeCachedResults();
    if (!notOwned_)
      delete modelPtr_;
    delete ws_;
    if ( rhs.modelPtr_  ) 
      modelPtr_ = new ClpSimplex(*rhs.modelPtr_);
    delete baseModel_;
    if ( rhs.baseModel_  ) 
      baseModel_ = new ClpSimplex(*rhs.baseModel_);
    else
      baseModel_ = NULL;
    delete continuousModel_;
    if ( rhs.continuousModel_  ) 
      continuousModel_ = new ClpSimplex(*rhs.continuousModel_);
    else
      continuousModel_ = NULL;
    delete matrixByRowAtContinuous_;
    delete matrixByRow_;
    matrixByRow_=NULL;
    if (rhs.matrixByRowAtContinuous_)
      matrixByRowAtContinuous_ = new CoinPackedMatrix(*rhs.matrixByRowAtContinuous_);
    else
      matrixByRowAtContinuous_=NULL;
    delete disasterHandler_;
    if ( rhs.disasterHandler_  ) 
      disasterHandler_ = dynamic_cast<OsiClpDisasterHandler *>(rhs.disasterHandler_->clone());
    else
      disasterHandler_ = NULL;
    delete fakeObjective_;
    if (rhs.fakeObjective_)
      fakeObjective_ = new ClpLinearObjective(*rhs.fakeObjective_);
    else
      fakeObjective_ = NULL;
    notOwned_=false;
    linearObjective_ = modelPtr_->objective();
    saveData_ = rhs.saveData_;
    solveOptions_  = rhs.solveOptions_;
    cleanupScaling_ = rhs.cleanupScaling_;
    specialOptions_ = rhs.specialOptions_;
    lastNumberRows_ = rhs.lastNumberRows_;
    rowScale_ = rhs.rowScale_;
    columnScale_ = rhs.columnScale_;
    basis_ = rhs.basis_;
    stuff_ = rhs.stuff_;
    if (rhs.integerInformation_) {
      int numberColumns = modelPtr_->numberColumns();
      integerInformation_ = new char[numberColumns];
      CoinMemcpyN(rhs.integerInformation_,	numberColumns,integerInformation_);
    }
    if ( rhs.ws_ ) 
      ws_ = new CoinWarmStartBasis(*rhs.ws_);
    else
      ws_=NULL;
    delete [] rowActivity_;
    delete [] columnActivity_;
    rowActivity_=NULL;
    columnActivity_=NULL;
    delete [] setInfo_;
    numberSOS_ = rhs.numberSOS_;
    setInfo_=NULL;
    if (numberSOS_) {
      setInfo_ = new CoinSet[numberSOS_];
      for (int i=0;i<numberSOS_;i++)
	setInfo_[i]=rhs.setInfo_[i];
    }
    assert(smallModel_==NULL);
    assert(factorization_==NULL);
    smallestElementInCut_ = rhs.smallestElementInCut_;
    smallestChangeInCut_ = rhs.smallestChangeInCut_;
    largestAway_ = -1.0;
    assert(spareArrays_==NULL);
    basis_ = rhs.basis_;
    fillParamMaps();
    messageHandler()->setLogLevel(rhs.messageHandler()->logLevel());
  }
  return *this;
}

//#############################################################################
// Applying cuts
//#############################################################################

void OsiClpSolverInterface::applyRowCut( const OsiRowCut & rowCut )
{
  applyRowCuts(1, &rowCut);
}
/* Apply a collection of row cuts which are all effective.
   applyCuts seems to do one at a time which seems inefficient.
*/
void 
OsiClpSolverInterface::applyRowCuts(int numberCuts, const OsiRowCut * cuts)
{
  if (numberCuts) {
    // Say can't gurantee optimal basis etc
    lastAlgorithm_=999;

    // Thanks to js
    const OsiRowCut * * cutsp = new const OsiRowCut * [numberCuts];
    for (int i=0;i<numberCuts;i++) 
      cutsp[i] = &cuts[i];
    
    applyRowCuts(numberCuts, cutsp);
    
    delete [] cutsp;
  }
}
/* Apply a collection of row cuts which are all effective.
   applyCuts seems to do one at a time which seems inefficient.
*/
void 
OsiClpSolverInterface::applyRowCuts(int numberCuts, const OsiRowCut ** cuts)
{
  int i;
  if (!numberCuts)
    return;
  modelPtr_->whatsChanged_ &= (0xffff&~(1|2|4|16|32));
  CoinPackedMatrix * saveRowCopy = matrixByRow_;
  matrixByRow_=NULL;
#if 0 // was #ifndef NDEBUG
  int nameDiscipline;
  getIntParam(OsiNameDiscipline,nameDiscipline) ;
  assert (!nameDiscipline);
#endif
  freeCachedResults0();
  // Say can't gurantee optimal basis etc
  lastAlgorithm_=999;
  int numberRows = modelPtr_->numberRows();
  modelPtr_->resize(numberRows+numberCuts,modelPtr_->numberColumns());
  basis_.resize(numberRows+numberCuts,modelPtr_->numberColumns());
  // redo as relaxed - use modelPtr_-> addRows with starts etc
  int size = 0;
  for (i=0;i<numberCuts;i++) 
    size += cuts[i]->row().getNumElements();
  CoinBigIndex * starts = new CoinBigIndex [numberCuts+1];
  int * indices = new int[size];
  double * elements = new double[size];
  double * lower = modelPtr_->rowLower()+numberRows;
  double * upper = modelPtr_->rowUpper()+numberRows;
  const double * columnLower = modelPtr_->columnLower();
  const double * columnUpper = modelPtr_->columnUpper();
  size=0;
  for (i=0;i<numberCuts;i++) {
    double rowLb = cuts[i]->lb();
    double rowUb = cuts[i]->ub();
    int n=cuts[i]->row().getNumElements();
    const int * index = cuts[i]->row().getIndices();
    const double * elem = cuts[i]->row().getElements();
    starts[i]=size;
    for (int j=0;j<n;j++) {
      double value = elem[j];
      int column = index[j];
      if (fabs(value)>=smallestChangeInCut_) {
        // always take
        indices[size]=column;
        elements[size++]=value;
      } else if (fabs(value)>=smallestElementInCut_) {
        double lowerValue = columnLower[column];
        double upperValue = columnUpper[column];
        double difference = upperValue-lowerValue;
        if (difference<1.0e20&&difference*fabs(value)<smallestChangeInCut_&&
            (rowLb<-1.0e20||rowUb>1.0e20)) {
          // Take out and adjust to relax
          //printf("small el %g adjusted\n",value);
          if (rowLb>-1.0e20) {
            // just lower bound on row
            if (value>0.0) {
              // pretend at upper
              rowLb -= value*upperValue;
            } else {
              // pretend at lower
              rowLb -= value*lowerValue;
            }
          } else {
            // just upper bound on row
            if (value>0.0) {
              // pretend at lower
              rowUb -= value*lowerValue;
            } else {
              // pretend at upper
              rowUb -= value*upperValue;
            }
          }
        } else {
          // take (unwillingly)
          indices[size]=column;
          elements[size++]=value;
        }
      } else {
        //printf("small el %g ignored\n",value);
      }
    }
    lower[i]= forceIntoRange(rowLb, -OsiClpInfinity, OsiClpInfinity);
    upper[i]= forceIntoRange(rowUb, -OsiClpInfinity, OsiClpInfinity);
    if (lower[i]<-1.0e27)
      lower[i]=-COIN_DBL_MAX;
    if (upper[i]>1.0e27)
      upper[i]=COIN_DBL_MAX;
  }
  starts[numberCuts]=size;
  if (!modelPtr_->clpMatrix())
    modelPtr_->createEmptyMatrix();
  //modelPtr_->matrix()->appendRows(numberCuts,rows);
  modelPtr_->clpMatrix()->appendMatrix(numberCuts,0,starts,indices,elements);
  modelPtr_->setNewRowCopy(NULL);
  freeCachedResults1();
  redoScaleFactors( numberCuts,starts, indices, elements);
  if (saveRowCopy) {
#if 1
    matrixByRow_=saveRowCopy;
    matrixByRow_->appendRows(numberCuts,starts,indices,elements,0);
    assert (matrixByRow_->getNumElements()==modelPtr_->clpMatrix()->getNumElements());
#else
    delete saveRowCopy;
#endif
  }
  delete [] starts;
  delete [] indices;
  delete [] elements;

}
//#############################################################################
// Apply Cuts
//#############################################################################

OsiSolverInterface::ApplyCutsReturnCode
OsiClpSolverInterface::applyCuts( const OsiCuts & cs, double effectivenessLb ) 
{
  OsiSolverInterface::ApplyCutsReturnCode retVal;
  int i;

  // Loop once for each column cut
  for ( i=0; i<cs.sizeColCuts(); i ++ ) {
    if ( cs.colCut(i).effectiveness() < effectivenessLb ) {
      retVal.incrementIneffective();
      continue;
    }
    if ( !cs.colCut(i).consistent() ) {
      retVal.incrementInternallyInconsistent();
      continue;
    }
    if ( !cs.colCut(i).consistent(*this) ) {
      retVal.incrementExternallyInconsistent();
      continue;
    }
    if ( cs.colCut(i).infeasible(*this) ) {
      retVal.incrementInfeasible();
      continue;
    }
    applyColCut( cs.colCut(i) );
    retVal.incrementApplied();
  }

  // Loop once for each row cut
  const OsiRowCut ** addCuts = new const OsiRowCut* [cs.sizeRowCuts()];
  int nAdd=0;
  for ( i=0; i<cs.sizeRowCuts(); i ++ ) {
    if ( cs.rowCut(i).effectiveness() < effectivenessLb ) {
      retVal.incrementIneffective();
      continue;
    }
    if ( !cs.rowCut(i).consistent() ) {
      retVal.incrementInternallyInconsistent();
      continue;
    }
    if ( !cs.rowCut(i).consistent(*this) ) {
      retVal.incrementExternallyInconsistent();
      continue;
    }
    if ( cs.rowCut(i).infeasible(*this) ) {
      retVal.incrementInfeasible();
      continue;
    }
    addCuts[nAdd++] = cs.rowCutPtr(i);
    retVal.incrementApplied();
  }
  // now apply
  applyRowCuts(nAdd,addCuts);
  delete [] addCuts;
  
  return retVal;
}
// Extend scale factors
void 
OsiClpSolverInterface::redoScaleFactors(int numberAdd,const CoinBigIndex * starts,
					const int * indices, const double * elements)
{
  if ((specialOptions_&131072)!=0) {
    int numberRows = modelPtr_->numberRows()-numberAdd;
    assert (lastNumberRows_==numberRows); // ???
    int iRow;
    int newNumberRows = numberRows + numberAdd;
    rowScale_.extend(static_cast<int>(2*newNumberRows*sizeof(double)));
    double * rowScale = rowScale_.array();
    double * oldInverseScale = rowScale + lastNumberRows_;
    double * inverseRowScale = rowScale + newNumberRows;
    for (iRow=lastNumberRows_-1;iRow>=0;iRow--)
      inverseRowScale[iRow] = oldInverseScale[iRow] ;
    //int numberColumns = baseModel_->numberColumns();
    const double * columnScale = columnScale_.array();
    //const double * inverseColumnScale = columnScale + numberColumns;
    // Geometric mean on row scales
    // adjust arrays
    rowScale += lastNumberRows_;
    inverseRowScale += lastNumberRows_;
    for (iRow=0;iRow<numberAdd;iRow++) {
      CoinBigIndex j;
      double largest=1.0e-20;
      double smallest=1.0e50;
      for (j=starts[iRow];j<starts[iRow+1];j++) {
	int iColumn = indices[j];
	double value = fabs(elements[j]);
	// Don't bother with tiny elements
	if (value>1.0e-20) {
	  value *= columnScale[iColumn];
	  largest = CoinMax(largest,value);
	  smallest = CoinMin(smallest,value);
	}
      }
      double scale=sqrt(smallest*largest);
      scale=CoinMax(1.0e-10,CoinMin(1.0e10,scale));
      inverseRowScale[iRow]=scale;
      rowScale[iRow]=1.0/scale;
    }
    lastNumberRows_=newNumberRows;
  }
}
// Delete all scale factor stuff and reset option
void OsiClpSolverInterface::deleteScaleFactors()
{
  delete baseModel_;
  baseModel_=NULL;
  lastNumberRows_=0;
  specialOptions_ &= ~131072;
}
//-----------------------------------------------------------------------------

void OsiClpSolverInterface::applyColCut( const OsiColCut & cc )
{
  modelPtr_->whatsChanged_ &= (0x1ffff&~(128|256));
  // Say can't gurantee optimal basis etc
  lastAlgorithm_=999;
  double * lower = modelPtr_->columnLower();
  double * upper = modelPtr_->columnUpper();
  const CoinPackedVector & lbs = cc.lbs();
  const CoinPackedVector & ubs = cc.ubs();
  int i;

  for ( i=0; i<lbs.getNumElements(); i++ ) {
    int iCol = lbs.getIndices()[i];
    double value = lbs.getElements()[i];
    if ( value > lower[iCol] )
      lower[iCol]= value;
  }
  for ( i=0; i<ubs.getNumElements(); i++ ) {
    int iCol = ubs.getIndices()[i];
    double value = ubs.getElements()[i];
    if ( value < upper[iCol] )
      upper[iCol]= value;
  }
}
//#############################################################################
// Private methods
//#############################################################################


//------------------------------------------------------------------- 

void OsiClpSolverInterface::freeCachedResults() const
{  
  // Say can't gurantee optimal basis etc
  lastAlgorithm_=999;
  delete [] rowsense_;
  delete [] rhs_;
  delete [] rowrange_;
  delete matrixByRow_;
  if (modelPtr_&&modelPtr_->scaledMatrix_) {
    delete modelPtr_->scaledMatrix_;
    modelPtr_->scaledMatrix_=NULL;
  }
  //delete ws_;
  rowsense_=NULL;
  rhs_=NULL;
  rowrange_=NULL;
  matrixByRow_=NULL;
  //ws_ = NULL;
  if (modelPtr_&&modelPtr_->clpMatrix()) {
    modelPtr_->clpMatrix()->refresh(modelPtr_); // make sure all clean
#ifndef NDEBUG
    ClpPackedMatrix * clpMatrix = dynamic_cast<ClpPackedMatrix *> (modelPtr_->clpMatrix());
    if (clpMatrix) {
      if (clpMatrix->getNumCols())
	assert (clpMatrix->getNumRows()==modelPtr_->getNumRows());
      if (clpMatrix->getNumRows())
	assert (clpMatrix->getNumCols()==modelPtr_->getNumCols());
    }
#endif
  }
}

//------------------------------------------------------------------- 

void OsiClpSolverInterface::freeCachedResults0() const
{  
  delete [] rowsense_;
  delete [] rhs_;
  delete [] rowrange_;
  rowsense_=NULL;
  rhs_=NULL;
  rowrange_=NULL;
}

//------------------------------------------------------------------- 

void OsiClpSolverInterface::freeCachedResults1() const
{  
  // Say can't gurantee optimal basis etc
  lastAlgorithm_=999;
  delete matrixByRow_;
  matrixByRow_=NULL;
  //ws_ = NULL;
  if (modelPtr_&&modelPtr_->clpMatrix()) {
    delete modelPtr_->scaledMatrix_;
    modelPtr_->scaledMatrix_=NULL;
    modelPtr_->clpMatrix()->refresh(modelPtr_); // make sure all clean
#ifndef NDEBUG
    ClpPackedMatrix * clpMatrix = dynamic_cast<ClpPackedMatrix *> (modelPtr_->clpMatrix());
    if (clpMatrix) {
      assert (clpMatrix->getNumRows()==modelPtr_->getNumRows());
      assert (clpMatrix->getNumCols()==modelPtr_->getNumCols());
    }
#endif
  }
}

//------------------------------------------------------------------
void OsiClpSolverInterface::extractSenseRhsRange() const
{
  if (rowsense_ == NULL) {
    // all three must be NULL
    assert ((rhs_ == NULL) && (rowrange_ == NULL));
    
    int nr=modelPtr_->numberRows();
    if ( nr!=0 ) {
      rowsense_ = new char[nr];
      rhs_ = new double[nr];
      rowrange_ = new double[nr];
      std::fill(rowrange_,rowrange_+nr,0.0);
      
      const double * lb = modelPtr_->rowLower();
      const double * ub = modelPtr_->rowUpper();
      
      int i;
      for ( i=0; i<nr; i++ ) {
        convertBoundToSense(lb[i], ub[i], rowsense_[i], rhs_[i], rowrange_[i]);
      }
    }
  }
}
// Set language
void 
OsiClpSolverInterface::newLanguage(CoinMessages::Language language)
{
  modelPtr_->newLanguage(language);
  OsiSolverInterface::newLanguage(language);
}
//#############################################################################

void
OsiClpSolverInterface::fillParamMaps()
{
  assert (static_cast<int> (OsiMaxNumIteration)==        static_cast<int>(ClpMaxNumIteration));
  assert (static_cast<int> (OsiMaxNumIterationHotStart)==static_cast<int>(ClpMaxNumIterationHotStart));
  //assert (static_cast<int> (OsiLastIntParam)==           static_cast<int>(ClpLastIntParam));
  
  assert (static_cast<int> (OsiDualObjectiveLimit)==  static_cast<int>(ClpDualObjectiveLimit));
  assert (static_cast<int> (OsiPrimalObjectiveLimit)==static_cast<int>(ClpPrimalObjectiveLimit));
  assert (static_cast<int> (OsiDualTolerance)==       static_cast<int>(ClpDualTolerance));
  assert (static_cast<int> (OsiPrimalTolerance)==     static_cast<int>(ClpPrimalTolerance));
  assert (static_cast<int> (OsiObjOffset)==           static_cast<int>(ClpObjOffset));
  //assert (static_cast<int> (OsiLastDblParam)==        static_cast<int>(ClpLastDblParam));
  
  assert (static_cast<int> (OsiProbName)==    static_cast<int> (ClpProbName));
  //strParamMap_[OsiLastStrParam] = ClpLastStrParam;
}
// Sets up basis
void 
OsiClpSolverInterface::setBasis ( const CoinWarmStartBasis & basis)
{
  setBasis(basis,modelPtr_);
  setWarmStart(&basis); 
}
// Warm start
CoinWarmStartBasis
OsiClpSolverInterface::getBasis(ClpSimplex * model) const
{
  int iRow,iColumn;
  int numberRows = model->numberRows();
  int numberColumns = model->numberColumns();
  CoinWarmStartBasis basis;
  basis.setSize(numberColumns,numberRows);
  if (model->statusExists()) {
    // Flip slacks
    int lookupA[]={0,1,3,2,0,2};
    for (iRow=0;iRow<numberRows;iRow++) {
      int iStatus = model->getRowStatus(iRow);
      iStatus = lookupA[iStatus];
      basis.setArtifStatus(iRow,static_cast<CoinWarmStartBasis::Status> (iStatus));
    }
    int lookupS[]={0,1,2,3,0,3};
    for (iColumn=0;iColumn<numberColumns;iColumn++) {
      int iStatus = model->getColumnStatus(iColumn);
      iStatus = lookupS[iStatus];
      basis.setStructStatus(iColumn,static_cast<CoinWarmStartBasis::Status> (iStatus));
    }
  }
  //basis.print();
  return basis;
}
// Warm start from statusArray
CoinWarmStartBasis * 
OsiClpSolverInterface::getBasis(const unsigned char * statusArray) const 
{
  int iRow,iColumn;
  int numberRows = modelPtr_->numberRows();
  int numberColumns = modelPtr_->numberColumns();
  CoinWarmStartBasis * basis = new CoinWarmStartBasis();
  basis->setSize(numberColumns,numberRows);
  // Flip slacks
  int lookupA[]={0,1,3,2,0,2};
  for (iRow=0;iRow<numberRows;iRow++) {
    int iStatus = statusArray[numberColumns+iRow]&7;
    iStatus = lookupA[iStatus];
    basis->setArtifStatus(iRow,static_cast<CoinWarmStartBasis::Status> (iStatus));
  }
  int lookupS[]={0,1,2,3,0,3};
  for (iColumn=0;iColumn<numberColumns;iColumn++) {
    int iStatus = statusArray[iColumn]&7;
    iStatus = lookupS[iStatus];
    basis->setStructStatus(iColumn,static_cast<CoinWarmStartBasis::Status> (iStatus));
  }
  //basis->print();
  return basis;
}
// Sets up basis
void 
OsiClpSolverInterface::setBasis ( const CoinWarmStartBasis & basis,
				  ClpSimplex * model)
{
  // Say can't gurantee optimal basis etc
  lastAlgorithm_=999;
  // transform basis to status arrays
  int iRow,iColumn;
  int numberRows = model->numberRows();
  int numberColumns = model->numberColumns();
  if (!model->statusExists()) {
    /*
      get status arrays
      ClpBasis would seem to have overheads and we will need
      extra bits anyway.
    */
    model->createStatus();
  }
  if (basis.getNumArtificial()!=numberRows||
      basis.getNumStructural()!=numberColumns) {
    CoinWarmStartBasis basis2 = basis;
    // resize 
    basis2.resize(numberRows,numberColumns);
    // move status
    model->createStatus();
    // For rows lower and upper are flipped
    for (iRow=0;iRow<numberRows;iRow++) {
      int stat = basis2.getArtifStatus(iRow);
      if (stat>1)
	stat = 5 - stat; // so 2->3 and 3->2
      model->setRowStatus(iRow, static_cast<ClpSimplex::Status> (stat));
    }
    for (iColumn=0;iColumn<numberColumns;iColumn++) {
      model->setColumnStatus(iColumn,
			     static_cast<ClpSimplex::Status> (basis2.getStructStatus(iColumn)));
    }
  } else {
    // move status
    model->createStatus();
    // For rows lower and upper are flipped
    for (iRow=0;iRow<numberRows;iRow++) {
      int stat = basis.getArtifStatus(iRow);
      if (stat>1)
	stat = 5 - stat; // so 2->3 and 3->2
      model->setRowStatus(iRow, static_cast<ClpSimplex::Status> (stat));
    }
    for (iColumn=0;iColumn<numberColumns;iColumn++) {
      model->setColumnStatus(iColumn,
			     static_cast<ClpSimplex::Status> (basis.getStructStatus(iColumn)));
    }
  }
}
// Warm start difference from basis_ to statusArray
CoinWarmStartDiff * 
OsiClpSolverInterface::getBasisDiff(const unsigned char * statusArray) const
{
  int iRow,iColumn;
  int numberRows = modelPtr_->numberRows();
  int numberColumns = modelPtr_->numberColumns();
  CoinWarmStartBasis basis;
  basis.setSize(numberColumns,numberRows);
  assert (modelPtr_->statusExists());
  int lookupS[]={0,1,2,3,0,3};
  for (iColumn=0;iColumn<numberColumns;iColumn++) {
    int iStatus = statusArray[iColumn]&7;
    iStatus = lookupS[iStatus];
    basis.setStructStatus(iColumn,static_cast<CoinWarmStartBasis::Status> (iStatus));
  }
  statusArray += numberColumns;
  // Flip slacks
  int lookupA[]={0,1,3,2,0,2};
  for (iRow=0;iRow<numberRows;iRow++) {
    int iStatus = statusArray[iRow]&7;
    iStatus = lookupA[iStatus];
    basis.setArtifStatus(iRow,static_cast<CoinWarmStartBasis::Status> (iStatus));
  }
  // Now basis is what we want while basis_ is old
  CoinWarmStartDiff * difference = basis.generateDiff(&basis_);
  return difference;
}
/*
  Read an mps file from the given filename - returns number of errors
  (see CoinMpsIO class)
*/
int 
OsiClpSolverInterface::readMps(const char *filename,
			       const char *extension ) 
{
  // Get rid of integer stuff
  delete [] integerInformation_;
  integerInformation_=NULL;
  freeCachedResults();
  
  CoinMpsIO m;
  m.setInfinity(getInfinity());
  m.passInMessageHandler(modelPtr_->messageHandler());
  *m.messagesPointer()=modelPtr_->coinMessages();

  delete [] setInfo_;
  setInfo_=NULL;
  numberSOS_=0;
  CoinSet ** sets=NULL;
  // Temporarily reduce log level to get CoinMpsIO to shut up.
  int saveLogLevel = modelPtr_->messageHandler()->logLevel() ;
  modelPtr_->messageHandler()->setLogLevel(0) ;
  int numberErrors = m.readMps(filename,extension,numberSOS_,sets);
  modelPtr_->messageHandler()->setLogLevel(saveLogLevel) ;
  if (numberSOS_) {
    setInfo_ = new CoinSet[numberSOS_];
    for (int i=0;i<numberSOS_;i++) {
      setInfo_[i]=*sets[i];
      delete sets[i];
    }
    delete [] sets;
  }
  handler_->message(COIN_SOLVER_MPS,messages_)
    <<m.getProblemName()<< numberErrors <<CoinMessageEol;
  if (!numberErrors) {

    // set objective function offest
    setDblParam(OsiObjOffset,m.objectiveOffset());

    // set problem name
    setStrParam(OsiProbName,m.getProblemName());
    
    // no errors
    loadProblem(*m.getMatrixByCol(),m.getColLower(),m.getColUpper(),
		m.getObjCoefficients(),m.getRowSense(),m.getRightHandSide(),
		m.getRowRange());
    const char * integer = m.integerColumns();
    int nCols=m.getNumCols();
    int nRows=m.getNumRows();
    if (integer) {
      int i,n=0;
      int * index = new int [nCols];
      for (i=0;i<nCols;i++) {
	if (integer[i]) {
	  index[n++]=i;
        }
      }
      setInteger(index,n);
      delete [] index;
      if (n) 
        modelPtr_->copyInIntegerInformation(integer);
    }

    // set objective name
    setObjName(m.getObjectiveName());

    // Always keep names
    int nameDiscipline;
    getIntParam(OsiNameDiscipline,nameDiscipline) ;
    int iRow;
    std::vector<std::string> rowNames = std::vector<std::string> ();
    std::vector<std::string> columnNames = std::vector<std::string> ();
    rowNames.reserve(nRows);
    for (iRow=0;iRow<nRows;iRow++) {
      const char * name = m.rowName(iRow);
      rowNames.push_back(name);
      if (nameDiscipline) 
	OsiSolverInterface::setRowName(iRow,name) ;
    }
    
    int iColumn;
    columnNames.reserve(nCols);
    for (iColumn=0;iColumn<nCols;iColumn++) {
      const char * name = m.columnName(iColumn);
      columnNames.push_back(name);
      if (nameDiscipline) 
	OsiSolverInterface::setColName(iColumn,name) ;
    }
    modelPtr_->copyNames(rowNames,columnNames);
  }
  return numberErrors;
}
int 
OsiClpSolverInterface::readMps(const char *filename, const char*extension,
			    int & numberSets, CoinSet ** & sets)
{
  int numberErrors = readMps(filename,extension);
  numberSets= numberSOS_;
  sets = &setInfo_;
  return numberErrors;
}
/* Read an mps file from the given filename returns
   number of errors (see OsiMpsReader class) */
int 
OsiClpSolverInterface::readMps(const char *filename,bool keepNames,bool allowErrors)
{
  // Get rid of integer stuff
  delete [] integerInformation_;
  integerInformation_=NULL;
  freeCachedResults();
  
  CoinMpsIO m;
  m.setInfinity(getInfinity());
  m.passInMessageHandler(modelPtr_->messageHandler());
  *m.messagesPointer()=modelPtr_->coinMessages();

  delete [] setInfo_;
  setInfo_=NULL;
  numberSOS_=0;
  CoinSet ** sets=NULL;
  int numberErrors = m.readMps(filename,"",numberSOS_,sets);
  if (numberSOS_) {
    setInfo_ = new CoinSet[numberSOS_];
    for (int i=0;i<numberSOS_;i++) {
      setInfo_[i]=*sets[i];
      delete sets[i];
    }
    delete [] sets;
  }
  handler_->message(COIN_SOLVER_MPS,messages_)
    <<m.getProblemName()<< numberErrors <<CoinMessageEol;
  if (!numberErrors||((numberErrors>0&&numberErrors<100000)&&allowErrors)) {

    // set objective function offest
    setDblParam(OsiObjOffset,m.objectiveOffset());

    // set problem name
    setStrParam(OsiProbName,m.getProblemName());

    // set objective name
    setObjName(m.getObjectiveName());

    // no errors
    loadProblem(*m.getMatrixByCol(),m.getColLower(),m.getColUpper(),
		m.getObjCoefficients(),m.getRowSense(),m.getRightHandSide(),
		m.getRowRange());
    int nCols=m.getNumCols();
    // get quadratic part
    if (m.reader()->whichSection (  ) == COIN_QUAD_SECTION ) {
      int * start=NULL;
      int * column = NULL;
      double * element = NULL;
      int status=m.readQuadraticMps(NULL,start,column,element,2);
      if (!status) 
	modelPtr_->loadQuadraticObjective(nCols,start,column,element);
      delete [] start;
      delete [] column;
      delete [] element;
    }
    const char * integer = m.integerColumns();
    int nRows=m.getNumRows();
    if (integer) {
      int i,n=0;
      int * index = new int [nCols];
      for (i=0;i<nCols;i++) {
	if (integer[i]) {
	  index[n++]=i;
        }
      }
      setInteger(index,n);
      delete [] index;
      if (n) 
        modelPtr_->copyInIntegerInformation(integer);
    }
    if (keepNames) {
      // keep names
      int nameDiscipline;
      getIntParam(OsiNameDiscipline,nameDiscipline) ;
      int iRow;
      std::vector<std::string> rowNames = std::vector<std::string> ();
      std::vector<std::string> columnNames = std::vector<std::string> ();
      rowNames.reserve(nRows);
      for (iRow=0;iRow<nRows;iRow++) {
	const char * name = m.rowName(iRow);
	rowNames.push_back(name);
	if (nameDiscipline) 
	  OsiSolverInterface::setRowName(iRow,name) ;
      }
      
      int iColumn;
      columnNames.reserve(nCols);
      for (iColumn=0;iColumn<nCols;iColumn++) {
	const char * name = m.columnName(iColumn);
	columnNames.push_back(name);
	if (nameDiscipline) 
	  OsiSolverInterface::setColName(iColumn,name) ;
      }
      modelPtr_->copyNames(rowNames,columnNames);
    }
  }
  return numberErrors;
}
// Read file in LP format (with names)
int 
OsiClpSolverInterface::readLp(const char *filename, const double epsilon )
{
  CoinLpIO m;
  m.readLp(filename, epsilon);
  freeCachedResults();

  // set objective function offest
  setDblParam(OsiObjOffset, 0);

  // set problem name
  setStrParam(OsiProbName, m.getProblemName());

  // set objective name
  setObjName(m.getObjName());

  // no errors
  loadProblem(*m.getMatrixByRow(), m.getColLower(), m.getColUpper(),
	      m.getObjCoefficients(), m.getRowLower(), m.getRowUpper());

  const char *integer = m.integerColumns();
  int nCols = m.getNumCols();
  int nRows = m.getNumRows();
  if (integer) {
    int i, n = 0;
    int *index = new int [nCols];
    for (i=0; i<nCols; i++) {
      if (integer[i]) {
	index[n++] = i;
      }
    }
    setInteger(index,n);
    delete [] index;
  }
  // Always keep names
  int nameDiscipline;
  getIntParam(OsiNameDiscipline,nameDiscipline) ;
  int iRow;
  std::vector<std::string> rowNames = std::vector<std::string> ();
  std::vector<std::string> columnNames = std::vector<std::string> ();
  rowNames.reserve(nRows);
  for (iRow=0;iRow<nRows;iRow++) {
    const char * name = m.rowName(iRow);
    rowNames.push_back(name);
    if (nameDiscipline) 
      OsiSolverInterface::setRowName(iRow,name) ;
  }
  
  int iColumn;
  columnNames.reserve(nCols);
  for (iColumn=0;iColumn<nCols;iColumn++) {
    const char * name = m.columnName(iColumn);
    columnNames.push_back(name);
    if (nameDiscipline) 
      OsiSolverInterface::setColName(iColumn,name) ;
  }
  modelPtr_->copyNames(rowNames,columnNames);
  return(0);
}
/* Write the problem into an Lp file of the given filename.
   If objSense is non zero then -1.0 forces the code to write a
   maximization objective and +1.0 to write a minimization one.
   If 0.0 then solver can do what it wants.
   This version calls writeLpNative with names */
void 
OsiClpSolverInterface::writeLp(const char *filename,
                               const char *extension ,
                               double epsilon ,
                               int numberAcross ,
                               int decimals ,
                               double objSense ,
                               bool changeNameOnRange) const
{
  std::string f(filename);
  std::string e(extension);
  std::string fullname;
  if (e!="") {
    fullname = f + "." + e;
  } else {
    // no extension so no trailing period
    fullname = f;
  }
  // get names
  const char * const * const rowNames = modelPtr_->rowNamesAsChar();
  const char * const * const columnNames = modelPtr_->columnNamesAsChar();
  // Fall back on Osi version - possibly with names
  OsiSolverInterface::writeLpNative(fullname.c_str(), 
				    rowNames,columnNames, epsilon, numberAcross,
				    decimals, objSense,changeNameOnRange);
  if (rowNames) {
    modelPtr_->deleteNamesAsChar(rowNames, modelPtr_->numberRows_+1);
    modelPtr_->deleteNamesAsChar(columnNames, modelPtr_->numberColumns_);
  }
}
void 
OsiClpSolverInterface::writeLp(FILE * fp,
                               double epsilon ,
                               int numberAcross ,
                               int decimals ,
                               double objSense ,
                               bool changeNameOnRange) const
{
  // get names
  const char * const * const rowNames = modelPtr_->rowNamesAsChar();
  const char * const * const columnNames = modelPtr_->columnNamesAsChar();
  // Fall back on Osi version - possibly with names
  OsiSolverInterface::writeLpNative(fp,
				    rowNames,columnNames, epsilon, numberAcross,
				    decimals, objSense,changeNameOnRange);
  if (rowNames) {
    modelPtr_->deleteNamesAsChar(rowNames, modelPtr_->numberRows_+1);
    modelPtr_->deleteNamesAsChar(columnNames, modelPtr_->numberColumns_);
  }
}
/*
  I (JJF) am getting incredibly annoyed because I can't just replace a matrix.
  The default behavior of this is do nothing so only use where that would not matter
  e.g. strengthening a matrix for MIP
*/
void 
OsiClpSolverInterface::replaceMatrixOptional(const CoinPackedMatrix & matrix)
{
  modelPtr_->whatsChanged_ &= (0xffff&~(2|4|8));
  replaceMatrix(matrix);
}
// And if it does matter (not used at present)
void 
OsiClpSolverInterface::replaceMatrix(const CoinPackedMatrix & matrix)
{
  modelPtr_->whatsChanged_ &= (0xffff&~(2|4|8));
  delete modelPtr_->matrix_;
  delete modelPtr_->rowCopy_;
  modelPtr_->rowCopy_=NULL;
  if (matrix.isColOrdered()) {
    modelPtr_->matrix_=new ClpPackedMatrix(matrix);
  } else {
    CoinPackedMatrix matrix2;
    matrix2.setExtraGap(0.0);
    matrix2.setExtraMajor(0.0);
    matrix2.reverseOrderedCopyOf(matrix);
    modelPtr_->matrix_=new ClpPackedMatrix(matrix2);
  }    
  modelPtr_->matrix_->setDimensions(modelPtr_->numberRows_,modelPtr_->numberColumns_);
  freeCachedResults();
}
// Get pointer to array[getNumCols()] of primal solution vector
const double * 
OsiClpSolverInterface::getColSolution() const 
{ 
  if (modelPtr_->solveType()!=2) {
    return modelPtr_->primalColumnSolution();
  } else {
    // simplex interface
    return modelPtr_->solutionRegion(1);
  }
}
  
// Get pointer to array[getNumRows()] of dual prices
const double * 
OsiClpSolverInterface::getRowPrice() const
{ 
  if (modelPtr_->solveType()!=2) {
    return modelPtr_->dualRowSolution();
  } else {
    // simplex interface
    //return modelPtr_->djRegion(0);
    return modelPtr_->dualRowSolution();
  }
}
  
// Get a pointer to array[getNumCols()] of reduced costs
const double * 
OsiClpSolverInterface::getReducedCost() const 
{ 
  if (modelPtr_->solveType()!=2) {
    return modelPtr_->dualColumnSolution();
  } else {
    // simplex interface
    return modelPtr_->djRegion(1);
  }
}

/* Get pointer to array[getNumRows()] of row activity levels (constraint
   matrix times the solution vector */
const double * 
OsiClpSolverInterface::getRowActivity() const 
{ 
  if (modelPtr_->solveType()!=2) {
    return modelPtr_->primalRowSolution();
  } else {
    // simplex interface
    return modelPtr_->solutionRegion(0);
  }
}
double 
OsiClpSolverInterface::getObjValue() const 
{
  if (modelPtr_->numberIterations()||modelPtr_->upperIn_!=-COIN_DBL_MAX) {
    // This does not pass unitTest when getObjValue is called before solve.
    //printf("obj a %g %g\n",modelPtr_->objectiveValue(),
    //     OsiSolverInterface::getObjValue());
    if (fakeMinInSimplex_)
      return -modelPtr_->objectiveValue() ;
    else
      return modelPtr_->objectiveValue();
  } else {
    return OsiSolverInterface::getObjValue();
  }
}

/* Set an objective function coefficient */
void 
OsiClpSolverInterface::setObjCoeff( int elementIndex, double elementValue )
{
  modelPtr_->whatsChanged_ &= 0xffff;
  // Say can't gurantee optimal basis etc
  lastAlgorithm_=999;
#ifndef NDEBUG
  int n = modelPtr_->numberColumns();
  if (elementIndex<0||elementIndex>=n) {
    indexError(elementIndex,"setObjCoeff");
  }
#endif
  modelPtr_->setObjectiveCoefficient(elementIndex,
    ((fakeMinInSimplex_)?-elementValue:elementValue));
}

/* Set a single column lower bound<br>
   Use -DBL_MAX for -infinity. */
void 
OsiClpSolverInterface::setColLower( int index, double elementValue )
{
  modelPtr_->whatsChanged_ &= 0x1ffff;
#ifndef NDEBUG
  int n = modelPtr_->numberColumns();
  if (index<0||index>=n) {
    indexError(index,"setColLower");
  }
#endif
  double currentValue = modelPtr_->columnActivity_[index];
  bool changed=(currentValue<elementValue-modelPtr_->primalTolerance()||
                index>=basis_.getNumStructural()||
                basis_.getStructStatus(index)==CoinWarmStartBasis::atLowerBound);
  // Say can't gurantee optimal basis etc
  if (changed)
    lastAlgorithm_=999;
  if (!modelPtr_->lower_)
    modelPtr_->whatsChanged_ &= ~0xffff; // switch off
  modelPtr_->setColumnLower(index,elementValue);
}
      
/* Set a single column upper bound<br>
   Use DBL_MAX for infinity. */
void 
OsiClpSolverInterface::setColUpper( int index, double elementValue )
{
  modelPtr_->whatsChanged_ &= 0x1ffff;
#ifndef NDEBUG
  int n = modelPtr_->numberColumns();
  if (index<0||index>=n) {
    indexError(index,"setColUpper");
  }
#endif
  double currentValue = modelPtr_->columnActivity_[index];
  bool changed=(currentValue>elementValue+modelPtr_->primalTolerance()||
                index>=basis_.getNumStructural()||
                basis_.getStructStatus(index)==CoinWarmStartBasis::atUpperBound);
  // Say can't gurantee optimal basis etc
  if (changed)
    lastAlgorithm_=999;
  if (!modelPtr_->upper_)
    modelPtr_->whatsChanged_ &= ~0xffff; // switch off
  modelPtr_->setColumnUpper(index,elementValue);
}

/* Set a single column lower and upper bound */
void 
OsiClpSolverInterface::setColBounds( int elementIndex,
				     double lower, double upper )
{
  modelPtr_->whatsChanged_ &= 0x1ffff;
  // Say can't gurantee optimal basis etc
  lastAlgorithm_=999;
#ifndef NDEBUG
  int n = modelPtr_->numberColumns();
  if (elementIndex<0||elementIndex>=n) {
    indexError(elementIndex,"setColBounds");
  }
#endif
  if (!modelPtr_->lower_)
    modelPtr_->whatsChanged_ &= ~0xffff; // switch off
  modelPtr_->setColumnBounds(elementIndex,lower,upper);
}
void OsiClpSolverInterface::setColSetBounds(const int* indexFirst,
					    const int* indexLast,
					    const double* boundList)
{
  modelPtr_->whatsChanged_ &= 0x1ffff;
  // Say can't gurantee optimal basis etc
  lastAlgorithm_=999;
#ifndef NDEBUG
  int n = modelPtr_->numberColumns();
  const int * indexFirst2=indexFirst;
  while (indexFirst2 != indexLast) {
    const int iColumn=*indexFirst2++;
    if (iColumn<0||iColumn>=n) {
      indexError(iColumn,"setColSetBounds");
    }
  }
#endif
  modelPtr_->setColSetBounds(indexFirst,indexLast,boundList);
}
//------------------------------------------------------------------
/* Set a single row lower bound<br>
   Use -DBL_MAX for -infinity. */
void 
OsiClpSolverInterface::setRowLower( int elementIndex, double elementValue ) {
  // Say can't gurantee optimal basis etc
  lastAlgorithm_=999;
  modelPtr_->whatsChanged_ &= 0xffff;
#ifndef NDEBUG
  int n = modelPtr_->numberRows();
  if (elementIndex<0||elementIndex>=n) {
    indexError(elementIndex,"setRowLower");
  }
#endif
  modelPtr_->setRowLower(elementIndex , elementValue);
  if (rowsense_!=NULL) {
    assert ((rhs_ != NULL) && (rowrange_ != NULL));
    convertBoundToSense(modelPtr_->rowLower_[elementIndex], 
			modelPtr_->rowUpper_[elementIndex],
			rowsense_[elementIndex], rhs_[elementIndex], rowrange_[elementIndex]);
  }
}
      
/* Set a single row upper bound<br>
   Use DBL_MAX for infinity. */
void 
OsiClpSolverInterface::setRowUpper( int elementIndex, double elementValue ) {
  modelPtr_->whatsChanged_ &= 0xffff;
  // Say can't gurantee optimal basis etc
  lastAlgorithm_=999;
#ifndef NDEBUG
  int n = modelPtr_->numberRows();
  if (elementIndex<0||elementIndex>=n) {
    indexError(elementIndex,"setRowUpper");
  }
#endif
  modelPtr_->setRowUpper(elementIndex , elementValue);
  if (rowsense_!=NULL) {
    assert ((rhs_ != NULL) && (rowrange_ != NULL));
    convertBoundToSense(modelPtr_->rowLower_[elementIndex], 
			modelPtr_->rowUpper_[elementIndex],
			rowsense_[elementIndex], rhs_[elementIndex], rowrange_[elementIndex]);
  }
}
    
/* Set a single row lower and upper bound */
void 
OsiClpSolverInterface::setRowBounds( int elementIndex,
	      double lower, double upper ) {
  modelPtr_->whatsChanged_ &= 0xffff;
  // Say can't gurantee optimal basis etc
  lastAlgorithm_=999;
#ifndef NDEBUG
  int n = modelPtr_->numberRows();
  if (elementIndex<0||elementIndex>=n) {
    indexError(elementIndex,"setRowBounds");
  }
#endif
  modelPtr_->setRowBounds(elementIndex,lower,upper);
  if (rowsense_!=NULL) {
    assert ((rhs_ != NULL) && (rowrange_ != NULL));
    convertBoundToSense(modelPtr_->rowLower_[elementIndex], 
			modelPtr_->rowUpper_[elementIndex],
			rowsense_[elementIndex], rhs_[elementIndex], rowrange_[elementIndex]);
  }
}
//-----------------------------------------------------------------------------
void
OsiClpSolverInterface::setRowType(int i, char sense, double rightHandSide,
				  double range)
{
  modelPtr_->whatsChanged_ &= 0xffff;
  // Say can't gurantee optimal basis etc
  lastAlgorithm_=999;
#ifndef NDEBUG
  int n = modelPtr_->numberRows();
  if (i<0||i>=n) {
    indexError(i,"setRowType");
  }
#endif
  double lower = 0, upper = 0;
  convertSenseToBound(sense, rightHandSide, range, lower, upper);
  setRowBounds(i, lower, upper);
  // If user is using sense then set
  if (rowsense_) {
    rowsense_[i] = sense;
    rhs_[i] = rightHandSide;
    rowrange_[i] = range;
  }
}
// Set name of row
void 
//OsiClpSolverInterface::setRowName(int rowIndex, std::string & name) 
OsiClpSolverInterface::setRowName(int rowIndex, std::string name) 
{
  if (rowIndex>=0&&rowIndex<modelPtr_->numberRows()) {
    int nameDiscipline;
    getIntParam(OsiNameDiscipline,nameDiscipline) ;
    if (nameDiscipline) {
      modelPtr_->setRowName(rowIndex,name);
      OsiSolverInterface::setRowName(rowIndex,name) ;
    }
  }
}
// Return name of row if one exists or Rnnnnnnn
// we ignore maxLen
std::string 
OsiClpSolverInterface::getRowName(int rowIndex, unsigned int /*maxLen*/) const
{ 
	if (rowIndex == getNumRows())
		return getObjName();
  return modelPtr_->getRowName(rowIndex);
}
    
// Set name of col
void 
//OsiClpSolverInterface::setColName(int colIndex, std::string & name) 
OsiClpSolverInterface::setColName(int colIndex, std::string name) 
{
  if (colIndex>=0&&colIndex<modelPtr_->numberColumns()) {
    int nameDiscipline;
    getIntParam(OsiNameDiscipline,nameDiscipline) ;
    if (nameDiscipline) {
      modelPtr_->setColumnName(colIndex,name);
      OsiSolverInterface::setColName(colIndex,name) ;
    }
  }
}
// Return name of col if one exists or Rnnnnnnn
std::string 
OsiClpSolverInterface::getColName(int colIndex, unsigned int /*maxLen*/) const
{
  return modelPtr_->getColumnName(colIndex);
}
    
    
//-----------------------------------------------------------------------------
void OsiClpSolverInterface::setRowSetBounds(const int* indexFirst,
					    const int* indexLast,
					    const double* boundList)
{
  modelPtr_->whatsChanged_ &= 0xffff;
  // Say can't gurantee optimal basis etc
  lastAlgorithm_=999;
#ifndef NDEBUG
  int n = modelPtr_->numberRows();
  const int * indexFirst2=indexFirst;
  while (indexFirst2 != indexLast) {
    const int iColumn=*indexFirst2++;
    if (iColumn<0||iColumn>=n) {
      indexError(iColumn,"setColumnSetBounds");
    }
  }
#endif
  modelPtr_->setRowSetBounds(indexFirst,indexLast,boundList);
  if (rowsense_ != NULL) {
    assert ((rhs_ != NULL) && (rowrange_ != NULL));
    double * lower = modelPtr_->rowLower();
    double * upper = modelPtr_->rowUpper();
    while (indexFirst != indexLast) {
      const int iRow=*indexFirst++;
      convertBoundToSense(lower[iRow], upper[iRow],
			  rowsense_[iRow], rhs_[iRow], rowrange_[iRow]);
    }
  }
}
//-----------------------------------------------------------------------------
void
OsiClpSolverInterface::setRowSetTypes(const int* indexFirst,
				      const int* indexLast,
				      const char* senseList,
				      const double* rhsList,
				      const double* rangeList)
{
  modelPtr_->whatsChanged_ &= 0xffff;
  // Say can't gurantee optimal basis etc
  lastAlgorithm_=999;
#ifndef NDEBUG
  int n = modelPtr_->numberRows();
#endif
  const int len = static_cast<int>(indexLast - indexFirst);
  while (indexFirst != indexLast) {
    const int iRow= *indexFirst++;
#ifndef NDEBUG
    if (iRow<0||iRow>=n) {
      indexError(iRow,"isContinuous");
    }
#endif
    double lowerValue = 0;
    double upperValue = 0;
    if (rangeList){
      convertSenseToBound(*senseList++, *rhsList++, *rangeList++,
			  lowerValue, upperValue);
    } else {
      convertSenseToBound(*senseList++, *rhsList++, 0,
			  lowerValue, upperValue);
    }
    modelPtr_->setRowBounds(iRow,lowerValue,upperValue);
  }
  if (rowsense_ != NULL) {
    assert ((rhs_ != NULL) && (rowrange_ != NULL));
    indexFirst -= len;
    senseList -= len;
    rhsList -= len;
    if (rangeList)
       rangeList -= len;
    while (indexFirst != indexLast) {
      const int iRow=*indexFirst++;
      rowsense_[iRow] = *senseList++;
      rhs_[iRow] = *rhsList++;
      if (rangeList)
	 rowrange_[iRow] = *rangeList++;
    }
  }
}

/*
  Clp's copy-in/copy-out design paradigm is a challenge for the simplex modes.
  Normal operation goes like this:
    * startup() loads clp's work arrays, performing scaling for numerical
      stability and compensating for max.
    * clp solves the problem
    * finish() unloads the work arrays into answer arrays, undoing scaling
      and max compensation.
  There are two solutions: undo scaling and max on demand, or make them
  into noops. The various getBInv* methods undo scaling on demand (but
  see special option 512) and do not need to worry about max. Other get
  solution methods are not coded to do this, so the second approach is
  used. For simplex modes, turn off scaling (necessary for both primal and
  dual solutions) and temporarily convert max to min (necessary for dual
  solution). This makes the unscaling in getBInv* superfluous, but don't
  remove it. Arguably the better solution here would be to go through and
  add unscaling and max compensation to the get solution methods. Look for
  fakeMinInSimplex to see the places this propagates to.

  TODO: setRowPrice never has worked properly, and I didn't try to fix it in
        this go-round.

  As of 100907, change applied to [enable|disable]Factorization (mode 1).
  Limitation of [enable|disable]SimplexInterface (mode 2) noted in
  documentation.  -- lh, 100907 --
*/
/*
  Enables normal operation of subsequent functions.  This method is supposed
  to ensure that all typical things (like reduced costs, etc.) are updated
  when individual pivots are executed and can be queried by other methods
*/
void 
OsiClpSolverInterface::enableSimplexInterface(bool doingPrimal)
{
  modelPtr_->whatsChanged_ &= 0xffff;
  if (modelPtr_->solveType()==2)
    return;
  assert (modelPtr_->solveType()==1);
  int saveIts = modelPtr_->numberIterations_;
  modelPtr_->setSolveType(2);
  if (doingPrimal)
    modelPtr_->setAlgorithm(1);
  else
    modelPtr_->setAlgorithm(-1);
  // Do initialization
  saveData_ = modelPtr_->saveData();
  saveData_.scalingFlag_=modelPtr_->scalingFlag();
  modelPtr_->scaling(0);
  specialOptions_ = 0x80000000;
  // set infeasibility cost up
  modelPtr_->setInfeasibilityCost(1.0e12);
  ClpDualRowDantzig dantzig;
  modelPtr_->setDualRowPivotAlgorithm(dantzig);
  ClpPrimalColumnDantzig dantzigP;
  dantzigP.saveWeights(modelPtr_,0); // set modelPtr 
  modelPtr_->setPrimalColumnPivotAlgorithm(dantzigP);
  int saveOptions = modelPtr_->specialOptions_;
  modelPtr_->specialOptions_ &= ~262144;
  delete modelPtr_->scaledMatrix_;
  modelPtr_->scaledMatrix_=NULL;
#ifdef NDEBUG
  modelPtr_->startup(0);
#else
  int returnCode=modelPtr_->startup(0);
  assert (!returnCode||returnCode==2);
#endif
  modelPtr_->specialOptions_=saveOptions;
  modelPtr_->numberIterations_=saveIts;
}

//Undo whatever setting changes the above method had to make
void 
OsiClpSolverInterface::disableSimplexInterface()
{
  modelPtr_->whatsChanged_ &= 0xffff;
  assert (modelPtr_->solveType()==2);
  // declare optimality anyway  (for message handler)
  modelPtr_->setProblemStatus(0);
  modelPtr_->setSolveType(1);
  // message will not appear anyway
  int saveMessageLevel=modelPtr_->messageHandler()->logLevel();
  modelPtr_->messageHandler()->setLogLevel(0);
  modelPtr_->finish();
  modelPtr_->messageHandler()->setLogLevel(saveMessageLevel);
  modelPtr_->restoreData(saveData_);
  modelPtr_->scaling(saveData_.scalingFlag_);
  ClpDualRowSteepest steepest;
  modelPtr_->setDualRowPivotAlgorithm(steepest);
  ClpPrimalColumnSteepest steepestP;
  modelPtr_->setPrimalColumnPivotAlgorithm(steepestP);
  basis_ = getBasis(modelPtr_);
  modelPtr_->setSolveType(1);
}

/*
  Force scaling off. If the client thinks we're maximising, arrange it so
  that clp sees minimisation while the client still sees maximisation. In
  keeping with the spirit of the getBInv methods, special option 512 will
  leave all work to the client.
*/
void 
OsiClpSolverInterface::enableFactorization() const
{
  saveData_.specialOptions_=specialOptions_;
  // Try to preserve work regions, reuse factorization
  if ((specialOptions_&(1+8))!=1+8)
    setSpecialOptionsMutable((1+8)|specialOptions_);
  // Are we allowed to make the output sensible to mere mortals?
  if ((specialOptions_&512)==0) {
    // Force scaling to off
    saveData_.scalingFlag_ = modelPtr_->scalingFlag() ;
    modelPtr_->scaling(0) ;
    // Temporarily force to min but keep a copy of original objective.
    if (getObjSense() < 0.0) {
      fakeMinInSimplex_ = true ;
      modelPtr_->setOptimizationDirection(1.0) ;
      double *c = modelPtr_->objective() ;
      int n = getNumCols() ;
      linearObjective_ = new double[n] ;
      CoinMemcpyN(c,n,linearObjective_) ;
      std::transform(c,c+n,c,std::negate<double>()) ;
    }
  }
  int saveStatus = modelPtr_->problemStatus_;
#ifdef NDEBUG
  modelPtr_->startup(0);
#else
  int returnCode=modelPtr_->startup(0);
  assert (!returnCode||returnCode==2);
#endif
  modelPtr_->problemStatus_=saveStatus;
}

/*
  Undo enableFactorization. Retrieve the special options and scaling and
  remove the temporary objective used to fake minimisation in clp.
*/
void 
OsiClpSolverInterface::disableFactorization() const
{
  specialOptions_=saveData_.specialOptions_;
  // declare optimality anyway  (for message handler)
  modelPtr_->setProblemStatus(0);
  // message will not appear anyway
  int saveMessageLevel=modelPtr_->messageHandler()->logLevel();
  modelPtr_->messageHandler()->setLogLevel(0);
  modelPtr_->finish();
  modelPtr_->messageHandler()->setLogLevel(saveMessageLevel);
  // Client asked for transforms on the way in, so back out.
  if ((specialOptions_&512)==0) {
    modelPtr_->scaling(saveData_.scalingFlag_) ;
    if (fakeMinInSimplex_ == true) {
      fakeMinInSimplex_ = false ;
      modelPtr_->setOptimizationDirection(-1.0) ;
      double *c = modelPtr_->objective() ;
      int n = getNumCols() ;
      std::transform(c,c+n,c,std::negate<double>()) ;
      delete[] linearObjective_ ;
    }
  }
}



/* The following two methods may be replaced by the
   methods of OsiSolverInterface using OsiWarmStartBasis if:
   1. OsiWarmStartBasis resize operation is implemented
   more efficiently and
   2. It is ensured that effects on the solver are the same
   
   Returns a basis status of the structural/artificial variables 
*/
void 
OsiClpSolverInterface::getBasisStatus(int* cstat, int* rstat) const
{
  int iRow,iColumn;
  int numberRows = modelPtr_->numberRows();
  int numberColumns = modelPtr_->numberColumns();
  const double * pi = modelPtr_->dualRowSolution();
  const double * dj = modelPtr_->dualColumnSolution();
  double multiplier = modelPtr_->optimizationDirection();
  // Flip slacks
  int lookupA[]={0,1,3,2,0,3};
  for (iRow=0;iRow<numberRows;iRow++) {
    int iStatus = modelPtr_->getRowStatus(iRow);
    if (iStatus==5) {
      // Fixed - look at reduced cost
      if (pi[iRow]*multiplier>1.0e-7)
        iStatus = 3;
    }
    iStatus = lookupA[iStatus];
    rstat[iRow]=iStatus;
  }
  int lookupS[]={0,1,2,3,0,3};
  for (iColumn=0;iColumn<numberColumns;iColumn++) {
    int iStatus = modelPtr_->getColumnStatus(iColumn);
    if (iStatus==5) {
      // Fixed - look at reduced cost
      if (dj[iColumn]*multiplier<-1.0e-7)
        iStatus = 2;
    }
    iStatus = lookupS[iStatus];
    cstat[iColumn]=iStatus;
  }
}

//Set the status of structural/artificial variables 
//Returns 0 if OK, 1 if problem is bad e.g. duplicate elements, too large ...
int 
OsiClpSolverInterface::setBasisStatus(const int* cstat, const int* rstat)
{
  modelPtr_->whatsChanged_ &= 0xffff;
  // Say can't gurantee optimal basis etc
  lastAlgorithm_=999;
  modelPtr_->createStatus();
  int i, n;
  double * lower, * upper, * solution;
  n=modelPtr_->numberRows();
  lower = modelPtr_->rowLower();
  upper = modelPtr_->rowUpper();
  solution = modelPtr_->primalRowSolution();
  // For rows lower and upper are flipped
  int lookupA[]={0,1,3,2};
  for (i=0;i<n;i++) {
    int status = lookupA[rstat[i]];
    if (status<0||status>3)
      status = 3;
    if (lower[i]<-1.0e50&&upper[i]>1.0e50&&status!=1)
      status = 0; // set free if should be
    else if (lower[i]<-1.0e50&&status==3)
      status = 2; // can't be at lower bound
    else if (upper[i]>1.0e50&&status==2)
      status = 3; // can't be at upper bound
    switch (status) {
      // free or superbasic
    case 0:
      if (lower[i]<-1.0e50&&upper[i]>1.0e50) {
	modelPtr_->setRowStatus(i,ClpSimplex::isFree);
	if (fabs(solution[i])>1.0e20)
	  solution[i]=0.0;
      } else {
	modelPtr_->setRowStatus(i,ClpSimplex::superBasic);
	if (fabs(solution[i])>1.0e20)
	  solution[i]=0.0;
      }
      break;
    case 1:
      // basic
      modelPtr_->setRowStatus(i,ClpSimplex::basic);
      break;
    case 2:
      // at upper bound
      solution[i]=upper[i];
      if (upper[i]>lower[i])
	modelPtr_->setRowStatus(i,ClpSimplex::atUpperBound);
      else
	modelPtr_->setRowStatus(i,ClpSimplex::isFixed);
      break;
    case 3:
      // at lower bound
      solution[i]=lower[i];
      if (upper[i]>lower[i])
	modelPtr_->setRowStatus(i,ClpSimplex::atLowerBound);
      else
	modelPtr_->setRowStatus(i,ClpSimplex::isFixed);
      break;
    }
  }
  n=modelPtr_->numberColumns();
  lower = modelPtr_->columnLower();
  upper = modelPtr_->columnUpper();
  solution = modelPtr_->primalColumnSolution();
  for (i=0;i<n;i++) {
    int status = cstat[i];
    if (status<0||status>3)
      status = 3;
    if (lower[i]<-1.0e50&&upper[i]>1.0e50&&status!=1)
      status = 0; // set free if should be
    else if (lower[i]<-1.0e50&&status==3)
      status = 2; // can't be at lower bound
    else if (upper[i]>1.0e50&&status==2)
      status = 3; // can't be at upper bound
    switch (status) {
      // free or superbasic
    case 0:
      if (lower[i]<-1.0e50&&upper[i]>1.0e50) {
	modelPtr_->setColumnStatus(i,ClpSimplex::isFree);
	if (fabs(solution[i])>1.0e20)
	  solution[i]=0.0;
      } else {
	modelPtr_->setColumnStatus(i,ClpSimplex::superBasic);
	if (fabs(solution[i])>1.0e20)
	  solution[i]=0.0;
      }
      break;
    case 1:
      // basic
      modelPtr_->setColumnStatus(i,ClpSimplex::basic);
      break;
    case 2:
      // at upper bound
      solution[i]=upper[i];
      if (upper[i]>lower[i])
	modelPtr_->setColumnStatus(i,ClpSimplex::atUpperBound);
      else
	modelPtr_->setColumnStatus(i,ClpSimplex::isFixed);
      break;
    case 3:
      // at lower bound
      solution[i]=lower[i];
      if (upper[i]>lower[i])
	modelPtr_->setColumnStatus(i,ClpSimplex::atLowerBound);
      else
	modelPtr_->setColumnStatus(i,ClpSimplex::isFixed);
      break;
    }
  }
  // say first time
  modelPtr_->statusOfProblem(true);
  // May be bad model
  if (modelPtr_->status()==4)
    return 1;
  // Save 
  basis_ = getBasis(modelPtr_);
  return 0;
}

/* Perform a pivot by substituting a colIn for colOut in the basis. 
   The status of the leaving variable is given in statOut. Where
   1 is to upper bound, -1 to lower bound
   Return code is 0 for okay,
   1 if inaccuracy forced re-factorization (should be okay) and
   -1 for singular factorization
*/
int 
OsiClpSolverInterface::pivot(int colIn, int colOut, int outStatus)
{
  assert (modelPtr_->solveType()==2);
  // convert to Clp style (what about flips?)
  if (colIn<0) 
    colIn = modelPtr_->numberColumns()+(-1-colIn);
  if (colOut<0) 
    colOut = modelPtr_->numberColumns()+(-1-colOut);
  // in clp direction of out is reversed
  outStatus = - outStatus;
  // set in clp
  modelPtr_->setDirectionOut(outStatus);
  modelPtr_->setSequenceIn(colIn);
  modelPtr_->setSequenceOut(colOut);
  // do pivot
  return modelPtr_->pivot();
}

/* Obtain a result of the primal pivot 
   Outputs: colOut -- leaving column, outStatus -- its status,
   t -- step size, and, if dx!=NULL, *dx -- primal ray direction.
   Inputs: colIn -- entering column, sign -- direction of its change (+/-1).
   Both for colIn and colOut, artificial variables are index by
   the negative of the row index minus 1.
   Return code (for now): 0 -- leaving variable found, 
   -1 -- everything else?
   Clearly, more informative set of return values is required 
   Primal and dual solutions are updated
*/
int 
OsiClpSolverInterface::primalPivotResult(int colIn, int sign, 
					 int& colOut, int& outStatus, 
					 double& t, CoinPackedVector* dx)
{
  assert (modelPtr_->solveType()==2);
  // convert to Clp style
  if (colIn<0) 
    colIn = modelPtr_->numberColumns()+(-1-colIn);
  // set in clp
  modelPtr_->setDirectionIn(sign);
  modelPtr_->setSequenceIn(colIn);
  modelPtr_->setSequenceOut(-1);
  int returnCode = modelPtr_->primalPivotResult();
  t = modelPtr_->theta();
  int numberColumns = modelPtr_->numberColumns();
  if (dx) {
    double * ray = modelPtr_->unboundedRay();
    if  (ray)
      dx->setFullNonZero(numberColumns,ray);
    else
      printf("No ray?\n");
    delete [] ray;
  }
  outStatus = - modelPtr_->directionOut();
  colOut = modelPtr_->sequenceOut();
  if (colOut>= numberColumns) 
    colOut = -1-(colOut - numberColumns);
  return returnCode;
}

/* Obtain a result of the dual pivot (similar to the previous method)
   Differences: entering variable and a sign of its change are now
   the outputs, the leaving variable and its statuts -- the inputs
   If dx!=NULL, then *dx contains dual ray
   Return code: same
*/
int 
OsiClpSolverInterface::dualPivotResult(int& /*colIn*/, int& /*sign*/, 
				       int /*colOut*/, int /*outStatus*/, 
				       double& /*t*/, CoinPackedVector* /*dx*/)
{
  assert (modelPtr_->solveType()==2);
  abort();
  return 0;
}

/*
  This method should not leave a permanent change in the solver. For
  this reason, save a copy of the cost region and replace it after we've
  calculated the duals and reduced costs.

  On the good side, if we're maximising, we should negate the objective on
  the way in and negate the duals on the way out. Since clp won't be doing
  anything more with c, we can exploit (-1)(-1) = 1 and do nothing.
*/
void 
OsiClpSolverInterface::getReducedGradient(
					  double* columnReducedCosts, 
					  double * duals,
					  const double * c) const
{
  //assert (modelPtr_->solveType()==2);
  // could do this faster with coding inside Clp
  // save current costs
  int numberColumns = modelPtr_->numberColumns();
  double * save = new double [numberColumns];
  double * obj = modelPtr_->costRegion();
  CoinMemcpyN(obj,numberColumns,save);
  // Compute new duals and reduced costs.
  const double * columnScale = modelPtr_->columnScale();
  if (!columnScale) {
    CoinMemcpyN(c,numberColumns,obj) ;
  } else {
    // need to scale
    for (int i=0;i<numberColumns;i++)
      obj[i] = c[i]*columnScale[i];
  }
  modelPtr_->computeDuals(NULL);

  // Restore previous cost vector
  CoinMemcpyN(save,numberColumns,obj);
  delete [] save;

  // Transfer results to parameters
  int numberRows = modelPtr_->numberRows();
  const double * dualScaled = modelPtr_->dualRowSolution();
  const double * djScaled = modelPtr_->djRegion(1);
  if (!columnScale) {
      CoinMemcpyN(dualScaled,numberRows,duals) ;
      CoinMemcpyN(djScaled,numberColumns,columnReducedCosts) ;
  } else {
    // need to scale
    const double * rowScale = modelPtr_->rowScale();
    for (int i=0;i<numberRows;i++)
      duals[i] = dualScaled[i]*rowScale[i];
    for (int i=0;i<numberColumns;i++)
      columnReducedCosts[i] = djScaled[i]/columnScale[i];
  }
}

#if 0

  Deleted from OsiSimplex API 100828. Leave the code here for a bit just in
  case someone yells.  -- lh, 100828 --

/* Set a new objective and apply the old basis so that the
   reduced costs are properly updated
*/
void OsiClpSolverInterface::setObjectiveAndRefresh(const double* c)
{
  modelPtr_->whatsChanged_ &= (0xffff&~(64));
  assert (modelPtr_->solveType()==2);
  int numberColumns = modelPtr_->numberColumns();
  CoinMemcpyN(c,numberColumns,modelPtr_->objective());
  if (modelPtr_->nonLinearCost()) {
    modelPtr_->nonLinearCost()->refreshCosts(c);
  }
  CoinMemcpyN(c,numberColumns,modelPtr_->costRegion());
  modelPtr_->computeDuals(NULL);
}
#endif

//Get a row of the tableau (slack part in slack if not NULL)
void 
OsiClpSolverInterface::getBInvARow(int row, double* z, double * slack) const
{
#ifndef NDEBUG
  int n = modelPtr_->numberRows();
  if (row<0||row>=n) {
    indexError(row,"getBInvARow");
  }
#endif
  //assert (modelPtr_->solveType()==2||(specialOptions_&1));
  CoinIndexedVector * rowArray0 = modelPtr_->rowArray(0);
  CoinIndexedVector * rowArray1 = modelPtr_->rowArray(1);
  CoinIndexedVector * columnArray0 = modelPtr_->columnArray(0);
  CoinIndexedVector * columnArray1 = modelPtr_->columnArray(1);
  rowArray0->clear();
  rowArray1->clear();
  columnArray0->clear();
  columnArray1->clear();
  int numberRows = modelPtr_->numberRows();
  int numberColumns = modelPtr_->numberColumns();
  // put +1 in row 
  // But swap if pivot variable was slack as clp stores slack as -1.0
  const int * pivotVariable = modelPtr_->pivotVariable();
  const double * rowScale = modelPtr_->rowScale();
  const double * columnScale = modelPtr_->columnScale();
  int pivot = pivotVariable[row];
  double value;
  // And if scaled then adjust
  if (!rowScale) {
    if (pivot<numberColumns)
      value = 1.0;
    else
      value = -1.0;
  } else {
    if (pivot<numberColumns)
      value = columnScale[pivot];
    else
      value = -1.0/rowScale[pivot-numberColumns];
  }
  rowArray1->insert(row,value);
  modelPtr_->factorization()->updateColumnTranspose(rowArray0,rowArray1);
  // put row of tableau in rowArray1 and columnArray0
  modelPtr_->clpMatrix()->transposeTimes(modelPtr_,1.0,
                                         rowArray1,columnArray1,columnArray0);
  // If user is sophisticated then let her/him do work
  if ((specialOptions_&512)==0) {
    // otherwise copy and clear
    if (!rowScale) {
      CoinMemcpyN(columnArray0->denseVector(),numberColumns,z);
    } else {
      double * array = columnArray0->denseVector();
      for (int i=0;i<numberColumns;i++)
        z[i] = array[i]/columnScale[i];
    }
    if (slack) {
      if (!rowScale) {
        CoinMemcpyN(rowArray1->denseVector(),numberRows,slack);
      } else {
        double * array = rowArray1->denseVector();
      for (int i=0;i<numberRows;i++)
        slack[i] = array[i]*rowScale[i];
      }
    }
    columnArray0->clear();
    rowArray1->clear();
  }
  // don't need to clear everything always, but doesn't cost
  rowArray0->clear();
  columnArray1->clear();
}
//Get a row of the tableau (slack part in slack if not NULL)
void 
OsiClpSolverInterface::getBInvARow(int row, CoinIndexedVector * columnArray0, CoinIndexedVector * slack,
				   bool keepScaled) const
{
#ifndef NDEBUG
  int nx = modelPtr_->numberRows();
  if (row<0||row>=nx) {
    indexError(row,"getBInvARow");
  }
#endif
  //assert (modelPtr_->solveType()==2||(specialOptions_&1));
  CoinIndexedVector * rowArray0 = modelPtr_->rowArray(0);
  CoinIndexedVector * rowArray1 = slack ? slack : modelPtr_->rowArray(1);
  CoinIndexedVector * columnArray1 = modelPtr_->columnArray(1);
  rowArray0->clear();
  rowArray1->clear();
  columnArray0->clear();
  columnArray1->clear();
  //int numberRows = modelPtr_->numberRows();
  int numberColumns = modelPtr_->numberColumns();
  // put +1 in row 
  // But swap if pivot variable was slack as clp stores slack as -1.0
  const int * pivotVariable = modelPtr_->pivotVariable();
  const double * rowScale = modelPtr_->rowScale();
  const double * columnScale = modelPtr_->columnScale();
  int pivot = pivotVariable[row];
  double value;
  // And if scaled then adjust
  if (!rowScale) {
    if (pivot<numberColumns)
      value = 1.0;
    else
      value = -1.0;
  } else {
    if (pivot<numberColumns)
      value = columnScale[pivot];
    else
      value = -1.0/rowScale[pivot-numberColumns];
  }
  rowArray1->insert(row,value);
  modelPtr_->factorization()->updateColumnTranspose(rowArray0,rowArray1);
  // put row of tableau in rowArray1 and columnArray0
  modelPtr_->clpMatrix()->transposeTimes(modelPtr_,1.0,
                                         rowArray1,columnArray1,columnArray0);
  int n;
  const int * which;
  double * array;
  // deal with scaling etc
  if (rowScale&&!keepScaled) {
    int j;
    // First columns
    n = columnArray0->getNumElements();
    which = columnArray0->getIndices();
    array = columnArray0->denseVector();
    for (j=0; j < n; j++) {
      int k=which[j];
      array[k] /= columnScale[k];
    }
    if (slack) {
      n = slack->getNumElements();
      which = slack->getIndices();
      array = slack->denseVector();
      for(j=0; j < n; j++) {
	int k=which[j];
	array[k] *= rowScale[k];
      }
    }
  }
  if (!slack)
    rowArray1->clear();
}

//Get a row of the basis inverse
void 
OsiClpSolverInterface::getBInvRow(int row, double* z) const

{
#ifndef NDEBUG
  int n = modelPtr_->numberRows();
  if (row<0||row>=n) {
    indexError(row,"getBInvRow");
  }
#endif
  //assert (modelPtr_->solveType()==2||(specialOptions_&1)!=0);
  ClpFactorization * factorization = modelPtr_->factorization();
  CoinIndexedVector * rowArray0 = modelPtr_->rowArray(0);
  CoinIndexedVector * rowArray1 = modelPtr_->rowArray(1);
  rowArray0->clear();
  rowArray1->clear();
  // put +1 in row
  // But swap if pivot variable was slack as clp stores slack as -1.0
  double value = (modelPtr_->pivotVariable()[row]<modelPtr_->numberColumns()) ? 1.0 : -1.0;
  int numberRows = modelPtr_->numberRows();
  int numberColumns = modelPtr_->numberColumns();
  const double * rowScale = modelPtr_->rowScale();
  const double * columnScale = modelPtr_->columnScale();
  const int * pivotVariable = modelPtr_->pivotVariable();
  // but scale
  if (rowScale) {
    int pivot = pivotVariable[row];
    if (pivot<numberColumns) 
      value *= columnScale[pivot];
    else
      value /= rowScale[pivot-numberColumns];
  }
  rowArray1->insert(row,value);
  factorization->updateColumnTranspose(rowArray0,rowArray1);
  // If user is sophisticated then let her/him do work
  if ((specialOptions_&512)==0) {
    // otherwise copy and clear
    if (!rowScale) {
      CoinMemcpyN(rowArray1->denseVector(),modelPtr_->numberRows(),z);
    } else {
      double * array = rowArray1->denseVector();
      for (int i=0;i<numberRows;i++) {
        z[i] = array[i] * rowScale[i];
      }
    }
    rowArray1->clear();
  }
}

//Get a column of the tableau
void 
OsiClpSolverInterface::getBInvACol(int col, double* vec) const
{
  //assert (modelPtr_->solveType()==2||(specialOptions_&1)!=0);
  CoinIndexedVector * rowArray0 = modelPtr_->rowArray(0);
  CoinIndexedVector * rowArray1 = modelPtr_->rowArray(1);
  rowArray0->clear();
  rowArray1->clear();
  // get column of matrix
#ifndef NDEBUG
  int n = modelPtr_->numberColumns()+modelPtr_->numberRows();
  if (col<0||col>=n) {
    indexError(col,"getBInvACol");
  }
#endif
  int numberRows = modelPtr_->numberRows();
  int numberColumns = modelPtr_->numberColumns();
  const int * pivotVariable = modelPtr_->pivotVariable();
  const double * rowScale = modelPtr_->rowScale();
  const double * columnScale = modelPtr_->columnScale();
  if (!rowScale) {
    if (col<numberColumns) {
      modelPtr_->unpack(rowArray1,col);
    } else {
      rowArray1->insert(col-numberColumns,1.0);
    }
  } else {
    if (col<numberColumns) {
      modelPtr_->unpack(rowArray1,col);
      double multiplier = 1.0/columnScale[col];
      int number = rowArray1->getNumElements();
      int * index = rowArray1->getIndices();
      double * array = rowArray1->denseVector();
      for (int i=0;i<number;i++) {
	int iRow = index[i];
	// make sure not packed
	assert (array[iRow]);
	array[iRow] *= multiplier;
      }
    } else {
      rowArray1->insert(col-numberColumns,rowScale[col-numberColumns]);
    }
  }
  modelPtr_->factorization()->updateColumn(rowArray0,rowArray1,false);
  // If user is sophisticated then let her/him do work
  if ((specialOptions_&512)==0) {
    // otherwise copy and clear
    // But swap if pivot variable was slack as clp stores slack as -1.0
    double * array = rowArray1->denseVector();
    if (!rowScale) {
      for (int i=0;i<numberRows;i++) {
        double multiplier = (pivotVariable[i]<numberColumns) ? 1.0 : -1.0;
        vec[i] = multiplier * array[i];
      }
    } else {
      for (int i=0;i<numberRows;i++) {
        int pivot = pivotVariable[i];
        if (pivot<numberColumns)
          vec[i] = array[i] * columnScale[pivot];
        else
          vec[i] = - array[i] / rowScale[pivot-numberColumns];
      }
    }
    rowArray1->clear();
  }
}
//Get a column of the tableau
void 
OsiClpSolverInterface::getBInvACol(int col, CoinIndexedVector * rowArray1) const
{
  CoinIndexedVector * rowArray0 = modelPtr_->rowArray(0);
  rowArray0->clear();
  rowArray1->clear();
  // get column of matrix
#ifndef NDEBUG
  int nx = modelPtr_->numberColumns()+modelPtr_->numberRows();
  if (col<0||col>=nx) {
    indexError(col,"getBInvACol");
  }
#endif
  //int numberRows = modelPtr_->numberRows();
  int numberColumns = modelPtr_->numberColumns();
  const int * pivotVariable = modelPtr_->pivotVariable();
  const double * rowScale = modelPtr_->rowScale();
  const double * columnScale = modelPtr_->columnScale();
  if (!rowScale) {
    if (col<numberColumns) {
      modelPtr_->unpack(rowArray1,col);
    } else {
      rowArray1->insert(col-numberColumns,1.0);
    }
  } else {
    if (col<numberColumns) {
      modelPtr_->unpack(rowArray1,col);
      double multiplier = 1.0/columnScale[col];
      int number = rowArray1->getNumElements();
      int * index = rowArray1->getIndices();
      double * array = rowArray1->denseVector();
      for (int i=0;i<number;i++) {
	int iRow = index[i];
	// make sure not packed
	assert (array[iRow]);
	array[iRow] *= multiplier;
      }
    } else {
      rowArray1->insert(col-numberColumns,rowScale[col-numberColumns]);
    }
  }
  modelPtr_->factorization()->updateColumn(rowArray0,rowArray1,false);
  // Deal with stuff
  int n = rowArray1->getNumElements();
  const int * which = rowArray1->getIndices();
  double * array = rowArray1->denseVector();
  for(int j=0; j < n; j++){
    int k=which[j];
    // need to know pivot variable for +1/-1 (slack) and row/column scaling
    int pivot = pivotVariable[k];
    if (pivot<numberColumns) {
      if (columnScale) 
	array[k] *= columnScale[pivot];
    } else {
      if (!rowScale) {
	array[k] = -array[k];
      } else {
	array[k] = -array[k]/rowScale[pivot-numberColumns];
      }
    }
  }
}

//Get an updated column
void 
OsiClpSolverInterface::getBInvACol(CoinIndexedVector * rowArray1) const
{
  CoinIndexedVector * rowArray0 = modelPtr_->rowArray(0);
  rowArray0->clear();
  // get column of matrix
  //int numberRows = modelPtr_->numberRows();
  int numberColumns = modelPtr_->numberColumns();
  const int * pivotVariable = modelPtr_->pivotVariable();
  const double * rowScale = modelPtr_->rowScale();
  const double * columnScale = modelPtr_->columnScale();
  // rowArray1 is not a column - so column scale can't be applied before
  modelPtr_->factorization()->updateColumn(rowArray0,rowArray1,false);
  // Deal with stuff
  int n = rowArray1->getNumElements();
  const int * which = rowArray1->getIndices();
  double * array = rowArray1->denseVector();
  for(int j=0; j < n; j++){
    int k=which[j];
    // need to know pivot variable for +1/-1 (slack) and row/column scaling
    int pivot = pivotVariable[k];
    if (pivot<numberColumns) {
      if (columnScale) 
	array[k] *= columnScale[pivot];
    } else {
      if (!rowScale) {
	array[k] = -array[k];
      } else {
	array[k] = -array[k]/rowScale[pivot-numberColumns];
      }
    }
  }
}

//Get a column of the basis inverse
void 
OsiClpSolverInterface::getBInvCol(int col, double* vec) const
{
  //assert (modelPtr_->solveType()==2||(specialOptions_&1)!=0);
  ClpFactorization * factorization = modelPtr_->factorization();
  CoinIndexedVector * rowArray0 = modelPtr_->rowArray(0);
  CoinIndexedVector * rowArray1 = modelPtr_->rowArray(1);
  rowArray0->clear();
  rowArray1->clear();
#ifndef NDEBUG
  int n = modelPtr_->numberRows();
  if (col<0||col>=n) {
    indexError(col,"getBInvCol");
  }
#endif
  // put +1 in row
  int numberRows = modelPtr_->numberRows();
  int numberColumns = modelPtr_->numberColumns();
  const double * rowScale = modelPtr_->rowScale();
  const double * columnScale = modelPtr_->columnScale();
  const int * pivotVariable = modelPtr_->pivotVariable();
  // but scale
  double value;
  if (!rowScale) {
    value=1.0;
  } else {
    value = rowScale[col];
  }
  rowArray1->insert(col,value);
  factorization->updateColumn(rowArray0,rowArray1,false);
  // If user is sophisticated then let her/him do work
  if ((specialOptions_&512)==0) {
    // otherwise copy and clear
    // But swap if pivot variable was slack as clp stores slack as -1.0
    double * array = rowArray1->denseVector();
    if (!rowScale) {
      for (int i=0;i<numberRows;i++) {
        double multiplier = (pivotVariable[i]<numberColumns) ? 1.0 : -1.0;
        vec[i] = multiplier * array[i];
      }
    } else {
      for (int i=0;i<numberRows;i++) {
        int pivot = pivotVariable[i];
        double value = array[i];
        if (pivot<numberColumns) 
          vec[i] = value * columnScale[pivot];
        else
          vec[i] = - value / rowScale[pivot-numberColumns];
      }
    }
    rowArray1->clear();
  }
}

/* Get basic indices (order of indices corresponds to the
   order of elements in a vector returned by getBInvACol() and
   getBInvCol()).
*/
void 
OsiClpSolverInterface::getBasics(int* index) const
{
  //assert (modelPtr_->solveType()==2||(specialOptions_&1)!=0);
  assert (index);
  if (modelPtr_->pivotVariable()) {
    CoinMemcpyN(modelPtr_->pivotVariable(),modelPtr_->numberRows(),index);
  } else {
    std::cerr<<"getBasics is only available with enableSimplexInterface."
	     <<std::endl;
    std::cerr<<"much of the same information can be had from getWarmStart."
	     <<std::endl;
    throw CoinError("No pivot variable array","getBasics",
		    "OsiClpSolverInterface");
  }
}
//Returns true if a basis is available and optimal
bool 
OsiClpSolverInterface::basisIsAvailable() const 
{
  return (lastAlgorithm_==1||lastAlgorithm_==2)&&(!modelPtr_->problemStatus_);
}
// Resets as if default constructor
void 
OsiClpSolverInterface::reset()
{
  setInitialData(); // clear base class
  freeCachedResults();
  if (!notOwned_)
    delete modelPtr_;
  delete ws_;
  ws_ = NULL;
  delete [] rowActivity_;
  delete [] columnActivity_;
  assert(smallModel_==NULL);
  assert(factorization_==NULL);
  smallestElementInCut_ = 1.0e-15;
  smallestChangeInCut_ = 1.0e-10;
  largestAway_ = -1.0;
  assert(spareArrays_==NULL);
  delete [] integerInformation_;
  rowActivity_ = NULL;
  columnActivity_ = NULL;
  integerInformation_ = NULL;
  basis_ = CoinWarmStartBasis();
  itlimOrig_=9999999;
  lastAlgorithm_=0;
  notOwned_=false;
  modelPtr_ = new ClpSimplex();
  linearObjective_ = NULL;
  fillParamMaps();
}
// Set a hint parameter
bool 
OsiClpSolverInterface::setHintParam(OsiHintParam key, bool yesNo,
                                    OsiHintStrength strength,
                                    void * otherInformation)
{
  if ( OsiSolverInterface::setHintParam(key,yesNo,strength,otherInformation)) {
    // special coding for branch and cut
    if (yesNo&&strength == OsiHintDo&&key==OsiDoInBranchAndCut) {
      if ( specialOptions_==0x80000000) {
        setupForRepeatedUse(0,0);
        specialOptions_=0;
      }
      // set normal
      specialOptions_ &= (2047+3*8192+15*65536);
      if (otherInformation!=NULL) {
        int * array = static_cast<int *> (otherInformation);
        if (array[0]>=0||array[0]<=2)
          specialOptions_ |= array[0]<<10;
      }
    }
    // Printing
    if (key==OsiDoReducePrint) {
      handler_->setLogLevel(yesNo ? 0 : 1);
    }
    return true;
  } else {
    return false;
  }
}

// Crunch down model
void 
OsiClpSolverInterface::crunch()
{
  //if (modelPtr_->scalingFlag_>0&&!modelPtr_->rowScale_&&
  //  modelPtr_->rowCopy_) {
  //printf("BBBB could crunch2\n");
  //}
  int numberColumns = modelPtr_->numberColumns();
  int numberRows = modelPtr_->numberRows();
  int totalIterations=0;
  bool abortSearch=false;
  // Use dual region
  double * rhs = modelPtr_->dualRowSolution();
  // Get space for strong branching 
  int size = static_cast<int>((1+4*(numberRows+numberColumns))*sizeof(double));
  // and for save of original column bounds
  size += static_cast<int>(2*numberColumns*sizeof(double));
  size += static_cast<int>((1+4*numberRows+2*numberColumns)*sizeof(int));
  size += numberRows+numberColumns;
#ifdef KEEP_SMALL
  char * spareArrays = NULL;
  if(!(modelPtr_->whatsChanged_&0x30000)) {
    delete smallModel_;
    smallModel_ = NULL;
    delete [] spareArrays_;
    spareArrays_ = NULL;
  }
  if (!spareArrays_) {
    spareArrays = new char[size];
    //memset(spareArrays,0x20,size);
  } else {
    spareArrays = spareArrays_;
  }
  double * arrayD = reinterpret_cast<double *> (spareArrays);
  double * saveSolution = arrayD+1;
  double * saveLower = saveSolution + (numberRows+numberColumns);
  double * saveUpper = saveLower + (numberRows+numberColumns);
  double * saveObjective = saveUpper + (numberRows+numberColumns);
  double * saveLowerOriginal = saveObjective + (numberRows+numberColumns);
  double * saveUpperOriginal = saveLowerOriginal + numberColumns;
  double * lowerOriginal = modelPtr_->columnLower();
  double * upperOriginal = modelPtr_->columnUpper();
  int * savePivot = reinterpret_cast<int *> (saveUpperOriginal + numberColumns);
  int * whichRow = savePivot+numberRows;
  int * whichColumn = whichRow + 3*numberRows;
  int * arrayI = whichColumn + 2*numberColumns;
  if (spareArrays_) {
    assert (smallModel_);
    int nSame=0; 
    int nSub=0;
    for (int i=0;i<numberColumns;i++) {
      double lo = lowerOriginal[i];
      //char * xx = (char *) (saveLowerOriginal+i);
      //assert (xx[0]!=0x20||xx[1]!=0x20);
      double loOld = saveLowerOriginal[i];
      //assert (!loOld||fabs(loOld)>1.0e-30);
      double up = upperOriginal[i];
      double upOld = saveUpperOriginal[i];
      if (lo>=loOld&&up<=upOld) {
	if (lo==loOld&&up==upOld) {
	  nSame++;
	} else {
	  nSub++;
	  //if (!isInteger(i))
	  //nSub+=10;
	}
      }
    }
    //printf("%d bounds same, %d interior, %d bad\n",
    //   nSame,nSub,numberColumns-nSame-nSub);
    if (nSame<numberColumns) {
      if (nSame+nSub<numberColumns||nSub>0) {
	delete smallModel_;
	smallModel_=NULL;
      } else {
	// we can fix up (but should we if large number fixed?)
	assert (smallModel_);
	double * lowerSmall = smallModel_->columnLower();
	double * upperSmall = smallModel_->columnUpper();
	int numberColumns2 = smallModel_->numberColumns();
	for (int i=0;i<numberColumns2;i++) {
	  int iColumn = whichColumn[i];
	  lowerSmall[i]=lowerOriginal[iColumn];
	  upperSmall[i]=upperOriginal[iColumn];
	}
      }
    }
  }
  CoinMemcpyN( lowerOriginal,numberColumns, saveLowerOriginal);
  CoinMemcpyN( upperOriginal,numberColumns, saveUpperOriginal);
  if (smallModel_) {
    if (!spareArrays_) {
      assert((specialOptions_&131072)==0);
#if 1
      delete smallModel_;
      smallModel_=NULL;
#endif
    }
  }
  //spareArrays=spareArrays_;
  //spareArrays_ = NULL;
#else
  assert (spareArrays_==NULL);
  int * whichRow = new int[3*numberRows+2*numberColumns];
  int * whichColumn = whichRow+3*numberRows;
#endif
  int nBound;
#ifdef KEEP_SMALL
  bool tightenBounds = ((specialOptions_&64)==0) ? false : true; 
  bool moreBounds=false;
  ClpSimplex * small=NULL;
  if (!smallModel_) {
#ifndef NDEBUG
    CoinFillN(whichRow,3*numberRows+2*numberColumns,-1);
#endif
    small = static_cast<ClpSimplexOther *> 
      (modelPtr_)->crunch(rhs,whichRow,whichColumn,
			  nBound,moreBounds,tightenBounds);
#ifndef NDEBUG
    int nCopy = 3*numberRows+2*numberColumns;
    for (int i=0;i<nCopy;i++)
      assert (whichRow[i]>=-CoinMax(numberRows,numberColumns)&&whichRow[i]<CoinMax(numberRows,numberColumns));
#endif
    smallModel_=small;
    spareArrays_ = spareArrays;
  } else {  
    assert((modelPtr_->whatsChanged_&0x30000));
    //delete [] spareArrays_;
    //spareArrays_ = NULL;
    assert (spareArrays_);
    int nCopy = 3*numberRows+2*numberColumns;
    nBound = whichRow[nCopy];
#ifndef NDEBUG
    for (int i=0;i<nCopy;i++)
      assert (whichRow[i]>=-CoinMax(numberRows,numberColumns)&&whichRow[i]<CoinMax(numberRows,numberColumns));
#endif
    small = smallModel_;
  }
#if 0 //def CLP_INVESTIGATE
#ifndef NDEBUG
  if (smallModel_) {
    int * whichColumn = whichRow+3*numberRows;
    unsigned char * stat1=modelPtr_->status_;
    int nr1=modelPtr_->numberRows_;
    int nc1=modelPtr_->numberColumns_;
    unsigned char * stat2=smallModel_->status_;
    int nr2=smallModel_->numberRows_;
    int nc2=smallModel_->numberColumns_;
    int n=0;
    for (int i=0;i<nr2+nc2;i++) {
      if ((stat2[i]&7)==1)
	n++;
    }
    assert (n==nr2);
    n=0;
    for (int i=0;i<nr1+nc1;i++) {
      if ((stat1[i]&7)==1)
	n++;
    }
    assert (n==nr1);
    //const double * lo1=modelPtr_->columnLower_;
    //const double * up1=modelPtr_->columnUpper_;
    //const double * lo2=smallModel_->columnLower_;
    //const double * up2=smallModel_->columnUpper_;
    int nBad=0;
    for (int i=0;i<nc2;i++) {
      int j=whichColumn[i];
      if ((stat2[i]&7)!=(stat1[j]&7)) {
	if ((stat2[i]&7)==5) {
	  if ((stat1[j]&7)==1)
	    nBad++;
	} else {
	  assert ((stat2[i]&7)==(stat1[j]&7));
	}
      }
    }
    for (int i=0;i<nr2;i++) {
      int j=whichRow[i];
      if ((stat2[i+nc2]&7)!=(stat1[j+nc1]&7)) {
	if ((stat2[i+nc2]&7)==5) {
	  assert ((stat1[j+nc1]&7)!=1);
	} else {
	  assert ((stat2[i+nc2]&7)==(stat1[j+nc1]&7));
	}
      }
    }
    if (nBad) {
      printf("%d basic moved to fixed\n",nBad);
    }
  }
#endif
#endif
#else
  bool tightenBounds = false;
  bool moreBounds=true;
#ifndef NDEBUG
  CoinFillN(whichRow,3*numberRows+2*numberColumns,-1);
#endif
  ClpSimplex * small = static_cast<ClpSimplexOther *> 
    (modelPtr_)->crunch(rhs,whichRow,whichColumn,
			nBound,moreBounds,tightenBounds);
#endif
  bool inCbcOrOther = (modelPtr_->specialOptions()&0x03000000)!=0;
  if (small) {
    small->specialOptions_ |= 262144;
    if ((specialOptions_&131072)!=0) {
      assert (lastNumberRows_>=0);
      int numberRows2 = small->numberRows();
      int numberColumns2 = small->numberColumns();
      double * rowScale2 = new double [2*numberRows2];
      assert (rowScale_.getSize()>=2*numberRows);
      const double * rowScale = rowScale_.array();
      double * inverseScale2 = rowScale2+numberRows2;
      const double * inverseScale = rowScale+modelPtr_->numberRows_;
      int i;
      for (i=0;i<numberRows2;i++) {
	int iRow = whichRow[i];
	assert (iRow>=0&&iRow<numberRows);
	rowScale2[i]=rowScale[iRow];
	inverseScale2[i]=inverseScale[iRow];
      }
      small->setRowScale(rowScale2);
      double * columnScale2 = new double [2*numberColumns2];
      assert (columnScale_.getSize()>=2*numberColumns);
      const double * columnScale = columnScale_.array();
      inverseScale2 = columnScale2+numberColumns2;
      inverseScale = columnScale+modelPtr_->numberColumns_;
      for (i=0;i<numberColumns2;i++) {
	int iColumn = whichColumn[i];
	//assert (iColumn<numberColumns);
	columnScale2[i]=columnScale[iColumn];
	inverseScale2[i]=inverseScale[iColumn];
      }
      small->setColumnScale(columnScale2);
    }
    disasterHandler_->setOsiModel(this);
    if (inCbcOrOther) {
      disasterHandler_->setSimplex(small);
      disasterHandler_->setWhereFrom(1); // crunch
      small->setDisasterHandler(disasterHandler_);
    }
#if 0
    const double * obj =small->objective();
    int numberColumns2 = small->numberColumns();
    int iColumn;
    for (iColumn=0;iColumn<numberColumns2;iColumn++) {
      if (obj[iColumn])
	break;
    }
    if (iColumn<numberColumns2)
      small->dual();
    else
      small->primal(); // No objective - use primal!
#else
    small->moreSpecialOptions_ = modelPtr_->moreSpecialOptions_;
    small->dual(0,7);
#endif
    totalIterations += small->numberIterations();
    int problemStatus = small->problemStatus();
    if (problemStatus>=0&&problemStatus<=2) {
      modelPtr_->setProblemStatus(problemStatus);
      if (!inCbcOrOther||!problemStatus) {
	// Scaling may have changed - if so pass across
	if (modelPtr_->scalingFlag()==4)
	  modelPtr_->scaling(small->scalingFlag());
	static_cast<ClpSimplexOther *> (modelPtr_)->afterCrunch(*small,whichRow,whichColumn,nBound);
	if ((specialOptions_&1048576)==0) {
	  // get correct rays
	  if (problemStatus==2)
	    modelPtr_->primal(1);
	  else if (problemStatus==1)
	    modelPtr_->dual();
	} else {
	  delete [] modelPtr_->ray_;
	  modelPtr_->ray_=NULL;
	}
      }
#ifdef KEEP_SMALL
      //assert (!smallModel_);
      //smallModel_ = small;
      small=NULL;
      int nCopy = 3*numberRows+2*numberColumns;
      //int * copy = CoinCopyOfArrayPartial(whichRow,nCopy+1,nCopy);
      whichRow[nCopy]=nBound;
      assert (arrayI[0]==nBound);
      arrayI[0]=nBound; // same
      spareArrays_ = spareArrays_;
      spareArrays=NULL;
#endif
    } else if (problemStatus!=3) {
      modelPtr_->setProblemStatus(1);
    } else {
      if (problemStatus==3) {
	// may be problems
	if (inCbcOrOther&&disasterHandler_->inTrouble()) {
	  if (disasterHandler_->typeOfDisaster()) {
	    // We want to abort 
	    abortSearch=true;
	    goto disaster;
	  }
	  // in case scaling bad
	  small->setRowScale(NULL);
	  small->setColumnScale(NULL);
    	  // try just going back in
	  disasterHandler_->setPhase(1);
	  small->dual();
	  totalIterations += small->numberIterations();
	  if (disasterHandler_->inTrouble()) {
	    if (disasterHandler_->typeOfDisaster()) {
	      // We want to abort 
	      abortSearch=true;
	      goto disaster;
	    }
	    // try primal on original model
	    disasterHandler_->setPhase(2);
	    disasterHandler_->setOsiModel(this);
	    modelPtr_->setDisasterHandler(disasterHandler_);
	    modelPtr_->primal();
	    totalIterations += modelPtr_->numberIterations();
	    if(disasterHandler_->inTrouble()) {
#ifdef COIN_DEVELOP
	      printf("disaster crunch - treat as infeasible\n");
#endif
	      if (disasterHandler_->typeOfDisaster()) {
		// We want to abort 
		abortSearch=true;
		goto disaster;
	      }
	      modelPtr_->setProblemStatus(1);
	    }
	    // give up for now
	    modelPtr_->setDisasterHandler(NULL);
	  } else {
	    modelPtr_->setProblemStatus(small->problemStatus());
	  }
	} else {
	  small->computeObjectiveValue();
	  modelPtr_->setObjectiveValue(small->objectiveValue());
	  modelPtr_->setProblemStatus(3);
	}
      } else {
	modelPtr_->setProblemStatus(3);
      }
    }
  disaster:
    delete small;
#ifdef KEEP_SMALL
    if (small==smallModel_) {
      smallModel_ = NULL;
      delete [] spareArrays_;
      spareArrays_ = NULL;
      spareArrays = NULL;
    }
#endif
  } else {
    modelPtr_->setProblemStatus(1);
#ifdef KEEP_SMALL
    delete [] spareArrays_;
    spareArrays_ = NULL;
    spareArrays = NULL;
#endif
  }
  modelPtr_->setNumberIterations(totalIterations);
  if (abortSearch) {
    lastAlgorithm_=-911;
    modelPtr_->setProblemStatus(4);
  }
#ifdef KEEP_SMALL
  delete [] spareArrays;
#else
  delete [] whichRow;
#endif
}
// Synchronize model 
void 
OsiClpSolverInterface::synchronizeModel() 
{
  if ((specialOptions_ &128)!=0) {
    if (!modelPtr_->rowScale_&&(specialOptions_&131072)!=0) {
      assert (lastNumberRows_==modelPtr_->numberRows_);
      int numberRows = modelPtr_->numberRows();
      int numberColumns = modelPtr_->numberColumns();
      double * rowScale = CoinCopyOfArray(rowScale_.array(),2*numberRows);
      modelPtr_->setRowScale(rowScale);
      double * columnScale = CoinCopyOfArray(columnScale_.array(),2*numberColumns);
      modelPtr_->setColumnScale(columnScale);
      modelPtr_->setRowScale(NULL);
      modelPtr_->setColumnScale(NULL);
    }
  }
}
// Returns true if has OsiSimplex methods
/* Returns 1 if can just do getBInv etc
   2 if has all OsiSimplex methods
   and 0 if it has none */
int
OsiClpSolverInterface::canDoSimplexInterface() const
{
  return 2;
}
// Pass in sos stuff from AMPl
void 
OsiClpSolverInterface::setSOSData(int numberSOS,const char * type,
				  const int * start,const int * indices, const double * weights)
{
  delete [] setInfo_;
  setInfo_=NULL;
  numberSOS_=numberSOS;
  if (numberSOS_) {
    setInfo_ = new CoinSet[numberSOS_];
    for (int i=0;i<numberSOS_;i++) {
      int iStart = start[i];
      setInfo_[i]=CoinSosSet(start[i+1]-iStart,indices+iStart,weights ? weights+iStart : NULL,
			     type[i]);
    }
  }
}
/* Identify integer variables and SOS and create corresponding objects.
  
      Record integer variables and create an OsiSimpleInteger object for each
      one.  All existing OsiSimpleInteger objects will be destroyed.
      If the solver supports SOS then do the same for SOS.

      If justCount then no objects created and we just store numberIntegers_
      Returns number of SOS
*/
int 
OsiClpSolverInterface::findIntegersAndSOS(bool justCount)
{
  findIntegers(justCount);
  int nObjects=0;
  OsiObject ** oldObject = object_;
  int iObject;
  int numberSOS=0;
  for (iObject = 0;iObject<numberObjects_;iObject++) {
    OsiSOS * obj =
      dynamic_cast <OsiSOS *>(oldObject[iObject]) ;
    if (obj) 
      numberSOS++;
  }
  if (numberSOS_&&!numberSOS) {
    // make a large enough array for new objects
    nObjects = numberObjects_;
    numberObjects_=numberSOS_+nObjects;
    if (numberObjects_)
      object_ = new OsiObject * [numberObjects_];
    else
      object_=NULL;
    // copy
    CoinMemcpyN(oldObject,nObjects,object_);
    // Delete old array (just array)
    delete [] oldObject;
    
    for (int i=0;i<numberSOS_;i++) {
      CoinSet * set =  setInfo_+i;
      object_[nObjects++] =
	new OsiSOS(this,set->numberEntries(),set->which(),set->weights(),
		   set->setType());
    }
  } else if (!numberSOS_&&numberSOS) {
    // create Coin sets
    assert (!setInfo_);
    setInfo_ = new CoinSet[numberSOS];
    for (iObject = 0;iObject<numberObjects_;iObject++) {
      OsiSOS * obj =
	dynamic_cast <OsiSOS *>(oldObject[iObject]) ;
      if (obj) 
	setInfo_[numberSOS_++]=CoinSosSet(obj->numberMembers(),obj->members(),obj->weights(),obj->sosType());
    }
  } else if (numberSOS!=numberSOS_) {
    printf("mismatch on SOS\n");
  }
  return numberSOS_;
}
// below needed for pathetic branch and bound code
#include <vector>
#include <map>

// Trivial class for Branch and Bound

class OsiNodeSimple  {
  
public:
    
  // Default Constructor 
  OsiNodeSimple ();

  // Constructor from current state (and list of integers)
  // Also chooses branching variable (if none set to -1)
  OsiNodeSimple (OsiSolverInterface &model,
                 int numberIntegers, int * integer,
                 CoinWarmStart * basis);
  void gutsOfConstructor (OsiSolverInterface &model,
                 int numberIntegers, int * integer,
                 CoinWarmStart * basis);
  // Copy constructor 
  OsiNodeSimple ( const OsiNodeSimple &);
   
  // Assignment operator 
  OsiNodeSimple & operator=( const OsiNodeSimple& rhs);

  // Destructor 
  ~OsiNodeSimple ();
  // Work of destructor
  void gutsOfDestructor();
  // Extension - true if other extension of this
  bool extension(const OsiNodeSimple & other,
		 const double * originalLower,
		 const double * originalUpper) const;
  inline void incrementDescendants()
  { descendants_++;}
  // Public data
  // Basis (should use tree, but not as wasteful as bounds!)
  CoinWarmStart * basis_;
  // Objective value (COIN_DBL_MAX) if spare node
  double objectiveValue_;
  // Branching variable (0 is first integer) 
  int variable_;
  // Way to branch - -1 down (first), 1 up, -2 down (second), 2 up (second)
  int way_;
  // Number of integers (for length of arrays)
  int numberIntegers_;
  // Current value
  double value_;
  // Number of descendant nodes (so 2 is in interior)
  int descendants_;
  // Parent 
  int parent_;
  // Previous in chain
  int previous_;
  // Next in chain
  int next_;
  // Now I must use tree
  // Bounds stored in full (for integers)
  int * lower_;
  int * upper_;
};


OsiNodeSimple::OsiNodeSimple() :
  basis_(NULL),
  objectiveValue_(COIN_DBL_MAX),
  variable_(-100),
  way_(-1),
  numberIntegers_(0),
  value_(0.5),
  descendants_(-1),
  parent_(-1),
  previous_(-1),
  next_(-1),
  lower_(NULL),
  upper_(NULL)
{
}
OsiNodeSimple::OsiNodeSimple(OsiSolverInterface & model,
		 int numberIntegers, int * integer,CoinWarmStart * basis)
{
  gutsOfConstructor(model,numberIntegers,integer,basis);
}
void
OsiNodeSimple::gutsOfConstructor(OsiSolverInterface & model,
		 int numberIntegers, int * integer,CoinWarmStart * basis)
{
  basis_ = basis;
  variable_=-1;
  way_=-1;
  numberIntegers_=numberIntegers;
  value_=0.0;
  descendants_ = 0;
  parent_ = -1;
  previous_ = -1;
  next_ = -1;
  if (model.isProvenOptimal()&&!model.isDualObjectiveLimitReached()) {
    objectiveValue_ = model.getObjSense()*model.getObjValue();
  } else {
    objectiveValue_ = 1.0e100;
    lower_ = NULL;
    upper_ = NULL;
    return; // node cutoff
  }
  lower_ = new int [numberIntegers_];
  upper_ = new int [numberIntegers_];
  assert (upper_!=NULL);
  const double * lower = model.getColLower();
  const double * upper = model.getColUpper();
  const double * solution = model.getColSolution();
  int i;
  // Hard coded integer tolerance
#define INTEGER_TOLERANCE 1.0e-6
  ///////// Start of Strong branching code - can be ignored
  // Number of strong branching candidates
#define STRONG_BRANCHING 5
#ifdef STRONG_BRANCHING
  double upMovement[STRONG_BRANCHING];
  double downMovement[STRONG_BRANCHING];
  double solutionValue[STRONG_BRANCHING];
  int chosen[STRONG_BRANCHING];
  int iSmallest=0;
  // initialize distance from integer
  for (i=0;i<STRONG_BRANCHING;i++) {
    upMovement[i]=0.0;
    chosen[i]=-1;
  }
  variable_=-1;
  // This has hard coded integer tolerance
  double mostAway=INTEGER_TOLERANCE;
  int numberAway=0;
  for (i=0;i<numberIntegers;i++) {
    int iColumn = integer[i];
    lower_[i]=static_cast<int>(lower[iColumn]);
    upper_[i]=static_cast<int>(upper[iColumn]);
    double value = solution[iColumn];
    value = CoinMax(value,static_cast<double> (lower_[i]));
    value = CoinMin(value,static_cast<double> (upper_[i]));
    double nearest = floor(value+0.5);
    if (fabs(value-nearest)>INTEGER_TOLERANCE)
      numberAway++;
    if (fabs(value-nearest)>mostAway) {
      double away = fabs(value-nearest);
      if (away>upMovement[iSmallest]) {
	//add to list
	upMovement[iSmallest]=away;
	solutionValue[iSmallest]=value;
	chosen[iSmallest]=i;
	int j;
	iSmallest=-1;
	double smallest = 1.0;
	for (j=0;j<STRONG_BRANCHING;j++) {
	  if (upMovement[j]<smallest) {
	    smallest=upMovement[j];
	    iSmallest=j;
	  }
	}
      }
    }
  }
  int numberStrong=0;
  for (i=0;i<STRONG_BRANCHING;i++) {
    if (chosen[i]>=0) { 
      numberStrong ++;
      variable_ = chosen[i];
    }
  }
  // out strong branching if bit set
  OsiClpSolverInterface* clp =
    dynamic_cast<OsiClpSolverInterface*>(&model);
  if (clp&&(clp->specialOptions()&16)!=0&&numberStrong>1) {
    int j;
    int iBest=-1;
    double best = 0.0;
    for (j=0;j<STRONG_BRANCHING;j++) {
      if (upMovement[j]>best) {
        best=upMovement[j];
        iBest=j;
      }
    }
    numberStrong=1;
    variable_=chosen[iBest];
  }
  if (numberStrong==1) {
    // just one - makes it easy
    int iColumn = integer[variable_];
    double value = solution[iColumn];
    value = CoinMax(value,static_cast<double> (lower_[variable_]));
    value = CoinMin(value,static_cast<double> (upper_[variable_]));
    double nearest = floor(value+0.5);
    value_=value;
    if (value<=nearest)
      way_=1; // up
    else
      way_=-1; // down
  } else if (numberStrong) {
    // more than one - choose
    bool chooseOne=true;
    model.markHotStart();
    for (i=0;i<STRONG_BRANCHING;i++) {
      int iInt = chosen[i];
      if (iInt>=0) {
	int iColumn = integer[iInt];
	double value = solutionValue[i]; // value of variable in original
	double objectiveChange;
	value = CoinMax(value,static_cast<double> (lower_[iInt]));
	value = CoinMin(value,static_cast<double> (upper_[iInt]));

	// try down

	model.setColUpper(iColumn,floor(value));
	model.solveFromHotStart();
	model.setColUpper(iColumn,upper_[iInt]);
	if (model.isProvenOptimal()&&!model.isDualObjectiveLimitReached()) {
	  objectiveChange = model.getObjSense()*model.getObjValue()
	    - objectiveValue_;
	} else {
	  objectiveChange = 1.0e100;
	}
	assert (objectiveChange>-1.0e-5);
	objectiveChange = CoinMax(objectiveChange,0.0);
	downMovement[i]=objectiveChange;

	// try up

	model.setColLower(iColumn,ceil(value));
	model.solveFromHotStart();
	model.setColLower(iColumn,lower_[iInt]);
	if (model.isProvenOptimal()&&!model.isDualObjectiveLimitReached()) {
	  objectiveChange = model.getObjSense()*model.getObjValue()
	    - objectiveValue_;
	} else {
	  objectiveChange = 1.0e100;
	}
	assert (objectiveChange>-1.0e-5);
	objectiveChange = CoinMax(objectiveChange,0.0);
	upMovement[i]=objectiveChange;

	/* Possibilities are:
	   Both sides feasible - store
	   Neither side feasible - set objective high and exit
	   One side feasible - change bounds and resolve
	*/
	bool solveAgain=false;
	if (upMovement[i]<1.0e100) {
	  if(downMovement[i]<1.0e100) {
	    // feasible - no action
	  } else {
	    // up feasible, down infeasible
	    solveAgain = true;
	    model.setColLower(iColumn,ceil(value));
	  }
	} else {
	  if(downMovement[i]<1.0e100) {
	    // down feasible, up infeasible
	    solveAgain = true;
	    model.setColUpper(iColumn,floor(value));
	  } else {
	    // neither side feasible
	    objectiveValue_=1.0e100;
	    chooseOne=false;
	    break;
	  }
	}
	if (solveAgain) {
	  // need to solve problem again - signal this
	  variable_ = numberIntegers;
	  chooseOne=false;
	  break;
	}
      }
    }
    if (chooseOne) {
      // choose the one that makes most difference both ways
      double best = -1.0;
      double best2 = -1.0;
      for (i=0;i<STRONG_BRANCHING;i++) {
	int iInt = chosen[i];
	if (iInt>=0) {
	  //std::cout<<"Strong branching on "
          //   <<i<<""<<iInt<<" down "<<downMovement[i]
          //   <<" up "<<upMovement[i]
          //   <<" value "<<solutionValue[i]
          //   <<std::endl;
	  bool better = false;
	  if (CoinMin(upMovement[i],downMovement[i])>best) {
	    // smaller is better
	    better=true;
	  } else if (CoinMin(upMovement[i],downMovement[i])>best-1.0e-5) {
	    if (CoinMax(upMovement[i],downMovement[i])>best2+1.0e-5) {
	      // smaller is about same, but larger is better
	      better=true;
	    }
	  }
	  if (better) {
	    best = CoinMin(upMovement[i],downMovement[i]);
	    best2 = CoinMax(upMovement[i],downMovement[i]);
	    variable_ = iInt;
	    double value = solutionValue[i];
	    value = CoinMax(value,static_cast<double> (lower_[variable_]));
	    value = CoinMin(value,static_cast<double> (upper_[variable_]));
	    value_=value;
	    if (upMovement[i]<=downMovement[i])
	      way_=1; // up
	    else
	      way_=-1; // down
	  }
	}
      }
    }
    // Delete the snapshot
    model.unmarkHotStart();
  }
  ////// End of Strong branching
#else
  variable_=-1;
  // This has hard coded integer tolerance
  double mostAway=INTEGER_TOLERANCE;
  int numberAway=0;
  for (i=0;i<numberIntegers;i++) {
    int iColumn = integer[i];
    lower_[i]=static_cast<int>(lower[iColumn]);
    upper_[i]=static_cast<int>(upper[iColumn]);
    double value = solution[iColumn];
    value = CoinMax(value,(double) lower_[i]);
    value = CoinMin(value,(double) upper_[i]);
    double nearest = floor(value+0.5);
    if (fabs(value-nearest)>INTEGER_TOLERANCE)
      numberAway++;
    if (fabs(value-nearest)>mostAway) {
      mostAway=fabs(value-nearest);
      variable_=i;
      value_=value;
      if (value<=nearest)
	way_=1; // up
      else
	way_=-1; // down
    }
  }
#endif
}

OsiNodeSimple::OsiNodeSimple(const OsiNodeSimple & rhs) 
{
  if (rhs.basis_)
    basis_=rhs.basis_->clone();
  else
    basis_ = NULL;
  objectiveValue_=rhs.objectiveValue_;
  variable_=rhs.variable_;
  way_=rhs.way_;
  numberIntegers_=rhs.numberIntegers_;
  value_=rhs.value_;
  descendants_ = rhs.descendants_;
  parent_ = rhs.parent_;
  previous_ = rhs.previous_;
  next_ = rhs.next_;
  lower_=NULL;
  upper_=NULL;
  if (rhs.lower_!=NULL) {
    lower_ = new int [numberIntegers_];
    upper_ = new int [numberIntegers_];
    assert (upper_!=NULL);
    CoinMemcpyN(rhs.lower_,numberIntegers_,lower_);
    CoinMemcpyN(rhs.upper_,numberIntegers_,upper_);
  }
}

OsiNodeSimple &
OsiNodeSimple::operator=(const OsiNodeSimple & rhs)
{
  if (this != &rhs) {
    gutsOfDestructor();
    if (rhs.basis_)
      basis_=rhs.basis_->clone();
    objectiveValue_=rhs.objectiveValue_;
    variable_=rhs.variable_;
    way_=rhs.way_;
    numberIntegers_=rhs.numberIntegers_;
    value_=rhs.value_;
    descendants_ = rhs.descendants_;
    parent_ = rhs.parent_;
    previous_ = rhs.previous_;
    next_ = rhs.next_;
    if (rhs.lower_!=NULL) {
      lower_ = new int [numberIntegers_];
      upper_ = new int [numberIntegers_];
      assert (upper_!=NULL);
      CoinMemcpyN(rhs.lower_,numberIntegers_,lower_);
      CoinMemcpyN(rhs.upper_,numberIntegers_,upper_);
    }
  }
  return *this;
}


OsiNodeSimple::~OsiNodeSimple ()
{
  gutsOfDestructor();
}
// Work of destructor
void 
OsiNodeSimple::gutsOfDestructor()
{
  delete [] lower_;
  delete [] upper_;
  delete basis_;
  lower_ = NULL;
  upper_ = NULL;
  basis_ = NULL;
  objectiveValue_ = COIN_DBL_MAX;
}
// Extension - true if other extension of this
bool 
OsiNodeSimple::extension(const OsiNodeSimple & other,
			 const double * originalLower,
			 const double * originalUpper) const
{
  bool ok=true;
  for (int i=0;i<numberIntegers_;i++) {
    if (upper_[i]<originalUpper[i]||
	lower_[i]>originalLower[i]) {
      if (other.upper_[i]>upper_[i]||
	  other.lower_[i]<lower_[i]) {
	ok=false;
	break;
      }
    }
  }
  return ok;
}

#include <vector>
#define FUNNY_BRANCHING 1
#define FUNNY_TREE
#ifndef FUNNY_TREE
// Vector of OsiNodeSimples 
typedef std::vector<OsiNodeSimple>    OsiVectorNode;
#else
// Must code up by hand
class OsiVectorNode  {
  
public:
    
  // Default Constructor 
  OsiVectorNode ();

  // Copy constructor 
  OsiVectorNode ( const OsiVectorNode &);
   
  // Assignment operator 
  OsiVectorNode & operator=( const OsiVectorNode& rhs);

  // Destructor 
  ~OsiVectorNode ();
  // Size
  inline int size() const
  { return size_-sizeDeferred_;}
  // Push
  void push_back(const OsiNodeSimple & node);
  // Last one in (or other criterion)
  OsiNodeSimple back() const;
  // Get rid of last one
  void pop_back();
  // Works out best one
  int best() const;
  
  // Public data
  // Maximum size
  int maximumSize_;
  // Current size
  int size_;
  // Number still hanging around
  int sizeDeferred_;
  // First spare
  int firstSpare_;
  // First 
  int first_;
  // Last 
  int last_;
  // Chosen one
  mutable int chosen_;
  // Nodes
  OsiNodeSimple * nodes_;
};


OsiVectorNode::OsiVectorNode() :
  maximumSize_(10),
  size_(0),
  sizeDeferred_(0),
  firstSpare_(0),
  first_(-1),
  last_(-1)
{
  nodes_ = new OsiNodeSimple[maximumSize_];
  for (int i=0;i<maximumSize_;i++) {
    nodes_[i].previous_=i-1;
    nodes_[i].next_=i+1;
  }
}

OsiVectorNode::OsiVectorNode(const OsiVectorNode & rhs) 
{  
  maximumSize_ = rhs.maximumSize_;
  size_ = rhs.size_;
  sizeDeferred_ = rhs.sizeDeferred_;
  firstSpare_ = rhs.firstSpare_;
  first_ = rhs.first_;
  last_ = rhs.last_;
  nodes_ = new OsiNodeSimple[maximumSize_];
  for (int i=0;i<maximumSize_;i++) {
    nodes_[i] = rhs.nodes_[i];
  }
}

OsiVectorNode &
OsiVectorNode::operator=(const OsiVectorNode & rhs)
{
  if (this != &rhs) {
    delete [] nodes_;
    maximumSize_ = rhs.maximumSize_;
    size_ = rhs.size_;
    sizeDeferred_ = rhs.sizeDeferred_;
    firstSpare_ = rhs.firstSpare_;
    first_ = rhs.first_;
    last_ = rhs.last_;
    nodes_ = new OsiNodeSimple[maximumSize_];
    for (int i=0;i<maximumSize_;i++) {
      nodes_[i] = rhs.nodes_[i];
    }
  }
  return *this;
}


OsiVectorNode::~OsiVectorNode ()
{
  delete [] nodes_;
}
// Push
void 
OsiVectorNode::push_back(const OsiNodeSimple & node)
{
  if (size_==maximumSize_) {
    assert (firstSpare_==size_);
    maximumSize_ = (maximumSize_*3)+10;
    OsiNodeSimple * temp = new OsiNodeSimple[maximumSize_];
    int i;
    for (i=0;i<size_;i++) {
      temp[i]=nodes_[i];
    }
    delete [] nodes_;
    nodes_ = temp;
    //firstSpare_=size_;
    int last = -1;
    for ( i=size_;i<maximumSize_;i++) {
      nodes_[i].previous_=last;
      nodes_[i].next_=i+1;
      last = i;
    }
  }
  assert (firstSpare_<maximumSize_);
  assert (nodes_[firstSpare_].previous_<0);
  int next = nodes_[firstSpare_].next_;
  nodes_[firstSpare_]=node;
  if (last_>=0) {
    assert (nodes_[last_].next_==-1);
    nodes_[last_].next_=firstSpare_;
  }
  nodes_[firstSpare_].previous_=last_;
  nodes_[firstSpare_].next_=-1;
  if (last_==-1) {
    assert (first_==-1);
    first_ = firstSpare_;
  }
  last_=firstSpare_;
  if (next>=0&&next<maximumSize_) {
    firstSpare_ = next;
    nodes_[firstSpare_].previous_=-1;
  } else {
    firstSpare_=maximumSize_;
  }
  chosen_ = -1;
  //best();
  size_++;
  assert (node.descendants_<=2);
  if (node.descendants_==2)
    sizeDeferred_++;
}
// Works out best one
int 
OsiVectorNode::best() const
{
  // can modify
  chosen_=-1;
  if (chosen_<0) {
    chosen_=last_;
#if FUNNY_BRANCHING
    while (nodes_[chosen_].descendants_==2) {
      chosen_ = nodes_[chosen_].previous_;
      assert (chosen_>=0);
    }
#endif
  }
  return chosen_;
}
// Last one in (or other criterion)
OsiNodeSimple 
OsiVectorNode::back() const
{
  assert (last_>=0);
  return nodes_[best()];
}
// Get rid of last one
void 
OsiVectorNode::pop_back()
{
  // Temporary until more sophisticated
  //assert (last_==chosen_);
  if (nodes_[chosen_].descendants_==2)
    sizeDeferred_--;
  int previous = nodes_[chosen_].previous_;
  int next = nodes_[chosen_].next_;
  nodes_[chosen_].gutsOfDestructor();
  if (previous>=0) {
    nodes_[previous].next_=next;
  } else {
    first_ = next;
  }
  if (next>=0) {
    nodes_[next].previous_ = previous;
  } else {
    last_ = previous;
  }
  nodes_[chosen_].previous_=-1;
  if (firstSpare_>=0) {
    nodes_[chosen_].next_ = firstSpare_;
  } else {
    nodes_[chosen_].next_ = -1;
  }
  firstSpare_ = chosen_;
  chosen_ = -1;
  assert (size_>0);
  size_--;
}
#endif
// Invoke solver's built-in enumeration algorithm
void 
OsiClpSolverInterface::branchAndBound() {
  double time1 = CoinCpuTime();
  // solve LP
  initialSolve();
  int funnyBranching=FUNNY_BRANCHING;

  if (isProvenOptimal()&&!isDualObjectiveLimitReached()) {
    // Continuous is feasible - find integers
    int numberIntegers=0;
    int numberColumns = getNumCols();
    int iColumn;
    int i;
    for (iColumn=0;iColumn<numberColumns;iColumn++) {
      if( isInteger(iColumn))
        numberIntegers++;
    }
    if (!numberIntegers) {
      std::cout<<"No integer variables"
               <<std::endl;
      return;
    }
    int * which = new int[numberIntegers]; // which variables are integer
    // original bounds
    int * originalLower = new int[numberIntegers];
    int * originalUpper = new int[numberIntegers];
    int * relaxedLower = new int[numberIntegers];
    int * relaxedUpper = new int[numberIntegers];
    {
      const double * lower = getColLower();
      const double * upper = getColUpper();
      numberIntegers=0;
      for (iColumn=0;iColumn<numberColumns;iColumn++) {
	if( isInteger(iColumn)) {
	  originalLower[numberIntegers]=static_cast<int> (lower[iColumn]);
	  if (upper[iColumn]>1.0e9) {
	    // This is not meant to be a bulletproof code
	    setColUpper(iColumn,1.0e9);
	  }
	  originalUpper[numberIntegers]=static_cast<int> (upper[iColumn]);
	  which[numberIntegers++]=iColumn;
	}
      }
    }
    double direction = getObjSense();
    // empty tree
    OsiVectorNode branchingTree;
    
    // Add continuous to it;
    OsiNodeSimple rootNode(*this,numberIntegers,which,getWarmStart());
    // something extra may have been fixed by strong branching
    // if so go round again
    while (rootNode.variable_==numberIntegers) {
      resolve();
      rootNode = OsiNodeSimple(*this,numberIntegers,which,getWarmStart());
    }
    if (rootNode.objectiveValue_<1.0e100) {
      // push on stack
      branchingTree.push_back(rootNode);
    }
    
    // For printing totals
    int numberIterations=0;
    int numberNodes =0;
    int nRedundantUp=0;
    int nRedundantDown=0;
    int nRedundantUp2=0;
    int nRedundantDown2=0;
    OsiNodeSimple bestNode;
    ////// Start main while of branch and bound
    // while until nothing on stack
    while (branchingTree.size()) {
      // last node
      OsiNodeSimple node = branchingTree.back();
      int kNode = branchingTree.chosen_;
      branchingTree.pop_back();
      assert (node.descendants_<2);
      numberNodes++;
      if (node.variable_>=0) {
        // branch - do bounds
        for (i=0;i<numberIntegers;i++) {
          iColumn=which[i];
          setColBounds( iColumn,node.lower_[i],node.upper_[i]);
        }
        // move basis
        setWarmStart(node.basis_);
        // do branching variable
	node.incrementDescendants();
        if (node.way_<0) {
          setColUpper(which[node.variable_],floor(node.value_));
          // now push back node if more to come
          if (node.way_==-1) { 
            node.way_=+2;	  // Swap direction
            branchingTree.push_back(node);
          } else if (funnyBranching) {
	    // put back on tree anyway
            branchingTree.push_back(node);
	  }
        } else {
          setColLower(which[node.variable_],ceil(node.value_));
          // now push back node if more to come
          if (node.way_==1) { 
            node.way_=-2;	  // Swap direction
            branchingTree.push_back(node);
          } else if (funnyBranching) {
	    // put back on tree anyway
            branchingTree.push_back(node);
          }
        }

        // solve
        resolve();
        CoinWarmStart * ws = getWarmStart();
        const CoinWarmStartBasis* wsb =
          dynamic_cast<const CoinWarmStartBasis*>(ws);
        assert (wsb!=NULL); // make sure not volume
        numberIterations += getIterationCount();
        // fix on reduced costs
        int nFixed0=0,nFixed1=0;
        double cutoff;
        getDblParam(OsiDualObjectiveLimit,cutoff);
        double gap=(cutoff-modelPtr_->objectiveValue())*direction+1.0e-4;
        if (gap<1.0e10&&isProvenOptimal()&&!isDualObjectiveLimitReached()) {
          const double * dj = getReducedCost();
          const double * lower = getColLower();
          const double * upper = getColUpper();
          for (i=0;i<numberIntegers;i++) {
            iColumn=which[i];
            if (upper[iColumn]>lower[iColumn]) {
              double djValue = dj[iColumn]*direction;
              if (wsb->getStructStatus(iColumn)==CoinWarmStartBasis::atLowerBound&&
                  djValue>gap) {
                nFixed0++;
                setColUpper(iColumn,lower[iColumn]);
              } else if (wsb->getStructStatus(iColumn)==CoinWarmStartBasis::atUpperBound&&
                         -djValue>gap) {
                nFixed1++;
                setColLower(iColumn,upper[iColumn]);
              }
            }
          }
          //if (nFixed0+nFixed1)
          //printf("%d fixed to lower, %d fixed to upper\n",nFixed0,nFixed1);
        }
        if (!isIterationLimitReached()) {
	  if (isProvenOptimal()&&!isDualObjectiveLimitReached()) {
#if FUNNY_BRANCHING
	    // See if branched variable off bounds
	    const double * dj = getReducedCost();
	    const double * lower = getColLower();
	    const double * upper = getColUpper();
	    const double * solution = getColSolution();
	    // Better to use "natural" value - need flag to say fixed
	    for (i=0;i<numberIntegers;i++) {
	      iColumn=which[i];
	      relaxedLower[i]=originalLower[i];
	      relaxedUpper[i]=originalUpper[i];
	      double djValue = dj[iColumn]*direction;
	      if (djValue>1.0e-6) {
		// wants to go down
		if (lower[iColumn]>originalLower[i]) {
		  // Lower bound active
		  relaxedLower[i]=static_cast<int> (lower[iColumn]);
		}
		if (upper[iColumn]<originalUpper[i]) {
		  // Upper bound NOT active
		}
	      } else if (djValue<-1.0e-6) {
		// wants to go up
		if (lower[iColumn]>originalLower[i]) {
		  // Lower bound NOT active
		}
		if (upper[iColumn]<originalUpper[i]) {
		  // Upper bound active
		  relaxedUpper[i]=static_cast<int> (upper[iColumn]);
		}
	      }
	    }
	    // See if can do anything
	    {
	      /*
		If kNode is on second branch then
		a) If other feasible could free up as well
		b) If other infeasible could do something clever.
		For now - we have to give up
	      */
	      int jNode=branchingTree.nodes_[kNode].parent_;
	      bool canDelete = (branchingTree.nodes_[kNode].descendants_<2);
	      while (jNode>=0) {
		OsiNodeSimple & node = branchingTree.nodes_[jNode];
		int next = node.parent_;
		if (node.descendants_<2) {
		  int variable = node.variable_;
		  iColumn=which[variable];
		  double value = node.value_;
		  double djValue = dj[iColumn]*direction;
		  assert (node.way_==2||node.way_==-2);
		  // we don't know which branch it was - look at current bounds
		  if (upper[iColumn]<value&&node.lower_[variable]<upper[iColumn]) {
		    // must have been down branch
		    if (djValue>1.0e-3||solution[iColumn]<upper[iColumn]-1.0e-5) {
		      if (canDelete) {
			nRedundantDown++;
#if 1
			printf("%d redundant branch down with value %g current upper %g solution %g dj %g\n",
			       variable,node.value_,upper[iColumn],solution[iColumn],djValue);
#endif
			node.descendants_=2; // ignore
			branchingTree.sizeDeferred_++;
			int newUpper = originalUpper[variable];
			if (next>=0) {
			  OsiNodeSimple & node2 = branchingTree.nodes_[next];
			  newUpper = node2.upper_[variable];
			}
			if (branchingTree.nodes_[jNode].parent_!=next)
			  assert (newUpper>upper[iColumn]);
			setColUpper(iColumn,newUpper);
			int kNode2=next;
			int jNode2=branchingTree.nodes_[kNode].parent_;
			assert (newUpper>branchingTree.nodes_[kNode].upper_[variable]);
			branchingTree.nodes_[kNode].upper_[variable]= newUpper;
			while (jNode2!=kNode2) {
			  OsiNodeSimple & node2 = branchingTree.nodes_[jNode2];
			  int next = node2.parent_;
			  if (next!=kNode2)
			    assert (newUpper>node2.upper_[variable]);
			  node2.upper_[variable]= newUpper;
			  jNode2=next;
			}
		      } else {
			// can't delete but can add other way to jNode
			nRedundantDown2++;
			OsiNodeSimple & node2 = branchingTree.nodes_[kNode];
			assert (node2.way_==2||node2.way_==-2);
			double value2 = node2.value_;
			int variable2 = node2.variable_;
			int iColumn2 = which[variable2];
			if (variable != variable2) {
			  if (node2.way_==2&&upper[iColumn2]<value2) {
			    // must have been down branch which was done - carry over
			    int newUpper = static_cast<int> (floor(value2));
			    assert (newUpper<node.upper_[variable2]);
			    node.upper_[variable2]=newUpper;
			  } else if (node2.way_==-2&&lower[iColumn2]>value2) {
			    // must have been up branch which was done - carry over
			    int newLower = static_cast<int> (ceil(value2));
			    assert (newLower>node.lower_[variable2]);
			    node.lower_[variable2]=newLower;
			  }
			  if (node.lower_[variable2]>node.upper_[variable2]) {
			    // infeasible
			    node.descendants_=2; // ignore
			    branchingTree.sizeDeferred_++;
			  }
			}
		      }
		      break;
		    } 
		    // we don't know which branch it was - look at current bounds
		  } else if (lower[iColumn]>value&&node.upper_[variable]>lower[iColumn]) {
		    // must have been up branch
		    if (djValue<-1.0e-3||solution[iColumn]>lower[iColumn]+1.0e-5) {
		      if (canDelete) {
			nRedundantUp++;
#if 1
			printf("%d redundant branch up with value %g current lower %g solution %g dj %g\n",
			       variable,node.value_,lower[iColumn],solution[iColumn],djValue);
#endif
			node.descendants_=2; // ignore
			branchingTree.sizeDeferred_++;
			int newLower = originalLower[variable];
			if (next>=0) {
			  OsiNodeSimple & node2 = branchingTree.nodes_[next];
			  newLower = node2.lower_[variable];
			}
			if (branchingTree.nodes_[jNode].parent_!=next)
			  assert (newLower<lower[iColumn]);
			setColLower(iColumn,newLower);
			int kNode2=next;
			int jNode2=branchingTree.nodes_[kNode].parent_;
			assert (newLower<branchingTree.nodes_[kNode].lower_[variable]);
			branchingTree.nodes_[kNode].lower_[variable]= newLower;
			while (jNode2!=kNode2) {
			  OsiNodeSimple & node2 = branchingTree.nodes_[jNode2];
			  int next = node2.parent_;
			  if (next!=kNode2)
			    assert (newLower<node2.lower_[variable]);
			  node2.lower_[variable]=newLower;
			  jNode2=next;
			}
		      } else {
			// can't delete but can add other way to jNode
			nRedundantUp2++;
			OsiNodeSimple & node2 = branchingTree.nodes_[kNode];
			assert (node2.way_==2||node2.way_==-2);
			double value2 = node2.value_;
			int variable2 = node2.variable_;
			int iColumn2 = which[variable2];
			if (variable != variable2) {
			  if (node2.way_==2&&upper[iColumn2]<value2) {
			    // must have been down branch which was done - carry over
			    int newUpper = static_cast<int> (floor(value2));
			    assert (newUpper<node.upper_[variable2]);
			    node.upper_[variable2]=newUpper;
			  } else if (node2.way_==-2&&lower[iColumn2]>value2) {
			    // must have been up branch which was done - carry over
			    int newLower = static_cast<int> (ceil(value2));
			    assert (newLower>node.lower_[variable2]);
			    node.lower_[variable2]=newLower;
			  }
			  if (node.lower_[variable2]>node.upper_[variable2]) {
			    // infeasible
			    node.descendants_=2; // ignore
			    branchingTree.sizeDeferred_++;
			  }
			}
		      }
		      break;
		    } 
		  }
		} else {
		  break;
		}
		jNode=next;
	      }
	    }
	    // solve
	    //resolve();
	    //assert(!getIterationCount());
	    if ((numberNodes%1000)==0) 
	      printf("%d nodes, redundant down %d (%d) up %d (%d) tree size %d\n",
		     numberNodes,nRedundantDown,nRedundantDown2,nRedundantUp,nRedundantUp2,branchingTree.size());
#else
	    if ((numberNodes%1000)==0) 
	      printf("%d nodes, tree size %d\n",
		     numberNodes,branchingTree.size());
#endif
	    if (CoinCpuTime()-time1>3600.0) {
	      printf("stopping after 3600 seconds\n");
	      exit(77);
	    }
	    OsiNodeSimple newNode(*this,numberIntegers,which,ws);
	    // something extra may have been fixed by strong branching
	    // if so go round again
	    while (newNode.variable_==numberIntegers) {
	      resolve();
	      newNode = OsiNodeSimple(*this,numberIntegers,which,getWarmStart());
	    }
	    if (newNode.objectiveValue_<1.0e100) {
	      if (newNode.variable_>=0) 
		assert (fabs(newNode.value_-floor(newNode.value_+0.5))>1.0e-6);
	      newNode.parent_ = kNode;
	      // push on stack
	      branchingTree.push_back(newNode);
	    }
	  } else {
	    // infeasible
	    delete ws;
 	  }
        } else {
          // maximum iterations - exit
          std::cout<<"Exiting on maximum iterations"
                   <<std::endl;
	  break;
        }
      } else {
        // integer solution - save
        bestNode = node;
        // set cutoff (hard coded tolerance)
        setDblParam(OsiDualObjectiveLimit,(bestNode.objectiveValue_-1.0e-5)*direction);
        std::cout<<"Integer solution of "
                 <<bestNode.objectiveValue_
                 <<" found after "<<numberIterations
                 <<" iterations and "<<numberNodes<<" nodes"
                 <<std::endl;
      }
    }
    ////// End main while of branch and bound
    std::cout<<"Search took "
             <<numberIterations
             <<" iterations and "<<numberNodes<<" nodes"
             <<std::endl;
    if (bestNode.numberIntegers_) {
      // we have a solution restore
      // do bounds
      for (i=0;i<numberIntegers;i++) {
        iColumn=which[i];
        setColBounds( iColumn,bestNode.lower_[i],bestNode.upper_[i]);
      }
      // move basis
      setWarmStart(bestNode.basis_);
      // set cutoff so will be good (hard coded tolerance)
      setDblParam(OsiDualObjectiveLimit,(bestNode.objectiveValue_+1.0e-5)*direction);
      resolve();
    } else {
      modelPtr_->setProblemStatus(1);
    }
    delete [] which;
    delete [] originalLower;
    delete [] originalUpper;
    delete [] relaxedLower;
    delete [] relaxedUpper;
  } else {
    if(messageHandler())
      *messageHandler() <<"The LP relaxation is infeasible" <<CoinMessageEol;
    modelPtr_->setProblemStatus(1);
    //throw CoinError("The LP relaxation is infeasible or too expensive",
    //"branchAndBound", "OsiClpSolverInterface");
  }
}
void 
OsiClpSolverInterface::setSpecialOptions(unsigned int value)
{ 
  if ((value&131072)!=0&&(specialOptions_&131072)==0) {
    // Try and keep scaling factors around
    delete baseModel_;
    baseModel_ = new ClpSimplex(*modelPtr_);
    ClpPackedMatrix * clpMatrix = 
      dynamic_cast< ClpPackedMatrix*>(baseModel_->matrix_);
    if (!clpMatrix||clpMatrix->scale(baseModel_)) {
      // switch off again
      delete baseModel_;
      baseModel_=NULL;
      value &= ~131072;
    } else {
      // Off current scaling
      modelPtr_->setRowScale(NULL);
      modelPtr_->setColumnScale(NULL);
      lastNumberRows_=baseModel_->numberRows();
      rowScale_ = CoinDoubleArrayWithLength(2*lastNumberRows_,0);
      int i;
      double * scale;
      double * inverseScale;
      scale = rowScale_.array();
      inverseScale = scale + lastNumberRows_;
      const double * rowScale = baseModel_->rowScale_;
      for (i=0;i<lastNumberRows_;i++) {
	scale[i] = rowScale[i];
	inverseScale[i] = 1.0/scale[i];
      }
      int numberColumns = baseModel_->numberColumns();
      columnScale_ = CoinDoubleArrayWithLength(2*numberColumns,0);
      scale = columnScale_.array();
      inverseScale = scale + numberColumns;
      const double * columnScale = baseModel_->columnScale_;
      for (i=0;i<numberColumns;i++) {
	scale[i] = columnScale[i];
	inverseScale[i] = 1.0/scale[i];
      }
    }
  }
  specialOptions_=value;
  if ((specialOptions_&0x80000000)!=0) {
    // unset top bit if anything set
    if (specialOptions_!=0x80000000) 
      specialOptions_ &= 0x7fffffff;
  }
}
void 
OsiClpSolverInterface::setSpecialOptionsMutable(unsigned int value) const
{ 
  specialOptions_=value;
  if ((specialOptions_&0x80000000)!=0) {
    // unset top bit if anything set
    if (specialOptions_!=0x80000000) 
      specialOptions_ &= 0x7fffffff;
  }
}
/*  If solver wants it can save a copy of "base" (continuous) model here
 */
void 
OsiClpSolverInterface::saveBaseModel() 
{
  delete continuousModel_;
  continuousModel_ = new ClpSimplex(*modelPtr_);
  delete matrixByRowAtContinuous_;
  matrixByRowAtContinuous_ = new CoinPackedMatrix();
  matrixByRowAtContinuous_->setExtraGap(0.0);
  matrixByRowAtContinuous_->setExtraMajor(0.0);
  matrixByRowAtContinuous_->reverseOrderedCopyOf(*modelPtr_->matrix());
  //continuousModel_->createRim(63);
}
// Pass in disaster handler
void 
OsiClpSolverInterface::passInDisasterHandler(OsiClpDisasterHandler * handler)
{
  delete disasterHandler_;
  if ( handler  ) 
    disasterHandler_ = dynamic_cast<OsiClpDisasterHandler *>(handler->clone());
  else
    disasterHandler_ = NULL;
}
/*  Strip off rows to get to this number of rows.
    If solver wants it can restore a copy of "base" (continuous) model here
*/
void 
OsiClpSolverInterface::restoreBaseModel(int numberRows)
{
  if (continuousModel_&&continuousModel_->numberRows()==numberRows) {
    modelPtr_->numberRows_ = numberRows;
    //ClpDisjointCopyN ( continuousModel_->columnLower_, modelPtr_->numberColumns_,modelPtr_->columnLower_ );
    //ClpDisjointCopyN ( continuousModel_->columnUpper_, modelPtr_->numberColumns_,modelPtr_->columnUpper_ );
    // Could keep copy of scaledMatrix_ around??
    delete modelPtr_->scaledMatrix_;
    modelPtr_->scaledMatrix_=NULL;
    if (continuousModel_->rowCopy_) {
      modelPtr_->copy(continuousModel_->rowCopy_,modelPtr_->rowCopy_);
    } else {
      delete modelPtr_->rowCopy_;
      modelPtr_->rowCopy_=NULL;
    }
    modelPtr_->copy(continuousModel_->matrix_,modelPtr_->matrix_);
    if (matrixByRowAtContinuous_) {
      if (matrixByRow_) {
	*matrixByRow_ = *matrixByRowAtContinuous_;
      } else {
	//printf("BBBB could new\n");
	// matrixByRow_ = new CoinPackedMatrix(*matrixByRowAtContinuous_);
      }
    } else {
      delete matrixByRow_;
      matrixByRow_=NULL;
    }
  } else {
    OsiSolverInterface::restoreBaseModel(numberRows);
  }
}
// Tighten bounds - lightweight
int 
OsiClpSolverInterface::tightenBounds(int lightweight)
{
  if (!integerInformation_||(specialOptions_&262144)!=0)
    return 0; // no integers
  //CoinPackedMatrix matrixByRow(*getMatrixByRow());
  int numberRows = getNumRows();
  int numberColumns = getNumCols();

  int iRow,iColumn;

  // Row copy
  //const double * elementByRow = matrixByRow.getElements();
  //const int * column = matrixByRow.getIndices();
  //const CoinBigIndex * rowStart = matrixByRow.getVectorStarts();
  //const int * rowLength = matrixByRow.getVectorLengths();

  const double * columnUpper = getColUpper();
  const double * columnLower = getColLower();
  const double * rowUpper = getRowUpper();
  const double * rowLower = getRowLower();

  // Column copy of matrix
  const double * element = getMatrixByCol()->getElements();
  const int * row = getMatrixByCol()->getIndices();
  const CoinBigIndex * columnStart = getMatrixByCol()->getVectorStarts();
  const int * columnLength = getMatrixByCol()->getVectorLengths();
  const double *objective = getObjCoefficients() ;
  double direction = getObjSense();
  double * down = new double [numberRows];
  if (lightweight>0) {
    int * first = new int[numberRows];
    CoinZeroN(first,numberRows);
    CoinZeroN(down,numberRows);
    double * sum = new double [numberRows];
    CoinZeroN(sum,numberRows);
    int numberTightened=0;
    for (int iColumn=0;iColumn<numberColumns;iColumn++) {
      CoinBigIndex start = columnStart[iColumn];
      CoinBigIndex end = start + columnLength[iColumn];
      double lower = columnLower[iColumn];
      double upper = columnUpper[iColumn];
      if (lower==upper) {
	for (CoinBigIndex j=start;j<end;j++) {
	  int iRow = row[j];
	  double value = element[j];
	  down[iRow] += value*lower;
	  sum[iRow] += fabs(value*lower);
	}
      } else {
	for (CoinBigIndex j=start;j<end;j++) {
	  int iRow = row[j];
	  int n=first[iRow];
	  if (n==0&&element[j])
	    first[iRow]=-iColumn-1;
	  else if (n<0) 
	    first[iRow]=2;
	}
      }
    }
    double tolerance = 1.0e-6;
    const char * integerInformation = modelPtr_->integerType_;
    for (int iRow=0;iRow<numberRows;iRow++) {
      int iColumn = first[iRow];
      if (iColumn<0) {
	iColumn = -iColumn-1;
	if ((integerInformation&&integerInformation[iColumn])||lightweight==2) {
	  double lowerRow = rowLower[iRow];
	  if (lowerRow>-1.0e20)
	    lowerRow -= down[iRow];
	  double upperRow = rowUpper[iRow];
	  if (upperRow<1.0e20)
	    upperRow -= down[iRow];
	  double lower = columnLower[iColumn];
	  double upper = columnUpper[iColumn];
	  double value=0.0;
	  for (CoinBigIndex j = columnStart[iColumn];
	       j<columnStart[iColumn]+columnLength[iColumn];j++) {
	    if (iRow==row[j]) {
	      value=element[j];
	      break;
	    }
	  }
	  assert (value);
	  // convert rowLower and Upper to implied bounds on column
	  double newLower=-COIN_DBL_MAX;
	  double newUpper=COIN_DBL_MAX;
	  if (value>0.0) {
	    if (lowerRow>-1.0e20)
	      newLower = lowerRow/value;
	    if (upperRow<1.0e20)
	      newUpper = upperRow/value;
	  } else {
	    if (upperRow<1.0e20)
	      newLower = upperRow/value;
	    if (lowerRow>-1.0e20)
	      newUpper = lowerRow/value;
	  }
	  double tolerance2 = 1.0e-6+1.0e-8*sum[iRow];
	  if (integerInformation&&integerInformation[iColumn]) {
	    if (newLower-floor(newLower)<tolerance2) 
	      newLower=floor(newLower);
	    else
	      newLower=ceil(newLower);
	    if (ceil(newUpper)-newUpper<tolerance2) 
	      newUpper=ceil(newUpper);
	    else
	      newUpper=floor(newUpper);
	  }
	  if (newLower>lower+10.0*tolerance2||
	      newUpper<upper-10.0*tolerance2) {
	    numberTightened++;
	    newLower = CoinMax(lower,newLower);
	    newUpper = CoinMin(upper,newUpper);
	    if (newLower>newUpper+tolerance) {
	      //printf("XXYY inf on bound\n");
	      numberTightened=-1;
	      break;
	    }
	    setColLower(iColumn,newLower);
	    setColUpper(iColumn,CoinMax(newLower,newUpper));
	  }
	}
      }
    }
    delete [] first;
    delete [] down;
    delete [] sum;
    return numberTightened;
  }
  double * up = new double [numberRows];
  double * sum = new double [numberRows];
  int * type = new int [numberRows];
  CoinZeroN(down,numberRows);
  CoinZeroN(up,numberRows);
  CoinZeroN(sum,numberRows);
  CoinZeroN(type,numberRows);
  double infinity = getInfinity();
  for (iColumn=0;iColumn<numberColumns;iColumn++) {
    CoinBigIndex start = columnStart[iColumn];
    CoinBigIndex end = start + columnLength[iColumn];
    double lower = columnLower[iColumn];
    double upper = columnUpper[iColumn];
    if (lower==upper) {
      for (CoinBigIndex j=start;j<end;j++) {
	int iRow = row[j];
	double value = element[j];
	sum[iRow]+=2.0*fabs(value*lower);
	if ((type[iRow]&1)==0)
	  down[iRow] += value*lower;
	if ((type[iRow]&2)==0)
	  up[iRow] += value*lower;
      }
    } else {
      for (CoinBigIndex j=start;j<end;j++) {
	int iRow = row[j];
	double value = element[j];
	if (value>0.0) {
	  if ((type[iRow]&1)==0) {
	    if (lower!=-infinity) {
	      down[iRow] += value*lower;
	      sum[iRow]+=fabs(value*lower);
	    } else {
	      type[iRow] |= 1;
	    }
	  }
	  if ((type[iRow]&2)==0) {
	    if (upper!=infinity) {
	      up[iRow] += value*upper;
	      sum[iRow]+=fabs(value*upper);
	    } else {
	      type[iRow] |= 2;
	    }
	  }
	} else {
	  if ((type[iRow]&1)==0) {
	    if (upper!=infinity) {
	      down[iRow] += value*upper;
	      sum[iRow]+=fabs(value*upper);
	    } else {
	      type[iRow] |= 1;
	    }
	  }
	  if ((type[iRow]&2)==0) {
	    if (lower!=-infinity) {
	      up[iRow] += value*lower;
	      sum[iRow]+=fabs(value*lower);
	    } else {
	      type[iRow] |= 2;
	    }
	  }
	}
      }
    }
  }
  int nTightened=0;
  double tolerance = 1.0e-6;
  for (iRow=0;iRow<numberRows;iRow++) {
    if ((type[iRow]&1)!=0)
      down[iRow]=-infinity;
    if (down[iRow]>rowUpper[iRow]) {
      if (down[iRow]>rowUpper[iRow]+tolerance+1.0e-8*sum[iRow]) {
	// infeasible
#ifdef COIN_DEVELOP
	printf("infeasible on row %d\n",iRow);
#endif
	nTightened=-1;
	break;
      } else {
	down[iRow]=rowUpper[iRow];
      }
    }
    if ((type[iRow]&2)!=0)
      up[iRow]=infinity;
    if (up[iRow]<rowLower[iRow]) {
      if (up[iRow]<rowLower[iRow]-tolerance-1.0e-8*sum[iRow]) {
	// infeasible
#ifdef COIN_DEVELOP
	printf("infeasible on row %d\n",iRow);
#endif
	nTightened=-1;
	break;
      } else {
	up[iRow]=rowLower[iRow];
      }
    }
  }
  if (nTightened)
    numberColumns=0; // so will skip
  for (iColumn=0;iColumn<numberColumns;iColumn++) {
    double lower = columnLower[iColumn];
    double upper = columnUpper[iColumn];
    double gap = upper-lower;
    if (!gap)
      continue;
    int canGo=0;
    CoinBigIndex start = columnStart[iColumn];
    CoinBigIndex end = start + columnLength[iColumn];
    if (lower<-1.0e8&&upper>1.0e8)
      continue; // Could do severe damage to accuracy
    if (integerInformation_[iColumn]) {
      if (lower!=floor(lower+0.5)) {
#ifdef COIN_DEVELOP
	printf("increasing lower bound on %d from %g to %g\n",iColumn,
	       lower,ceil(lower));
#endif
	lower=ceil(lower);
	gap=upper-lower;
	setColLower(iColumn,lower);
      }
      if (upper!=floor(upper+0.5)) {
#ifdef COIN_DEVELOP
	printf("decreasing upper bound on %d from %g to %g\n",iColumn,
	       upper,floor(upper));
#endif
	upper=floor(upper);
	gap=upper-lower;
	setColUpper(iColumn,upper);
      }
      double newLower=lower;
      double newUpper=upper;
      for (CoinBigIndex j=start;j<end;j++) {
	int iRow = row[j];
	double value = element[j];
	if (value>0.0) {
	  if ((type[iRow]&1)==0) {
	    // has to be at most something
	    if (down[iRow] + value*gap > rowUpper[iRow]+tolerance) {
	      double newGap = (rowUpper[iRow]-down[iRow])/value;
	      // adjust
	      newGap += 1.0e-10*sum[iRow];
	      newGap = floor(newGap);
	      if (lower+newGap<newUpper)
		newUpper=lower+newGap;
	    }
	  }
	  if (down[iRow]<rowLower[iRow])
	    canGo |=1; // can't go down without affecting result
	  if ((type[iRow]&2)==0) {
	    // has to be at least something
	    if (up[iRow] - value*gap < rowLower[iRow]-tolerance) {
	      double newGap = (up[iRow]-rowLower[iRow])/value;
	      // adjust
	      newGap += 1.0e-10*sum[iRow];
	      newGap = floor(newGap);
	      if (upper-newGap>newLower)
		newLower=upper-newGap;
	    }
	  }
	  if (up[iRow]>rowUpper[iRow])
	    canGo |=2; // can't go up without affecting result
	} else {
	  if ((type[iRow]&1)==0) {
	    // has to be at least something
	    if (down[iRow] - value*gap > rowUpper[iRow]+tolerance) {
	      double newGap = -(rowUpper[iRow]-down[iRow])/value;
	      // adjust
	      newGap += 1.0e-10*sum[iRow];
	      newGap = floor(newGap);
	      if (upper-newGap>newLower)
		newLower=upper-newGap;
	    }
	  }
	  if (up[iRow]>rowUpper[iRow])
	    canGo |=1; // can't go down without affecting result
	  if ((type[iRow]&2)==0) {
	    // has to be at most something
	    if (up[iRow] + value*gap < rowLower[iRow]-tolerance) {
	      double newGap = -(up[iRow]-rowLower[iRow])/value;
	      // adjust
	      newGap += 1.0e-10*sum[iRow];
	      newGap = floor(newGap);
	      if (lower+newGap<newUpper)
		newUpper=lower+newGap;
	    }
	  }
	  if (down[iRow]<rowLower[iRow])
	    canGo |=2; // can't go up without affecting result
	}
      }
      if (newUpper<upper||newLower>lower) {
	nTightened++;
	if (newLower>newUpper) {
	  // infeasible
#if COIN_DEVELOP>1
	  printf("infeasible on column %d\n",iColumn);
#endif
	  nTightened=-1;
	  break;
	} else {
	  setColLower(iColumn,newLower);
	  setColUpper(iColumn,newUpper);
	}
	for (CoinBigIndex j=start;j<end;j++) {
	  int iRow = row[j];
	  double value = element[j];
	  if (value>0.0) {
	    if ((type[iRow]&1)==0) {
	      down[iRow] += value*(newLower-lower);
	    }
	    if ((type[iRow]&2)==0) {
	      up[iRow] += value*(newUpper-upper);
	    }
	  } else {
	    if ((type[iRow]&1)==0) {
	      down[iRow] += value*(newUpper-upper);
	    }
	    if ((type[iRow]&2)==0) {
	      up[iRow] += value*(newLower-lower);
	    }
	  }
	}
      } else {
	if (canGo!=3) {
	  double objValue = direction*objective[iColumn];
	  if (objValue>=0.0&&(canGo&1)==0) {
#if COIN_DEVELOP>2
	    printf("dual fix down on column %d\n",iColumn);
#endif
	    // Only if won't cause numerical problems
	    if (lower>-1.0e10) {
	      nTightened++;
	      setColUpper(iColumn,lower);
	    }
	  } else if (objValue<=0.0&&(canGo&2)==0) {
#if COIN_DEVELOP>2
	    printf("dual fix up on column %d\n",iColumn);
#endif
	    // Only if won't cause numerical problems
	    if (upper<1.0e10) {
	      nTightened++;
	      setColLower(iColumn,upper);
	    }
	  }
	}	    
      }
    } else {
      // just do dual tests
      for (CoinBigIndex j=start;j<end;j++) {
	int iRow = row[j];
	double value = element[j];
	if (value>0.0) {
	  if (down[iRow]<rowLower[iRow])
	    canGo |=1; // can't go down without affecting result
	  if (up[iRow]>rowUpper[iRow])
	    canGo |=2; // can't go up without affecting result
	} else {
	  if (up[iRow]>rowUpper[iRow])
	    canGo |=1; // can't go down without affecting result
	  if (down[iRow]<rowLower[iRow])
	    canGo |=2; // can't go up without affecting result
	}
      }
      if (canGo!=3) {
	double objValue = direction*objective[iColumn];
	if (objValue>=0.0&&(canGo&1)==0) {
#if COIN_DEVELOP>2
	  printf("dual fix down on continuous column %d lower %g\n",
		 iColumn,lower);
#endif
	  // Only if won't cause numerical problems
	  if (lower>-1.0e10) {
	    nTightened++;
	    setColUpper(iColumn,lower);
	  }
	} else if (objValue<=0.0&&(canGo&2)==0) {
#if COIN_DEVELOP>2
	  printf("dual fix up on continuous column %d upper %g\n",
		 iColumn,upper);
#endif
	  // Only if won't cause numerical problems
	  if (upper<1.0e10) {
	    nTightened++;
	    setColLower(iColumn,upper);
	  }
	}
      }
    }
  }
  if (lightweight<0) {
    // get max down and up again
    CoinZeroN(down,numberRows);
    CoinZeroN(up,numberRows);
    CoinZeroN(type,numberRows);
    int * seqDown = new int [2*numberRows];
    int * seqUp=seqDown+numberRows;
    for (int i=0;i<numberRows;i++) {
      seqDown[i]=-1;
      seqUp[i]=-1;
    }
    for (iColumn=0;iColumn<numberColumns;iColumn++) {
      CoinBigIndex start = columnStart[iColumn];
      CoinBigIndex end = start + columnLength[iColumn];
      double lower = columnLower[iColumn];
      double upper = columnUpper[iColumn];
      if (lower==upper) {
	for (CoinBigIndex j=start;j<end;j++) {
	  int iRow = row[j];
	  double value = element[j];
	  if ((type[iRow]&1)==0)
	    down[iRow] += value*lower;
	  if ((type[iRow]&2)==0)
	    up[iRow] += value*lower;
	}
      } else {
	for (CoinBigIndex j=start;j<end;j++) {
	  int iRow = row[j];
	  double value = element[j];
	  if (value>0.0) {
	    if ((type[iRow]&1)==0) {
	      if (lower>-1.0e8) {
		down[iRow] += value*lower;
	      } else if (seqDown[iRow]<0) {
		seqDown[iRow]=iColumn;
	      } else {
		type[iRow] |= 1;
	      }
	    }
	    if ((type[iRow]&2)==0) {
	      if (upper<1.0e8) {
		up[iRow] += value*upper;
		sum[iRow]+=fabs(value*upper);
	      } else if (seqUp[iRow]<0) {
		seqUp[iRow]=iColumn;
	      } else {
		type[iRow] |= 2;
	      }
	    }
	  } else {
	    if ((type[iRow]&1)==0) {
	      if (upper<1.0e8) {
		down[iRow] += value*upper;
		sum[iRow]+=fabs(value*upper);
	      } else if (seqDown[iRow]<0) {
		seqDown[iRow]=iColumn;
	      } else {
		type[iRow] |= 1;
	      }
	    }
	    if ((type[iRow]&2)==0) {
	      if (lower>-1.0e8) {
		up[iRow] += value*lower;
		sum[iRow]+=fabs(value*lower);
	      } else if (seqUp[iRow]<0) {
		seqUp[iRow]=iColumn;
	      } else {
		type[iRow] |= 2;
	      }
	    }
	  }
	}
      }
    }
    for (iColumn=0;iColumn<numberColumns;iColumn++) {
      double lower = columnLower[iColumn];
      double upper = columnUpper[iColumn];
      double gap = upper-lower;
      if (!gap)
	continue;
      CoinBigIndex start = columnStart[iColumn];
      CoinBigIndex end = start + columnLength[iColumn];
      if (lower<-1.0e8&&upper>1.0e8)
	continue; // Could do severe damage to accuracy
      double newLower=upper;
      double newUpper=lower;
      bool badUpper=false;
      bool badLower=false;
      double objValue = objective[iColumn]*direction;
      for (CoinBigIndex j=start;j<end;j++) {
	int iRow = row[j];
	double value = element[j];
	if (value>0.0) {
	  if (rowLower[iRow]>-COIN_DBL_MAX) {
	    if (!badUpper&&(type[iRow]&1)==0&&
		(seqDown[iRow]<0||seqDown[iRow]==iColumn)) {
	      double s=down[iRow];
	      if (seqDown[iRow]!=iColumn)
		s -= lower*value;
	      if (s+newUpper*value<rowLower[iRow]) {
		newUpper = CoinMax(newUpper,(rowLower[iRow]-s)/value);
	      }
	    } else {
	      badUpper=true;
	    }
	  }
	  if (rowUpper[iRow]<COIN_DBL_MAX) {
	    if (!badLower&&(type[iRow]&2)==0&&
		(seqUp[iRow]<0||seqUp[iRow]==iColumn)) {
	      double s=up[iRow];
	      if (seqUp[iRow]!=iColumn)
		s -= upper*value;
	      if (s+newLower*value>rowUpper[iRow]) {
		newLower = CoinMin(newLower,(rowUpper[iRow]-s)/value);
	      }
	    } else {
	      badLower=true;
	    }
	  }
	} else {
	  if (rowUpper[iRow]<COIN_DBL_MAX) {
	    if (!badUpper&&(type[iRow]&2)==0&&
		(seqUp[iRow]<0||seqUp[iRow]==iColumn)) {
	      double s=up[iRow];
	      if (seqUp[iRow]!=iColumn)
		s -= lower*value;
	      if (s+newUpper*value>rowUpper[iRow]) {
		newUpper = CoinMax(newUpper,(rowUpper[iRow]-s)/value);
	      }
	    } else {
	      badUpper=true;
	    }
	  }
	  if (rowLower[iRow]>-COIN_DBL_MAX) {
	    if (!badLower&&(type[iRow]&1)==0&&
		(seqDown[iRow]<0||seqDown[iRow]==iColumn)) {
	      double s=down[iRow];
	      if (seqDown[iRow]!=iColumn)
		s -= lower*value;
	      if (s+newLower*value<rowLower[iRow]) {
		newLower = CoinMin(newLower,(rowLower[iRow]-s)/value);
	      }
	    } else {
	      badLower=true;
	    }
	  }
	}
      }
      if (badLower||objValue>0.0)
	newLower=lower;
      if (badUpper||objValue<0.0)
	newUpper=upper;
      if (newUpper<upper||newLower>lower) {
	nTightened++;
	if (newLower>newUpper) {
	  // infeasible
#if COIN_DEVELOP>0
	  printf("infeasible on column %d\n",iColumn);
#endif
	  nTightened=-1;
	  break;
	} else {
	  newLower=CoinMax(newLower,lower);
	  newUpper=CoinMin(newUpper,upper);
	  if (integerInformation_[iColumn]) {
	    newLower=ceil(newLower-1.0e-5);
	    newUpper=floor(newUpper+1.0e-5);
	  }
	  setColLower(iColumn,newLower);
	  setColUpper(iColumn,newUpper);
	}
      }
    }
    delete [] seqDown;
  }
  delete [] type;
  delete [] down;
  delete [] up;
  delete [] sum;
  return nTightened;
}
// Return number of entries in L part of current factorization
CoinBigIndex 
OsiClpSolverInterface::getSizeL() const
{
  return modelPtr_->factorization_->numberElementsL();
}
// Return number of entries in U part of current factorization
CoinBigIndex 
OsiClpSolverInterface::getSizeU() const
{
  return modelPtr_->factorization_->numberElementsU();
}
/* Add a named row (constraint) to the problem.
 */
void 
OsiClpSolverInterface::addRow(const CoinPackedVectorBase& vec,
       const char rowsen, const double rowrhs,   
       const double rowrng, std::string name) 
{
  int ndx = getNumRows() ;
  addRow(vec,rowsen,rowrhs,rowrng) ;
  setRowName(ndx,name) ;
}
/* Add a named column (primal variable) to the problem.
 */
void 
OsiClpSolverInterface::addCol(int numberElements,
       const int* rows, const double* elements,
       const double collb, const double colub,   
       const double obj, std::string name) 
{
  int ndx = getNumCols() ;
  addCol(numberElements,rows,elements,collb,colub,obj) ;
  setColName(ndx,name) ;
}
/* Start faster dual - returns negative if problems 1 if infeasible,
   Options to pass to solver
   1 - create external reduced costs for columns
   2 - create external reduced costs for rows
   4 - create external row activity (columns always done)
   Above only done if feasible
   When set resolve does less work
*/
int 
OsiClpSolverInterface::startFastDual(int options)
{
  stuff_.zap(3);
  stuff_.solverOptions_=options;
  return modelPtr_->startFastDual2(&stuff_);
}
// Sets integer tolerance and increment
void
OsiClpSolverInterface::setStuff(double tolerance,double increment)
{
  stuff_.integerTolerance_ = tolerance;
  stuff_.integerIncrement_ = increment;
}
// Stops faster dual
void 
OsiClpSolverInterface::stopFastDual()
{
  modelPtr_->stopFastDual2(&stuff_);
}
// Compute largest amount any at continuous away from bound
void 
OsiClpSolverInterface::computeLargestAway()
{
  // get largest scaled away from bound
  ClpSimplex temp=*modelPtr_;
  temp.setLogLevel(0);
  temp.dual();
  if (temp.status()==1)
    temp.primal(); // may mean we have optimal so continuous cutoff
  temp.dual(0,7);
  double largestScaled=1.0e-12;
  double largest=1.0e-12;
  int numberRows = temp.numberRows();
  const double * rowPrimal = temp.primalRowSolution();
  const double * rowLower = temp.rowLower();
  const double * rowUpper = temp.rowUpper();
  const double * rowScale = temp.rowScale();
  int iRow;
  for (iRow=0;iRow<numberRows;iRow++) {
    double value = rowPrimal[iRow];
    double above = value-rowLower[iRow];
    double below = rowUpper[iRow]-value;
    if (above<1.0e12) {
      largest = CoinMax(largest,above);
    }
    if (below<1.0e12) {
      largest = CoinMax(largest,below);
    }
    if (rowScale) {
      double multiplier = rowScale[iRow];
      above *= multiplier;
      below *= multiplier;
    }
    if (above<1.0e12) {
      largestScaled = CoinMax(largestScaled,above);
    }
    if (below<1.0e12) {
      largestScaled = CoinMax(largestScaled,below);
    }
  }
  
  int numberColumns = temp.numberColumns();
  const double * columnPrimal = temp.primalColumnSolution();
  const double * columnLower = temp.columnLower();
  const double * columnUpper = temp.columnUpper();
  const double * columnScale = temp.columnScale();
  int iColumn;
  for (iColumn=0;iColumn<numberColumns;iColumn++) {
    double value = columnPrimal[iColumn];
    double above = value-columnLower[iColumn];
    double below = columnUpper[iColumn]-value;
    if (above<1.0e12) {
      largest = CoinMax(largest,above);
    }
    if (below<1.0e12) {
      largest = CoinMax(largest,below);
    }
    if (columnScale) {
      double multiplier = 1.0/columnScale[iColumn];
      above *= multiplier;
      below *= multiplier;
    }
    if (above<1.0e12) {
      largestScaled = CoinMax(largestScaled,above);
    }
    if (below<1.0e12) {
      largestScaled = CoinMax(largestScaled,below);
    }
  }
#ifdef COIN_DEVELOP
  std::cout<<"Largest (scaled) away from bound "<<largestScaled
	   <<" unscaled "<<largest<<std::endl;
#endif
  largestAway_ = largestScaled;
  // go for safety
  if (numberRows>4000)
    modelPtr_->setSpecialOptions(modelPtr_->specialOptions()&~(2048+4096));
}
// Pass in Message handler (not deleted at end)
void 
OsiClpSolverInterface::passInMessageHandler(CoinMessageHandler * handler)
{
  if (defaultHandler_) {
    delete handler_;
    handler_ = NULL;
  }
  defaultHandler_=false;
  handler_=handler;
  if (modelPtr_)
    modelPtr_->passInMessageHandler(handler);
}
// Set log level (will also set underlying solver's log level)
void 
OsiClpSolverInterface::setLogLevel(int value)
{
  handler_->setLogLevel(value);
  if (modelPtr_)
    modelPtr_->setLogLevel(value);
}
// Set fake objective (and take ownership)
void 
OsiClpSolverInterface::setFakeObjective(ClpLinearObjective * fakeObjective)
{
  delete fakeObjective_;
  fakeObjective_ = fakeObjective;
}
// Set fake objective
void 
OsiClpSolverInterface::setFakeObjective(double * fakeObjective)
{
  delete fakeObjective_;
  if (fakeObjective)
    fakeObjective_ = new ClpLinearObjective(fakeObjective,
					    modelPtr_->numberColumns_);
  else
    fakeObjective_ = NULL;
}
/* Solve when primal column and dual row solutions are near-optimal
   options - 0 no presolve (use primal and dual)
             1 presolve (just use primal)
	     2 no presolve (just use primal)
   basis - 0 use all slack basis
           1 try and put some in basis
*/
void 
OsiClpSolverInterface::crossover(int options,int basis)
{
  int numberRows = modelPtr_->getNumRows();
  int numberColumns = modelPtr_->getNumCols();
  // Get row activities and column reduced costs
  const double * objective = modelPtr_->objective();
  double direction = modelPtr_->optimizationDirection();
  double * dual = modelPtr_->dualRowSolution();
  double * dj = modelPtr_->dualColumnSolution();
  CoinMemcpyN(objective,numberColumns,dj);
  if (direction==-1.0) {
    for (int i=0;i<numberColumns;i++)
      dj[i] = - dj[i];
  }
  modelPtr_->clpMatrix()->transposeTimes(-1.0,dual,dj);
  double * rowActivity = modelPtr_->primalRowSolution();
  double * columnActivity = modelPtr_->primalColumnSolution();
  CoinZeroN(rowActivity,numberRows);
  modelPtr_->clpMatrix()->times(1.0,columnActivity,rowActivity);
  modelPtr_->checkSolution();
  printf("%d primal infeasibilities summing to %g\n",
	 modelPtr_->numberPrimalInfeasibilities(),
	 modelPtr_->sumPrimalInfeasibilities());
  printf("%d dual infeasibilities summing to %g\n",
	 modelPtr_->numberDualInfeasibilities(),
	 modelPtr_->sumDualInfeasibilities());
  // get which variables are fixed
  double * saveLower=NULL;
  double * saveUpper=NULL;
  ClpPresolve pinfo2;
  bool extraPresolve=false;
  bool useBoth= (options==0);
  // create all slack basis
  modelPtr_->createStatus();
  // Point to model - so can use in presolved model
  ClpSimplex * model2 = modelPtr_;
  double tolerance = modelPtr_->primalTolerance()*10.0;
  if (options==1) {
    int numberTotal = numberRows+numberColumns;
    saveLower = new double [numberTotal];
    saveUpper = new double [numberTotal];
    CoinMemcpyN(modelPtr_->columnLower(),numberColumns,saveLower);
    CoinMemcpyN(modelPtr_->rowLower(),numberRows,saveLower+numberColumns);
    CoinMemcpyN(modelPtr_->columnUpper(),numberColumns,saveUpper);
    CoinMemcpyN(modelPtr_->rowUpper(),numberRows,saveUpper+numberColumns);
    double * lower = modelPtr_->columnLower();
    double * upper = modelPtr_->columnUpper();
    double * solution = modelPtr_->primalColumnSolution();
    int nFix=0;
    for (int i=0;i<numberColumns;i++) {
      if (lower[i]<upper[i]&&(lower[i]>-1.0e10||upper[i]<1.0e10)) {
	double value = solution[i];
	if (value<lower[i]+tolerance&&value-lower[i]<upper[i]-value) {
	  solution[i]=lower[i];
	  upper[i]=lower[i];
	  nFix++;
	} else if (value>upper[i]-tolerance&&value-lower[i]>upper[i]-value) {
	  solution[i]=upper[i];
	  lower[i]=upper[i];
	  nFix++;
	}
      }
    }
#ifdef CLP_INVESTIGATE
    printf("%d columns fixed\n",nFix);
#endif
#if 0
    int nr=modelPtr_->numberRows();
    lower = modelPtr_->rowLower();
    upper = modelPtr_->rowUpper();
    solution = modelPtr_->primalRowSolution();
    nFix=0;
    for (int i=0;i<nr;i++) {
      if (lower[i]<upper[i]) {
	double value = solution[i];
	if (value<lower[i]+tolerance&&value-lower[i]<upper[i]-value) {
	  solution[i]=lower[i];
	  upper[i]=lower[i];
	  nFix++;
	} else if (value>upper[i]-tolerance&&value-lower[i]>upper[i]-value) {
	  solution[i]=upper[i];
	  lower[i]=upper[i];
	  nFix++;
	}
      }
    }
#ifdef CLP_INVESTIGATE
    printf("%d row slacks fixed\n",nFix);
#endif
#endif
    extraPresolve=true;
    // do presolve
    model2 = pinfo2.presolvedModel(*modelPtr_,modelPtr_->presolveTolerance(),
				   false,5,true);
    if (!model2) {
      model2=modelPtr_;
      CoinMemcpyN(saveLower,numberColumns,model2->columnLower());
      CoinMemcpyN(saveLower+numberColumns,numberRows,model2->rowLower());
      delete [] saveLower;
      CoinMemcpyN(saveUpper,numberColumns,model2->columnUpper());
      CoinMemcpyN(saveUpper+numberColumns,numberRows,model2->rowUpper());
      delete [] saveUpper;
      saveLower=NULL;
      saveUpper=NULL;
      extraPresolve=false;
    }
  }
  if (model2->factorizationFrequency()==200) {
    // User did not touch preset
    model2->defaultFactorizationFrequency();
  }
  if (basis) {
    // throw some into basis 
    int numberRows = model2->numberRows();
    int numberColumns = model2->numberColumns();
    double * dsort = new double[numberColumns];
    int * sort = new int[numberColumns];
    int n=0;
    const double * columnLower = model2->columnLower();
    const double * columnUpper = model2->columnUpper();
    double * primalSolution = model2->primalColumnSolution();
    const double * dualSolution = model2->dualColumnSolution();
    int i;
    for ( i=0;i<numberRows;i++) 
      model2->setRowStatus(i,ClpSimplex::superBasic);
    for ( i=0;i<numberColumns;i++) {
      double distance = CoinMin(columnUpper[i]-primalSolution[i],
				primalSolution[i]-columnLower[i]);
      if (distance>tolerance) {
	if (fabs(dualSolution[i])<1.0e-5)
	  distance *= 100.0;
	dsort[n]=-distance;
	sort[n++]=i;
	model2->setStatus(i,ClpSimplex::superBasic);
      } else if (distance>tolerance) {
	model2->setStatus(i,ClpSimplex::superBasic);
      } else if (primalSolution[i]<=columnLower[i]+tolerance) {
	model2->setStatus(i,ClpSimplex::atLowerBound);
	primalSolution[i]=columnLower[i];
      } else {
	model2->setStatus(i,ClpSimplex::atUpperBound);
	primalSolution[i]=columnUpper[i];
      }
    }
    CoinSort_2(dsort,dsort+n,sort);
    n = CoinMin(numberRows,n);
    for ( i=0;i<n;i++) {
      int iColumn = sort[i];
      model2->setStatus(iColumn,ClpSimplex::basic);
    }
    delete [] sort;
    delete [] dsort;
  }
  // Start crossover
  if (useBoth) {
    int numberRows = model2->numberRows();
    int numberColumns = model2->numberColumns();
    double * rowPrimal = new double [numberRows];
    double * columnPrimal = new double [numberColumns];
    double * rowDual = new double [numberRows];
    double * columnDual = new double [numberColumns];
    // move solutions
    CoinMemcpyN(model2->primalRowSolution(),
		numberRows,rowPrimal);
    CoinMemcpyN(model2->dualRowSolution(),
		numberRows,rowDual);
    CoinMemcpyN(model2->primalColumnSolution(),
		numberColumns,columnPrimal);
    CoinMemcpyN(model2->dualColumnSolution(),
		numberColumns,columnDual);
    // primal values pass
    double saveScale = model2->objectiveScale();
    model2->setObjectiveScale(1.0e-3);
    model2->primal(2);
    model2->setObjectiveScale(saveScale);
    // save primal solution and copy back dual
    CoinMemcpyN(model2->primalRowSolution(),
		numberRows,rowPrimal);
    CoinMemcpyN(rowDual,
		numberRows,model2->dualRowSolution());
    CoinMemcpyN(model2->primalColumnSolution(),
		numberColumns,columnPrimal);
    CoinMemcpyN(columnDual,
		numberColumns,model2->dualColumnSolution());
    // clean up reduced costs and flag variables
    double * dj = model2->dualColumnSolution();
    double * cost = model2->objective();
    double * saveCost = new double[numberColumns];
    CoinMemcpyN(cost,numberColumns,saveCost);
    double * saveLower = new double[numberColumns];
    double * lower = model2->columnLower();
    CoinMemcpyN(lower,numberColumns,saveLower);
    double * saveUpper = new double[numberColumns];
    double * upper = model2->columnUpper();
    CoinMemcpyN(upper,numberColumns,saveUpper);
    int i;
    for ( i=0;i<numberColumns;i++) {
      if (model2->getStatus(i)==ClpSimplex::basic) {
	dj[i]=0.0;
      } else if (model2->getStatus(i)==ClpSimplex::atLowerBound) {
	if (direction*dj[i]<tolerance) {
	  if (direction*dj[i]<0.0) {
	    //if (dj[i]<-1.0e-3)
	    //printf("bad dj at lb %d %g\n",i,dj[i]);
	    cost[i] -= dj[i];
	    dj[i]=0.0;
	  }
	} else {
	  upper[i]=lower[i];
	}
      } else if (model2->getStatus(i)==ClpSimplex::atUpperBound) {
	if (direction*dj[i]>tolerance) {
	  if (direction*dj[i]>0.0) {
	    //if (dj[i]>1.0e-3)
	    //printf("bad dj at ub %d %g\n",i,dj[i]);
	    cost[i] -= dj[i];
	    dj[i]=0.0;
	  }
	} else {
	  lower[i]=upper[i];
	}
      }
    }
    // just dual values pass
    model2->dual(2);
    CoinMemcpyN(saveCost,numberColumns,cost);
    delete [] saveCost;
    CoinMemcpyN(saveLower,numberColumns,lower);
    delete [] saveLower;
    CoinMemcpyN(saveUpper,numberColumns,upper);
    delete [] saveUpper;
    // move solutions
    CoinMemcpyN(rowPrimal,
		numberRows,model2->primalRowSolution());
    CoinMemcpyN(columnPrimal,
		numberColumns,model2->primalColumnSolution());
    // and finish
    delete [] rowPrimal;
    delete [] columnPrimal;
    delete [] rowDual;
    delete [] columnDual;
    model2->setObjectiveScale(1.0e-3);
    model2->primal(2);
    model2->setObjectiveScale(saveScale);
    model2->primal(1);
  } else {
    // primal values pass
    double saveScale = model2->objectiveScale();
    model2->setObjectiveScale(1.0e-3);
    model2->primal(2);
    model2->setObjectiveScale(saveScale);
    model2->primal(1);
  }
  if (extraPresolve) {
    pinfo2.postsolve(true);
    delete model2;
    modelPtr_->primal(1);
    CoinMemcpyN(saveLower,numberColumns,modelPtr_->columnLower());
    CoinMemcpyN(saveLower+numberColumns,numberRows,modelPtr_->rowLower());
    CoinMemcpyN(saveUpper,numberColumns,modelPtr_->columnUpper());
    CoinMemcpyN(saveUpper+numberColumns,numberRows,modelPtr_->rowUpper());
    delete [] saveLower;
    delete [] saveUpper;
    modelPtr_->primal(1);
  }
  // Save basis in Osi object
  setWarmStart(NULL);
}
  
//#############################################################################
// Constructors / Destructor / Assignment
//#############################################################################

//-------------------------------------------------------------------
// Default Constructor 
//-------------------------------------------------------------------
OsiClpDisasterHandler::OsiClpDisasterHandler (OsiClpSolverInterface * model) 
  : ClpDisasterHandler(),
    osiModel_(model),
    whereFrom_(0),
    phase_(0),
    inTrouble_(false)
{
  if (model)
    setSimplex(model->getModelPtr());
}

//-------------------------------------------------------------------
// Copy constructor 
//-------------------------------------------------------------------
OsiClpDisasterHandler::OsiClpDisasterHandler (const OsiClpDisasterHandler & rhs) 
  : ClpDisasterHandler(rhs),
    osiModel_(rhs.osiModel_),
    whereFrom_(rhs.whereFrom_),
    phase_(rhs.phase_),
    inTrouble_(rhs.inTrouble_)
{  
}


//-------------------------------------------------------------------
// Destructor 
//-------------------------------------------------------------------
OsiClpDisasterHandler::~OsiClpDisasterHandler ()
{
}

//----------------------------------------------------------------
// Assignment operator 
//-------------------------------------------------------------------
OsiClpDisasterHandler &
OsiClpDisasterHandler::operator=(const OsiClpDisasterHandler& rhs)
{
  if (this != &rhs) {
    ClpDisasterHandler::operator=(rhs);
    osiModel_ = rhs.osiModel_;
    whereFrom_ = rhs.whereFrom_;
    phase_ = rhs.phase_;
    inTrouble_ = rhs.inTrouble_;
  }
  return *this;
}
//-------------------------------------------------------------------
// Clone
//-------------------------------------------------------------------
ClpDisasterHandler * OsiClpDisasterHandler::clone() const
{
  return new OsiClpDisasterHandler(*this);
}

void
OsiClpDisasterHandler::intoSimplex()
{
  inTrouble_=false;
}
bool
OsiClpDisasterHandler::check() const
{
  // Exit if really large number of iterations
  if (model_->numberIterations()> model_->baseIteration()+100000+100*(model_->numberRows()+model_->numberColumns()))
    return true;
  if ((whereFrom_&2)==0||!model_->nonLinearCost()) {
    // dual
    if (model_->numberIterations()<model_->baseIteration()+model_->numberRows()+1000) {
      return false;
    } else if (phase_<2) {
      if (model_->numberIterations()> model_->baseIteration()+2*model_->numberRows()+model_->numberColumns()+2000||
	  model_->largestDualError()>=1.0e-1) {
	// had model_->numberDualInfeasibilitiesWithoutFree()||
#ifdef COIN_DEVELOP
	printf("trouble in phase %d\n",phase_);
#endif
	if (osiModel_->largestAway()>0.0) {
	  // go for safety
	  model_->setSpecialOptions(model_->specialOptions()&~(2048+4096));
	  int frequency = model_->factorizationFrequency();
	  if (frequency>100)
	    frequency=100;
	  model_->setFactorizationFrequency(frequency);
	  double oldBound = model_->dualBound();
	  double newBound = CoinMax(1.0001e8,
				    CoinMin(10.0*osiModel_->largestAway(),1.e10));
	  if (newBound!=oldBound) {
	    model_->setDualBound(newBound);
	    if (model_->upperRegion()&&model_->algorithm()<0) {
	      // need to fix up fake bounds
	      (static_cast<ClpSimplexDual *>(model_))->resetFakeBounds(0);
	    }
	  }
	  osiModel_->setLargestAway(-1.0);
	}
	return true;
      } else {
	return false;
      }
    } else {
      assert (phase_==2);
      if (model_->numberIterations()> model_->baseIteration()+3*model_->numberRows()+model_->numberColumns()+2000||
	  model_->largestPrimalError()>=1.0e3) {
#ifdef COIN_DEVELOP
	printf("trouble in phase %d\n",phase_);
#endif
	return true;
      } else {
	return false;
      }
    }
  } else {
    // primal
    if (model_->numberIterations()<model_->baseIteration()+2*model_->numberRows()+model_->numberColumns()+4000) {
      return false;
    } else if (phase_<2) {
      if (model_->numberIterations()> model_->baseIteration()+3*model_->numberRows()+2000+
	  model_->numberColumns()&&
	  model_->numberDualInfeasibilitiesWithoutFree()>0&&
	  model_->numberPrimalInfeasibilities()>0&&
	  model_->nonLinearCost()->changeInCost()>1.0e8) {
#ifdef COIN_DEVELOP
	printf("trouble in phase %d\n",phase_);
#endif
	return true;
      } else {
	return false;
      }
    } else {
      assert (phase_==2);
      if (model_->numberIterations()> model_->baseIteration()+3*model_->numberRows()+2000||
	  model_->largestPrimalError()>=1.0e3) {
#ifdef COIN_DEVELOP
	printf("trouble in phase %d\n",phase_);
#endif
	return true;
      } else {
	return false;
      }
    }
  }
}
void
OsiClpDisasterHandler::saveInfo()
{
  inTrouble_=true;
}
// Type of disaster 0 can fix, 1 abort
int 
OsiClpDisasterHandler::typeOfDisaster()
{
  return 0;
}
/* set model. */
void 
OsiClpDisasterHandler::setOsiModel(OsiClpSolverInterface * model)
{
  osiModel_=model;
  model_=model->getModelPtr();
}
// Create C++ lines to get to current state
void 
OsiClpSolverInterface::generateCpp( FILE * fp)
{
  modelPtr_->generateCpp(fp,true);
  // Stuff that can't be done easily
  // setupForRepeatedUse here
  if (!messageHandler()->prefix())
    fprintf(fp,"3  clpModel->messageHandler()->setPrefix(false);\n");
  OsiClpSolverInterface defaultModel;
  OsiClpSolverInterface * other = &defaultModel;
  int iValue1, iValue2;
  double dValue1, dValue2;
  bool takeHint1,takeHint2;
  int add;
  OsiHintStrength strength1,strength2;
  std::string strengthName[] = {"OsiHintIgnore","OsiHintTry","OsiHintDo",
				"OsiForceDo"};
  iValue1 = this->specialOptions();
  iValue2 = other->specialOptions();
  fprintf(fp,"%d  int save_specialOptions = osiclpModel->specialOptions();\n",iValue1==iValue2 ? 2 : 1);
  fprintf(fp,"%d  osiclpModel->setSpecialOptions(%d);\n",iValue1==iValue2 ? 4 : 3,iValue1);
  fprintf(fp,"%d  osiclpModel->setSpecialOptions(save_specialOptions);\n",iValue1==iValue2 ? 7 : 6);
  iValue1 = this->messageHandler()->logLevel();
  iValue2 = other->messageHandler()->logLevel();
  fprintf(fp,"%d  int save_messageHandler = osiclpModel->messageHandler()->logLevel();\n",iValue1==iValue2 ? 2 : 1);
  fprintf(fp,"%d  osiclpModel->messageHandler()->setLogLevel(%d);\n",iValue1==iValue2 ? 4 : 3,iValue1);
  fprintf(fp,"%d  osiclpModel->messageHandler()->setLogLevel(save_messageHandler);\n",iValue1==iValue2 ? 7 : 6);
  iValue1 = this->cleanupScaling();
  iValue2 = other->cleanupScaling();
  fprintf(fp,"%d  int save_cleanupScaling = osiclpModel->cleanupScaling();\n",iValue1==iValue2 ? 2 : 1);
  fprintf(fp,"%d  osiclpModel->setCleanupScaling(%d);\n",iValue1==iValue2 ? 4 : 3,iValue1);
  fprintf(fp,"%d  osiclpModel->setCleanupScaling(save_cleanupScaling);\n",iValue1==iValue2 ? 7 : 6);
  dValue1 = this->smallestElementInCut();
  dValue2 = other->smallestElementInCut();
  fprintf(fp,"%d  double save_smallestElementInCut = osiclpModel->smallestElementInCut();\n",dValue1==dValue2 ? 2 : 1);
  fprintf(fp,"%d  osiclpModel->setSmallestElementInCut(%g);\n",dValue1==dValue2 ? 4 : 3,dValue1);
  fprintf(fp,"%d  osiclpModel->setSmallestElementInCut(save_smallestElementInCut);\n",dValue1==dValue2 ? 7 : 6);
  dValue1 = this->smallestChangeInCut();
  dValue2 = other->smallestChangeInCut();
  fprintf(fp,"%d  double save_smallestChangeInCut = osiclpModel->smallestChangeInCut();\n",dValue1==dValue2 ? 2 : 1);
  fprintf(fp,"%d  osiclpModel->setSmallestChangeInCut(%g);\n",dValue1==dValue2 ? 4 : 3,dValue1);
  fprintf(fp,"%d  osiclpModel->setSmallestChangeInCut(save_smallestChangeInCut);\n",dValue1==dValue2 ? 7 : 6);
  this->getIntParam(OsiMaxNumIterationHotStart,iValue1);
  other->getIntParam(OsiMaxNumIterationHotStart,iValue2);
  fprintf(fp,"%d  int save_OsiMaxNumIterationHotStart;\n",iValue1==iValue2 ? 2 : 1);
  fprintf(fp,"%d  osiclpModel->getIntParam(OsiMaxNumIterationHotStart,save_OsiMaxNumIterationHotStart);\n",iValue1==iValue2 ? 2 : 1);
  fprintf(fp,"%d  osiclpModel->setIntParam(OsiMaxNumIterationHotStart,%d);\n",iValue1==iValue2 ? 4 : 3,iValue1);
  fprintf(fp,"%d  osiclpModel->setIntParam(OsiMaxNumIterationHotStart,save_OsiMaxNumIterationHotStart);\n",iValue1==iValue2 ? 7 : 6);
  this->getDblParam(OsiDualObjectiveLimit,dValue1);
  other->getDblParam(OsiDualObjectiveLimit,dValue2);
  fprintf(fp,"%d  double save_OsiDualObjectiveLimit;\n",dValue1==dValue2 ? 2 : 1);
  fprintf(fp,"%d  osiclpModel->getDblParam(OsiDualObjectiveLimit,save_OsiDualObjectiveLimit);\n",dValue1==dValue2 ? 2 : 1);
  fprintf(fp,"%d  osiclpModel->setDblParam(OsiDualObjectiveLimit,%g);\n",dValue1==dValue2 ? 4 : 3,dValue1);
  fprintf(fp,"%d  osiclpModel->setDblParam(OsiDualObjectiveLimit,save_OsiDualObjectiveLimit);\n",dValue1==dValue2 ? 7 : 6);
  this->getDblParam(OsiPrimalObjectiveLimit,dValue1);
  other->getDblParam(OsiPrimalObjectiveLimit,dValue2);
  fprintf(fp,"%d  double save_OsiPrimalObjectiveLimit;\n",dValue1==dValue2 ? 2 : 1);
  fprintf(fp,"%d  osiclpModel->getDblParam(OsiPrimalObjectiveLimit,save_OsiPrimalObjectiveLimit);\n",dValue1==dValue2 ? 2 : 1);
  fprintf(fp,"%d  osiclpModel->setDblParam(OsiPrimalObjectiveLimit,%g);\n",dValue1==dValue2 ? 4 : 3,dValue1);
  fprintf(fp,"%d  osiclpModel->setDblParam(OsiPrimalObjectiveLimit,save_OsiPrimalObjectiveLimit);\n",dValue1==dValue2 ? 7 : 6);
  this->getHintParam(OsiDoPresolveInInitial,takeHint1,strength1);
  other->getHintParam(OsiDoPresolveInInitial,takeHint2,strength2);
  add = ((takeHint1==takeHint2)&&(strength1==strength2)) ? 1 : 0;
  fprintf(fp,"%d  bool saveHint_OsiDoPresolveInInitial;\n",add+1);
  fprintf(fp,"%d  OsiHintStrength saveStrength_OsiDoPresolveInInitial;\n",add+1);
  fprintf(fp,"%d  osiclpModel->getHintParam(OsiDoPresolveInInitial,saveHint_OsiDoPresolveInInitial,saveStrength_OsiDoPresolveInInitial);\n",add+1);
  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoPresolveInInitial,%s,%s);\n",add+3,takeHint1 ? "true" : "false",strengthName[strength1].c_str());
  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoPresolveInInitial,saveHint_OsiDoPresolveInInitial,saveStrength_OsiDoPresolveInInitial);\n",add+6);
  this->getHintParam(OsiDoDualInInitial,takeHint1,strength1);
  other->getHintParam(OsiDoDualInInitial,takeHint2,strength2);
  add = ((takeHint1==takeHint2)&&(strength1==strength2)) ? 1 : 0;
  fprintf(fp,"%d  bool saveHint_OsiDoDualInInitial;\n",add+1);
  fprintf(fp,"%d  OsiHintStrength saveStrength_OsiDoDualInInitial;\n",add+1);
  fprintf(fp,"%d  osiclpModel->getHintParam(OsiDoDualInInitial,saveHint_OsiDoDualInInitial,saveStrength_OsiDoDualInInitial);\n",add+1);
  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoDualInInitial,%s,%s);\n",add+3,takeHint1 ? "true" : "false",strengthName[strength1].c_str());
  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoDualInInitial,saveHint_OsiDoDualInInitial,saveStrength_OsiDoDualInInitial);\n",add+6);
  this->getHintParam(OsiDoPresolveInResolve,takeHint1,strength1);
  other->getHintParam(OsiDoPresolveInResolve,takeHint2,strength2);
  add = ((takeHint1==takeHint2)&&(strength1==strength2)) ? 1 : 0;
  fprintf(fp,"%d  bool saveHint_OsiDoPresolveInResolve;\n",add+1);
  fprintf(fp,"%d  OsiHintStrength saveStrength_OsiDoPresolveInResolve;\n",add+1);
  fprintf(fp,"%d  osiclpModel->getHintParam(OsiDoPresolveInResolve,saveHint_OsiDoPresolveInResolve,saveStrength_OsiDoPresolveInResolve);\n",add+1);
  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoPresolveInResolve,%s,%s);\n",add+3,takeHint1 ? "true" : "false",strengthName[strength1].c_str());
  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoPresolveInResolve,saveHint_OsiDoPresolveInResolve,saveStrength_OsiDoPresolveInResolve);\n",add+6);
  this->getHintParam(OsiDoDualInResolve,takeHint1,strength1);
  other->getHintParam(OsiDoDualInResolve,takeHint2,strength2);
  add = ((takeHint1==takeHint2)&&(strength1==strength2)) ? 1 : 0;
  fprintf(fp,"%d  bool saveHint_OsiDoDualInResolve;\n",add+1);
  fprintf(fp,"%d  OsiHintStrength saveStrength_OsiDoDualInResolve;\n",add+1);
  fprintf(fp,"%d  osiclpModel->getHintParam(OsiDoDualInResolve,saveHint_OsiDoDualInResolve,saveStrength_OsiDoDualInResolve);\n",add+1);
  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoDualInResolve,%s,%s);\n",add+3,takeHint1 ? "true" : "false",strengthName[strength1].c_str());
  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoDualInResolve,saveHint_OsiDoDualInResolve,saveStrength_OsiDoDualInResolve);\n",add+6);
  this->getHintParam(OsiDoScale,takeHint1,strength1);
  other->getHintParam(OsiDoScale,takeHint2,strength2);
  add = ((takeHint1==takeHint2)&&(strength1==strength2)) ? 1 : 0;
  fprintf(fp,"%d  bool saveHint_OsiDoScale;\n",add+1);
  fprintf(fp,"%d  OsiHintStrength saveStrength_OsiDoScale;\n",add+1);
  fprintf(fp,"%d  osiclpModel->getHintParam(OsiDoScale,saveHint_OsiDoScale,saveStrength_OsiDoScale);\n",add+1);
  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoScale,%s,%s);\n",add+3,takeHint1 ? "true" : "false",strengthName[strength1].c_str());
  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoScale,saveHint_OsiDoScale,saveStrength_OsiDoScale);\n",add+6);
  this->getHintParam(OsiDoCrash,takeHint1,strength1);
  other->getHintParam(OsiDoCrash,takeHint2,strength2);
  add = ((takeHint1==takeHint2)&&(strength1==strength2)) ? 1 : 0;
  fprintf(fp,"%d  bool saveHint_OsiDoCrash;\n",add+1);
  fprintf(fp,"%d  OsiHintStrength saveStrength_OsiDoCrash;\n",add+1);
  fprintf(fp,"%d  osiclpModel->getHintParam(OsiDoCrash,saveHint_OsiDoCrash,saveStrength_OsiDoCrash);\n",add+1);
  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoCrash,%s,%s);\n",add+3,takeHint1 ? "true" : "false",strengthName[strength1].c_str());
  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoCrash,saveHint_OsiDoCrash,saveStrength_OsiDoCrash);\n",add+6);
  this->getHintParam(OsiDoReducePrint,takeHint1,strength1);
  other->getHintParam(OsiDoReducePrint,takeHint2,strength2);
  add = ((takeHint1==takeHint2)&&(strength1==strength2)) ? 1 : 0;
  fprintf(fp,"%d  bool saveHint_OsiDoReducePrint;\n",add+1);
  fprintf(fp,"%d  OsiHintStrength saveStrength_OsiDoReducePrint;\n",add+1);
  fprintf(fp,"%d  osiclpModel->getHintParam(OsiDoReducePrint,saveHint_OsiDoReducePrint,saveStrength_OsiDoReducePrint);\n",add+1);
  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoReducePrint,%s,%s);\n",add+3,takeHint1 ? "true" : "false",strengthName[strength1].c_str());
  fprintf(fp,"%d  osiclpModel->setHintParam(OsiDoReducePrint,saveHint_OsiDoReducePrint,saveStrength_OsiDoReducePrint);\n",add+6);
}
// So unit test can find out if NDEBUG set
bool OsiClpHasNDEBUG() 
{
#ifdef NDEBUG
  return true;
#else
  return false;
#endif
}
