Logo Search packages:      
Sourcecode: rsymphony version File versions  Download package

OsiCpxSolverInterface.cpp

//-----------------------------------------------------------------------------
// name:     OSI Interface for CPLEX
// author:   Tobias Pfender
//           Konrad-Zuse-Zentrum Berlin (Germany)
//           email: pfender@zib.de
// date:     09/25/2000
// comments: please scan this file for '???' and read the comments
//-----------------------------------------------------------------------------
// Copyright (C) 2000, Tobias Pfender, International Business Machines
// Corporation and others.  All Rights Reserved.

#include <iostream>
#include <cassert>
#include <string>
#include <numeric>

#include "CoinPragma.hpp"
#include "CoinError.hpp"

#include "OsiCpxSolverInterface.hpp"
#include "OsiRowCut.hpp"
#include "OsiColCut.hpp"
#include "CoinPackedMatrix.hpp"
#include "CoinWarmStartBasis.hpp"

#include "cplex.h"

// CPLEX 10.0 removed CPXERR_NO_INT_SOLN
#if !defined(CPXERR_NO_INT_SOLN)
#define CPXERR_NO_INT_SOLN CPXERR_NO_SOLN
#endif

// #define DEBUG 1

#ifdef DEBUG
#define debugMessage printf
#else
#define debugMessage if( false ) printf
#endif


//#############################################################################
// A couple of helper functions
//#############################################################################

inline void freeCacheDouble( double*& ptr )
{
  if( ptr != NULL )
    {
      delete [] ptr;
      ptr = NULL;
    }
}

inline void freeCacheChar( char*& ptr )
{
  if( ptr != NULL )
    {
      delete [] ptr;
      ptr = NULL;
    }
}

inline void freeCacheMatrix( CoinPackedMatrix*& ptr )
{
  if( ptr != NULL )
    {
      delete ptr;
      ptr = NULL;
    }
}

static inline void
checkCPXerror( int err, std::string cpxfuncname, std::string osimethod )
{
  if( err != 0 )
    {
      char s[100];
      sprintf( s, "%s returned error %d", cpxfuncname.c_str(), err );
      std::cout << "ERROR: " << s << " (" << osimethod << 
      " in OsiCpxSolverInterface)" << std::endl;
      throw CoinError( s, osimethod.c_str(), "OsiCpxSolverInterface" );
    }
}

static bool incompletemessage = false;

static
void CPXPUBLIC OsiCpxMessageCallbackPrint(CoinMessageHandler* handler, const char* msg)
{
      /* cplex adds the newlines into their message, while the coin message handler like to add its own newlines
       * we treat the cases where there is a newline in the beginning or no newline at the end separately
       * TODO a better way is to scan msg for newlines and to send each line to the handler separately */
      if( msg[0] == '\n' ) {
            if (incompletemessage) {
                  *handler << CoinMessageEol;
                  incompletemessage = false;
            } else
                  handler->message(0, "CPX", " ", ' ') << CoinMessageEol;
            
            ++msg;
            
            if(!*msg)
                  return;
      }
      
      int len = strlen(msg);
      
      if( msg[len-1] == '\n') {
            (const_cast<char*>(msg))[len-1] = '\0';
            if (incompletemessage) {
                  *handler << msg << CoinMessageEol;
                  incompletemessage = false;
            } else
                  handler->message(0, "CPX", msg, ' ') << CoinMessageEol;
      } else {
            handler->message(0, "CPX", msg, ' ');
            incompletemessage = true;
      }
}

static
void CPXPUBLIC OsiCpxMessageCallbackResultLog(void* handle, const char* msg)
{
      if (!*msg)
            return;
      
      if (handle) {
            if( ((CoinMessageHandler*)handle)->logLevel() >= 1 )
                  OsiCpxMessageCallbackPrint((CoinMessageHandler*)handle, msg);
      } else {
            printf(msg);
      }
}

static
void CPXPUBLIC OsiCpxMessageCallbackWarning(void* handle, const char* msg)
{
      if (handle) {
            if( ((CoinMessageHandler*)handle)->logLevel() >= 0 )
                  OsiCpxMessageCallbackPrint((CoinMessageHandler*)handle, msg);
      } else {
            printf(msg);
      }
}

static
void CPXPUBLIC OsiCpxMessageCallbackError(void* handle, const char* msg)
{
      if (handle) {
            OsiCpxMessageCallbackPrint((CoinMessageHandler*)handle, msg);
      } else {
            fprintf(stderr, msg);
      }
}

void
00158 OsiCpxSolverInterface::switchToLP( void )
{
  debugMessage("OsiCpxSolverInterface::switchToLP()\n");

  if( probtypemip_ )
  {
     CPXLPptr lp = getMutableLpPtr();

#if CPX_VERSION >= 800
     assert(CPXgetprobtype(env_,lp) == CPXPROB_MILP);
#else
     assert(CPXgetprobtype(env_,lp) == CPXPROB_MIP);
#endif

     int err = CPXchgprobtype( env_, lp, CPXPROB_LP );
     checkCPXerror( err, "CPXchgprobtype", "switchToLP" );
     probtypemip_ = false;
  }
}

void
00179 OsiCpxSolverInterface::switchToMIP( void )
{
  debugMessage("OsiCpxSolverInterface::switchToMIP()\n");

  if( !probtypemip_ )
  {
     CPXLPptr lp = getMutableLpPtr();
     int nc = getNumCols();
     int *cindarray = new int[nc];

     assert(CPXgetprobtype(env_,lp) == CPXPROB_LP);
     assert(coltype_ != NULL);

     for( int i = 0; i < nc; ++i )
        cindarray[i] = i;

#if CPX_VERSION >= 800
     int err = CPXchgprobtype( env_, lp, CPXPROB_MILP );
#else
     int err = CPXchgprobtype( env_, lp, CPXPROB_MIP );
#endif
     checkCPXerror( err, "CPXchgprobtype", "switchToMIP" );

     err = CPXchgctype( env_, lp, nc, cindarray, coltype_ );
     checkCPXerror( err, "CPXchgctype", "switchToMIP" );

     delete[] cindarray;
     probtypemip_ = true;
  }
}

void
00211 OsiCpxSolverInterface::resizeColType( int minsize )
{
  debugMessage("OsiCpxSolverInterface::resizeColType()\n");

  if( minsize > coltypesize_ )
  {
     int newcoltypesize = 2*coltypesize_;
     if( minsize > newcoltypesize )
        newcoltypesize = minsize;
     char *newcoltype = new char[newcoltypesize];

     if( coltype_ != NULL )
     {
        CoinDisjointCopyN( coltype_, coltypesize_, newcoltype );
        delete[] coltype_;
     }
     coltype_ = newcoltype;
     coltypesize_ = newcoltypesize;
  }
  assert(minsize == 0 || coltype_ != NULL);
  assert(coltypesize_ >= minsize);
}

void
00235 OsiCpxSolverInterface::freeColType()
{
  debugMessage("OsiCpxSolverInterface::freeColType()\n");

   if( coltypesize_ > 0 )
   {
      delete[] coltype_;
      coltype_ = NULL;
      coltypesize_ = 0;
   }
   assert(coltype_ == NULL);
}


//#############################################################################
// Solve methods
//#############################################################################

00253 void OsiCpxSolverInterface::initialSolve()
{
  debugMessage("OsiCpxSolverInterface::initialSolve()\n");
  
  switchToLP();

  int algorithm = 1;
  bool takeHint, gotHint;
  OsiHintStrength strength;
  gotHint = (getHintParam(OsiDoDualInInitial,takeHint,strength));
  assert (gotHint);
  if (strength!=OsiHintIgnore)
     algorithm = takeHint ? -1 : 1;

  int presolve = 1;
  gotHint = (getHintParam(OsiDoPresolveInInitial,takeHint,strength));
  assert (gotHint);
  if (strength!=OsiHintIgnore)
     presolve = takeHint ? 1 : 0;

  CPXLPptr lp = getLpPtr( OsiCpxSolverInterface::FREECACHED_RESULTS );

  if (presolve)
     CPXsetintparam( env_, CPX_PARAM_PREIND, CPX_ON );
  else
     CPXsetintparam( env_, CPX_PARAM_PREIND, CPX_OFF );

//  if (messageHandler()->logLevel() == 0)
//     CPXsetintparam( env_, CPX_PARAM_SCRIND, CPX_OFF );
//  else
//     CPXsetintparam( env_, CPX_PARAM_SCRIND, CPX_ON );

  if (messageHandler()->logLevel() == 0)
     CPXsetintparam( env_, CPX_PARAM_SIMDISPLAY, 0 );
  else if (messageHandler()->logLevel() == 1)
     CPXsetintparam( env_, CPX_PARAM_SIMDISPLAY, 1 );
  else if (messageHandler()->logLevel() > 1)
     CPXsetintparam( env_, CPX_PARAM_SIMDISPLAY, 2 );

  int term;
  if (algorithm==1)
     term = CPXprimopt( env_, lp );
  else
     term = CPXdualopt( env_, lp );

  /* If the problem is found infeasible during presolve, resolve it to get a 
     proper term code */
#if CPX_VERSION >= 800
  int stat = CPXgetstat( env_, getMutableLpPtr() );
  if (stat == CPX_STAT_INForUNBD && presolve){
     CPXsetintparam( env_, CPX_PARAM_PREIND, CPX_OFF );
     if (algorithm==1)
        term = CPXprimopt( env_, lp );
     else
        term = CPXdualopt( env_, lp );
     CPXsetintparam( env_, CPX_PARAM_PREIND, CPX_ON );
  }
#else
  if (term == CPXERR_PRESLV_INForUNBD && presolve){
     CPXsetintparam( env_, CPX_PARAM_PREIND, CPX_OFF );
     if (algorithm==1)
        term = CPXprimopt( env_, lp );
     else
        term = CPXdualopt( env_, lp );
     CPXsetintparam( env_, CPX_PARAM_PREIND, CPX_ON );
  }
#endif
}
//-----------------------------------------------------------------------------
00322 void OsiCpxSolverInterface::resolve()
{
  debugMessage("OsiCpxSolverInterface::resolve()\n");

  switchToLP();

  int algorithm = -1;
  bool takeHint, gotHint;
  OsiHintStrength strength;
  gotHint = (getHintParam(OsiDoDualInResolve,takeHint,strength));
  assert (gotHint);
  if (strength!=OsiHintIgnore)
     algorithm = takeHint ? -1 : 1;

  int presolve = 0;
  gotHint = (getHintParam(OsiDoPresolveInResolve,takeHint,strength));
  assert (gotHint);
  if (strength!=OsiHintIgnore)
     presolve = takeHint ? 1 : 0;

  CPXLPptr lp = getLpPtr( OsiCpxSolverInterface::FREECACHED_RESULTS );

  if (presolve)
     CPXsetintparam( env_, CPX_PARAM_PREIND, CPX_ON );
  else
     CPXsetintparam( env_, CPX_PARAM_PREIND, CPX_OFF );

//  if (messageHandler()->logLevel() == 0)
//     CPXsetintparam( env_, CPX_PARAM_SCRIND, CPX_OFF );
//  else
//     CPXsetintparam( env_, CPX_PARAM_SCRIND, CPX_ON );

  if (messageHandler()->logLevel() == 0)
     CPXsetintparam( env_, CPX_PARAM_SIMDISPLAY, 0 );
  else if (messageHandler()->logLevel() == 1)
     CPXsetintparam( env_, CPX_PARAM_SIMDISPLAY, 1 );
  else if (messageHandler()->logLevel() > 1)
     CPXsetintparam( env_, CPX_PARAM_SIMDISPLAY, 2 );

  int term;
  if (algorithm==1)
     term = CPXprimopt( env_, lp );
  else
     term = CPXdualopt( env_, lp );

  /* If the problem is found infeasible during presolve, resolve it to get a 
     proper term code */
#if CPX_VERSION >= 800
  int stat = CPXgetstat( env_, getMutableLpPtr() );
  if (stat == CPX_STAT_INForUNBD && presolve){
    CPXsetintparam( env_, CPX_PARAM_PREIND, CPX_OFF );
    if (algorithm==1)
       term = CPXprimopt( env_, lp );
    else
       term = CPXdualopt( env_, lp );
    CPXsetintparam( env_, CPX_PARAM_PREIND, CPX_ON );
  }
#else
  if (term == CPXERR_PRESLV_INForUNBD && presolve){
    CPXsetintparam( env_, CPX_PARAM_PREIND, CPX_OFF );
    if (algorithm==1)
       term = CPXprimopt( env_, lp );
    else
       term = CPXdualopt( env_, lp );
    CPXsetintparam( env_, CPX_PARAM_PREIND, CPX_ON );
  }
#endif
}
//-----------------------------------------------------------------------------
00391 void OsiCpxSolverInterface::branchAndBound()
{
  debugMessage("OsiCpxSolverInterface::branchAndBound()\n");

  switchToMIP();

  CPXLPptr lp = getLpPtr( OsiCpxSolverInterface::FREECACHED_RESULTS );

//  if (messageHandler()->logLevel() == 0)
//     CPXsetintparam( env_, CPX_PARAM_SCRIND, CPX_OFF );
//  else
//     CPXsetintparam( env_, CPX_PARAM_SCRIND, CPX_ON );

  if (messageHandler()->logLevel() == 0)
     CPXsetintparam( env_, CPX_PARAM_SIMDISPLAY, 0 );
  else if (messageHandler()->logLevel() == 1)
     CPXsetintparam( env_, CPX_PARAM_SIMDISPLAY, 1 );
  else if (messageHandler()->logLevel() > 1)
     CPXsetintparam( env_, CPX_PARAM_SIMDISPLAY, 2 );

  CPXmipopt( env_, lp );
}

//#############################################################################
// Parameter related methods
//#############################################################################

bool
OsiCpxSolverInterface::setIntParam(OsiIntParam key, int value)
{
  debugMessage("OsiCpxSolverInterface::setIntParam(%d, %d)\n", key, value);

  bool retval = false;
  switch (key)
    {
    case OsiMaxNumIteration:
      retval = ( CPXsetintparam( env_, CPX_PARAM_ITLIM, value ) == 0 );  // ??? OsiMaxNumIteration == #Simplex-iterations ???
      break;
    case OsiMaxNumIterationHotStart:
      if( value >= 0 )
      {
        hotStartMaxIteration_ = value;
        retval = true;
      }
      else
      retval = false;
      break;
    case OsiLastIntParam:
      retval = false;
      break;
    default:
      retval = false ;
      break ;
    }
  return retval;
}

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

bool
OsiCpxSolverInterface::setDblParam(OsiDblParam key, double value)
{
  debugMessage("OsiCpxSolverInterface::setDblParam(%d, %g)\n", key, value);

  bool retval = false;
  switch (key)
    {
    case OsiDualObjectiveLimit:
      if( getObjSense() == +1 )
      retval = ( CPXsetdblparam( env_, CPX_PARAM_OBJULIM, value ) == 0 ); // min
      else
      retval = ( CPXsetdblparam( env_, CPX_PARAM_OBJLLIM, value ) == 0 ); // max
      break;
    case OsiPrimalObjectiveLimit:
      if( getObjSense() == +1 )
      retval = ( CPXsetdblparam( env_, CPX_PARAM_OBJLLIM, value ) == 0 ); // min
      else
      retval = ( CPXsetdblparam( env_, CPX_PARAM_OBJULIM, value ) == 0 ); // max
      break;
    case OsiDualTolerance:
      retval = ( CPXsetdblparam( env_, CPX_PARAM_EPOPT, value ) == 0 ); // ??? OsiDualTolerance == CPLEX Optimality tolerance ???
      break;
    case OsiPrimalTolerance:
      retval = ( CPXsetdblparam( env_, CPX_PARAM_EPRHS, value ) == 0 ); // ??? OsiPrimalTolerance == CPLEX Feasibility tolerance ???
      break;
    case OsiObjOffset:
      retval = OsiSolverInterface::setDblParam(key,value);
      break;
    case OsiLastDblParam:
      retval = false;
      break;
    default:
      retval = false ;
      break ;
    }
  return retval;
}


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

bool
OsiCpxSolverInterface::setStrParam(OsiStrParam key, const std::string & value)
{
  debugMessage("OsiCpxSolverInterface::setStrParam(%d, %s)\n", key, value.c_str());

  bool retval=false;
  switch (key) {
  case OsiProbName:
    OsiSolverInterface::setStrParam(key,value);
    return retval = true;
  case OsiSolverName:
    return false;
  case OsiLastStrParam:
    return false;
  default:
    return false ;
  }
  return false;
}

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

bool
OsiCpxSolverInterface::getIntParam(OsiIntParam key, int& value) const
{
  debugMessage("OsiCpxSolverInterface::getIntParam(%d)\n", key);

  bool retval = false;
  switch (key)
    {
    case OsiMaxNumIteration:
      retval = ( CPXgetintparam( env_, CPX_PARAM_ITLIM, &value ) == 0 );  // ??? OsiMaxNumIteration == #Simplex-iterations ???
      break;
    case OsiMaxNumIterationHotStart:
      value = hotStartMaxIteration_;
      retval = true;
      break;
    case OsiLastIntParam:
      retval = false;
      break;
    default:
      retval = false ;
      break ;
    }
  return retval;
}

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

bool
OsiCpxSolverInterface::getDblParam(OsiDblParam key, double& value) const
{
  debugMessage("OsiCpxSolverInterface::getDblParam(%d)\n", key);

  bool retval = false;
  switch (key) 
    {
    case OsiDualObjectiveLimit:
      if( getObjSense() == +1 )
      retval = ( CPXgetdblparam( env_, CPX_PARAM_OBJULIM, &value ) == 0 ); // min
      else
      retval = ( CPXgetdblparam( env_, CPX_PARAM_OBJLLIM, &value ) == 0 ); // max
      break;
    case OsiPrimalObjectiveLimit:
      if( getObjSense() == +1 )
      retval = ( CPXgetdblparam( env_, CPX_PARAM_OBJLLIM, &value ) == 0 ); // min
      else
      retval = ( CPXgetdblparam( env_, CPX_PARAM_OBJULIM, &value ) == 0 ); // max
      break;
    case OsiDualTolerance:
      retval = ( CPXgetdblparam( env_, CPX_PARAM_EPOPT, &value ) == 0 ); // ??? OsiDualTolerance == CPLEX Optimality tolerance ???
      break;
    case OsiPrimalTolerance:
      retval = ( CPXgetdblparam( env_, CPX_PARAM_EPRHS, &value ) == 0 ); // ??? OsiPrimalTolerance == CPLEX Feasibility tolerance ???
      break;
    case OsiObjOffset:
      retval = OsiSolverInterface::getDblParam(key, value);
      break;
    case OsiLastDblParam:
      retval = false;
      break;
    default:
      retval = false ;
      break ;
    }
  return retval;
}


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

bool
OsiCpxSolverInterface::getStrParam(OsiStrParam key, std::string & value) const
{
  debugMessage("OsiCpxSolverInterface::getStrParam(%d)\n", key);

  switch (key) {
  case OsiProbName:
    OsiSolverInterface::getStrParam(key, value);
    break;
  case OsiSolverName:
    value = "cplex";
    break;
  case OsiLastStrParam:
    return false;
  default:
    return false ;
  }

  return true;
}

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

00608 bool OsiCpxSolverInterface::isAbandoned() const
{
  debugMessage("OsiCpxSolverInterface::isAbandoned()\n");

  int stat = CPXgetstat( env_, getMutableLpPtr() );

#if CPX_VERSION >= 800
  return (stat == 0 || 
        stat == CPX_STAT_NUM_BEST || 
        stat == CPX_STAT_ABORT_USER);
#else
  return (stat == 0 || 
        stat == CPX_NUM_BEST_FEAS || 
        stat == CPX_NUM_BEST_INFEAS || 
        stat == CPX_ABORT_FEAS || 
        stat == CPX_ABORT_INFEAS || 
        stat == CPX_ABORT_CROSSOVER);
#endif
}

00628 bool OsiCpxSolverInterface::isProvenOptimal() const
{
  debugMessage("OsiCpxSolverInterface::isProvenOptimal()\n");

  int stat = CPXgetstat( env_, getMutableLpPtr() );

#if CPX_VERSION >= 800
  return ((probtypemip_ == false &&
          (stat == CPX_STAT_OPTIMAL || stat == CPX_STAT_OPTIMAL_INFEAS))
        || (probtypemip_ == true &&
          (stat == CPXMIP_OPTIMAL || stat == CPXMIP_OPTIMAL_TOL)));
#else
  return ((probtypemip_ == false && 
        (stat == CPX_OPTIMAL || stat == CPX_OPTIMAL_INFEAS)) ||
        probtypemip_ == true && stat == CPXMIP_OPTIMAL);
#endif
}

00646 bool OsiCpxSolverInterface::isProvenPrimalInfeasible() const
{
  debugMessage("OsiCpxSolverInterface::isProvenPrimalInfeasible()\n");

  int stat = CPXgetstat( env_, getMutableLpPtr() );

#if CPX_VERSION >= 800
  // In CPLEX 8, the return code is with respect
  // to the original problem, regardless of the algorithm used to solve it
  // --tkr 7/31/03
  return (stat == CPX_STAT_INFEASIBLE);
  //  return (method == CPX_ALG_PRIMAL && stat == CPX_STAT_INFEASIBLE || 
  //  method == CPX_ALG_DUAL && stat == CPX_STAT_UNBOUNDED);
#else

  int method = CPXgetmethod( env_, getMutableLpPtr() );

  return (method == CPX_ALG_PRIMAL && stat == CPX_INFEASIBLE || 
        method == CPX_ALG_DUAL && stat == CPX_UNBOUNDED || 
        stat == CPX_ABORT_PRIM_INFEAS ||
        stat == CPX_ABORT_PRIM_DUAL_INFEAS);
#endif
}

00670 bool OsiCpxSolverInterface::isProvenDualInfeasible() const
{
  debugMessage("OsiCpxSolverInterface::isProvenDualInfeasible()\n");

  int stat = CPXgetstat( env_, getMutableLpPtr() );

#if CPX_VERSION >= 800
  // In CPLEX 8, the return code is with respect
  // to the original problem, regardless of the algorithm used to solve it
  // --tkr 7/31/03
  return (stat == CPX_STAT_UNBOUNDED);
  //return (method == CPX_ALG_PRIMAL && stat == CPX_STAT_UNBOUNDED || 
  //    method == CPX_ALG_DUAL && stat == CPX_STAT_INFEASIBLE);
#else

  int method = CPXgetmethod( env_, getMutableLpPtr() );

  return (method == CPX_ALG_PRIMAL && stat == CPX_UNBOUNDED || 
        method == CPX_ALG_DUAL && stat == CPX_INFEASIBLE || 
        stat == CPX_ABORT_DUAL_INFEAS || 
        stat == CPX_ABORT_PRIM_DUAL_INFEAS);
#endif
}

00694 bool OsiCpxSolverInterface::isPrimalObjectiveLimitReached() const
{
  debugMessage("OsiCpxSolverInterface::isPrimalObjectiveLimitReached()\n");

  int stat = CPXgetstat( env_, getMutableLpPtr() );
  int method = CPXgetmethod( env_, getMutableLpPtr() );

#if CPX_VERSION >= 800
  return method == CPX_ALG_PRIMAL && stat == CPX_STAT_ABORT_OBJ_LIM;
#else
  return method == CPX_ALG_PRIMAL && stat == CPX_OBJ_LIM;
#endif
}

00708 bool OsiCpxSolverInterface::isDualObjectiveLimitReached() const
{
  debugMessage("OsiCpxSolverInterface::isDualObjectiveLimitReached()\n");

  int stat = CPXgetstat( env_, getMutableLpPtr() );
  int method = CPXgetmethod( env_, getMutableLpPtr() );

#if CPX_VERSION >= 800
  return method == CPX_ALG_DUAL && stat == CPX_STAT_ABORT_OBJ_LIM;
#else
  return method == CPX_ALG_DUAL && stat == CPX_OBJ_LIM;
#endif
}

00722 bool OsiCpxSolverInterface::isIterationLimitReached() const
{
  debugMessage("OsiCpxSolverInterface::isIterationLimitReached()\n");

  int stat = CPXgetstat( env_, getMutableLpPtr() );

#if CPX_VERSION >= 800
  return stat == CPX_STAT_ABORT_IT_LIM;
#else
  return stat == CPX_IT_LIM_FEAS || stat == CPX_IT_LIM_INFEAS;
#endif
}

//#############################################################################
// WarmStart related methods
//#############################################################################

00739 CoinWarmStart* OsiCpxSolverInterface::getEmptyWarmStart () const
{ return (dynamic_cast<CoinWarmStart *>(new CoinWarmStartBasis())) ; }

00742 CoinWarmStart* OsiCpxSolverInterface::getWarmStart() const
{
  debugMessage("OsiCpxSolverInterface::getWarmStart()\n");

  CoinWarmStartBasis* ws = NULL;
  int numcols = getNumCols();
  int numrows = getNumRows();
  int *cstat = new int[numcols];
  int *rstat = new int[numrows];
  int restat, i;

  assert(!probtypemip_);

  restat = CPXgetbase( env_, getMutableLpPtr(), cstat, rstat );
  if( restat == 0 )
    {
      ws = new CoinWarmStartBasis;
      ws->setSize( numcols, numrows );
      
      for( i = 0; i < numrows; ++i )
      {
        switch( rstat[i] )
          {
          case CPX_BASIC:
            ws->setArtifStatus( i, CoinWarmStartBasis::basic );
            break;
          case CPX_AT_LOWER:
            ws->setArtifStatus( i, CoinWarmStartBasis::atLowerBound );
            break;
          case CPX_AT_UPPER:
            ws->setArtifStatus( i, CoinWarmStartBasis::atUpperBound );
            break;
          default:  // unknown row status
            delete ws;
            ws = NULL;
            goto TERMINATE;
          }
      }
      for( i = 0; i < numcols; ++i )
      {
        switch( cstat[i] )
          {
          case CPX_BASIC:
            ws->setStructStatus( i, CoinWarmStartBasis::basic );
            break;
          case CPX_AT_LOWER:
            ws->setStructStatus( i, CoinWarmStartBasis::atLowerBound );
            break;
          case CPX_AT_UPPER:
            ws->setStructStatus( i, CoinWarmStartBasis::atUpperBound );
            break;
          case CPX_FREE_SUPER:
            ws->setStructStatus( i, CoinWarmStartBasis::isFree );
            break;
          default:  // unknown column status
            delete ws;
            ws = NULL;
            goto TERMINATE;
          }
      }
    }
 TERMINATE:
  delete[] cstat;
  delete[] rstat;

  return ws;
}

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

00812 bool OsiCpxSolverInterface::setWarmStart(const CoinWarmStart* warmstart)
{
  debugMessage("OsiCpxSolverInterface::setWarmStart(%p)\n", (void*)warmstart);

  const CoinWarmStartBasis* ws = dynamic_cast<const CoinWarmStartBasis*>(warmstart);
  int numcols, numrows, i, restat;
  int *cstat, *rstat;
  bool retval = false;

  if( !ws )
    return false;

  numcols = ws->getNumStructural();
  numrows = ws->getNumArtificial();
  
  if( numcols != getNumCols() || numrows != getNumRows() )
    return false;

  switchToLP();

  cstat = new int[numcols];
  rstat = new int[numrows];
  for( i = 0; i < numrows; ++i )
    {
      switch( ws->getArtifStatus( i ) )
      {
      case CoinWarmStartBasis::basic:
        rstat[i] = CPX_BASIC;
        break;
      case CoinWarmStartBasis::atLowerBound:
        rstat[i] = CPX_AT_LOWER;
        break;
      case CoinWarmStartBasis::atUpperBound:
        rstat[i] = CPX_AT_UPPER;
        break;
      default:  // unknown row status
        retval = false;
        goto TERMINATE;
      }
    }
  for( i = 0; i < numcols; ++i )
    {
      switch( ws->getStructStatus( i ) )
      {
      case CoinWarmStartBasis::basic:
        cstat[i] = CPX_BASIC;
        break;
      case CoinWarmStartBasis::atLowerBound:
        cstat[i] = CPX_AT_LOWER;
        break;
      case CoinWarmStartBasis::atUpperBound:
        cstat[i] = CPX_AT_UPPER;
        break;
      case CoinWarmStartBasis::isFree:
        cstat[i] = CPX_FREE_SUPER;
        break;
      default:  // unknown row status
        retval = false;
        goto TERMINATE;
      }
    }

  // *FIXME* : can this be getMutableLpPtr() ? Does any cached data change by
  // *FIXME* : setting warmstart? Or at least wouldn't it be sufficient to
  // *FIXME* : clear the cached results but not the problem data?
  // -> is fixed by using FREECACHED_RESULTS; only cached solution will be discarded
  restat = CPXcopybase( env_, getLpPtr( OsiCpxSolverInterface::FREECACHED_RESULTS ), cstat, rstat );
  retval = (restat == 0);
 TERMINATE:
  delete[] cstat;
  delete[] rstat;
  return retval;
}

//#############################################################################
// Hotstart related methods (primarily used in strong branching)
//#############################################################################

00890 void OsiCpxSolverInterface::markHotStart()
{
  debugMessage("OsiCpxSolverInterface::markHotStart()\n");

  int err;
  int numcols, numrows;

  assert(!probtypemip_);

  numcols = getNumCols();
  numrows = getNumRows();
  if( numcols > hotStartCStatSize_ )
    {
      delete[] hotStartCStat_;
      hotStartCStatSize_ = static_cast<int>( 1.2 * static_cast<double>( numcols ) ); // get some extra space for future hot starts
      hotStartCStat_ = new int[hotStartCStatSize_];
    }
  if( numrows > hotStartRStatSize_ )
    {
      delete[] hotStartRStat_;
      hotStartRStatSize_ = static_cast<int>( 1.2 * static_cast<double>( numrows ) ); // get some extra space for future hot starts
      hotStartRStat_ = new int[hotStartRStatSize_];
    }
  err = CPXgetbase( env_, getMutableLpPtr(), hotStartCStat_, hotStartRStat_ );
  checkCPXerror( err, "CPXgetbase", "markHotStart" );
}

00917 void OsiCpxSolverInterface::solveFromHotStart()
{
  debugMessage("OsiCpxSolverInterface::solveFromHotStart()\n");

  int err;
  int maxiter;

  switchToLP();

  assert( getNumCols() <= hotStartCStatSize_ );
  assert( getNumRows() <= hotStartRStatSize_ );
  err = CPXcopybase( env_, getLpPtr( OsiCpxSolverInterface::FREECACHED_RESULTS ), hotStartCStat_, hotStartRStat_ );
  checkCPXerror( err, "CPXcopybase", "solveFromHotStart" );

  err = CPXgetintparam( env_, CPX_PARAM_ITLIM, &maxiter );
  checkCPXerror( err, "CPXgetintparam", "solveFromHotStart" );
  err = CPXsetintparam( env_, CPX_PARAM_ITLIM, hotStartMaxIteration_ );
  checkCPXerror( err, "CPXsetintparam", "solveFromHotStart" );
  
  resolve();

  err = CPXsetintparam( env_, CPX_PARAM_ITLIM, maxiter );
  checkCPXerror( err, "CPXsetintparam", "solveFromHotStart" );
}

00942 void OsiCpxSolverInterface::unmarkHotStart()
{
  debugMessage("OsiCpxSolverInterface::unmarkHotStart()\n");

  // ??? be lazy with deallocating memory and do nothing here, deallocate memory in the destructor
}

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

//------------------------------------------------------------------
// Get number of rows, columns, elements, ...
//------------------------------------------------------------------
00956 int OsiCpxSolverInterface::getNumCols() const
{
  debugMessage("OsiCpxSolverInterface::getNumCols()\n");

  return CPXgetnumcols( env_, getMutableLpPtr() );
}
00962 int OsiCpxSolverInterface::getNumRows() const
{
  debugMessage("OsiCpxSolverInterface::getNumRows()\n");

  return CPXgetnumrows( env_, getMutableLpPtr() );
}
00968 int OsiCpxSolverInterface::getNumElements() const
{
  debugMessage("OsiCpxSolverInterface::getNumElements()\n");

  return CPXgetnumnz( env_, getMutableLpPtr() );
}

//------------------------------------------------------------------
// Get pointer to rim vectors
//------------------------------------------------------------------  

00979 const double * OsiCpxSolverInterface::getColLower() const
{
  debugMessage("OsiCpxSolverInterface::getColLower()\n");

  if( collower_ == NULL )
    {
      int ncols = CPXgetnumcols( env_, getMutableLpPtr() );
      if( ncols > 0 )
      {
        collower_ = new double[ncols];
        CPXgetlb( env_, getMutableLpPtr(), collower_, 0, ncols-1 );
      }
    }
  return collower_;
}
//------------------------------------------------------------------
00995 const double * OsiCpxSolverInterface::getColUpper() const
{
  debugMessage("OsiCpxSolverInterface::getColUpper()\n");

  if( colupper_ == NULL )
    {
      int ncols = CPXgetnumcols( env_, getMutableLpPtr() );
      if( ncols > 0 )
      {
        colupper_ = new double[ncols];
        CPXgetub( env_, getMutableLpPtr(), colupper_, 0, ncols-1 );
      }
    }
  return colupper_;
}
//------------------------------------------------------------------
01011 const char * OsiCpxSolverInterface::getRowSense() const
{
  debugMessage("OsiCpxSolverInterface::getRowSense()\n");

  if ( rowsense_==NULL )
    {      
      // rowsense is determined with rhs, so invoke rhs
      getRightHandSide();
      assert( rowsense_!=NULL || getNumRows() == 0 );
    }
  return rowsense_;
}
//------------------------------------------------------------------
01024 const double * OsiCpxSolverInterface::getRightHandSide() const
{
  debugMessage("OsiCpxSolverInterface::getRightHandSide()\n");

  if ( rhs_==NULL )
    {
      CPXLPptr lp = getMutableLpPtr();
      int nrows = getNumRows();
      if( nrows > 0 ) 
      {
        rhs_ = new double[nrows];
        CPXgetrhs( env_, lp, rhs_, 0, nrows-1 );
        
        assert( rowrange_ == NULL );
        rowrange_ = new double[nrows];
        CPXgetrngval( env_, lp, rowrange_, 0, nrows-1 );
        
        assert( rowsense_ == NULL );
        rowsense_ = new char[nrows];
        CPXgetsense( env_, lp, rowsense_, 0, nrows-1 );
        
        double inf = getInfinity();
        int i;
        for ( i = 0; i < nrows; ++i ) 
          {  
            if ( rowsense_[i] != 'R' ) 
            rowrange_[i]=0.0;
            else
            {
              if ( rhs_[i] <= -inf ) 
                {
                  rowsense_[i] = 'N';
                  rowrange_[i] = 0.0;
                  rhs_[i] = 0.0;
                } 
              else 
                {
                  if( rowrange_[i] >= 0.0 )
                  rhs_[i] = rhs_[i] + rowrange_[i];
                  else
                  rowrange_[i] = -rowrange_[i];
                }
            }
          }
      }
    }
  return rhs_;
}
//------------------------------------------------------------------
01073 const double * OsiCpxSolverInterface::getRowRange() const
{
  debugMessage("OsiCpxSolverInterface::getRowRange()\n");

  if ( rowrange_==NULL ) 
    {
      // rowrange is determined with rhs, so invoke rhs
      getRightHandSide();
      assert( rowrange_!=NULL || getNumRows() == 0 );
    }
  return rowrange_;
}
//------------------------------------------------------------------
01086 const double * OsiCpxSolverInterface::getRowLower() const
{
  debugMessage("OsiCpxSolverInterface::getRowLower()\n");

  if ( rowlower_ == NULL )
    {
      int     nrows = getNumRows();
      const   char    *rowsense = getRowSense();
      const   double  *rhs      = getRightHandSide();
      const   double  *rowrange = getRowRange();
    
      if ( nrows > 0 )
      {
        rowlower_ = new double[nrows];
        
        double dum1;
        for ( int i = 0;  i < nrows;  i++ )
          convertSenseToBound( rowsense[i], rhs[i], rowrange[i],
                         rowlower_[i], dum1 );
      }
    }
  return rowlower_;
}
//------------------------------------------------------------------
01110 const double * OsiCpxSolverInterface::getRowUpper() const
{  
  debugMessage("OsiCpxSolverInterface::getRowUpper()\n");

  if ( rowupper_ == NULL )
    {
      int     nrows = getNumRows();
      const   char    *rowsense = getRowSense();
      const   double  *rhs      = getRightHandSide();
      const   double  *rowrange = getRowRange();
      
      if ( nrows > 0 ) 
      {
        rowupper_ = new double[nrows];
        
        double dum1;
        for ( int i = 0;  i < nrows;  i++ )
          convertSenseToBound( rowsense[i], rhs[i], rowrange[i],
                         dum1, rowupper_[i] );
      }
    }
  
  return rowupper_;
}
//------------------------------------------------------------------
01135 const double * OsiCpxSolverInterface::getObjCoefficients() const
{
  debugMessage("OsiCpxSolverInterface::getObjCoefficients()\n");

  if ( obj_==NULL )
    {
      int ncols = CPXgetnumcols( env_, getMutableLpPtr() );
      if( ncols > 0 )
      {
        obj_ = new double[ncols];
        int err = CPXgetobj( env_, getMutableLpPtr(), obj_, 0, ncols-1 );
        checkCPXerror( err, "CPXgetobj", "getObjCoefficients" );
      }
    }
  return obj_;
}
//------------------------------------------------------------------
01152 double OsiCpxSolverInterface::getObjSense() const
{
  debugMessage("OsiCpxSolverInterface::getObjSense()\n");

  if( CPXgetobjsen( env_, getMutableLpPtr() ) == CPX_MIN )
    return +1.0;
  else
    return -1.0;
}

//------------------------------------------------------------------
// Return information on integrality
//------------------------------------------------------------------

01166 bool OsiCpxSolverInterface::isContinuous( int colNumber ) const
{
  debugMessage("OsiCpxSolverInterface::isContinuous(%d)\n", colNumber);

  return getCtype()[colNumber] == 'C';
}

//------------------------------------------------------------------
// Row and column copies of the matrix ...
//------------------------------------------------------------------

01177 const CoinPackedMatrix * OsiCpxSolverInterface::getMatrixByRow() const
{
  debugMessage("OsiCpxSolverInterface::getMatrixByRow()\n");

  if ( matrixByRow_ == NULL ) 
    {
      int nrows = getNumRows();
      int ncols = getNumCols();
      int nelems;
      int *starts   = new int   [nrows + 1];
      int *len      = new int   [nrows];
      
      int requiredSpace;
      int rc = CPXgetrows( env_, getMutableLpPtr(), 
                     &nelems, starts, NULL, NULL, 0, &requiredSpace,
                     0, nrows-1 );
      
      assert( -requiredSpace == getNumElements() );
      int     *indices  = new int   [-requiredSpace];
      double  *elements = new double[-requiredSpace]; 
      
      rc = CPXgetrows( env_, getMutableLpPtr(), 
                   &nelems, starts, indices, elements, -requiredSpace,
                   &requiredSpace, 0, nrows-1 );
      assert( requiredSpace == 0 );
            
      matrixByRow_ = new CoinPackedMatrix();
      
      // Should be able to pass null for length of packed matrix,
      // assignMatrix does not seem to allow (even though documentation
      // say it is possible to do this). 
      // For now compute the length.
      starts[nrows] = nelems;
      for ( int i = 0; i < nrows; ++i )
      len[i]=starts[i+1] - starts[i];
      
      matrixByRow_->assignMatrix( false /* not column ordered */,
                          ncols, nrows, nelems,
                          elements, indices, starts, len /*NULL*/);
      
    }
  return matrixByRow_;
} 

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

01223 const CoinPackedMatrix * OsiCpxSolverInterface::getMatrixByCol() const
{
  debugMessage("OsiCpxSolverInterface::getMatrixByCol()\n");

  if ( matrixByCol_ == NULL )
    {
      int nrows = getNumRows();
      int ncols = getNumCols();
      int nelems;
      int *starts = new int   [ncols + 1];
      int *len    = new int   [ncols];
      
      int requiredSpace;
      int rc = CPXgetcols( env_, getMutableLpPtr(), 
                     &nelems, starts, NULL, NULL, 0, &requiredSpace,
                     0, ncols-1 );
      assert( -requiredSpace == getNumElements() );
      
      int     *indices  = new int   [-requiredSpace];
      double  *elements = new double[-requiredSpace]; 
      
      rc = CPXgetcols( env_, getMutableLpPtr(), 
                   &nelems, starts, indices, elements, -requiredSpace,
                   &requiredSpace, 0, ncols-1 );
      assert( requiredSpace == 0);
      
      matrixByCol_ = new CoinPackedMatrix();
      
      // Should be able to pass null for length of packed matrix,
      // assignMatrix does not seem to allow (even though documentation
      // say it is possible to do this). 
      // For now compute the length.
      starts[ncols] = nelems;
      for ( int i = 0; i < ncols; i++ )
      len[i]=starts[i+1] - starts[i];
      
      matrixByCol_->assignMatrix( true /* column ordered */,
                          nrows, ncols, nelems,
                          elements, indices, starts, len /*NULL*/);
      assert( matrixByCol_->getNumCols()==ncols );
      assert( matrixByCol_->getNumRows()==nrows );
    }
  return matrixByCol_;
} 

//------------------------------------------------------------------
// Get solver's value for infinity
//------------------------------------------------------------------
01271 double OsiCpxSolverInterface::getInfinity() const
{
  debugMessage("OsiCpxSolverInterface::getInfinity()\n");

  return CPX_INFBOUND;
}

//#############################################################################
// Problem information methods (results)
//#############################################################################

// *FIXME*: what should be done if a certain vector doesn't exist???

01284 const double * OsiCpxSolverInterface::getColSolution() const
{
  debugMessage("OsiCpxSolverInterface::getColSolution()\n");

  if( colsol_==NULL )
    {
      CPXLPptr lp = getMutableLpPtr();
      int ncols = CPXgetnumcols( env_, lp );
      if( ncols > 0 )
      {
        colsol_ = new double[ncols]; 

          if( probtypemip_ ) {
          int err = CPXgetmipx( env_, lp, colsol_, 0, ncols-1 );
          if ( err == CPXERR_NO_INT_SOLN ) 
            CoinFillN( colsol_, ncols, 0.0 );
          else
            checkCPXerror( err, "CPXgetmipx", "getColSolution" );
        } else {
          int err = CPXgetx( env_, lp, colsol_, 0, ncols-1 );
          if ( err == CPXERR_NO_SOLN ) 
            CoinFillN( colsol_, ncols, 0.0 );
          else
            checkCPXerror( err, "CPXgetx", "getColSolution" );
        }
      }
    }
  return colsol_;
}
//------------------------------------------------------------------
01314 const double * OsiCpxSolverInterface::getRowPrice() const
{
  debugMessage("OsiCpxSolverInterface::getRowPrice()\n");

  if( rowsol_==NULL )
    {
      int nrows = getNumRows();
      if( nrows > 0 )
      {
        rowsol_ = new double[nrows];
        int err = CPXgetpi( env_, getMutableLpPtr(), rowsol_, 0, nrows-1 );
        if ( err == CPXERR_NO_SOLN ) 
          CoinFillN( rowsol_, nrows, 0.0 );
        else
          checkCPXerror( err, "CPXgetpi", "getRowPrice" );
      }
    }
  return rowsol_;
}
//------------------------------------------------------------------
01334 const double * OsiCpxSolverInterface::getReducedCost() const
{
  debugMessage("OsiCpxSolverInterface::getReducedCost()\n");

  if( redcost_==NULL )
    {
      int ncols = CPXgetnumcols( env_, getMutableLpPtr() );
      if( ncols > 0 )
      {
        redcost_ = new double[ncols]; 
        int err = CPXgetdj( env_, getMutableLpPtr(), redcost_, 0, ncols-1 );
        if ( err == CPXERR_NO_SOLN ) 
          CoinFillN( redcost_, ncols, 0.0 );
        else
          checkCPXerror( err, "CPXgetdj", "getReducedCost" );
      }
    }
  return redcost_;
}
//------------------------------------------------------------------
01354 const double * OsiCpxSolverInterface::getRowActivity() const
{
  debugMessage("OsiCpxSolverInterface::getRowActivity()\n");

  if( rowact_==NULL )
    {
      int nrows = getNumRows();
      if( nrows > 0 )
      {
        rowact_ = new double[nrows];
          if( probtypemip_ )
          {
             double *rowslack = new double[nrows];
             int err = CPXgetmipslack( env_, getMutableLpPtr(), rowslack, 0, nrows-1 );
             if ( err == CPXERR_NO_SOLN || err == CPXERR_NO_INT_SOLN )
                CoinFillN( rowact_, nrows, 0.0 );
             else
             {
                checkCPXerror( err, "CPXgetmipslack", "getRowActivity" );
                for( int r = 0; r < nrows; ++r )
                   rowact_[r] = getRightHandSide()[r] + rowslack[r];
             }
             delete [] rowslack;
          }
          else
          {
             int err = CPXgetax( env_, getMutableLpPtr(), rowact_, 0, nrows-1 );
             if ( err == CPXERR_NO_SOLN )
                CoinFillN( rowact_, nrows, 0.0 );
             else
                checkCPXerror( err, "CPXgetax", "getRowActivity" );
          }
      }
    }
  return rowact_;
}
//------------------------------------------------------------------
01391 double OsiCpxSolverInterface::getObjValue() const
{
  debugMessage("OsiCpxSolverInterface::getObjValue()\n");

  double objval = 0.0;
  int err;

  CPXLPptr lp = getMutableLpPtr();

  if( probtypemip_ ) {
    err = CPXgetmipobjval( env_, lp, &objval);
    if ( err == CPXERR_NO_INT_SOLN ) 
      // => return 0.0 as objective value (?? is this the correct behaviour ??)
      objval = 0.0;
    else
      checkCPXerror( err, "CPXgetmipobjval", "getObjValue" );
  } else {
    err = CPXgetobjval( env_, lp, &objval );
    if ( err == CPXERR_NO_SOLN ) 
      objval = 0.0;
    else
      checkCPXerror( err, "CPXgetobjval", "getObjValue" );
  }

  // Adjust objective function value by constant term in objective function
  double objOffset;
  getDblParam(OsiObjOffset,objOffset);
  objval = objval - objOffset;

  return objval;
}
//------------------------------------------------------------------
01423 int OsiCpxSolverInterface::getIterationCount() const
{
  debugMessage("OsiCpxSolverInterface::getIterationCount()\n");

  return CPXgetitcnt( env_, getMutableLpPtr() );
}
//------------------------------------------------------------------
01430 std::vector<double*> OsiCpxSolverInterface::getDualRays(int maxNumRays) const
{
  debugMessage("OsiCpxSolverInterface::getDualRays(%d)\n", maxNumRays);

   OsiCpxSolverInterface solver(*this);

   const int numcols = getNumCols();
   const int numrows = getNumRows();
   int* index = new int[CoinMax(numcols,numrows)];
   int i;
   for ( i = CoinMax(numcols,numrows)-1; i >= 0; --i) {
      index[i] = i;
   }
   double* obj = new double[CoinMax(numcols,2*numrows)];
   CoinFillN(obj, numcols, 0.0);
   solver.setObjCoeffSet(index, index+numcols, obj);

   double* clb = new double[2*numrows];
   double* cub = new double[2*numrows];

   const double plusone = 1.0;
   const double minusone = -1.0;
   const char* sense = getRowSense();

   const CoinPackedVectorBase** cols =
      new const CoinPackedVectorBase*[2*numrows];
   int newcols = 0;
   for (i = 0; i < numrows; ++i) {
      switch (sense[i]) {
      case 'L':
       cols[newcols++] =
          new CoinShallowPackedVector(1, &index[i], &minusone, false);
       break;
      case 'G':
       cols[newcols++] =
          new CoinShallowPackedVector(1, &index[i], &plusone, false);
       break;
      case 'R':
       cols[newcols++] =
          new CoinShallowPackedVector(1, &index[i], &minusone, false);
       cols[newcols++] =
          new CoinShallowPackedVector(1, &index[i], &plusone, false);
       break;
      case 'N':
       break;
      }
   }

   CoinFillN(obj, newcols, 1.0);
   CoinFillN(clb, newcols, 0.0);
   CoinFillN(cub, newcols, getInfinity());

   solver.addCols(newcols, cols, clb, cub, obj);
   delete[] index;
   delete[] cols;
   delete[] clb;
   delete[] cub;
   delete[] obj;

   solver.setObjSense(1.0); // minimize
   solver.initialSolve();

   const double* solverpi = solver.getRowPrice();
   double* pi = new double[numrows];
   for ( i = numrows - 1; i >= 0; --i) {
      pi[i] = -solverpi[i];
   }
   return std::vector<double*>(1, pi);
}

//------------------------------------------------------------------
01501 std::vector<double*> OsiCpxSolverInterface::getPrimalRays(int maxNumRays) const
{
  debugMessage("OsiCpxSolverInterface::getPrimalRays(%d)\n", maxNumRays);

  double *ray = new double[getNumCols()];
  int err = CPXgetray(env_, getMutableLpPtr(), ray);
  checkCPXerror(err, "CPXgetray", "getPrimalRays");
  return std::vector<double*>(1, ray);
}

//#############################################################################
// Problem modifying methods (rim vectors)
//#############################################################################

01515 void OsiCpxSolverInterface::setObjCoeff( int elementIndex, double elementValue )
{
  debugMessage("OsiCpxSolverInterface::setObjCoeff(%d, %g)\n", elementIndex, elementValue);

  //  int err = CPXchgobj(env_, getLpPtr( OsiCpxSolverInterface::FREECACHED_COLUMN ), 1, &elementIndex, &elementValue);
  int err = CPXchgobj(env_, getLpPtr( OsiCpxSolverInterface::KEEPCACHED_PROBLEM ), 1, &elementIndex, &elementValue);
  checkCPXerror(err, "CPXchgobj", "setObjCoeff");
  if(obj_ != NULL) {
    obj_[elementIndex] = elementValue;
  }
}
//-----------------------------------------------------------------------------
01527 void OsiCpxSolverInterface::setObjCoeffSet(const int* indexFirst,
                                 const int* indexLast,
                                 const double* coeffList)
{
  debugMessage("OsiCpxSolverInterface::setObjCoeffSet(%p, %p, %p)\n", (void*)indexFirst, (void*)indexLast, (void*)coeffList);

   const int cnt = indexLast - indexFirst;
   //   int err = CPXchgobj(env_,
   //              getLpPtr(OsiCpxSolverInterface::FREECACHED_COLUMN), cnt,
   //              const_cast<int*>(indexFirst),
   //              const_cast<double*>(coeffList));
   int err = CPXchgobj(env_,
                   getLpPtr(OsiCpxSolverInterface::KEEPCACHED_PROBLEM), 
                   cnt,
                   const_cast<int*>(indexFirst),
                   const_cast<double*>(coeffList));
   checkCPXerror(err, "CPXchgobj", "setObjCoeffSet");
   if (obj_ != NULL) {
       for (int i = 0; i < cnt; ++i) {
         obj_[indexFirst[i]] = coeffList[i];
       }
   }
}
//-----------------------------------------------------------------------------
01551 void OsiCpxSolverInterface::setColLower(int elementIndex, double elementValue)
{
  debugMessage("OsiCpxSolverInterface::setColLower(%d, %g)\n", elementIndex, elementValue);

  char c = 'L';
  //  int err = CPXchgbds( env_, getLpPtr( OsiCpxSolverInterface::FREECACHED_COLUMN ), 1, &elementIndex, &c, &elementValue );
  int err = CPXchgbds( env_, 
                   getLpPtr( OsiCpxSolverInterface::KEEPCACHED_PROBLEM ), 
                   1, &elementIndex, &c, &elementValue );
  checkCPXerror( err, "CPXchgbds", "setColLower" );
  if(collower_ != NULL) {
    collower_[elementIndex] = elementValue;
  }
}
//-----------------------------------------------------------------------------
01566 void OsiCpxSolverInterface::setColUpper(int elementIndex, double elementValue)
{  
  debugMessage("OsiCpxSolverInterface::setColUpper(%d, %g)\n", elementIndex, elementValue);

  char c = 'U';
  //  int err = CPXchgbds( env_, getLpPtr( OsiCpxSolverInterface::FREECACHED_COLUMN ), 1, &elementIndex, &c, &elementValue );
  int err = CPXchgbds( env_, 
                   getLpPtr( OsiCpxSolverInterface::KEEPCACHED_PROBLEM ), 
                   1, &elementIndex, &c, &elementValue );
  checkCPXerror( err, "CPXchgbds", "setColUpper" );
  if(colupper_ != NULL) {
    colupper_[elementIndex] = elementValue;
  }
} 
//-----------------------------------------------------------------------------
01581 void OsiCpxSolverInterface::setColBounds( int elementIndex, double lower, double upper )
{
  debugMessage("OsiCpxSolverInterface::setColBounds(%d, %g, %g)\n", elementIndex, lower, upper);

  char c[2] = { 'L', 'U' };
  int ind[2];
  double bd[2];
  int err;

  ind[0] = elementIndex;
  ind[1] = elementIndex;
  bd[0] = lower;
  bd[1] = upper;
  //  err = CPXchgbds( env_, getLpPtr( OsiCpxSolverInterface::FREECACHED_COLUMN ), 2, ind, c, bd );
  err = CPXchgbds( env_, 
               getLpPtr( OsiCpxSolverInterface::KEEPCACHED_PROBLEM ), 
               2, ind, c, bd );
  checkCPXerror( err, "CPXchgbds", "setColBounds" );
  if(collower_ != NULL) {
    collower_[elementIndex] = lower;
  }
  if(colupper_ != NULL) {
    colupper_[elementIndex] = upper;
  }
}
//-----------------------------------------------------------------------------
01607 void OsiCpxSolverInterface::setColSetBounds(const int* indexFirst,
                                  const int* indexLast,
                                  const double* boundList)
{
  debugMessage("OsiCpxSolverInterface::setColSetBounds(%p, %p, %p)\n", (void*)indexFirst, (void*)indexLast, (void*)boundList);

   const int cnt = indexLast - indexFirst;
   if (cnt <= 0)
      return;

   char* c = new char[2*cnt];
   int* ind = new int[2*cnt];
   for (int i = 0; i < cnt; ++i) {
      register const int j = 2 * i;
      c[j] = 'L';
      c[j+1] = 'U';
      const int colind = indexFirst[i];
      ind[j] = colind;
      ind[j+1] = colind;

      if(collower_ != NULL) {
      collower_[colind] = boundList[2 * i];
      }
      if(colupper_ != NULL) {
      colupper_[colind] = boundList[2 * i + 1];
      }
   }
   //   int err = CPXchgbds( env_,
   //             getLpPtr(OsiCpxSolverInterface::FREECACHED_ROW ),
   //                            2*cnt, ind, c, 
   //                            const_cast<double*>(boundList) );
   int err = CPXchgbds( env_,
                  getLpPtr(OsiCpxSolverInterface::KEEPCACHED_PROBLEM),
                  2*cnt, ind, c, const_cast<double*>(boundList) );
   checkCPXerror( err, "CPXchgbds", "setColSetBounds" );
   delete[] ind;
   delete[] c;
   // OsiSolverInterface::setColSetBounds( indexFirst, indexLast, boundList );
}
//-----------------------------------------------------------------------------
void
01648 OsiCpxSolverInterface::setRowLower( int i, double elementValue )
{
  debugMessage("OsiCpxSolverInterface::setRowLower(%d, %g)\n", i, elementValue);

  double rhs   = getRightHandSide()[i];
  double range = getRowRange()[i];
  char   sense = getRowSense()[i];
  double lower = 0, upper = 0;

  convertSenseToBound( sense, rhs, range, lower, upper );
  if( lower != elementValue ) {
      convertBoundToSense( elementValue, upper, sense, rhs, range );
      setRowType( i, sense, rhs, range );
    }
}
//-----------------------------------------------------------------------------
void
01665 OsiCpxSolverInterface::setRowUpper( int i, double elementValue )
{
  debugMessage("OsiCpxSolverInterface::setRowUpper(%d, %g)\n", i, elementValue);

  double rhs   = getRightHandSide()[i];
  double range = getRowRange()[i];
  char   sense = getRowSense()[i];
  double lower = 0, upper = 0;

  convertSenseToBound( sense, rhs, range, lower, upper );
  if( upper != elementValue ) {
      convertBoundToSense( lower, elementValue, sense, rhs, range );
      setRowType( i, sense, rhs, range );
  }
}
//-----------------------------------------------------------------------------
void
01682 OsiCpxSolverInterface::setRowBounds( int elementIndex, double lower, double upper )
{
  debugMessage("OsiCpxSolverInterface::setRowBounds(%d, %g, %g)\n", elementIndex, lower, upper);

  double rhs, range;
  char sense;
  
  convertBoundToSense( lower, upper, sense, rhs, range );
  setRowType( elementIndex, sense, rhs, range );
}
//-----------------------------------------------------------------------------
void
01694 OsiCpxSolverInterface::setRowType(int i, char sense, double rightHandSide,
                          double range)
{
  debugMessage("OsiCpxSolverInterface::setRowType(%d, %c, %g, %g)\n", i, sense, rightHandSide, range);

  int err;

  // in CPLEX, ranged constraints are interpreted as rhs <= coeff*x <= rhs+range, which is different from Osi
  double cpxrhs = rightHandSide;
  if (sense == 'R') {
     assert( range >= 0.0 );
     cpxrhs -= range;
  }
  if (sense == 'N') {
     sense = 'R';
     cpxrhs = -getInfinity();
     range = 2*getInfinity();
  }

  /**************
  err = CPXchgsense( env_, getLpPtr( OsiCpxSolverInterface::FREECACHED_ROW ),
                 1, &i, &sense );
  checkCPXerror( err, "CPXchgsense", "setRowType" );
  err = CPXchgrhs( env_, getLpPtr( OsiCpxSolverInterface::FREECACHED_ROW ),
               1, &i, &rightHandSide );
  checkCPXerror( err, "CPXchgrhs", "setRowType" );
  err = CPXchgrngval( env_, getLpPtr( OsiCpxSolverInterface::FREECACHED_ROW ),
                  1, &i, &range );
  checkCPXerror( err, "CPXchgrngval", "setRowType" );
  ***************/

  err = CPXchgsense( env_, 
                 getLpPtr( OsiCpxSolverInterface::KEEPCACHED_PROBLEM ),
                 1, &i, &sense );
  checkCPXerror( err, "CPXchgsense", "setRowType" );
  if(rowsense_ != NULL) {
    rowsense_[i] = sense;
  }

  err = CPXchgrhs( env_, getLpPtr( OsiCpxSolverInterface::KEEPCACHED_PROBLEM ),
               1, &i, &cpxrhs );
  checkCPXerror( err, "CPXchgrhs", "setRowType" );
  if(rhs_ != NULL) {
    rhs_[i] = rightHandSide;
  }
  err = CPXchgrngval( env_, 
                  getLpPtr( OsiCpxSolverInterface::KEEPCACHED_PROBLEM ),
                  1, &i, &range );
  checkCPXerror( err, "CPXchgrngval", "setRowType" );
  if(rowrange_ != NULL) {
    rowrange_[i] = range;
  }
  
  if (rowlower_ != NULL || rowupper_ != NULL)
  {
      double dummy;
      convertSenseToBound(sense, rightHandSide, range, 
                  rowlower_ ? rowlower_[i] : dummy,
                  rowupper_ ? rowupper_[i] : dummy);
  }
}
//-----------------------------------------------------------------------------
01756 void OsiCpxSolverInterface::setRowSetBounds(const int* indexFirst,
                                  const int* indexLast,
                                  const double* boundList)
{
  debugMessage("OsiCpxSolverInterface::setRowSetBounds(%p, %p, %p)\n", (void*)indexFirst, (void*)indexLast, (void*)boundList);

   const int cnt = indexLast - indexFirst;
   if (cnt <= 0)
      return;

   char* sense = new char[cnt];
   double* rhs = new double[cnt];
   double* range = new double[cnt];
   for (int i = 0; i < cnt; ++i) {
      convertBoundToSense(boundList[2*i], boundList[2*i+1],
                    sense[i], rhs[i], range[i]);
   }
   setRowSetTypes(indexFirst, indexLast, sense, rhs, range);
   delete[] range;
   delete[] rhs;
   delete[] sense;
   
   //  OsiSolverInterface::setRowSetBounds( indexFirst, indexLast, boundList );
}
//-----------------------------------------------------------------------------
void
01782 OsiCpxSolverInterface::setRowSetTypes(const int* indexFirst,
                              const int* indexLast,
                              const char* senseList,
                              const double* rhsList,
                              const double* rangeList)
{
  debugMessage("OsiCpxSolverInterface::setRowSetTypes(%p, %p, %p, %p, %p)\n", 
            (void*)indexFirst, (void*)indexLast, (void*)senseList, (void*)rhsList, (void*)rangeList);

   const int cnt = indexLast - indexFirst;
   if (cnt <= 0)
      return;

   char* sense = new char[cnt];
   double* rhs = new double[cnt];
   double* range = new double[cnt];
   int* rangeind = new int[cnt];
   int rangecnt = 0;
   for (int i = 0; i < cnt; ++i) {
      sense[i] = senseList[i];
      rhs[i] = rhsList[i];
      if (sense[i] == 'R') {
       assert(rangeList[i] >= 0.0);
       rhs[i] -= rangeList[i];
       rangeind[rangecnt] = indexFirst[i];
       range[rangecnt] = rangeList[i];
       ++rangecnt;
      }
      if (sense[i] == 'N') {
       sense[i] = 'R';
       rhs[i] = -getInfinity();
       rangeind[rangecnt] = indexFirst[i];
       range[rangecnt] = 2*getInfinity();
       ++rangecnt;
      }
   }
   int err;
   /******************
   err = CPXchgsense(env_, getLpPtr(OsiCpxSolverInterface::FREECACHED_ROW),
                 cnt, const_cast<int*>(indexFirst), sense);
   checkCPXerror( err, "CPXchgsense", "setRowSetTypes" );
   err = CPXchgrhs(env_, getLpPtr(OsiCpxSolverInterface::FREECACHED_ROW),
               cnt, const_cast<int*>(indexFirst), rhs);
   checkCPXerror( err, "CPXchgrhs", "setRowSetTypes" );
   err = CPXchgrngval(env_, getLpPtr(OsiCpxSolverInterface::FREECACHED_ROW),
                  rangecnt, rangeind, range);
   checkCPXerror( err, "CPXchgrngval", "setRowSetTypes" );
   ********************/

   err = CPXchgsense(env_, getLpPtr(OsiCpxSolverInterface::KEEPCACHED_ROW),
                 cnt, const_cast<int*>(indexFirst), sense);
   checkCPXerror( err, "CPXchgsense", "setRowSetTypes" );
   err = CPXchgrhs(env_, getLpPtr(OsiCpxSolverInterface::FREECACHED_ROW),
               cnt, const_cast<int*>(indexFirst), rhs);
   checkCPXerror( err, "CPXchgrhs", "setRowSetTypes" );
   err = CPXchgrngval(env_, getLpPtr(OsiCpxSolverInterface::FREECACHED_ROW),
                  rangecnt, rangeind, range);
   checkCPXerror( err, "CPXchgrngval", "setRowSetTypes" );

   int j;
   if(rowsense_ != NULL) {
     for(j=0; j<cnt; j++) {
       rowsense_[indexFirst[j]] = sense[j];
     }
   }
   if(rhs_ != NULL) {
     for(j=0; j<cnt; j++) {
       rhs_[indexFirst[j]] = rhs[j];
     }
   }
   if(rowrange_ != NULL) {
     for(j=0; j<rangecnt; j++) {
       rowrange_[rangeind[j]] = range[j];
     }
   }
   delete[] rangeind;
   delete[] range;
   delete[] rhs;
   delete[] sense;
//    OsiSolverInterface::setRowSetTypes( indexFirst, indexLast, senseList,
//                            rhsList, rangeList );
}
//#############################################################################
void
01866 OsiCpxSolverInterface::setContinuous(int index)
{
  debugMessage("OsiCpxSolverInterface::setContinuous(%d)\n", index);

  assert(coltype_ != NULL);
  assert(coltypesize_ >= getNumCols());

  coltype_[index] = 'C';

  if ( probtypemip_ )
    {
      CPXLPptr lp = getMutableLpPtr();
      int err;
      err = CPXchgctype( env_, lp, 1, &index, &coltype_[index] );
      checkCPXerror( err, "CPXchgctype", "setContinuous" );
    }
}
//-----------------------------------------------------------------------------
void
01885 OsiCpxSolverInterface::setInteger(int index)
{
  debugMessage("OsiCpxSolverInterface::setInteger(%d)\n", index);

  assert(coltype_ != NULL);
  assert(coltypesize_ >= getNumCols());

  if( getColLower()[index] == 0.0 && getColUpper()[index] == 1.0 )
     coltype_[index] = 'B';
  else
     coltype_[index] = 'I';

  if ( probtypemip_ )
    {
      CPXLPptr lp = getMutableLpPtr();
      int err;
      err = CPXchgctype( env_, lp, 1, &index, &coltype_[index] );
      checkCPXerror( err, "CPXchgctype", "setInteger" );
    }
}
//-----------------------------------------------------------------------------
void
01907 OsiCpxSolverInterface::setContinuous(const int* indices, int len)
{
  debugMessage("OsiCpxSolverInterface::setContinuous(%p, %d)\n", (void*)indices, len);

  for( int i = 0; i < len; ++i )
     setContinuous(indices[i]);
}
//-----------------------------------------------------------------------------
void
01916 OsiCpxSolverInterface::setInteger(const int* indices, int len)
{
  debugMessage("OsiCpxSolverInterface::setInteger(%p, %d)\n", (void*)indices, len);

  for( int i = 0; i < len; ++i )
     setInteger(indices[i]);
}
//#############################################################################

01925 void OsiCpxSolverInterface::setObjSense(double s) 
{
  debugMessage("OsiCpxSolverInterface::setObjSense(%g)\n", s);

  if( s == +1.0 )
    CPXchgobjsen( env_, getLpPtr( OsiCpxSolverInterface::FREECACHED_RESULTS ), CPX_MIN );
  else
    CPXchgobjsen( env_, getLpPtr( OsiCpxSolverInterface::FREECACHED_RESULTS ), CPX_MAX );
}
 
//-----------------------------------------------------------------------------

01937 void OsiCpxSolverInterface::setColSolution(const double * cs) 
{
  debugMessage("OsiCpxSolverInterface::setColSolution(%p)\n", (void*)cs);

  int nc = getNumCols();

  if( cs == NULL )
    freeCachedResults();
  else if( nc > 0 )
    {
      // If colsol isn't allocated, then allocate it
      if ( colsol_ == NULL )
      colsol_ = new double[nc];
      
      // Copy in new col solution.
      CoinDisjointCopyN( cs, nc, colsol_ );

      // CPLEX < 7.0 doesn't support setting a col solution without a row solution
      // -> if a row solution exists or CPLEX version >= 7, then pass into CPLEX
#if CPX_VERSION < 700
      if ( rowsol_ != NULL )
#endif
      {
        int err = CPXcopystart( env_, getMutableLpPtr(), NULL, NULL, 
                          const_cast<double*>( colsol_ ), 
                          const_cast<double*>( rowsol_ ), 
                          NULL, NULL );
        checkCPXerror( err, "CPXcopystart", "setColSolution" );
      }
    }
}

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

01971 void OsiCpxSolverInterface::setRowPrice(const double * rs) 
{
  debugMessage("OsiCpxSolverInterface::setRowPrice(%p)\n", (void*)rs);

  int nr = getNumRows();

  if( rs == NULL )
    freeCachedResults();
  else if( nr > 0 )
    {
      // If rowsol isn't allocated, then allocate it
      if ( rowsol_ == NULL )
      rowsol_ = new double[nr];

      // Copy in new row solution.
      CoinDisjointCopyN( rs, nr, rowsol_ );
      
      // if a col solution exists, then pass into CPLEX
      if ( colsol_ != NULL )
      {
        int err = CPXcopystart( env_, getMutableLpPtr(), NULL, NULL, 
                          const_cast<double*>( colsol_ ), 
                          const_cast<double*>( rowsol_ ), 
                          NULL, NULL );
        checkCPXerror( err, "CPXcopystart", "setRowPrice" );
      }
    }
}

//#############################################################################
// Problem modifying methods (matrix)
//#############################################################################
void 
02004 OsiCpxSolverInterface::addCol(const CoinPackedVectorBase& vec,
                        const double collb, const double colub,   
                        const double obj)
{
  debugMessage("OsiCpxSolverInterface::addCol(%p, %g, %g, %g)\n", (void*)&vec, collb, colub, obj);

  int nc = getNumCols();
  assert(coltypesize_ >= nc);

  resizeColType(nc + 1);
  coltype_[nc] = 'C';

  int err;
  int cmatbeg[2] = {0, vec.getNumElements()};

  err = CPXaddcols( env_, getLpPtr( OsiCpxSolverInterface::KEEPCACHED_ROW ),
                1, vec.getNumElements(), const_cast<double*>(&obj),
                cmatbeg,
                const_cast<int*>(vec.getIndices()),
                const_cast<double*>(vec.getElements()),
                const_cast<double*>(&collb),
                const_cast<double*>(&colub), NULL );
  checkCPXerror( err, "CPXaddcols", "addCol" );
}
//-----------------------------------------------------------------------------
void 
02030 OsiCpxSolverInterface::addCols(const int numcols,
                         const CoinPackedVectorBase * const * cols,
                         const double* collb, const double* colub,   
                         const double* obj)
{
  debugMessage("OsiCpxSolverInterface::addCols(%d, %p, %p, %p, %p)\n", numcols, (void*)cols, (void*)collb, (void*)colub, (void*)obj);

  int nc = getNumCols();
  assert(coltypesize_ >= nc);

  resizeColType(nc + numcols);
  CoinFillN(&coltype_[nc], numcols, 'C');

  int i;
  int nz = 0;
  for (i = 0; i < numcols; ++i)
    nz += cols[i]->getNumElements();

  int* index = new int[nz];
  double* elem = new double[nz];
  int* start = new int[numcols+1];

  nz = 0;
  start[0] = 0;
  for (i = 0; i < numcols; ++i) {
    const CoinPackedVectorBase* col = cols[i];
    const int len = col->getNumElements();
    CoinDisjointCopyN(col->getIndices(), len, index+nz);
    CoinDisjointCopyN(col->getElements(), len, elem+nz);
    nz += len;
    start[i+1] = nz;
  }
  int err = CPXaddcols(env_, getLpPtr(OsiCpxSolverInterface::KEEPCACHED_ROW),
                   numcols, nz, const_cast<double*>(obj),
                   start, index, elem, 
                   const_cast<double*>(collb),
                   const_cast<double*>(colub), NULL );
  checkCPXerror( err, "CPXaddcols", "addCols" );

  delete[] start;
  delete[] elem;
  delete[] index;

//    int i;
//    for( i = 0; i < numcols; ++i )
//      addCol( *(cols[i]), collb[i], colub[i], obj[i] );
}
//-----------------------------------------------------------------------------
void 
02079 OsiCpxSolverInterface::deleteCols(const int num, const int * columnIndices)
{
  debugMessage("OsiCpxSolverInterface::deleteCols(%d, %p)\n", num, (void*)columnIndices);

  int ncols = getNumCols();
  int *delstat = new int[ncols];
  int i, err;

  CoinFillN(delstat, ncols, 0);
  for( i = 0; i < num; ++i )
    delstat[columnIndices[i]] = 1;
  err = CPXdelsetcols( env_, getLpPtr( OsiCpxSolverInterface::KEEPCACHED_ROW ), delstat );
  checkCPXerror( err, "CPXdelsetcols", "deleteCols" );

  for( i = 0; i < ncols; ++i )
  {
     assert(delstat[i] <= i);
     if( delstat[i] != -1 )
        coltype_[delstat[i]] = coltype_[i];
  }

  delete[] delstat;
}
//-----------------------------------------------------------------------------
void 
02104 OsiCpxSolverInterface::addRow(const CoinPackedVectorBase& vec,
                        const double rowlb, const double rowub)
{
  debugMessage("OsiCpxSolverInterface::addRow(%p, %g, %g)\n", (void*)&vec, rowlb, rowub);

  char sense;
  double rhs, range;

  convertBoundToSense( rowlb, rowub, sense, rhs, range );
  addRow( vec, sense, rhs, range );
}
//-----------------------------------------------------------------------------
void 
02117 OsiCpxSolverInterface::addRow(const CoinPackedVectorBase& vec,
                        const char rowsen, const double rowrhs,   
                        const double rowrng)
{
  debugMessage("OsiCpxSolverInterface::addRow(%p, %c, %g, %g)\n", (void*)&vec, rowsen, rowrhs, rowrng);

  int err;
  int rmatbeg = 0;
  double rhs;
  double range;
  char sense = rowsen;

  switch( rowsen )
    {
    case 'R':
      assert( rowrng >= 0.0 );
      rhs = rowrhs - rowrng;
      range = rowrng;
      break;
    case 'N':
      sense = 'R';
      rhs   = -getInfinity();
      range = 2*getInfinity();
      break;
    default:
      rhs = rowrhs;
      range = 0.0;
    }

  err = CPXaddrows( env_, getLpPtr( OsiCpxSolverInterface::KEEPCACHED_COLUMN ), 0, 1, vec.getNumElements(), 
                &rhs,
                &sense,
                &rmatbeg,
                const_cast<int*>(vec.getIndices()),
                const_cast<double*>(vec.getElements()),
                NULL, NULL );
  checkCPXerror( err, "CPXaddrows", "addRow" );
  if( sense == 'R' )
    {
      int row = getNumRows() - 1;
      err = CPXchgrngval( env_, getLpPtr( OsiCpxSolverInterface::FREECACHED_ROW ), 1, &row, &range );
      checkCPXerror( err, "CPXchgrngval", "addRow" );
    }
}
//-----------------------------------------------------------------------------
void 
02163 OsiCpxSolverInterface::addRows(const int numrows,
                         const CoinPackedVectorBase * const * rows,
                         const double* rowlb, const double* rowub)
{
  debugMessage("OsiCpxSolverInterface::addRows(%d, %p, %p, %p)\n", numrows, (void*)rows, (void*)rowlb, (void*)rowub);

  int i;

  for( i = 0; i < numrows; ++i )
    addRow( *(rows[i]), rowlb[i], rowub[i] );
}
//-----------------------------------------------------------------------------
void 
02176 OsiCpxSolverInterface::addRows(const int numrows,
                         const CoinPackedVectorBase * const * rows,
                         const char* rowsen, const double* rowrhs,   
                         const double* rowrng)
{
  debugMessage("OsiCpxSolverInterface::addRows(%d, %p, %p, %p, %p)\n", numrows, (void*)rows, (void*)rowsen, (void*)rowrhs, (void*)rowrng);

  int i;

  for( i = 0; i < numrows; ++i )
    addRow( *(rows[i]), rowsen[i], rowrhs[i], rowrng[i] );
}
//-----------------------------------------------------------------------------
void 
02190 OsiCpxSolverInterface::deleteRows(const int num, const int * rowIndices)
{
  debugMessage("OsiCpxSolverInterface::deleteRows(%d, %p)\n", num, (void*)rowIndices);

  int nrows = getNumRows();
  int *delstat = new int[nrows];
  int i, err;

  CoinFillN( delstat, nrows, 0 );
  for( i = 0; i < num; ++i )
    delstat[rowIndices[i]] = 1;
  err = CPXdelsetrows( env_, getLpPtr( OsiCpxSolverInterface::KEEPCACHED_COLUMN ), delstat );
  checkCPXerror( err, "CPXdelsetrows", "deleteRows" );
  delete[] delstat;
}

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

void
02211 OsiCpxSolverInterface::loadProblem( const CoinPackedMatrix& matrix,
                            const double* collb, const double* colub,
                            const double* obj,
                            const double* rowlb, const double* rowub )
{
  debugMessage("OsiCpxSolverInterface::loadProblem(1)(%p, %p, %p, %p, %p, %p)\n", (void*)&matrix, (void*)collb, (void*)colub, (void*)obj, (void*)rowlb, (void*)rowub);

  const double inf = getInfinity();
  
  int nrows = matrix.getNumRows();
  char   * rowSense = new char  [nrows];
  double * rowRhs   = new double[nrows];
  double * rowRange = new double[nrows];
  
  int i;
  for ( i = nrows - 1; i >= 0; --i )
    {
      const double lower = rowlb ? rowlb[i] : -inf;
      const double upper = rowub ? rowub[i] : inf;
      convertBoundToSense( lower, upper, rowSense[i], rowRhs[i], rowRange[i] );
    }

  loadProblem( matrix, collb, colub, obj, rowSense, rowRhs, rowRange ); 
  delete [] rowSense;
  delete [] rowRhs;
  delete [] rowRange;
}
                      
//-----------------------------------------------------------------------------

void
02242 OsiCpxSolverInterface::assignProblem( CoinPackedMatrix*& matrix,
                              double*& collb, double*& colub,
                              double*& obj,
                              double*& rowlb, double*& rowub )
{
  debugMessage("OsiCpxSolverInterface::assignProblem()\n");

  loadProblem( *matrix, collb, colub, obj, rowlb, rowub );
  delete matrix;   matrix = 0;
  delete[] collb;  collb = 0;
  delete[] colub;  colub = 0;
  delete[] obj;    obj = 0;
  delete[] rowlb;  rowlb = 0;
  delete[] rowub;  rowub = 0;
}

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

void
02261 OsiCpxSolverInterface::loadProblem( const CoinPackedMatrix& matrix,
                            const double* collb, const double* colub,
                            const double* obj,
                            const char* rowsen, const double* rowrhs,
                            const double* rowrng )
{
  debugMessage("OsiCpxSolverInterface::loadProblem(2)(%p, %p, %p, %p, %p, %p, %p)\n",
            (void*)&matrix, (void*)collb, (void*)colub, (void*)obj, (void*)rowsen, (void*)rowrhs, (void*)rowrng);

  char *lclRowsen = NULL ;
  double *lclRowrhs = NULL ;

  int nc=matrix.getNumCols();
  int nr=matrix.getNumRows();

  if( nr == 0 && nc == 0 ) {  // empty LP
      if (lp_ != NULL) { // kill old LP 
            int err = CPXfreeprob( env_, &lp_ );
            checkCPXerror( err, "CPXfreeprob", "loadProblem" );
            lp_ = NULL;
            freeAllMemory();
      }
    return;
  }
  
  if (nr == 0) {
    int objDirection = CPXgetobjsen( env_, getMutableLpPtr() );

      if (lp_ != NULL) { // kill old LP 
            int err = CPXfreeprob( env_, &lp_ );
            checkCPXerror( err, "CPXfreeprob", "loadProblem" );
            lp_ = NULL;
            freeAllMemory();
      }
    
      // getLpPtr() call will create new LP
    int err = CPXnewcols( env_, getLpPtr(), nc, obj, collb, colub, NULL, NULL);
    checkCPXerror( err, "CPXcopylp", "loadProblem" );
    
    CPXchgobjsen(env_, getLpPtr(), objDirection);
    
    return;
  }

      if (rowsen == NULL)
      { lclRowsen = new char[nr] ;
      CoinFillN(lclRowsen,nr,'G') ;
      rowsen = lclRowsen ; }
      if (rowrhs == NULL)
      { lclRowrhs = new double[nr] ;
      CoinFillN(lclRowrhs,nr,0.0) ;
      rowrhs = lclRowrhs ; }

      int i;
      
      // Set column values to defaults if NULL pointer passed
      double * clb;  
      double * cub;
      double * ob;
      double * rr = NULL;
      double * rhs;
      if ( collb!=NULL )
      clb=const_cast<double*>(collb);
      else
      {
        clb = new double[nc];
        CoinFillN(clb, nc, 0.0);
      }
      if ( colub!=NULL )
      cub=const_cast<double*>(colub);
      else
      {
        cub = new double[nc];
        CoinFillN(cub, nc, getInfinity());
      }
      if ( obj!=NULL )
      ob=const_cast<double*>(obj);
      else
      {
        ob = new double[nc];
        CoinFillN(ob, nc, 0.0);
      }
      if ( rowrng != NULL )
      {
        rhs = new double[nr];
        rr = new double[nr];
        for ( i=0; i<nr; i++ )
          {
            if (rowsen[i] == 'R')
            {
              if( rowrng[i] >= 0 )
                {
                  rhs[i] = rowrhs[i] - rowrng[i];
                  rr[i] = rowrng[i];
                }
              else
                {
                  rhs[i] = rowrhs[i];
                  rr[i] = -rowrng[i];
                }
            } 
            else
            {
              rhs[i] = rowrhs[i];
              rr[i] = 0.0;
            }
          }
      } 
      else
      rhs = const_cast<double*>(rowrhs);
      
      bool freeMatrixRequired = false;
      CoinPackedMatrix * m = NULL;
      if ( !matrix.isColOrdered() ) 
      {
        m = new CoinPackedMatrix();
        m->reverseOrderedCopyOf(matrix);
        freeMatrixRequired = true;
      } 
      else 
      m = const_cast<CoinPackedMatrix *>(&matrix);
      
      assert( nc == m->getNumCols() );
      assert( nr == m->getNumRows() );
      assert( m->isColOrdered() ); 
      
      int objDirection = CPXgetobjsen( env_, getMutableLpPtr() );
      
      int err = CPXcopylp( env_, getLpPtr(), 
                     nc, nr,
                     // Leave ObjSense alone(set to current value).
                     objDirection,
                     ob, 
                     rhs,
                     const_cast<char *>(rowsen),
                     const_cast<int *>(m->getVectorStarts()),
                     const_cast<int *>(m->getVectorLengths()),
                     const_cast<int *>(m->getIndices()),
                     const_cast<double *>(m->getElements()),
                     const_cast<double *>(clb), 
                     const_cast<double *>(cub), 
                     rr );
      checkCPXerror( err, "CPXcopylp", "loadProblem" );
            
      if ( collb == NULL )
      delete[] clb;
      if ( colub == NULL ) 
      delete[] cub;
      if ( obj   == NULL )
      delete[] ob;
      if ( rowrng != NULL ) {
      delete[] rr;
      delete[] rhs;
      }
      
      if ( freeMatrixRequired ) 
      delete m;

      resizeColType(nc);
      CoinFillN(coltype_, nc, 'C');

  if (lclRowsen != NULL) delete[] lclRowsen ;
  if (lclRowrhs != NULL) delete[] lclRowrhs ;
}
   
//-----------------------------------------------------------------------------

void
02429 OsiCpxSolverInterface::assignProblem( CoinPackedMatrix*& matrix,
                              double*& collb, double*& colub,
                              double*& obj,
                              char*& rowsen, double*& rowrhs,
                              double*& rowrng )
{
  debugMessage("OsiCpxSolverInterface::assignProblem()\n");

   loadProblem( *matrix, collb, colub, obj, rowsen, rowrhs, rowrng );
   delete matrix;   matrix = 0;
   delete[] collb;  collb = 0;
   delete[] colub;  colub = 0;
   delete[] obj;    obj = 0;
   delete[] rowsen; rowsen = 0;
   delete[] rowrhs; rowrhs = 0;
   delete[] rowrng; rowrng = 0;
}

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

void
02450 OsiCpxSolverInterface::loadProblem(const int numcols, const int numrows,
                           const int* start, const int* index,
                           const double* value,
                           const double* collb, const double* colub,   
                           const double* obj,
                           const double* rowlb, const double* rowub )
{
  debugMessage("OsiCpxSolverInterface::loadProblem(3)()\n");

  const double inf = getInfinity();
  
  char   * rowSense = new char  [numrows];
  double * rowRhs   = new double[numrows];
  double * rowRange = new double[numrows];
  
  for ( int i = numrows - 1; i >= 0; --i ) {
    const double lower = rowlb ? rowlb[i] : -inf;
    const double upper = rowub ? rowub[i] : inf;
    convertBoundToSense( lower, upper, rowSense[i], rowRhs[i], rowRange[i] );
  }

  loadProblem(numcols, numrows, start, index, value, collb, colub, obj,
            rowSense, rowRhs, rowRange);
  delete [] rowSense;
  delete [] rowRhs;
  delete [] rowRange;

}

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

void
02482 OsiCpxSolverInterface::loadProblem(const int numcols, const int numrows,
                           const int* 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 )
{
  debugMessage("OsiCpxSolverInterface::loadProblem(4)(%d, %d, %p, %p, %p, %p, %p, %p, %p, %p, %p)\n",
            numcols, numrows, (void*)start, (void*)index, (void*)value, (void*)collb, (void*)colub, (void*)obj, (void*)rowsen, (void*)rowrhs, (void*)rowrng);

  const int nc = numcols;
  const int nr = numrows;

  if( nr == 0 && nc == 0 ) {
    // empty LP
      if (lp_ != NULL) { // kill old LP 
            int err = CPXfreeprob( env_, &lp_ );
            checkCPXerror( err, "CPXfreeprob", "loadProblem" );
            lp_ = NULL;
            freeAllMemory();
      }
    return;
  }
  
  if (nr == 0) {
    int objDirection = CPXgetobjsen( env_, getMutableLpPtr() );

      if (lp_ != NULL) { // kill old LP 
            int err = CPXfreeprob( env_, &lp_ );
            checkCPXerror( err, "CPXfreeprob", "loadProblem" );
            lp_ = NULL;
            freeAllMemory();
      }
    
      // getLpPtr() call will create new LP
    int err = CPXnewcols( env_, getLpPtr(), nc, obj, collb, colub, NULL, NULL);
    checkCPXerror( err, "CPXcopylp", "loadProblem" );
    
    CPXchgobjsen(env_, getLpPtr(), objDirection);
    
    return;
  }

  char *lclRowsen = NULL ;
  double *lclRowrhs = NULL ;

  if (rowsen == NULL)
  { lclRowsen = new char[nr] ;
    CoinFillN(lclRowsen,nr,'G') ;
    rowsen = lclRowsen ; }
  if (rowrhs == NULL)
  { lclRowrhs = new double[nr] ;
    CoinFillN(lclRowrhs,nr,0.0) ; }
      
  int i;
      
  // Set column values to defaults if NULL pointer passed
  int * len = new int[nc];
  double * clb = new double[nc];  
  double * cub = new double[nc];  
  double * ob = new double[nc];  
  double * rr = new double[nr];
  double * rhs = new double[nr];
  char * sen = new char[nr];
  
  for (i = 0; i < nc; ++i) {
    len[i] = start[i+1] - start[i];
  }

  if ( collb != NULL )
    CoinDisjointCopyN(collb, nc, clb);
  else
    CoinFillN(clb, nc, 0.0);

  if ( colub!=NULL )
    CoinDisjointCopyN(colub, nc, cub);
  else
    CoinFillN(cub, nc, getInfinity());
  
  if ( obj!=NULL )
    CoinDisjointCopyN(obj, nc, ob);
  else
    CoinFillN(ob, nc, 0.0);
  
  if ( rowrng != NULL ) {
    for ( i=0; i<nr; i++ ) {
      if (rowsen[i] == 'R') {
      if ( rowrng[i] >= 0 ) {
        rhs[i] = rowrhs[i] - rowrng[i];
        rr[i] = rowrng[i];
      } else {
        rhs[i] = rowrhs[i];
        rr[i] = -rowrng[i];
      }
      } else {
      rhs[i] = rowrhs[i];
      rr[i] = 0.0;
      }
    }
  } else {
    CoinDisjointCopyN(rowrhs, nr, rhs);
  }

  CoinDisjointCopyN(rowsen, nr, sen);
  
  int objDirection = CPXgetobjsen( env_, getMutableLpPtr() );
      
  int err = CPXcopylp( env_, getLpPtr(), 
                   nc, nr,
                   // Leave ObjSense alone(set to current value).
                   objDirection, ob, rhs, sen,
                   const_cast<int *>(start), 
                   len, const_cast<int *>(index), 
                   const_cast<double *>(value),
                   clb, cub, rr);

  checkCPXerror( err, "CPXcopylp", "loadProblem" );
  
  delete[] len;
  delete[] clb;
  delete[] cub;
  delete[] ob;
  delete[] rr;
  delete[] rhs;
  delete[] sen;

  if (lclRowsen != NULL) delete[] lclRowsen ;
  if (lclRowrhs != NULL) delete[] lclRowrhs ;

  resizeColType(nc);
  CoinFillN(coltype_, nc, 'C');
}
 
//-----------------------------------------------------------------------------
// Read mps files
//-----------------------------------------------------------------------------
02619 int OsiCpxSolverInterface::readMps( const char * filename,
                             const char * extension )
{
  debugMessage("OsiCpxSolverInterface::readMps(%s, %s)\n", filename, extension);

#if 0
  std::string f(filename);
  std::string e(extension);
  std::string fullname = f + "." + e;
  int err = CPXreadcopyprob( env_, getLpPtr(), const_cast<char*>( fullname.c_str() ), NULL );
  checkCPXerror( err, "CPXreadcopyprob", "readMps" );
#endif
  // just call base class method
  return OsiSolverInterface::readMps(filename,extension);
}


//-----------------------------------------------------------------------------
// Write mps files
//-----------------------------------------------------------------------------
02639 void OsiCpxSolverInterface::writeMps( const char * filename,
                              const char * extension,
                              double objSense ) const
{
  debugMessage("OsiCpxSolverInterface::writeMps(%s, %s, %g)\n", filename, extension, objSense);

  // *FIXME* : this will not output ctype information to the MPS file
  char filetype[4] = "MPS";
  std::string f(filename);
  std::string e(extension);
  std::string fullname = f + "." + e;
  int err = CPXwriteprob( env_, getMutableLpPtr(), const_cast<char*>( fullname.c_str() ), filetype );
  checkCPXerror( err, "CPXwriteprob", "writeMps" );
}

02654 void OsiCpxSolverInterface::passInMessageHandler(CoinMessageHandler * handler) {
      int err;
  CPXCHANNELptr cpxresults;
  CPXCHANNELptr cpxwarning;
  CPXCHANNELptr cpxerror;
  CPXCHANNELptr cpxlog;
  err = CPXgetchannels(env_, &cpxresults, &cpxwarning, &cpxerror, &cpxlog);
      checkCPXerror( err, "CPXgetchannels", "gutsOfConstructor" );

      err = CPXdelfuncdest(env_, cpxresults, messageHandler(), OsiCpxMessageCallbackResultLog);
      checkCPXerror( err, "CPXdelfuncdest", "gutsOfConstructor" );
      err = CPXdelfuncdest(env_, cpxlog,     messageHandler(), OsiCpxMessageCallbackResultLog);
      checkCPXerror( err, "CPXdelfuncdest", "gutsOfConstructor" );
      err = CPXdelfuncdest(env_, cpxwarning, messageHandler(), OsiCpxMessageCallbackWarning);
      checkCPXerror( err, "CPXdelfuncdest", "gutsOfConstructor" );
      err = CPXdelfuncdest(env_, cpxerror,   messageHandler(), OsiCpxMessageCallbackError);
      checkCPXerror( err, "CPXdelfuncdest", "gutsOfConstructor" );

      OsiSolverInterface::passInMessageHandler(handler);
      
      err = CPXaddfuncdest(env_, cpxresults, messageHandler(), OsiCpxMessageCallbackResultLog);
      checkCPXerror( err, "CPXaddfuncdest", "gutsOfConstructor" );
      err = CPXaddfuncdest(env_, cpxlog,     messageHandler(), OsiCpxMessageCallbackResultLog);
      checkCPXerror( err, "CPXaddfuncdest", "gutsOfConstructor" );
      err = CPXaddfuncdest(env_, cpxwarning, messageHandler(), OsiCpxMessageCallbackWarning);
      checkCPXerror( err, "CPXaddfuncdest", "gutsOfConstructor" );
      err = CPXaddfuncdest(env_, cpxerror,   messageHandler(), OsiCpxMessageCallbackError);
      checkCPXerror( err, "CPXaddfuncdest", "gutsOfConstructor" );
}

//#############################################################################
// CPX specific public interfaces
//#############################################################################

02688 CPXENVptr OsiCpxSolverInterface::getEnvironmentPtr()
{
  assert( env_ != NULL );
  return env_;
}

CPXLPptr OsiCpxSolverInterface::getLpPtr( int keepCached )
{
  freeCachedData( keepCached );
  return getMutableLpPtr();
}

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

02702 const char * OsiCpxSolverInterface::getCtype() const
{
  debugMessage("OsiCpxSolverInterface::getCtype()\n");

  return coltype_;
}

//#############################################################################
// Constructors, destructors clone and assignment
//#############################################################################

//-------------------------------------------------------------------
// Default Constructor 
//-------------------------------------------------------------------
02716 OsiCpxSolverInterface::OsiCpxSolverInterface()
  : OsiSolverInterface(),
    env_(NULL),
    lp_(NULL),
    hotStartCStat_(NULL),
    hotStartCStatSize_(0),
    hotStartRStat_(NULL),
    hotStartRStatSize_(0),
    hotStartMaxIteration_(1000000), // ??? default iteration limit for strong branching is large
    obj_(NULL),
    collower_(NULL),
    colupper_(NULL),
    rowsense_(NULL),
    rhs_(NULL),
    rowrange_(NULL),
    rowlower_(NULL),
    rowupper_(NULL),
    colsol_(NULL),
    rowsol_(NULL),
    redcost_(NULL),
    rowact_(NULL),
    matrixByRow_(NULL),
    matrixByCol_(NULL),
    coltype_(NULL),
    coltypesize_(0),
    probtypemip_(false)
{
  debugMessage("OsiCpxSolverInterface::OsiCpxSolverInterface()\n");

  gutsOfConstructor();
}


//----------------------------------------------------------------
// Clone
//----------------------------------------------------------------
02752 OsiSolverInterface * OsiCpxSolverInterface::clone(bool copyData) const
{
  debugMessage("OsiCpxSolverInterface::clone(%d)\n", copyData);

  return( new OsiCpxSolverInterface( *this ) );
}

//-------------------------------------------------------------------
// Copy constructor 
//-------------------------------------------------------------------
02762 OsiCpxSolverInterface::OsiCpxSolverInterface( const OsiCpxSolverInterface & source )
  : OsiSolverInterface(source),
    env_(NULL),
    lp_(NULL),
    hotStartCStat_(NULL),
    hotStartCStatSize_(0),
    hotStartRStat_(NULL),
    hotStartRStatSize_(0),
    hotStartMaxIteration_(source.hotStartMaxIteration_),
    obj_(NULL),
    collower_(NULL),
    colupper_(NULL),
    rowsense_(NULL),
    rhs_(NULL),
    rowrange_(NULL),
    rowlower_(NULL),
    rowupper_(NULL),
    colsol_(NULL),
    rowsol_(NULL),
    redcost_(NULL),
    rowact_(NULL),
    matrixByRow_(NULL),
    matrixByCol_(NULL),
    coltype_(NULL),
    coltypesize_(0),
    probtypemip_(false)
{
  debugMessage("OsiCpxSolverInterface::OsiCpxSolverInterface(%p)\n", (void*)&source);

  gutsOfConstructor();
  gutsOfCopy( source );
}


//-------------------------------------------------------------------
// Destructor 
//-------------------------------------------------------------------
02799 OsiCpxSolverInterface::~OsiCpxSolverInterface()
{
  debugMessage("OsiCpxSolverInterface::~OsiCpxSolverInterface()\n");

  gutsOfDestructor();
}

//----------------------------------------------------------------
// Assignment operator 
//-------------------------------------------------------------------
02809 OsiCpxSolverInterface& OsiCpxSolverInterface::operator=( const OsiCpxSolverInterface& rhs )
{
  debugMessage("OsiCpxSolverInterface::operator=(%p)\n", (void*)&rhs);

  if (this != &rhs)
    {    
      OsiSolverInterface::operator=( rhs );
      gutsOfDestructor();
      gutsOfConstructor();
      if ( rhs.lp_ !=NULL )
      gutsOfCopy( rhs );
    }
  return *this;
}

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

02828 void OsiCpxSolverInterface::applyColCut( const OsiColCut & cc )
{
  debugMessage("OsiCpxSolverInterface::applyColCut(%p)\n", (void*)&cc);

  const double * cplexColLB = getColLower();
  const double * cplexColUB = getColUpper();
  const CoinPackedVector & lbs = cc.lbs();
  const CoinPackedVector & ubs = cc.ubs();
  int i;

  for( i = 0; i < lbs.getNumElements(); ++i ) 
    if ( lbs.getElements()[i] > cplexColLB[lbs.getIndices()[i]] )
      setColLower( lbs.getIndices()[i], lbs.getElements()[i] );
  for( i = 0; i < ubs.getNumElements(); ++i )
    if ( ubs.getElements()[i] < cplexColUB[ubs.getIndices()[i]] )
      setColUpper( ubs.getIndices()[i], ubs.getElements()[i] );
}

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

02848 void OsiCpxSolverInterface::applyRowCut( const OsiRowCut & rowCut )
{
  debugMessage("OsiCpxSolverInterface::applyRowCut(%p)\n", (void*)&rowCut);

  int err = 0;
  double rhs = 0.0;
  double rng = 0.0;
  char sns;
  double lb = rowCut.lb();
  double ub = rowCut.ub();
  if( lb <= -getInfinity() && ub >= getInfinity() )   // free constraint
    {
      rhs = -getInfinity();
      rng = 2*getInfinity();  // CPLEX doesn't support free constraints
      sns = 'R';           // -> implement them as ranged rows with infinite bounds
    }
  else if( lb <= -getInfinity() )  // <= constraint
    {
      rhs = ub;
      sns = 'L';
    }
  else if( ub >= getInfinity() )  // >= constraint
    {
      rhs = lb;
      sns = 'G';
    }
  else if( ub == lb )  // = constraint
    {
      rhs = ub;
      sns = 'E';
    }
  else  // range constraint
    {
      rhs = lb;
      rng = ub - lb;
      sns = 'R';
    }
  int rmatbeg = 0;
  err = CPXaddrows( env_, getLpPtr( OsiCpxSolverInterface::KEEPCACHED_COLUMN ), 0, 1, rowCut.row().getNumElements(),
                &rhs, &sns, &rmatbeg, 
                const_cast<int*>( rowCut.row().getIndices() ), 
                const_cast<double*>( rowCut.row().getElements() ),
                NULL, NULL );
  checkCPXerror( err, "CPXaddrows", "applyRowCut" );
  if( sns == 'R' )
    {
      err = CPXchgcoef( env_, getLpPtr( OsiCpxSolverInterface::KEEPCACHED_COLUMN ), 
                  CPXgetnumrows(env_, getLpPtr( OsiCpxSolverInterface::KEEPCACHED_COLUMN ))-1,
                  -2, rng );
      checkCPXerror( err, "CPXchgcoef", "applyRowCut" );
    }
}

//#############################################################################
// Private methods (non-static and static) and static data
//#############################################################################
 
//-------------------------------------------------------------------
// Get pointer to CPXLPptr.
// const methods should use getMutableLpPtr().
// non-const methods should use getLpPtr().
//------------------------------------------------------------------- 
02910 CPXLPptr OsiCpxSolverInterface::getMutableLpPtr() const
{
  if ( lp_ == NULL )
    {
      int err;
      assert(env_ != NULL);
#if 0
      //char pn[] = "OSI_CPLEX";
      lp_ = CPXcreateprob( env_, &err, pn );
#else
      std::string pn;
      getStrParam(OsiProbName,pn);
      lp_ = CPXcreateprob( env_, &err, const_cast<char*>(pn.c_str()) );
#endif
      checkCPXerror( err, "CPXcreateprob", "getMutableLpPtr" );
//      err = CPXchgprobtype(env_,lp_,CPXPROB_LP);
//      checkCPXerror( err, "CPXchgprobtype", "getMutableLpPtr" );
      assert( lp_ != NULL ); 
    }
  return lp_;
}

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

02934 void OsiCpxSolverInterface::gutsOfCopy( const OsiCpxSolverInterface & source )
{
  // Set Objective Sense
  setObjSense(source.getObjSense());

  // Set Rim and constraints
  const double* obj = source.getObjCoefficients();
  const double* rhs = source.getRightHandSide();
  const char* sense = source.getRowSense();
  const CoinPackedMatrix * cols = source.getMatrixByCol();
  const double* lb = source.getColLower();
  const double* ub = source.getColUpper();
  loadProblem(*cols,lb,ub,obj,sense,rhs,source.getRowRange());

  // Set MIP information
  resizeColType(source.coltypesize_);
  CoinDisjointCopyN( source.coltype_, source.coltypesize_, coltype_ );
  
  // Set Solution
  setColSolution(source.getColSolution());
  setRowPrice(source.getRowPrice());

  // Should also copy row and col names.
#if 0
  char** cname = new char*[numcols];
  char* cnamestore = NULL;
  int surplus;
  err = CPXgetcolname( env_, source.lp_, cname, NULL, 0, &surplus, 0, numcols-1 );
  if( err != CPXERR_NO_NAMES )
    {
      cnamestore = new char[-surplus];
      err = CPXgetcolname( env_, source.lp_, cname, cnamestore, -surplus, &surplus, 0, numcols-1 );
      checkCPXerror( err, "CPXgetcolname", "gutsOfCopy" );
      assert( surplus == 0 );
    }
  else
    {
      delete [] cname;
      cname = NULL;
    }
  
  char** rname = new char*[numrows];
  char* rnamestore = NULL;
  err = CPXgetrowname( env_, source.lp_, rname, NULL, 0, &surplus, 0, numrows-1 );
  if( err != CPXERR_NO_NAMES )
    {
      rnamestore = new char[-surplus];
      err = CPXgetrowname( env_, source.lp_, rname, rnamestore, -surplus, &surplus, 0, numrows-1 );
      checkCPXerror( err, "CPXgetrowname", "gutsOfCopy" );
      assert( surplus == 0 );
    }
  else
    {
      delete [] rname;
      rname = NULL;
    }

  err = CPXcopylpwnames( env_, getLpPtr(), 
                   numcols, numrows, objsen, 
                   const_cast<double *>(obj), 
                   const_cast<double *>(rhs), 
                   const_cast<char *>(sense),
                   const_cast<int *>(cols->vectorStarts()),
                   const_cast<int *>(cols->vectorLengths()),
                   const_cast<int *>(cols->indices()),
                   const_cast<double *>(cols->elements()),
                   const_cast<double *>(lb), 
                   const_cast<double *>(ub), 
                   rng, 
                   cname, rname);
  checkCPXerror( err, "CPXcopylpwnames", "gutsOfCopy" );
  
  if( rname != NULL )
    {
      delete [] rnamestore;
      delete [] rname;
    }
  if( cname != NULL )
    {
      delete [] cnamestore;
      delete [] cname;
    }
  delete [] rng;
#endif
 
}

//-------------------------------------------------------------------
03022 void OsiCpxSolverInterface::gutsOfConstructor()
{  
      int err;
#if CPX_VERSION >= 800
      env_ = CPXopenCPLEX( &err );
#else
      env_ = CPXopenCPLEXdevelop( &err );
#endif

      checkCPXerror( err, "CPXopenCPLEXdevelop", "gutsOfConstructor" );
      assert( env_ != NULL );

  CPXCHANNELptr cpxresults;
  CPXCHANNELptr cpxwarning;
  CPXCHANNELptr cpxerror;
  CPXCHANNELptr cpxlog;
  err = CPXgetchannels(env_, &cpxresults, &cpxwarning, &cpxerror, &cpxlog);
      checkCPXerror( err, "CPXgetchannels", "gutsOfConstructor" );
      
      err = CPXaddfuncdest(env_, cpxresults, messageHandler(), OsiCpxMessageCallbackResultLog);
      checkCPXerror( err, "CPXaddfuncdest", "gutsOfConstructor" );
      err = CPXaddfuncdest(env_, cpxlog,     messageHandler(), OsiCpxMessageCallbackResultLog);
      checkCPXerror( err, "CPXaddfuncdest", "gutsOfConstructor" );
      err = CPXaddfuncdest(env_, cpxwarning, messageHandler(), OsiCpxMessageCallbackWarning);
      checkCPXerror( err, "CPXaddfuncdest", "gutsOfConstructor" );
      err = CPXaddfuncdest(env_, cpxerror,   messageHandler(), OsiCpxMessageCallbackError);
      checkCPXerror( err, "CPXaddfuncdest", "gutsOfConstructor" );

      /* turn off all output to screen */
  err = CPXsetintparam( env_, CPX_PARAM_SCRIND, CPX_OFF );
      checkCPXerror( err, "CPXsetintparam", "gutsOfConstructor" );

#if 0
  // CPXcreateprob was moved to getLpPtr() method.
  lp_ = CPXcreateprob( env_, &err, "OSI_CPLEX" );
  checkCPXerror( err, "CPXcreateprob", "gutsOfConstructor" );
//  err = CPXchgprobtype(env_,lp_,CPXPROB_LP);
//  checkCPXerror( err, "CPXchgprobtype", "getMutableLpPtr" );
  assert( lp_ != NULL );
#endif
}

//-------------------------------------------------------------------
03065 void OsiCpxSolverInterface::gutsOfDestructor()
{  
  if ( lp_ != NULL )
    {
      int err = CPXfreeprob( env_, &lp_ );
      checkCPXerror( err, "CPXfreeprob", "gutsOfDestructor" );
      lp_=NULL;
      freeAllMemory();
    }

  if ( env_ != NULL )
  {
      int err = CPXcloseCPLEX( &env_ );
      checkCPXerror( err, "CPXcloseCPLEX", "gutsOfDestructor" );
      env_ = NULL;
  }

  assert( lp_==NULL );
  assert( env_==NULL );
  assert( obj_==NULL );
  assert( collower_==NULL );
  assert( colupper_==NULL );
  assert( rowsense_==NULL );
  assert( rhs_==NULL );
  assert( rowrange_==NULL );
  assert( rowlower_==NULL );
  assert( rowupper_==NULL );
  assert( colsol_==NULL );
  assert( rowsol_==NULL );
  assert( redcost_==NULL );
  assert( rowact_==NULL );
  assert( matrixByRow_==NULL );
  assert( matrixByCol_==NULL );
  assert( coltype_==NULL );
  assert( coltypesize_==0 );
}

//-------------------------------------------------------------------
/// free cached vectors

03105 void OsiCpxSolverInterface::freeCachedColRim()
{
  freeCacheDouble( obj_ );  
  freeCacheDouble( collower_ ); 
  freeCacheDouble( colupper_ ); 
  assert( obj_==NULL );
  assert( collower_==NULL );
  assert( colupper_==NULL );
}

03115 void OsiCpxSolverInterface::freeCachedRowRim()
{
  freeCacheChar( rowsense_ );
  freeCacheDouble( rhs_ );
  freeCacheDouble( rowrange_ );
  freeCacheDouble( rowlower_ );
  freeCacheDouble( rowupper_ );
  assert( rowsense_==NULL ); 
  assert( rhs_==NULL ); 
  assert( rowrange_==NULL ); 
  assert( rowlower_==NULL ); 
  assert( rowupper_==NULL );
 }

03129 void OsiCpxSolverInterface::freeCachedMatrix()
{
  freeCacheMatrix( matrixByRow_ );
  freeCacheMatrix( matrixByCol_ );
  assert( matrixByRow_==NULL ); 
  assert( matrixByCol_==NULL ); 
}

03137 void OsiCpxSolverInterface::freeCachedResults()
{
  freeCacheDouble( colsol_ ); 
  freeCacheDouble( rowsol_ );
  freeCacheDouble( redcost_ );
  freeCacheDouble( rowact_ );
  assert( colsol_==NULL );
  assert( rowsol_==NULL );
  assert( redcost_==NULL );
  assert( rowact_==NULL );
}


03150 void OsiCpxSolverInterface::freeCachedData( int keepCached )
{
  if( !(keepCached & OsiCpxSolverInterface::KEEPCACHED_COLUMN) )
    freeCachedColRim();
  if( !(keepCached & OsiCpxSolverInterface::KEEPCACHED_ROW) )
    freeCachedRowRim();
  if( !(keepCached & OsiCpxSolverInterface::KEEPCACHED_MATRIX) )
    freeCachedMatrix();
  if( !(keepCached & OsiCpxSolverInterface::KEEPCACHED_RESULTS) )
    freeCachedResults();
}

03162 void OsiCpxSolverInterface::freeAllMemory()
{
  freeCachedData();
  if( hotStartCStat_ != NULL )
    delete[] hotStartCStat_;
  if( hotStartRStat_ != NULL )
    delete[] hotStartRStat_;
  hotStartCStat_     = NULL;
  hotStartCStatSize_ = 0;
  hotStartRStat_     = NULL;
  hotStartRStatSize_ = 0;
  freeColType();
}

//#############################################################################
// Resets as if default constructor
void 
03179 OsiCpxSolverInterface::reset()
{
  setInitialData(); // clear base class
      if (lp_ != NULL) { // kill old LP 
            int err = CPXfreeprob( env_, &lp_ );
            checkCPXerror( err, "CPXfreeprob", "loadProblem" );
            lp_ = NULL;
            freeAllMemory();
      }
}
#if CPX_VERSION >= 900
/**********************************************************************/
/* Returns 1 if can just do getBInv etc
   2 if has all OsiSimplex methods
   and 0 if it has none */
int OsiCpxSolverInterface::canDoSimplexInterface() const {
  return  1;
}

/**********************************************************************/
bool OsiCpxSolverInterface::basisIsAvailable() const {
  CPXLPptr lp = getMutableLpPtr();

  int solnmethod, solntype, pfeasind, dfeasind;

  int status = CPXsolninfo (env_, lp, &solnmethod, &solntype,
                      &pfeasind, &dfeasind);
  if(status) {
    return false;
  }
  if(solntype == CPX_BASIC_SOLN) {
    return true;
  }
  return false;
}

/**********************************************************************/
/* CPLEX return codes: 
For cstat:
CPX_AT_LOWER   0 : variable at lower bound 
CPX_BASIC      1 : variable is basic 
CPX_AT_UPPER   2 : variable at upper bound 
CPX_FREE_SUPER 3 : variable free and non-basic 

For rstat:

Non ranged rows:
CPX_AT_LOWER 0 : associated slack/surplus/artificial variable non-basic 
                 at value 0.0 
CPX_BASIC    1 : associated slack/surplus/artificial variable basic 

Ranged rows:
CPX_AT_LOWER 0 : associated slack/surplus/artificial variable non-basic 
                 at its lower bound 
CPX_BASIC    1 : associated slack/surplus/artificial variable basic 
CPX_AT_UPPER 2 : associated slack/surplus/artificial variable non-basic 
                 at upper bound 

Cplex adds a slack with coeff +1 in <= and =, with coeff -1 in >=, slack being
non negative. We switch in order to get a "Clp tableau" where all the
slacks have coeff +1.

If a slack for >= is non basic, invB is not changed; column of the slack in
opt tableau is flipped.

If slack for >= is basic, corresp. row of invB is flipped; whole row of opt 
tableau is flipped; then whole column for the slack in opt tableau is flipped. 
*/

/* Osi return codes:
0: free  
1: basic  
2: upper 
3: lower
*/
void OsiCpxSolverInterface::getBasisStatus(int* cstat, int* rstat) const {
  CPXLPptr lp = getMutableLpPtr();
  int status = CPXgetbase(env_, lp, cstat, rstat);
  if(status) {
    printf("### ERROR: OsiCpxSolverInterface::getBasisStatus(): Unable to get base\n");
    exit(1);
  }

  int ncol = getNumCols();
  int nrow = getNumRows();
  const int objsense = (int)getObjSense();
  const double *dual = getRowPrice();
  const double *row_act = getRowActivity();
  const double *rowLower = getRowLower();
  const double *rowUpper = getRowUpper();

  char *sense = new char[nrow];
  status = CPXgetsense(env_, lp, sense, 0, nrow-1);

  if(status) {
    printf("### ERROR: OsiCpxSolverInterface::getBasisStatus(): Unable to get sense for the rows\n");
    exit(1);
  }

  for(int i=0; i<ncol; i++) {
    switch(cstat[i]) {
    case 0: cstat[i] = 3; break;
    case 1: break;
    case 2: break;
    case 3: cstat[i] = 0; break;
    default: printf("### ERROR: OsiCpxSolverInterface::getBasisStatus(): unknown column status: %d\n", cstat[i]); break;
    }
  }

  if(objsense == 1) {

    for(int i=0; i<nrow; i++) {
      switch(rstat[i]) {
      case 0: 
      rstat[i] = 3;
      
      if(sense[i] == 'E') {
        if(dual[i] > 0) {
          rstat[i] = 2;
        }
      }
      
      if(sense[i] == 'R') {
        if(rowUpper[i] > rowLower[i] + 1e-6) {
          if(row_act[i] < rowUpper[i] - 1e-6) {
            rstat[i] = 2;
          }
        }
        else {
          if(dual[i] > 0) {
            rstat[i] = 2;
          }     
        }
      }
      
      if(sense[i] == 'G') {
        rstat[i] = 2;
      }
      
      break;
      
      case 1: break;
      case 2: 
      if(sense[i] == 'E') {
        if(dual[i] < 0) {
          rstat[i] = 3;
        }
      }

      if(sense[i] == 'R') {
        if(rowUpper[i] > rowLower[i] + 1e-6) {
          if(row_act[i] > rowLower[i] + 1e-6) {
            rstat[i] = 3;
          }
        }
        else {
          if(dual[i] < 0) {
            rstat[i] = 3;
          }     
        }
      }
      
      break;
      default: printf("### ERROR: OsiCpxSolverInterface::getBasisStatus(): unknown row status: %d\n", rstat[i]); break;
      }    
    }
  }
  else { // objsense == -1
    for(int i=0; i<nrow; i++) {
      switch(rstat[i]) {
      case 0: 
      rstat[i] = 3;
      
      if(sense[i] == 'E') {
        if(dual[i] < 0) {
          rstat[i] = 2;
        }
      }
      
      if(sense[i] == 'R') {
        if(rowUpper[i] > rowLower[i] + 1e-6) {
          if(row_act[i] < rowUpper[i] - 1e-6) {
            rstat[i] = 2;
          }
        }
        else {
          if(dual[i] < 0) {
            rstat[i] = 2;
          }     
        }
      }
      
      if(sense[i] == 'G') {
        rstat[i] = 2;
      }
      
      break;
      
      case 1: break;
      case 2: 
      if(sense[i] == 'E') {
        if(dual[i] > 0) {
          rstat[i] = 3;
        }
      }

      if(sense[i] == 'R') {
        if(rowUpper[i] > rowLower[i] + 1e-6) {
          if(row_act[i] > rowLower[i] + 1e-6) {
            rstat[i] = 3;
          }
        }
        else {
          if(dual[i] > 0) {
            rstat[i] = 3;
          }     
        }
      }
      
      break;
      default: printf("### ERROR: OsiCpxSolverInterface::getBasisStatus(): unknown row status: %d\n", rstat[i]); break;
      }    
    }    
  }
  delete[] sense;
}

/**********************************************************************/
void OsiCpxSolverInterface::getBInvARow(int row, double* z, double * slack) 
  const {

  CPXLPptr lp = getMutableLpPtr();

  int nrow = getNumRows();
  int ncol = getNumCols();
  char *sense =new char[nrow];
  int status = CPXgetsense(env_, lp, sense, 0, nrow-1);
  if(status) {
    printf("### ERROR: OsiCpxSolverInterface::getBInvARow(): Unable to get senses for the rows\n");
    exit(1);
  }

  status = CPXbinvarow(env_, lp, row, z);
  if(status) {
    printf("### ERROR: OsiCpxSolverInterface::getBInvARow(): Unable to get row %d of the tableau\n", row);
    exit(1);
  }

  if(slack != NULL) {
    status = CPXbinvrow(env_, lp, row, slack);
    if(status) {
      printf("### ERROR: OsiCpxSolverInterface::getBInvARow(): Unable to get row %d of B inverse\n", row);
      exit(1);
    }

    // slack contains now the row of BInv(cplex);
    // slack(cplex) is obtained by flipping in slack all entries for >= constr
    // slack(clp) is obtained by flipping the same entries in slack(cplex)
    // i.e. slack(clp) is the current slack.

  }

  if(sense[row] == 'G') {
    int *ind_bas = new int[nrow];
    int ind_slack = ncol+row;
    getBasics(ind_bas);
    for(int i=0; i<nrow; i++) {
      if(ind_bas[i] == ind_slack) {  // slack for row is basic; whole row
                                     // must be flipped
      for(int j=0; j<nrow; j++) {
        z[j] = -z[j];
      }
      if(slack != NULL) {
        for(int j=0; j<nrow; j++) {
          slack[j] = -slack[j];
        }
      }
      }
      break;
    }
    delete[] ind_bas;
  }
  delete[] sense;
} /* getBInvARow */

/**********************************************************************/
void OsiCpxSolverInterface::getBInvRow(int row, double* z) const {

  CPXLPptr lp = getMutableLpPtr();

  int nrow = getNumRows();
  int ncol = getNumCols();

  int status = CPXbinvrow(env_, lp, row, z);
  if(status) {
    printf("### ERROR: OsiCpxSolverInterface::getBInvRow(): Unable to get row %d of the basis inverse\n", row);
    exit(1);
  }
  int *ind_bas = new int[nrow];
  getBasics(ind_bas);
  if (ind_bas[row]>=ncol) { // binv row corresponds to a slack variable
      int Arow=ind_bas[row]-ncol; // Arow is the number of the row in the problem matrix which this slack belongs to
    char sense;
    status = CPXgetsense(env_, lp, &sense, Arow, Arow);
    if(status) {
      printf("### ERROR: OsiCpxSolverInterface::getBInvRow(): Unable to get senses for row %d\n", Arow);
      exit(1);
    }
    if(sense == 'G') { // slack has coeff -1 in Cplex; thus row in binv must be flipped 
      for(int j=0; j<nrow; j++) {
        z[j] = -z[j];
      }
    }
  }
  delete[] ind_bas;
/*  
  char sense;
  status = CPXgetsense(env_, lp, &sense, row, row);
  if(status) {
    printf("### ERROR: OsiCpxSolverInterface::getBInvRow(): Unable to get senses for row %d\n", row);
    exit(1);
  }
  
  if(sense == 'G') {
    int *ind_bas = new int[nrow];
    getBasics(ind_bas);

    for(int i=0; i<nrow; i++) {
      int ind_piv = ind_bas[i] - ncol;
      if(ind_piv == row) {  
                           // slack has coeff -1 in Cplex and is basic; 
                           // row of invB must be flipped

      for(int j=0; j<nrow; j++) {
        z[j] = -z[j];
      }
      break;
      }
    }
    delete[] ind_bas;
  }
*/
} /* getBInvRow */
 
/**********************************************************************/
void OsiCpxSolverInterface::getBInvACol(int col, double* vec) const {

  CPXLPptr lp = getMutableLpPtr();

  int status = CPXbinvacol(env_, lp, col, vec);
  if(status) {
    printf("### ERROR: OsiCpxSolverInterface::getBInvACol(): Unable to get column %d of the tableau\n", col);
    exit(1);
  }

  int nrow = getNumRows();
  int ncol = getNumCols();
  char *sense =new char[nrow];
  status = CPXgetsense(env_, lp, sense, 0, nrow-1);
  if(status) {
    printf("### ERROR: OsiCpxSolverInterface::getBInvACol(): Unable to get senses for the rows\n");
    exit(1);
  }
  int *ind_bas = new int[nrow];
  getBasics(ind_bas);

  for(int i=0; i<nrow; i++)
    if(ind_bas[i] > ncol && sense[ind_bas[i]-ncol] == 'G')
      vec[i] = -vec[i];  // slack for row is basic; whole row must be flipped

  delete[] sense;
  delete[] ind_bas;
} /* getBInvACol */ 

/**********************************************************************/
void OsiCpxSolverInterface::getBInvCol(int col, double* vec) const {

  CPXLPptr lp = getMutableLpPtr();

  int status = CPXbinvcol(env_, lp, col, vec);
  if(status) {
    printf("### ERROR: OsiCpxSolverInterface::getBInvCol(): Unable to get column %d of the basis inverse\n", col);
    exit(1);
  }

  int nrow = getNumRows();
  int ncol = getNumCols();
  char *sense =new char[nrow];
  status = CPXgetsense(env_, lp, sense, 0, nrow-1);
  if(status) {
    printf("### ERROR: OsiCpxSolverInterface::getBInvCol(): Unable to get senses for the rows\n");
    exit(1);
  }
  int *ind_bas = new int[nrow];
  getBasics(ind_bas);

  for(int i=0; i<nrow; i++)
    if(ind_bas[i] > ncol && sense[ind_bas[i]-ncol] == 'G')
      vec[i] = -vec[i];  // slack for row i is basic; whole row must be flipped

  delete[] sense;
  delete[] ind_bas;
} /* getBInvCol */

/**********************************************************************/
void OsiCpxSolverInterface::getBasics(int* index) const {
  int ncol = getNumCols();
  int nrow = getNumRows();

  CPXLPptr lp = getMutableLpPtr();

  double *cplex_trash = new double[nrow];
  int status = CPXgetbhead(env_, lp, index, cplex_trash);
  if(status) {
    printf("### ERROR: OsiCpxSolverInterface::getBasics(): Unable to get basis head\n");
    exit(1);
  }

  for(int i=0; i<nrow; i++) {
    if(index[i] < 0) {
      index[i] = ncol - 1 - index[i];
    }
  }
  delete[] cplex_trash;
} /* getBasics */

#else /* not CPX_VERSION >= 900 */

/**********************************************************************/
/* Returns 1 if can just do getBInv etc
   2 if has all OsiSimplex methods
   and 0 if it has none */
03611 int OsiCpxSolverInterface::canDoSimplexInterface() const {
  return  0;
}

/**********************************************************************/
03616 bool OsiCpxSolverInterface::basisIsAvailable() const {
  printf("### ERROR: OsiCpxSolverInterface::basisIsAvailable(): Cplex version lower than 9.0\n");
  exit(1);
  return false;
}

/**********************************************************************/
03623 void OsiCpxSolverInterface::getBasisStatus(int* cstat, int* rstat) const {
  printf("### ERROR: OsiCpxSolverInterface::getBasisStatus(): Cplex version lower than 9.0\n");
  exit(1);
}
  
/**********************************************************************/
03629 void OsiCpxSolverInterface::getBInvARow(int row, double* z, double * slack) 
  const {
  printf("### ERROR: OsiCpxSolverInterface::getBInvARow(): Cplex version lower than 9.0\n");
  exit(1);
} /* getBInvARow */

/**********************************************************************/
03636 void OsiCpxSolverInterface::getBInvRow(int row, double* z) const {
  printf("### ERROR: OsiCpxSolverInterface::getBInvRow(): Cplex version lower than 9.0\n");
  exit(1);
} /* getBInvRow */
 
/**********************************************************************/
03642 void OsiCpxSolverInterface::getBInvACol(int col, double* vec) const {
  printf("### ERROR: OsiCpxSolverInterface::getBInvACol(): Cplex version lower than 9.0\n");
  exit(1);
} /* getBInvACol */ 

/**********************************************************************/
03648 void OsiCpxSolverInterface::getBInvCol(int col, double* vec) const {
  printf("### ERROR: OsiCpxSolverInterface::getBInvCol(): Cplex version lower than 9.0\n");
  exit(1);
} /* getBInvCol */

/**********************************************************************/
03654 void OsiCpxSolverInterface::getBasics(int* index) const {
  printf("### ERROR: OsiCpxSolverInterface::getBasics(): Cplex version lower than 9.0\n");
  exit(1);
} /* getBasics */
#endif /* not CPX_VERSION >= 900 */

Generated by  Doxygen 1.6.0   Back to index