
/* ----------------------------------------------------------------------------------
   Main library of routines for lp_solve v5.0+
   ----------------------------------------------------------------------------------
    Author:        Michel Berkelaar (to v3.2)
                   Kjell Eikland    (v4.0 and forward)
    Contact:       kjell.eikland@broadpark.no
    License terms: LGPL.

    Requires:      (see below)

    Release notes:
    v5.0.0  1 January 2004      First integrated and repackaged version.
    v5.0.1  8 May 2004          Cumulative update since initial release;
                                overall functionality scope maintained.
    v5.1.0  20 July 2004        Reworked lp_solve throughout to fit new
                                flexible matrix storage model.

   ---------------------------------------------------------------------------------- */

/* ---------------------------------------------------------------------------------- */
/* Main library of routines for lp_solve                                              */
/*----------------------------------------------------------------------------------- */
#include <signal.h>
#include <string.h>
#include <float.h>
#include <math.h>

#if LoadInverseLib == TRUE
  #ifdef WIN32
    #include <windows.h>
  #else
    #include <dlfcn.h>
  #endif
#endif


/* ---------------------------------------------------------------------------------- */
/* Include core and support modules via headers                                       */
/* ---------------------------------------------------------------------------------- */
#include "lp_lib.h"
#include "commonlib.h"
#include "lp_utils.h"
#include "lp_matrix.h"
#include "lp_SOS.h"
#include "lp_Hash.h"
#include "lp_MPS.h"
#include "lp_wlp.h"
#include "lp_presolve.h"
#include "lp_scale.h"
#include "lp_simplex.h"
#include "lp_mipbb.h"
#include "lp_report.h"
#include "lp_MDO.h"
#include "lp_bit.h"

#if INVERSE_ACTIVE==INVERSE_LUMOD
  #include "lp_LUMOD.h"
#elif INVERSE_ACTIVE==INVERSE_LUSOL
  #include "lp_LUSOL.h"
#elif INVERSE_ACTIVE==INVERSE_GLPKLU
  #include "lp_glpkLU.h"
#elif INVERSE_ACTIVE==INVERSE_ETAPFI
  #include "lp_etaPFI.h"
#elif INVERSE_ACTIVE==INVERSE_LEGACY
  #include "lp_etaPFI.h"
#endif

#if libBLAS > 0
  #include "myblas.h"
#endif

#ifdef __BORLANDC__
  #pragma hdrstop
  #pragma package(smart_init)
#endif

/* ---------------------------------------------------------------------------------- */
/* Include selected basis inverse routines and price norm scalars                     */
/* ---------------------------------------------------------------------------------- */

#include "lp_price.h"
#include "lp_pricePSE.h"

#ifdef FORTIFY
# include "lp_fortify.h"
#endif

#define sensrejvar TRUE

/* Return lp_solve version information */
void __WINAPI lp_solve_version(int *majorversion, int *minorversion, int *release, int *build)
{
  if(majorversion != NULL)
    (*majorversion) = MAJORVERSION;
  if(minorversion != NULL)
    (*minorversion) = MINORVERSION;
  if(release != NULL)
    (*release) = RELEASE;
  if(build != NULL)
    (*build) = BUILD;
}


/* ---------------------------------------------------------------------------------- */
/* Various interaction elements                                                       */
/* ---------------------------------------------------------------------------------- */

MYBOOL __WINAPI userabort(lprec *lp, int message)
{
  MYBOOL abort;
  int spx_save;

  spx_save = lp->spx_status;
  lp->spx_status = RUNNING;
  if(yieldformessages(lp) != 0) {
    lp->spx_status = USERABORT;
    if(lp->bb_level > 0)
      lp->bb_break = TRUE;
  }
  if((message > 0) && (lp->usermessage != NULL) && (lp->msgmask & message))
    lp->usermessage(lp, lp->msghandle, message);
  abort = (MYBOOL) (lp->spx_status != RUNNING);
  if(!abort)
    lp->spx_status = spx_save;
  return( abort );
}

STATIC int yieldformessages(lprec *lp)
{
  if((lp->sectimeout > 0) &&
     ((timeNow()-lp->timestart)-(REAL)lp->sectimeout>0))
    lp->spx_status = TIMEOUT;

  if(lp->ctrlc != NULL) {
    int retcode = lp->ctrlc(lp, lp->ctrlchandle);
    /* Check for command to restart the B&B */
    if((retcode == ACTION_RESTART) && (lp->bb_level > 1)) {
      lp->bb_break = AUTOMATIC;
      retcode = 0;
    }
    return(retcode);
  }
  else
    return(0);
}

void __WINAPI set_outputstream(lprec *lp, FILE *stream)
{
  if((lp->outstream != NULL) && (lp->outstream != stdout)) {
    if(lp->streamowned)
      fclose(lp->outstream);
    else
      fflush(lp->outstream);
  }
  if(stream == NULL)
    lp->outstream = stdout;
  else
    lp->outstream = stream;
  lp->streamowned = FALSE;
}

MYBOOL __WINAPI set_outputfile(lprec *lp, char *filename)
{
  MYBOOL ok;
  FILE   *output = stdout;

  ok = (MYBOOL) ((filename == NULL) || (*filename == 0) || ((output = fopen(filename,"w")) != NULL));
  if(ok) {
    set_outputstream(lp, output);
    lp->streamowned = (MYBOOL) ((filename != NULL) && (*filename != 0));
#if 1
    if((filename != NULL) && (*filename == 0))
      lp->outstream = NULL;
#endif
  }
  return(ok);
}

REAL __WINAPI time_elapsed(lprec *lp)
{
  if(lp->timeend > 0)
    return(lp->timeend - lp->timestart);
  else
    return(timeNow() - lp->timestart);
}

void __WINAPI put_bb_nodefunc(lprec *lp, lphandleint_intfunc newnode, void *bbnodehandle)
{
  lp->bb_usenode = newnode;
  lp->bb_nodehandle = bbnodehandle;         /* User-specified "owner process ID" */
}
void __WINAPI put_bb_branchfunc(lprec *lp, lphandleint_intfunc newbranch, void *bbbranchhandle)
{
  lp->bb_usebranch = newbranch;
  lp->bb_branchhandle = bbbranchhandle;     /* User-specified "owner process ID" */
}
void __WINAPI put_abortfunc(lprec *lp, lphandle_intfunc newctrlc, void *ctrlchandle)
{
  lp->ctrlc = newctrlc;
  lp->ctrlchandle = ctrlchandle;            /* User-specified "owner process ID" */
}
void __WINAPI put_logfunc(lprec *lp, lphandlestr_func newlog, void *loghandle)
{
  lp->writelog = newlog;
  lp->loghandle = loghandle;                /* User-specified "owner process ID" */
}
void __WINAPI put_msgfunc(lprec *lp, lphandleint_func newmsg, void *msghandle, int mask)
{
  lp->usermessage = newmsg;
  lp->msghandle = msghandle;                /* User-specified "owner process ID" */
  lp->msgmask = mask;
}


/* ---------------------------------------------------------------------------------- */
/* DLL exported function                                                              */
/* ---------------------------------------------------------------------------------- */
lprec * __WINAPI read_MPS(char *filename, int options)
{
  lprec *lp = NULL;
  int typeMPS;

  typeMPS = (options & ~0x07) >> 2;
  if ((typeMPS & (MPSFIXED|MPSFREE)) == 0)
    typeMPS |= MPSFIXED;
  if(MPS_readfile(&lp, filename, typeMPS, options & 0x07))
    return( lp );
  else
    return( NULL );
}
lprec * __WINAPI read_mps(FILE *filename, int options)
{
  lprec *lp = NULL;
  int typeMPS;

  typeMPS = (options & ~0x07) >> 2;
  if ((typeMPS & (MPSFIXED|MPSFREE)) == 0)
    typeMPS |= MPSFIXED;
  if(MPS_readhandle(&lp, filename, typeMPS, options & 0x07))
    return( lp );
  else
    return( NULL );
}
/* #if defined develop */
lprec * __WINAPI read_mpsex(void *userhandle, read_modeldata_func read_modeldata, int options)
{
  lprec *lp = NULL;
  int typeMPS;

  typeMPS = (options & ~0x07) >> 2;
  if ((typeMPS & (MPSFIXED|MPSFREE)) == 0)
    typeMPS |= MPSFIXED;
  if(MPS_readex(&lp, userhandle, read_modeldata, typeMPS, options & 0x07))
    return( lp );
  else
    return( NULL );
}
/* #endif */
lprec * __WINAPI read_freeMPS(char *filename, int options)
{
  lprec *lp = NULL;
  int typeMPS;

  typeMPS = (options & ~0x07) >> 2;
  typeMPS &= ~MPSFIXED;
  typeMPS |= MPSFREE;
  if(MPS_readfile(&lp, filename, typeMPS, options & 0x07))
    return( lp );
  else
    return( NULL );
}
lprec * __WINAPI read_freemps(FILE *filename, int options)
{
  lprec *lp = NULL;
  int typeMPS;

  typeMPS = (options & ~0x07) >> 2;
  typeMPS &= ~MPSFIXED;
  typeMPS |= MPSFREE;
  if(MPS_readhandle(&lp, filename, typeMPS, options & 0x07))
    return( lp );
  else
    return( NULL );
}
/* #if defined develop */
lprec * __WINAPI read_freempsex(void *userhandle, read_modeldata_func read_modeldata, int options)
{
  lprec *lp = NULL;
  int typeMPS;

  typeMPS = (options & ~0x07) >> 2;
  typeMPS &= ~MPSFIXED;
  typeMPS |= MPSFREE;
  if(MPS_readex(&lp, userhandle, read_modeldata, typeMPS, options & 0x07))
    return( lp );
  else
    return( NULL );
}
/* #endif */
MYBOOL __WINAPI write_mps(lprec *lp, char *filename)
{
  return(MPS_writefile(lp, MPSFIXED, filename));
}
MYBOOL __WINAPI write_MPS(lprec *lp, FILE *output)
{
  return(MPS_writehandle(lp, MPSFIXED, output));
}

MYBOOL __WINAPI write_freemps(lprec *lp, char *filename)
{
  return(MPS_writefile(lp, MPSFREE, filename));
}
MYBOOL __WINAPI write_freeMPS(lprec *lp, FILE *output)
{
  return(MPS_writehandle(lp, MPSFREE, output));
}

MYBOOL __WINAPI write_lp(lprec *lp, char *filename)
{
  return(LP_writefile(lp, filename));
}
MYBOOL __WINAPI write_LP(lprec *lp, FILE *output)
{
  return(LP_writehandle(lp, output));
}
#ifndef PARSER_LP
MYBOOL __WINAPI LP_readhandle(lprec **lp, FILE *filename, int verbose, char *lp_name)
{
  return(FALSE);
}
lprec * __WINAPI read_lp(FILE *filename, int verbose, char *lp_name)
{
  return(NULL);
}
lprec * __WINAPI read_LP(char *filename, int verbose, char *lp_name)
{
  return(NULL);
}
#endif

MYBOOL __WINAPI write_basis(lprec *lp, char *filename)
{
  int typeMPS = MPSFIXED;
  return( MPS_writeBAS(lp, typeMPS, filename) );
}
MYBOOL __WINAPI read_basis(lprec *lp, char *filename, char *info)
{
  int typeMPS = MPSFIXED;

  typeMPS = MPS_readBAS(lp, typeMPS, filename, info);

  /* Code basis */
  if(typeMPS) {
    set_action(&lp->spx_action, ACTION_REBASE | ACTION_REINVERT | ACTION_RECOMPUTE);
    lp->basis_valid = TRUE;   /* Do not re-initialize basis on entering Solve */
    lp->var_basic[0] = FALSE; /* Set to signal that this is a non-default basis */
  }
  return( (MYBOOL) typeMPS );
}

/* Write and read lp_solve parameters (placeholders) - see lp_params.c */
void __WINAPI reset_params(lprec *lp)
{
  int mode;

  lp->epsmachine        = DEF_EPSMACHINE;
  lp->epsperturb        = DEF_PERTURB;
  lp->lag_accept        = DEF_LAGACCEPT;
  set_epslevel(lp, EPS_DEFAULT);

  lp->tighten_on_set    = FALSE;
  lp->negrange          = DEF_NEGRANGE;

#if 0
  lp->do_presolve       = PRESOLVE_ROWS | PRESOLVE_COLS | PRESOLVE_MERGEROWS |
                          PRESOLVE_REDUCEGCD |
                          PRESOLVE_ROWDOMINATE;
#else
  lp->do_presolve       = PRESOLVE_NONE;
#endif
  lp->presolveloops     = DEF_MAXPRESOLVELOOPS;

  lp->scalelimit        = DEF_SCALINGLIMIT;
  lp->scalemode         = SCALE_INTEGERS |
#if 0
                          SCALE_POWER2 |
                          SCALE_LOGARITHMIC | SCALE_MEAN;
#else
                          SCALE_LINEAR | SCALE_GEOMETRIC |
                          SCALE_EQUILIBRATE;
#endif

  lp->crashmode         = CRASH_NONE;

  lp->max_pivots        = 0;
  lp->simplex_strategy  = SIMPLEX_DUAL_PRIMAL;
#define PricerDefaultOpt 1
#if PricerDefaultOpt == 1
  mode = PRICER_DEVEX;
#elif PricerDefaultOpt == 2
  mode = PRICER_STEEPESTEDGE;
  mode |= PRICE_TRUENORMINIT;
#else
  mode = PRICER_STEEPESTEDGE | PRICE_PRIMALFALLBACK;
#endif
  mode |= PRICE_ADAPTIVE;
#ifdef EnableRandomizedPricing
  mode |= PRICE_RANDOMIZE;
#endif
  set_pivoting(lp, mode);

  lp->improve           = IMPROVE_DEFAULT;
  lp->anti_degen        = ANTIDEGEN_DEFAULT;

  lp->bb_floorfirst     = BRANCH_AUTOMATIC;
  lp->bb_rule           = NODE_DYNAMICMODE | NODE_GREEDYMODE | NODE_GAPSELECT |
#if 1
                          NODE_PSEUDOCOSTSELECT |
#else
                          NODE_PSEUDOFEASSELECT |
#endif
                          NODE_RCOSTFIXING;
  lp->bb_limitlevel     = DEF_BB_LIMITLEVEL;
  lp->bb_PseudoUpdates  = DEF_PSEUDOCOSTUPDATES;

  lp->bb_heuristicOF    = my_chsign(is_maxim(lp), MAX(DEF_INFINITE, lp->infinite));
  lp->bb_breakOF        = -lp->bb_heuristicOF;

  lp->sectimeout        = 0;
  lp->solutionlimit     = 1;

  set_outputstream(lp, NULL);          /* Set to default output stream */
  lp->verbose           = NORMAL;
  lp->print_sol         = FALSE;       /* Can be FALSE, TRUE, AUTOMATIC (only non-zeros printed) */
  lp->spx_trace         = FALSE;
  lp->lag_trace         = FALSE;
  lp->bb_trace          = FALSE;
}

void __WINAPI unscale(lprec *lp)
{
  undoscale(lp);
}
int __WINAPI solve(lprec *lp)
{
#if defined FPUexception
  catchFPU(_EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW);
#endif

  if(has_BFP(lp)) {
    lp->solvecount++;
    if(is_add_rowmode(lp))
      set_add_rowmode(lp, FALSE);
    return(lin_solve(lp));
  }
  else
    return( NOBFP );
}
void __WINAPI print_lp(lprec *lp)
{
  REPORT_lp(lp);
}
void __WINAPI print_tableau(lprec *lp)
{
  REPORT_tableau(lp);
}
void __WINAPI print_objective(lprec *lp)
{
  REPORT_objective(lp);
}
void __WINAPI print_solution(lprec *lp, int columns)
{
  REPORT_solution(lp, columns);
}
void __WINAPI print_constraints(lprec *lp, int columns)
{
  REPORT_constraints(lp, columns);
}
void __WINAPI print_duals(lprec *lp)
{
  REPORT_duals(lp);
}
void __WINAPI print_scales(lprec *lp)
{
  REPORT_scales(lp);
}
MYBOOL __WINAPI print_debugdump(lprec *lp, char *filename)
{
  return(REPORT_debugdump(lp, filename, (MYBOOL) (get_total_iter(lp) > 0)));
}
void __WINAPI print_str(lprec *lp, char *str)
{
  report(lp, lp->verbose, "%s", str);
}



/* ---------------------------------------------------------------------------------- */
/* Parameter setting and retrieval functions                                          */
/* ---------------------------------------------------------------------------------- */

void __WINAPI set_timeout(lprec *lp, long sectimeout)
{
  lp->sectimeout = sectimeout;
}

long __WINAPI get_timeout(lprec *lp)
{
  return(lp->sectimeout);
}

void __WINAPI set_verbose(lprec *lp, int verbose)
{
  lp->verbose = verbose;
}

int __WINAPI get_verbose(lprec *lp)
{
  return(lp->verbose);
}

void __WINAPI set_print_sol(lprec *lp, int print_sol)
{
  lp->print_sol = print_sol;
}

int __WINAPI get_print_sol(lprec *lp)
{
  return(lp->print_sol);
}

void __WINAPI set_debug(lprec *lp, MYBOOL debug)
{
  lp->bb_trace = debug;
}

MYBOOL __WINAPI is_debug(lprec *lp)
{
  return(lp->bb_trace);
}

void __WINAPI set_trace(lprec *lp, MYBOOL trace)
{
  lp->spx_trace = trace;
}

MYBOOL __WINAPI is_trace(lprec *lp)
{
  return(lp->spx_trace);
}

void __WINAPI set_anti_degen(lprec *lp, int anti_degen)
{
  lp->anti_degen = anti_degen;
}

int __WINAPI get_anti_degen(lprec *lp)
{
  return(lp->anti_degen);
}

MYBOOL __WINAPI is_anti_degen(lprec *lp, int testmask)
{
  return((MYBOOL) ((lp->anti_degen == testmask) || ((lp->anti_degen & testmask) != 0)));
}

void __WINAPI set_presolve(lprec *lp, int presolvemode, int maxloops)
{
  presolvemode &= ~PRESOLVE_REDUCEMIP; /* disable PRESOLVE_REDUCEMIP since it is very rare that this is effective, and also that it adds code complications and delayed presolve effects that are not captured properly. */
  lp->do_presolve = presolvemode;
  lp->presolveloops = maxloops;
}

int __WINAPI get_presolve(lprec *lp)
{
  return(lp->do_presolve);
}

int __WINAPI get_presolveloops(lprec *lp)
{
  if(lp->presolveloops < 0)
    return(DEF_MAXPRESOLVELOOPS);
  else if(lp->presolveloops == 0)
    return(MAXINT32);
  else
    return(lp->presolveloops);
}

MYBOOL __WINAPI is_presolve(lprec *lp, int testmask)
{
  return((MYBOOL) ((lp->do_presolve == testmask) || ((lp->do_presolve & testmask) != 0)));
}

void __WINAPI set_maxpivot(lprec *lp, int maxpivot)
{
  lp->max_pivots = maxpivot;
}

int __WINAPI get_maxpivot(lprec *lp)
{
  return( lp->bfp_pivotmax(lp) );
}

void __WINAPI set_bb_rule(lprec *lp, int bb_rule)
{
  lp->bb_rule = bb_rule;
}

int __WINAPI get_bb_rule(lprec *lp)
{
  return(lp->bb_rule);
}

/* INLINE */ MYBOOL is_bb_rule(lprec *lp, int bb_rule)
{
  return( (MYBOOL) ((lp->bb_rule & NODE_STRATEGYMASK) == bb_rule) );
}

/* INLINE */ MYBOOL is_bb_mode(lprec *lp, int bb_mask)
{
  return( (MYBOOL) ((lp->bb_rule & bb_mask) > 0) );
}

void __WINAPI set_action(int *actionvar, int actionmask)
{
  *actionvar |= actionmask;
}

void __WINAPI clear_action(int *actionvar, int actionmask)
{
  *actionvar &= ~actionmask;
}

MYBOOL __WINAPI is_action(int actionvar, int testmask)
{
  return( (MYBOOL) ((actionvar & testmask) != 0) );
}

void __WINAPI set_bb_depthlimit(lprec *lp, int bb_maxlevel)
{
  lp->bb_limitlevel = bb_maxlevel;
}

int __WINAPI get_bb_depthlimit(lprec *lp)
{
  return(lp->bb_limitlevel);
}

void __WINAPI set_obj_bound(lprec *lp, REAL bb_heuristicOF)
{
  lp->bb_heuristicOF = bb_heuristicOF;
}

REAL __WINAPI get_obj_bound(lprec *lp)
{
  return(lp->bb_heuristicOF);
}

void __WINAPI set_mip_gap(lprec *lp, MYBOOL absolute, REAL mip_gap)
{
  if(absolute)
    lp->mip_absgap = mip_gap;
  else
    lp->mip_relgap = mip_gap;
}

REAL __WINAPI get_mip_gap(lprec *lp, MYBOOL absolute)
{
  if(absolute)
    return(lp->mip_absgap);
  else
    return(lp->mip_relgap);
}

MYBOOL __WINAPI set_var_branch(lprec *lp, int colnr, int branch_mode)
{
  if(colnr > lp->columns || colnr < 1) {
    report(lp, IMPORTANT, "set_var_branch: Column %d out of range\n", colnr);
    return( FALSE );
  }

  if(lp->bb_varbranch == NULL) {
    int i;
    if(branch_mode == BRANCH_DEFAULT)
      return( TRUE );
    allocMYBOOL(lp, &lp->bb_varbranch, lp->columns_alloc, FALSE);
    for(i = 0; i < lp->columns; i++)
      lp->bb_varbranch[i] = BRANCH_DEFAULT;
  }
  lp->bb_varbranch[colnr - 1] = (MYBOOL) branch_mode;
  return( TRUE );
}

int __WINAPI get_var_branch(lprec *lp, int colnr)
{
  if(colnr > lp->columns || colnr < 1) {
    report(lp, IMPORTANT, "get_var_branch: Column %d out of range\n", colnr);
    return(lp->bb_floorfirst);
  }

  if(lp->bb_varbranch == NULL)
    return(lp->bb_floorfirst);
  if(lp->bb_varbranch[colnr - 1] == BRANCH_DEFAULT)
    return(lp->bb_floorfirst);
  else
    return(lp->bb_varbranch[colnr - 1]);
}

static void set_infiniteex(lprec *lp, REAL infinite, MYBOOL init)
{
  int i;

  infinite = fabs(infinite);
  if((init) || is_infinite(lp, lp->bb_heuristicOF))
    lp->bb_heuristicOF = my_chsign(is_maxim(lp), infinite);
  if((init) || is_infinite(lp, lp->bb_breakOF))
    lp->bb_breakOF = my_chsign(is_maxim(lp), -infinite);
  for(i = 0; i <= lp->sum; i++) {
    if((!init) && is_infinite(lp, lp->orig_lowbo[i]))
      lp->orig_lowbo[i] = -infinite;
    if((init) || is_infinite(lp, lp->orig_upbo[i]))
      lp->orig_upbo[i] = infinite;
  }
  lp->infinite = infinite;
}


MYBOOL __WINAPI is_infinite(lprec *lp, REAL value)
{
#if 1
  return( (MYBOOL) (fabs(value) >= lp->infinite) );
#else
  if(fabs(value) >= lp->infinite)
    return( TRUE );
  else
    return( FALSE );
#endif
}

void __WINAPI set_infinite(lprec *lp, REAL infinite)
{
  set_infiniteex(lp, infinite, FALSE);
}

REAL __WINAPI get_infinite(lprec *lp)
{
  return(lp->infinite);
}

void __WINAPI set_epsperturb(lprec *lp, REAL epsperturb)
{
  lp->epsperturb = epsperturb;
}

REAL __WINAPI get_epsperturb(lprec *lp)
{
  return(lp->epsperturb);
}

void __WINAPI set_epspivot(lprec *lp, REAL epspivot)
{
  lp->epspivot = epspivot;
}

REAL __WINAPI get_epspivot(lprec *lp)
{
  return(lp->epspivot);
}

void __WINAPI set_epsint(lprec *lp, REAL epsint)
{
  lp->epsint = epsint;
}

REAL __WINAPI get_epsint(lprec *lp)
{
  return(lp->epsint);
}

void __WINAPI set_epsb(lprec *lp, REAL epsb)
{
  lp->epsprimal = MAX(epsb, lp->epsmachine);
}

REAL __WINAPI get_epsb(lprec *lp)
{
  return(lp->epsprimal);
}

void __WINAPI set_epsd(lprec *lp, REAL epsd)
{
  lp->epsdual = MAX(epsd, lp->epsmachine); /* Mainly used as tolerance for reduced cost */
}

REAL __WINAPI get_epsd(lprec *lp)
{
  return(lp->epsdual);
}

void __WINAPI set_epsel(lprec *lp, REAL epsel)
{
  lp->epsvalue = MAX(epsel, lp->epsmachine);
}

REAL __WINAPI get_epsel(lprec *lp)
{
  return(lp->epsvalue);
}

MYBOOL __WINAPI set_epslevel(lprec *lp, int epslevel)
{
  REAL SPX_RELAX, MIP_RELAX;

  switch(epslevel) {
    case EPS_TIGHT:  SPX_RELAX = 1;
                      MIP_RELAX = 1;
                      break;
    case EPS_MEDIUM: SPX_RELAX = 10;
                      MIP_RELAX = 1;
                      break;
    case EPS_LOOSE:  SPX_RELAX = 100;
                      MIP_RELAX = 10;
                      break;
    case EPS_BAGGY:  SPX_RELAX = 1000;
                      MIP_RELAX = 100;
                      break;
    default:        return( FALSE );
  }
  lp->epsvalue   = SPX_RELAX*DEF_EPSVALUE;
  lp->epsprimal  = SPX_RELAX*DEF_EPSPRIMAL;
  lp->epsdual    = SPX_RELAX*DEF_EPSDUAL;
  lp->epspivot   = SPX_RELAX*DEF_EPSPIVOT;
  lp->epssolution= MIP_RELAX*DEF_EPSSOLUTION;
  lp->epsint     = MIP_RELAX*DEF_EPSINT;
  lp->mip_absgap = MIP_RELAX*DEF_MIP_GAP;
  lp->mip_relgap = MIP_RELAX*DEF_MIP_GAP;

  return( TRUE );
}

void __WINAPI set_scaling(lprec *lp, int scalemode)
{
  lp->scalemode = scalemode;
}

int __WINAPI get_scaling(lprec *lp)
{
  return(lp->scalemode);
}

MYBOOL __WINAPI is_scalemode(lprec *lp, int testmask)
{
  return((MYBOOL) ((lp->scalemode & testmask) != 0));
}

MYBOOL __WINAPI is_scaletype(lprec *lp, int scaletype)
{
  int testtype;

  testtype = lp->scalemode & SCALE_MAXTYPE;
  return((MYBOOL) (scaletype == testtype));
}

void __WINAPI set_scalelimit(lprec *lp, REAL scalelimit)
/* Set the relative scaling convergence criterion for the active scaling mode;
   the integer part specifies the maximum number of iterations (default = 5). */
{
  lp->scalelimit = fabs(scalelimit);
}

REAL __WINAPI get_scalelimit(lprec *lp)
{
  return(lp->scalelimit);
}

MYBOOL __WINAPI is_integerscaling(lprec *lp)
{
  return(is_scalemode(lp, SCALE_INTEGERS));
}

void __WINAPI set_improve(lprec *lp, int improve)
{
  lp->improve = improve;
}

int __WINAPI get_improve(lprec *lp)
{
  return(lp->improve);
}

void __WINAPI set_lag_trace(lprec *lp, MYBOOL lag_trace)
{
  lp->lag_trace = lag_trace;
}

MYBOOL __WINAPI is_lag_trace(lprec *lp)
{
  return(lp->lag_trace);
}

void __WINAPI set_pivoting(lprec *lp, int pivoting)
{
  /* Set new pivoting strategy */
  lp->piv_strategy = pivoting;
  report(lp, DETAILED, "set_pivoting: Pricing strategy set to '%s'\n",
                       get_str_piv_rule(get_piv_rule(lp)));
}

int __WINAPI get_pivoting(lprec *lp)
{
  return( lp->piv_strategy );
}

/* INLINE */ int get_piv_rule(lprec *lp)
{
  return( (lp->piv_strategy | PRICE_STRATEGYMASK) ^ PRICE_STRATEGYMASK );
}

STATIC char *get_str_piv_rule(int rule)
{
  static char *pivotText[PRICER_LASTOPTION+1] =
  {"Bland first index", "Dantzig", "Devex", "Steepest Edge"};

  return( pivotText[rule] );
}

MYBOOL __WINAPI is_piv_rule(lprec *lp, int rule)
{
  return( (MYBOOL) (get_piv_rule(lp) == rule) );
}

MYBOOL __WINAPI is_piv_mode(lprec *lp, int testmask)
{
  return((MYBOOL) (((testmask & PRICE_STRATEGYMASK) != 0) &&
                   ((lp->piv_strategy & testmask) != 0)));
}

void __WINAPI set_break_at_first(lprec *lp, MYBOOL break_at_first)
{
  lp->bb_breakfirst = break_at_first;
}

MYBOOL __WINAPI is_break_at_first(lprec *lp)
{
  return(lp->bb_breakfirst);
}

void __WINAPI set_bb_floorfirst(lprec *lp, int bb_floorfirst)
{
  lp->bb_floorfirst = (MYBOOL) bb_floorfirst;
}

int __WINAPI get_bb_floorfirst(lprec *lp)
{
  return(lp->bb_floorfirst);
}

void __WINAPI set_break_at_value(lprec *lp, REAL break_at_value)
{
  lp->bb_breakOF = break_at_value;
}

REAL __WINAPI get_break_at_value(lprec *lp)
{
  return(lp->bb_breakOF);
}

void __WINAPI set_negrange(lprec *lp, REAL negrange)
{
  if(negrange <= 0)
    lp->negrange = negrange;
  else
    lp->negrange = 0.0;
}

REAL __WINAPI get_negrange(lprec *lp)
{
  return(lp->negrange);
}

int __WINAPI get_max_level(lprec *lp)
{
  return(lp->bb_maxlevel);
}

COUNTER __WINAPI get_total_nodes(lprec *lp)
{
  return(lp->bb_totalnodes);
}

COUNTER __WINAPI get_total_iter(lprec *lp)
{
  return(lp->total_iter + lp->current_iter);
}

REAL __WINAPI get_objective(lprec *lp)
{
  if(lp->spx_status == OPTIMAL)
    ;
  else if(!lp->basis_valid) {
    report(lp, CRITICAL, "get_objective: Not a valid basis\n");
    return(0.0);
  }

  return( lp->best_solution[0] );
}

int __WINAPI get_nonzeros(lprec *lp)
{
  return( mat_nonzeros(lp->matA) );
}

MYBOOL __WINAPI set_mat(lprec *lp, int rownr, int colnr, REAL value)
{
  if((rownr < 0) || (rownr > lp->rows)) {
    report(lp, IMPORTANT, "set_mat: Row %d out of range\n", rownr);
    return( FALSE );
  }
  if((colnr < 1) || (colnr > lp->columns)) {
    report(lp, IMPORTANT, "set_mat: Column %d out of range\n", colnr);
    return( FALSE );
  }

#ifdef DoMatrixRounding
  if(rownr == 0)
    value = roundToPrecision(value, lp->matA->epsvalue);
#endif
  value = scaled_mat(lp, value, rownr, colnr);
  if(rownr == 0) {
    lp->orig_obj[colnr] = my_chsign(is_chsign(lp, rownr), value);
    return( TRUE );
  }
  else
    return( mat_setvalue(lp->matA, rownr, colnr, value, FALSE) );
}

REAL __WINAPI get_working_objective(lprec *lp)
{
  REAL value = 0.0;

  if(!lp->basis_valid)
    report(lp, CRITICAL, "get_working_objective: Not a valid basis\n");
  else if((lp->spx_status == RUNNING) && (lp->solutioncount == 0))
    value = my_chsign(!is_maxim(lp), lp->rhs[0]);
  else
    value = lp->solution[0];

  return(value);
}

REAL __WINAPI get_var_primalresult(lprec *lp, int index)
{
  if((index < 0) || (index > lp->presolve_undo->orig_sum)) {
    report(lp, IMPORTANT, "get_var_primalresult: Index %d out of range\n", index);
    return( 0.0 );
  }
  if((lp->do_presolve & PRESOLVE_LASTMASKMODE) != PRESOLVE_NONE)
    return( lp->full_solution[index] );
  else
    return( lp->best_solution[index] );
}

REAL __WINAPI get_var_dualresult(lprec *lp, int index)
{
  REAL *duals;

  if((index < 0) || (index > lp->presolve_undo->orig_sum)) {
    report(lp, IMPORTANT, "get_var_dualresult: Index %d out of range\n", index);
    return( 0.0 );
  }

  if(index == 0)
    return( lp->best_solution[0] );

  /* Make sure we actually have dual information available */
  if(!get_ptr_sensitivity_rhs(lp, &duals, NULL, NULL))
    return( 0.0 );
  else
    duals = ((lp->full_duals == NULL) ? lp->duals : lp->full_duals);
  return( duals[index] );
}

MYBOOL __WINAPI get_variables(lprec *lp, REAL *var)
{
  if(lp->spx_status == OPTIMAL)
    ;
  else if(!lp->basis_valid) {
    report(lp, CRITICAL, "get_variables: Not a valid basis\n");
    return(FALSE);
  }

  MEMCOPY(var, lp->best_solution + (1 + lp->rows), lp->columns);
  return(TRUE);
}

MYBOOL __WINAPI get_ptr_variables(lprec *lp, REAL **var)
{
  if(lp->spx_status == OPTIMAL)
    ;
  else if(!lp->basis_valid) {
    report(lp, CRITICAL, "get_ptr_variables: Not a valid basis\n");
    return(FALSE);
  }

  if(var != NULL)
   *var = lp->best_solution + (1 + lp->rows);
  return(TRUE);
}

MYBOOL __WINAPI get_constraints(lprec *lp, REAL *constr)
{
  if(lp->spx_status == OPTIMAL)
    ;
  else if(!lp->basis_valid) {
    report(lp, CRITICAL, "get_constraints: Not a valid basis\n");
    return(FALSE);
  }

  MEMCOPY(constr, lp->best_solution + 1, lp->rows);
  return(TRUE);
}

MYBOOL __WINAPI get_ptr_constraints(lprec *lp, REAL **constr)
{
  if(lp->spx_status == OPTIMAL)
    ;
  else if(!lp->basis_valid) {
    report(lp, CRITICAL, "get_ptr_constraints: Not a valid basis\n");
    return(FALSE);
  }

  if(constr != NULL)
   *constr = lp->best_solution + 1;
  return(TRUE);
}

MYBOOL __WINAPI get_sensitivity_rhs(lprec *lp, REAL *duals, REAL *dualsfrom, REAL *dualstill)
{
  REAL *duals0, *dualsfrom0, *dualstill0;

  if(!lp->basis_valid) {
    report(lp, CRITICAL, "get_sensitivity_rhs: Not a valid basis\n");
    return(FALSE);
  }

  if(!get_ptr_sensitivity_rhs(lp,
                              (duals != NULL) ? &duals0 : NULL,
                              (dualsfrom != NULL) ? &dualsfrom0 : NULL,
                              (dualstill != NULL) ? &dualstill0 : NULL))
    return(FALSE);

  if(duals != NULL)
    MEMCOPY(duals, duals0, lp->sum);
  if(dualsfrom != NULL)
    MEMCOPY(dualsfrom, dualsfrom0, lp->sum);
  if(dualstill != NULL)
    MEMCOPY(dualstill, dualstill0, lp->sum);
  return(TRUE);
}

MYBOOL __WINAPI get_ptr_sensitivity_rhs(lprec *lp, REAL **duals, REAL **dualsfrom, REAL **dualstill)
{
  if(!lp->basis_valid) {
    report(lp, CRITICAL, "get_ptr_sensitivity_rhs: Not a valid basis\n");
    return(FALSE);
  }

  if(duals != NULL) {
    if(lp->duals == NULL) {
      if((MIP_count(lp) > 0) && (lp->bb_totalnodes > 0)) {
        report(lp, CRITICAL, "get_ptr_sensitivity_rhs: Sensitivity unknown\n");
        return(FALSE);
      }
      if(!construct_duals(lp))
        return(FALSE);
    }
    *duals = lp->duals + 1;
  }

  if((dualsfrom != NULL) || (dualstill != NULL)) {
    if((lp->dualsfrom == NULL) || (lp->dualstill == NULL)) {
      if((MIP_count(lp) > 0) && (lp->bb_totalnodes > 0)) {
        report(lp, CRITICAL, "get_ptr_sensitivity_rhs: Sensitivity unknown\n");
        return(FALSE);
      }
      construct_sensitivity_duals(lp);
      if((lp->dualsfrom == NULL) || (lp->dualstill == NULL))
        return(FALSE);
    }
    if(dualsfrom != NULL)
      *dualsfrom = lp->dualsfrom + 1;
    if(dualstill != NULL)
      *dualstill = lp->dualstill + 1;
  }
  return(TRUE);
}

MYBOOL __WINAPI get_sensitivity_objex(lprec *lp, REAL *objfrom, REAL *objtill, REAL *objfromvalue, REAL *objtillvalue)
{
  REAL *objfrom0, *objtill0, *objfromvalue0, *objtillvalue0;

  if(!lp->basis_valid) {
    report(lp, CRITICAL, "get_sensitivity_objex: Not a valid basis\n");
    return(FALSE);
  }

  if(!get_ptr_sensitivity_objex(lp, (objfrom != NULL) ? &objfrom0 : NULL,
                                    (objtill != NULL) ? &objtill0 : NULL,
                                    (objfromvalue != NULL) ? &objfromvalue0 : NULL,
                                    (objtillvalue != NULL) ? &objtillvalue0 : NULL))
    return(FALSE);

  if((objfrom != NULL) && (objfrom0 != NULL))
    MEMCOPY(objfrom, objfrom0, lp->columns);
  if((objtill != NULL) && (objtill0 != NULL))
    MEMCOPY(objtill, objtill0, lp->columns);
  if((objfromvalue != NULL) && (objfromvalue0 != NULL))
    MEMCOPY(objfromvalue, objfromvalue0, lp->columns);
  if((objtillvalue != NULL) && (objtillvalue0 != NULL))
    MEMCOPY(objtillvalue, objtillvalue0, lp->columns);
  return(TRUE);
}

MYBOOL __WINAPI get_sensitivity_obj(lprec *lp, REAL *objfrom, REAL *objtill)
{
  return(get_sensitivity_objex(lp, objfrom, objtill, NULL, NULL));
}

MYBOOL __WINAPI get_ptr_sensitivity_objex(lprec *lp, REAL **objfrom, REAL **objtill, REAL **objfromvalue, REAL **objtillvalue)
{
  if(!lp->basis_valid) {
    report(lp, CRITICAL, "get_ptr_sensitivity_objex: Not a valid basis\n");
    return(FALSE);
  }

  if((objfrom != NULL) || (objtill != NULL)) {
    if((lp->objfrom == NULL) || (lp->objtill == NULL)) {
      if((MIP_count(lp) > 0) && (lp->bb_totalnodes > 0)) {
        report(lp, CRITICAL, "get_ptr_sensitivity_objex: Sensitivity unknown\n");
        return(FALSE);
      }
      construct_sensitivity_obj(lp);
      if((lp->objfrom == NULL) || (lp->objtill == NULL))
        return(FALSE);
    }
    if(objfrom != NULL)
      *objfrom = lp->objfrom + 1;
    if(objtill != NULL)
      *objtill = lp->objtill + 1;
  }

  if((objfromvalue != NULL) /* || (objtillvalue != NULL) */) {
    if((lp->objfromvalue == NULL) /* || (lp->objtillvalue == NULL) */) {
      if((MIP_count(lp) > 0) && (lp->bb_totalnodes > 0)) {
        report(lp, CRITICAL, "get_ptr_sensitivity_objex: Sensitivity unknown\n");
        return(FALSE);
      }
      construct_sensitivity_duals(lp);
      if((lp->objfromvalue == NULL) /* || (lp->objtillvalue == NULL) */)
        return(FALSE);
    }
  }

  if(objfromvalue != NULL)
    *objfromvalue = lp->objfromvalue + 1;

  if(objtillvalue != NULL)
    *objtillvalue = NULL /* lp->objtillvalue + 1 */;

  return(TRUE);
}

MYBOOL __WINAPI get_ptr_sensitivity_obj(lprec *lp, REAL **objfrom, REAL **objtill)
{
  return(get_ptr_sensitivity_objex(lp, objfrom, objtill, NULL, NULL));
}

void __WINAPI set_solutionlimit(lprec *lp, int limit)
{
  lp->solutionlimit = limit;
}
int __WINAPI get_solutionlimit(lprec *lp)
{
  return(lp->solutionlimit);
}
int __WINAPI get_solutioncount(lprec *lp)
{
  return(lp->solutioncount);
}

int __WINAPI get_Nrows(lprec *lp)
{
  return(lp->rows);
}

int __WINAPI get_Norig_rows(lprec *lp)
{
  if(lp->varmap_locked)
    return(lp->presolve_undo->orig_rows);
  else
    return(lp->rows);
}

int __WINAPI get_Lrows(lprec *lp)
{
  if(lp->matL == NULL)
    return( 0 );
  else
    return( lp->matL->rows );
}

int __WINAPI get_Ncolumns(lprec *lp)
{
  return(lp->columns);
}

int __WINAPI get_Norig_columns(lprec *lp)
{
  if(lp->varmap_locked)
    return(lp->presolve_undo->orig_columns);
  else
    return(lp->columns);
}


/* ---------------------------------------------------------------------------------- */
/* Core routines for lp_solve                                                         */
/* ---------------------------------------------------------------------------------- */
int __WINAPI get_status(lprec *lp)
{
  return(lp->spx_status);
}

char * __WINAPI get_statustext(lprec *lp, int statuscode)
{
  if (statuscode == NOBFP)             return("No basis factorization package");
  else if (statuscode == DATAIGNORED)  return("Invalid input data provided");
  else if (statuscode == NOMEMORY)     return("Not enough memory available");
  else if (statuscode == NOTRUN)       return("Model has not been optimized");
  else if (statuscode == OPTIMAL)      return("OPTIMAL solution");
  else if (statuscode == SUBOPTIMAL)   return("SUB-OPTIMAL solution");
  else if (statuscode == INFEASIBLE)   return("Model is primal INFEASIBLE");
  else if (statuscode == UNBOUNDED)    return("Model is primal UNBOUNDED");
  else if (statuscode == RUNNING)      return("lp_solve is currently running");
  else if (statuscode == NUMFAILURE)   return("NUMERIC FAILURE encountered");
  else if (statuscode == DEGENERATE)   return("DEGENERATE situation");
  else if (statuscode == USERABORT)    return("User-requested termination");
  else if (statuscode == TIMEOUT)      return("Termination due to timeout");
  else if (statuscode == PRESOLVED)    return("Model solved by presolve");
  else if (statuscode == PROCFAIL)     return("B&B routine failed");
  else if (statuscode == PROCBREAK)    return("B&B routine terminated");
  else if (statuscode == FEASFOUND)    return("Feasible B&B solution found");
  else if (statuscode == NOFEASFOUND)  return("No feasible B&B solution found");
  else if (statuscode == FATHOMED)     return("Fathomed/pruned branch");
  else                                 return("Undefined internal error");
}

MYBOOL __WINAPI is_obj_in_basis(lprec *lp)
{
  return( lp->obj_in_basis );
}

void __WINAPI set_obj_in_basis(lprec *lp, MYBOOL obj_in_basis)
{
  lp->obj_in_basis = (MYBOOL) (obj_in_basis == TRUE);
}

lprec * __WINAPI make_lp(int rows, int columns)
{
  lprec *lp;

# if defined FORTIFY
   /* Fortify_EnterScope(); */
# endif

  if(rows < 0 || columns < 0)
    return(NULL);

  lp = (lprec*) calloc(1, sizeof(*lp));
  if(!lp)
    return(NULL);

  set_lp_name(lp, NULL);
  lp->names_used    = FALSE;
  lp->use_row_names = TRUE;
  lp->use_col_names = TRUE;
  lp->rowcol_name   = NULL;

  /* Do standard initializations ------------------------------------------------------------ */
#if 1
  lp->obj_in_basis  = DEF_OBJINBASIS;
#else
  lp->obj_in_basis  = FALSE;
#endif
  lp->verbose       = NORMAL;
  set_callbacks(lp);
  set_BFP(lp, NULL);
  set_XLI(lp, NULL);
#if libBLAS > 0
  init_BLAS();
#if libBLAS > 1
  if(is_nativeBLAS() && !load_BLAS(libnameBLAS))
    /*report(lp, "make_lp: Could not load external BLAS library '%s'.\n", libnameBLAS)*/;
#endif
#endif

  /* Define the defaults for key user-settable values --------------------------------------- */
  reset_params(lp);

  /* Do other initializations --------------------------------------------------------------- */
  lp->source_is_file    = FALSE;
  lp->model_is_pure     = TRUE;
  lp->model_is_valid    = FALSE;
  lp->spx_status        = NOTRUN;
  lp->lag_status        = NOTRUN;

  lp->workarrays = mempool_create(lp);
  lp->wasPreprocessed   = FALSE;
  lp->wasPresolved      = FALSE;
  presolve_createUndo(lp);

  lp->bb_varactive      = NULL;
  lp->bb_varbranch      = NULL;
  lp->var_priority      = NULL;

  lp->rhsmax            = 0.0;
  lp->bigM              = 0.0;
  lp->bb_deltaOF        = 0.0;

  lp->equalities        = 0;
  lp->fixedvars         = 0;
  lp->int_vars          = 0;
  lp->sc_vars           = 0;

  lp->sos_ints          = 0;
  lp->sos_vars          = 0;
  lp->sos_priority      = NULL;

  lp->rows_alloc        = 0;
  lp->columns_alloc     = 0;
  lp->sum_alloc         = 0;

  lp->rows              = rows;
  lp->columns           = columns;
  lp->sum               = rows + columns;
  varmap_clear(lp);

  lp->matA = mat_create(lp, rows, columns, lp->epsvalue);
  lp->matL = NULL;
  lp->invB = NULL;
  lp->duals = NULL;
  lp->dualsfrom = NULL;
  lp->dualstill = NULL;
  lp->objfromvalue = NULL;
  lp->objfrom = NULL;
  lp->objtill = NULL;

  inc_col_space(lp, columns + 1);
  inc_row_space(lp, rows + 1);

  /* Avoid bound-checker uninitialized variable error */
  lp->orig_lowbo[0] = 0;

  lp->rootbounds = NULL;
  lp->bb_bounds = NULL;
  lp->bb_basis = NULL;

  lp->basis_valid       = FALSE;
  lp->simplex_mode      = SIMPLEX_DYNAMIC;
  lp->scaling_used      = FALSE;
  lp->columns_scaled    = FALSE;
  lp->P1extraDim        = 0;
  lp->P1extraVal        = 0.0;
  lp->bb_strongbranches = 0;
  lp->current_iter      = 0;
  lp->total_iter        = 0;
  lp->current_bswap     = 0;
  lp->total_bswap       = 0;
  lp->solutioncount     = 0;
  lp->solvecount        = 0;

  allocINT(lp, &lp->rejectpivot, DEF_MAXPIVOTRETRY + 1, TRUE);

  set_minim(lp);
  set_infiniteex(lp, DEF_INFINITE, TRUE);

  initPricer(lp);

  /* Call-back routines by KE */
  lp->ctrlc = NULL;
  lp->ctrlchandle = NULL;
  lp->writelog = NULL;
  lp->loghandle = NULL;
  lp->debuginfo = NULL;
  lp->usermessage = NULL;
  lp->msgmask = MSG_NONE;
  lp->msghandle = NULL;

  lp->timecreate = timeNow();

  return(lp);
}

MYBOOL __WINAPI resize_lp(lprec *lp, int rows, int columns)
{
  MYBOOL status = TRUE;

  if(columns > lp->columns)
    status = inc_col_space(lp, columns - lp->columns);
  else
    while(status && (lp->columns > columns)) {
      status = del_column(lp, lp->columns);
    }
  if(status && (rows > lp->rows))
    status = inc_row_space(lp, rows - lp->rows);
  else
    while(status && (lp->rows > rows)) {
      status = del_constraint(lp, lp->rows);
    }
  return( status );
}

void __WINAPI free_lp(lprec **plp)
{
  if(plp != NULL) {
    lprec *lp = *plp;
    if(lp != NULL)
      delete_lp(lp);
    *plp = NULL;
  }
}

void __WINAPI delete_lp(lprec *lp)
{
  if(lp == NULL)
    return;

  FREE(lp->rowcol_name);
  FREE(lp->lp_name);
  FREE(lp->ex_status);
  if(lp->names_used) {
    FREE(lp->row_name);
    FREE(lp->col_name);
    free_hash_table(lp->rowname_hashtab);
    free_hash_table(lp->colname_hashtab);
  }

  mat_free(&lp->matA);
  lp->bfp_free(lp);
#if LoadInverseLib == TRUE
  if(lp->hBFP != NULL)
    set_BFP(lp, NULL);
#endif
#if LoadLanguageLib == TRUE
  if(lp->hXLI != NULL)
    set_XLI(lp, NULL);
#endif

  unset_OF_p1extra(lp);
  FREE(lp->orig_obj);
  FREE(lp->orig_rhs);
  FREE(lp->rhs);
  FREE(lp->var_type);
  set_var_weights(lp, NULL);
  FREE(lp->bb_varbranch);
  FREE(lp->sc_lobound);
  FREE(lp->var_is_free);
  FREE(lp->orig_upbo);
  FREE(lp->orig_lowbo);
  FREE(lp->upbo);
  FREE(lp->lowbo);
  FREE(lp->var_basic);
  FREE(lp->is_basic);
  FREE(lp->is_lower);
  if(lp->bb_PseudoCost != NULL) {
/*    report(lp, SEVERE, "delete_lp: The B&B pseudo-cost array was not cleared on delete\n"); */
    free_pseudocost(lp);
  }
  if(lp->bb_bounds != NULL) {
    report(lp, SEVERE, "delete_lp: The stack of B&B levels was not empty (failed at %.0f nodes)\n",
                       (double) lp->bb_totalnodes);
    unload_BB(lp);
  }
  if(lp->bb_basis != NULL) {
/*    report(lp, SEVERE, "delete_lp: The stack of saved bases was not empty on delete\n"); */
    unload_basis(lp, FALSE);
  }

  FREE(lp->rejectpivot);
  partial_freeBlocks(&(lp->rowblocks));
  partial_freeBlocks(&(lp->colblocks));
  multi_free(&(lp->multivars));
  multi_free(&(lp->longsteps));

  FREE(lp->solution);
  FREE(lp->best_solution);
  FREE(lp->full_solution);

  presolve_freeUndo(lp);
  mempool_free(&(lp->workarrays));

  freePricer(lp);

  FREE(lp->drow);
  FREE(lp->nzdrow);

  FREE(lp->duals);
  FREE(lp->full_duals);
  FREE(lp->dualsfrom);
  FREE(lp->dualstill);
  FREE(lp->objfromvalue);
  FREE(lp->objfrom);
  FREE(lp->objtill);
  FREE(lp->row_type);

  if(lp->sos_vars > 0)
    FREE(lp->sos_priority);
  free_SOSgroup(&(lp->SOS));
  free_SOSgroup(&(lp->GUB));
  freecuts_BB(lp);

  if(lp->scaling_used)
    FREE(lp->scalars);
  if(lp->matL != NULL) {
    FREE(lp->lag_rhs);
    FREE(lp->lambda);
    FREE(lp->lag_con_type);
    mat_free(&lp->matL);
  }
  if(lp->streamowned)
    set_outputstream(lp, NULL);

#if libBLAS > 0
  if(!is_nativeBLAS())
    unload_BLAS();
#endif

  FREE(lp);

# if defined FORTIFY
    /* Fortify_LeaveScope(); */
# endif
}

static MYBOOL get_SOS(lprec *lp, int index, char *name, int *sostype, int *priority, int *count, int *sosvars, REAL *weights)
{
  SOSrec *SOS;

  if((index < 1) || (index > SOS_count(lp)))
    return( FALSE );
  SOS = lp->SOS->sos_list[index-1];
  if(name != NULL)
    strcpy(name, SOS->name);
  if(sostype != NULL)
    *sostype = SOS->type;
  if(priority != NULL)
    *priority = SOS->priority;
  if(count != NULL) {
    *count = SOS->size;
    if(sosvars != NULL) {
      int i;
      for(i = 1; i <= *count; i++) {
        sosvars[i-1] = SOS->members[i];
        if(weights != NULL)
          weights[i-1] = SOS->weights[i];
      }
    }
  }
  return( TRUE );
}

/* Make a copy of the existing model using (mostly) high-level
   construction routines to simplify future maintainance. */
lprec* __WINAPI copy_lp(lprec *lp)
{
  int   i, n, *idx = NULL;
  REAL  hold, *val = NULL, infinite;
  lprec *newlp = NULL;
  char buf[256], ok = FALSE;
  int sostype, priority, count, *sosvars, rows, columns;
  REAL *weights = NULL;

#if 0
  if(lp->wasPresolved)
    return( newlp );
#endif

  rows = get_Nrows(lp);
  columns = get_Ncolumns(lp);

  if(!allocINT(lp, &idx, rows+1, FALSE) ||
     !allocREAL(lp, &val, rows+1, FALSE))
    goto Finish;

  /* Create the new object */
  newlp = make_lp(rows, 0);
  if(newlp == NULL)
    goto Finish;
  if(!resize_lp(newlp, rows, columns))
    goto Finish;
  set_sense(newlp, is_maxim(lp));
  set_use_names(newlp, FALSE, is_use_names(lp, FALSE));
  set_use_names(newlp, TRUE, is_use_names(lp, TRUE));
  if(!set_lp_name(newlp, get_lp_name(lp)))
    goto Finish;
  /* set_algopt(newlp, get_algopt(lp)); */ /* v6 */
  set_verbose(newlp, get_verbose(lp));

  /* Transfer standard simplex parameters */
  set_epspivot(newlp, get_epspivot(lp));
  set_epsel(newlp, get_epsel(lp));
  set_epsb(newlp, get_epsb(lp));
  set_epsd(newlp, get_epsd(lp));
  set_pivoting(newlp, get_pivoting(lp));
  set_negrange(newlp, lp->negrange);
  set_infinite(newlp, get_infinite(lp));
  set_presolve(newlp, get_presolve(lp), get_presolveloops(lp));
  set_scaling(newlp, get_scaling(lp));
  set_scalelimit(newlp, get_scalelimit(lp));
  set_simplextype(newlp, get_simplextype(lp));
  set_epsperturb(newlp, get_epsperturb(lp));
  set_anti_degen(newlp, get_anti_degen(lp));
  set_improve(newlp, get_improve(lp));
  set_basiscrash(newlp, get_basiscrash(lp));
  set_maxpivot(newlp, get_maxpivot(lp));
  set_timeout(newlp, get_timeout(lp));

  /* Transfer MILP parameters */
  set_epsint(newlp, get_epsint(lp));
  set_bb_rule(newlp, get_bb_rule(lp));
  set_bb_depthlimit(newlp, get_bb_depthlimit(lp));
  set_bb_floorfirst(newlp, get_bb_floorfirst(lp));
  set_mip_gap(newlp, TRUE, get_mip_gap(lp, TRUE));
  set_mip_gap(newlp, FALSE, get_mip_gap(lp, FALSE));
  set_break_at_first(newlp, is_break_at_first(lp));
  set_break_at_value(newlp, get_break_at_value(lp));

  /* Set RHS and range */
  infinite = get_infinite(lp);
  for(i = 0; i <= rows; i++) {
    if(i > 0)
      if(!set_constr_type(newlp, i, get_constr_type(lp, i)))
        goto Finish;
    if(!set_rh(newlp, i, get_rh(lp, i)))
      goto Finish;
    if((i > 0) && ((hold = get_rh_range(lp, i)) < infinite))
      if(!set_rh_range(newlp, i, hold))
        goto Finish;
    if(lp->names_used && lp->use_row_names && (lp->row_name[i] != NULL) && (lp->row_name[i]->name != NULL))
      if(!set_row_name(newlp, i, get_row_name(lp, i)))
        goto Finish;
  }

  /* Load the constraint matrix and variable definitions */
  for(i = 1; i <= columns; i++) {
    n = get_columnex(lp, i, val, idx);
    if ((n < 0) || (!add_columnex(newlp, n, val, idx)))
      goto Finish;
    if(is_binary(lp, i)) {
      if (!set_binary(newlp, i, TRUE))
        goto Finish;
    }
    else {
      if(is_int(lp, i))
        if(!set_int(newlp, i, TRUE))
          goto Finish;
      if((hold = get_lowbo(lp, i)) != 0)
        if(!set_lowbo(newlp, i, hold))
          goto Finish;
      if((hold = get_upbo(lp, i)) < infinite)
        if(!set_upbo(newlp, i, hold))
          goto Finish;
    }
    if(is_semicont(lp, i))
      if(!set_semicont(newlp, i, TRUE))
        goto Finish;
    if(lp->names_used && lp->use_col_names && (lp->col_name[i] != NULL) && (lp->col_name[i]->name != NULL))
      if(!set_col_name(newlp, i, get_col_name(lp, i)))
        goto Finish;
  }

  /* copy SOS data */
  for(i = 1; get_SOS(lp, i, buf, &sostype, &priority, &count, NULL, NULL); i++)
    if (count) {
      if(!allocINT(lp, &sosvars, count, FALSE) ||
         !allocREAL(lp, &weights, count, FALSE))
        n = 0;
      else {
        get_SOS(lp, i, buf, &sostype, &priority, &count, sosvars, weights);
        n = add_SOS(newlp, buf, sostype, priority, count, sosvars, weights);
      }
      FREE(weights);
      FREE(sosvars);
      if(n == 0)
        goto Finish;
    }

#if 0
  /* Other parameters set if the source model was previously solved */
  if(lp->solvecount > 0) {
    MEMCOPY(newlp->scalars, lp->scalars, lp->sum+1);
    MEMCOPY(newlp->var_basic, lp->var_basic, rows+1);
    MEMCOPY(newlp->is_basic, lp->is_basic, lp->sum+1);
    MEMCOPY(newlp->is_lower, lp->is_lower, lp->sum+1);
    MEMCOPY(newlp->solution, lp->solution, lp->sum+1);
    if(lp->duals != NULL) {
      allocREAL(newlp, &newlp->duals, newlp->sum_alloc+1, FALSE);
      MEMCOPY(newlp->duals, lp->duals, lp->sum+1);
    }
    newlp->solutioncount = lp->solutioncount;
    newlp->solvecount = lp->solvecount;
  }
#endif

  ok = TRUE;

  /* Clean up before returning */
Finish:
  if(!ok)
    free_lp(&newlp);
  FREE(val);
  FREE(idx);

  return( newlp );
}
MYBOOL __WINAPI dualize_lp(lprec *lp)
{
  int     i, n;
  MATrec  *mat = lp->matA;
  REAL    *item;

  /* Are we allowed to perform the operation? */
  if((MIP_count(lp) > 0) || (lp->solvecount > 0))
    return( FALSE );

  /* Modify sense */
  set_sense(lp, (MYBOOL) !is_maxim(lp));

  /* Transpose matrix and reverse signs */
  n = mat_nonzeros(mat);
  mat_transpose(mat);
  item = &COL_MAT_VALUE(0);
  for(i = 0; i < n; i++, item += matValueStep)
    *item *= -1;

  /* Row-column swap other vectors */
  swapINT(&lp->rows, &lp->columns);
  swapINT(&lp->rows_alloc, &lp->columns_alloc);
  swapREAL(lp->orig_rhs, lp->orig_obj);
  if ((lp->rhs != NULL) && (lp->obj != NULL))
    swapREAL(lp->rhs, lp->obj);

  /* Reallocate storage */
/*
var_type
sc_bound
solution
best_solution
full_solution
duals
*/

  /* Shift variable bounds */
/*
is_basic
orig_upbo
orig_lowbo
scalars
*/

  return( TRUE );
}

/* Optimize memory usage */
STATIC MYBOOL memopt_lp(lprec *lp, int rowextra, int colextra, int nzextra)
{
  MYBOOL status = FALSE;

  if(lp == NULL)
    return( status );

  status = mat_memopt(lp->matA, rowextra, colextra, nzextra) &&
           (++rowextra > 0) && (++colextra > 0) && (++nzextra > 0);

#if 0 /* inc_ routines not well-tested for reduction in size allocation */
  if(status) {
    int colalloc = lp->columns_alloc - MIN(lp->columns_alloc, lp->columns + colextra),
        rowalloc = lp->rows_alloc    - MIN(lp->rows_alloc,    lp->rows + rowextra);

    status = inc_lag_space(lp, rowalloc, FALSE) &&
             inc_row_space(lp, rowalloc) &&
             inc_col_space(lp, colalloc);
  }
#endif

  return( status );
}


/* Utility routine group for constraint and column deletion/insertion
   mapping in relation to the original set of constraints and columns */
STATIC void varmap_lock(lprec *lp)
{
  presolve_fillUndo(lp, lp->rows, lp->columns, TRUE);
  lp->varmap_locked = TRUE;
}
STATIC void varmap_clear(lprec *lp)
{
  presolve_setOrig(lp, 0, 0);
  lp->varmap_locked = FALSE;
}
STATIC MYBOOL varmap_canunlock(lprec *lp)
{
  /* Don't do anything if variables aren't locked yet */
  if(lp->varmap_locked) {
    int i;
    presolveundorec *psundo = lp->presolve_undo;

    /* Check for the obvious */
    if(/*lp->names_used ||
       (psundo->orig_columns != lp->columns) || (psundo->orig_rows != lp->rows)) */
       (psundo->orig_columns > lp->columns) || (psundo->orig_rows > lp->rows))
      return( FALSE );

    /* Check for deletions */
    for(i = psundo->orig_rows + psundo->orig_columns; i > 0; i--)
      if(psundo->orig_to_var[i] == 0)
        return( FALSE );

    /* Check for insertions */
    for(i = lp->sum; i > 0; i--)
      if(psundo->var_to_orig[i] == 0)
        return( FALSE );
  }
  return( TRUE );
}
STATIC void varmap_add(lprec *lp, int base, int delta)
{
  int i, ii;
  presolveundorec *psundo = lp->presolve_undo;

  /* Don't do anything if variables aren't locked yet */
  if(!lp->varmap_locked)
    return;

  /* Set new constraints/columns to have an "undefined" mapping to original
     constraints/columns (assumes that counters have NOT yet been updated) */
  for(i = lp->sum; i >= base; i--) {
    ii = i + delta;
    psundo->var_to_orig[ii] = psundo->var_to_orig[i];
  }

  /* Initialize map of added rows/columns */
  for(i = 0; i < delta; i++) {
    ii = base + i;
    psundo->var_to_orig[ii] = 0;
  }
}

STATIC void varmap_delete(lprec *lp, int base, int delta, LLrec *varmap)
{
  int             i, ii, j;
  MYBOOL          preparecompact = (MYBOOL) (varmap != NULL);
  presolveundorec *psundo = lp->presolve_undo;

  /* Set the model "dirty" if we are deleting row of constraint */
  lp->model_is_pure &= (MYBOOL) ((lp->solutioncount == 0) && !preparecompact);

  /* Don't do anything if
     1) variables aren't locked yet, or
     2) the constraint was added after the variables were locked */
  if(!lp->varmap_locked) {
#if 0
   if(lp->names_used)
     varmap_lock(lp);
   else
     return;
#else
    if(!lp->model_is_pure && lp->names_used)
      varmap_lock(lp);
#endif
  }

  /* Do mass deletion via a linked list */
  preparecompact = (MYBOOL) (varmap != NULL);
  if(preparecompact) {
    preparecompact = (MYBOOL) (base > lp->rows);  /* Set TRUE for columns */
    for(j = firstInactiveLink(varmap); j != 0; j = nextInactiveLink(varmap, j)) {
      i = j;
      if(preparecompact) {
#ifdef Paranoia
        if(SOS_is_member(lp->SOS, 0, j))
          report(lp, SEVERE, "varmap_delete: Deleting variable %d, which is in a SOS!\n", j);
#endif
        i += lp->rows;
      }
      ii = psundo->var_to_orig[i];
      if(ii > 0)  /* It was an original variable; reverse sign of index to flag deletion */
        psundo->var_to_orig[i] = -ii;
      else        /* It was a non-original variable; add special code for deletion */
        psundo->var_to_orig[i] = -(psundo->orig_rows+psundo->orig_columns+i);
    }
    return;
  }

  /* Do legacy simplified version if we are doing batch delete operations */
  preparecompact = (MYBOOL) (base < 0);
  if(preparecompact) {
    base = -base;
    if(base > lp->rows)
      base += (psundo->orig_rows - lp->rows);
    for(i = base; i < base-delta; i++) {
      ii = psundo->var_to_orig[i];
      if(ii > 0)  /* It was an original variable; reverse sign of index to flag deletion */
        psundo->var_to_orig[i] = -ii;
      else       /* It was a non-original variable; add special code for deletion */
        psundo->var_to_orig[i] = -(psundo->orig_rows+psundo->orig_columns+i);
    }
    return;
  }

  /* We are deleting an original constraint/column;
     1) clear mapping of original to deleted
     2) shift the deleted variable to original mappings left
     3) decrement all subsequent original-to-current pointers
  */
  if(varmap_canunlock(lp))    lp->varmap_locked = FALSE;
  for(i = base; i < base-delta; i++) {
    ii = psundo->var_to_orig[i];
    if(ii > 0)
      psundo->orig_to_var[ii] = 0;
  }
  for(i = base; i <= lp->sum+delta; i++) {
    ii = i - delta;
    psundo->var_to_orig[i] = psundo->var_to_orig[ii];
  }

  i = 1;
  j = psundo->orig_rows;
  if(base > lp->rows) {
    i += j;
    j += psundo->orig_columns;
  }
  ii = base-delta;
  for(; i <= j; i++) {
    if(psundo->orig_to_var[i] >= ii)
      psundo->orig_to_var[i] += delta;
  }

}

STATIC MYBOOL varmap_validate(lprec *lp, int varno)
{
  MYBOOL success = TRUE;
  int i, ii, ix, ie,
       n_rows = lp->rows,
       orig_sum = lp->presolve_undo->orig_sum,
       orig_rows = lp->presolve_undo->orig_rows;

  if(varno <= 0) {
    varno = 1;
    ie = orig_sum;
  }
  else
    ie = varno;
  for(i = varno; success && (i <= ie); i++) {
    ix = lp->presolve_undo->orig_to_var[i];
    if((ix > 0) && (i > orig_rows))
      ix += n_rows;

    /* Check for index out of range due to presolve */
    success = (MYBOOL) (ix <= orig_sum);
    if(!success)
      report(lp, SEVERE, "varmap_validate: Invalid new mapping found for variable %d\n",
                           i);
    else if(ix != 0) {
      ii = lp->presolve_undo->var_to_orig[ix];
      if(ix > n_rows)
        ii += orig_rows;
      success = (MYBOOL) (ii == i);
      if(!success)
        report(lp, SEVERE, "varmap_validate: Invalid old mapping found for variable %d (%d)\n",
                           i, ii);
    }
  }
  return( success );
}

STATIC void varmap_compact(lprec *lp, int prev_rows, int prev_cols)
{
  presolveundorec *psundo = lp->presolve_undo;
  int             i, ii, n_sum, n_rows,
                  orig_rows = psundo->orig_rows,
                  prev_sum = prev_rows + prev_cols;

  /* Nothing to do if the model is not "dirty" or the variable map is not locked */
  if(lp->model_is_pure || !lp->varmap_locked)
    return;

  /* We are deleting an original constraint/column;
     1) clear mapping of original to deleted
     2) shift the deleted variable to original mappings left
     3) decrement all subsequent original-to-current pointers
  */
  n_sum = 0;
  n_rows = 0;
  for(i = 1; i <= prev_sum; i++) {
    ii = psundo->var_to_orig[i];

    /* Process variable if it was deleted in the previous round */
    if(ii < 0) {
      ii = -ii;
      /* Update map back if we have an original variable, otherwise just skip */
      if(i <= prev_rows)
        psundo->orig_to_var[ii] = 0;
      else
        psundo->orig_to_var[orig_rows+ii] = 0;
    }
    /* Otherwise shift and update map back */
    else {
      n_sum++;
      /* Shift only if necessary */
      if(n_sum < i)
        psundo->var_to_orig[n_sum] = ii;
      /* Update map back if we have an original variable */
      if(ii > 0) {
        if(i <= prev_rows) {
          psundo->orig_to_var[ii] = n_sum;
          n_rows = n_sum;
        }
        else
          psundo->orig_to_var[orig_rows+ii] = n_sum-n_rows;
      }
    }
  }
#ifdef xxParanoia
  if(!varmap_validate(lp, 0))
    report(lp, SEVERE, "varmap_compact: Internal presolve mapping error at exit\n");
#endif

}

/* Utility group for shifting row and column data */
STATIC MYBOOL shift_rowcoldata(lprec *lp, int base, int delta, LLrec *usedmap, MYBOOL isrow)
/* Note: Assumes that "lp->sum" and "lp->rows" HAVE NOT been updated to the new counts */
{
  int  i, ii;
  REAL lodefault;

  /* Shift data right/down (insert), and set default values in positive delta-gap */
  if(delta > 0) {

    /* Determine if we can take the easy way out */
    MYBOOL easyout = (MYBOOL) ((lp->solvecount == 0) && (base > lp->rows));

    /* Shift the row/column data */

    MEMMOVE(lp->orig_upbo + base + delta, lp->orig_upbo + base, lp->sum - base + 1);
    MEMMOVE(lp->orig_lowbo + base + delta, lp->orig_lowbo + base, lp->sum - base + 1);

    if(!easyout) {
      MEMMOVE(lp->upbo + base + delta, lp->upbo + base, lp->sum - base + 1);
      MEMMOVE(lp->lowbo + base + delta, lp->lowbo + base, lp->sum - base + 1);
      if(lp->model_is_valid) {
        MEMMOVE(lp->solution + base + delta, lp->solution + base, lp->sum - base + 1);
        MEMMOVE(lp->best_solution + base + delta, lp->best_solution + base, lp->sum - base + 1);
      }
      MEMMOVE(lp->is_lower + base + delta, lp->is_lower + base, lp->sum - base + 1);
    }

    /* Deal with scalars; the vector can be NULL */
    if(lp->scalars != NULL) {
      if(!easyout)
        for(ii = lp->sum; ii >= base; ii--) {
          i = ii + delta;
          lp->scalars[i] = lp->scalars[ii];
        }
      for(ii = base; ii < base + delta; ii++)
        lp->scalars[ii] = 1;
    }

    /* Set defaults */
#ifdef SlackInitMinusInf
    if(isrow)
      lodefault = -lp->infinite;
    else
#endif
      lodefault = 0;

    for(i = 0; i < delta; i++) {
      ii = base + i;
      lp->orig_upbo[ii] = lp->infinite;
      lp->orig_lowbo[ii] = lodefault;
      if(!easyout) {
        lp->upbo[ii] = lp->orig_upbo[ii];
        lp->lowbo[ii] = lp->orig_lowbo[ii];
        lp->is_lower[ii] = TRUE;
      }
    }
  }

  /* Shift data left/up (delete) */
  else if(usedmap != NULL) {
    int k, offset = 0;
    if(!isrow)
      offset += lp->rows;
    i = offset + 1;
    for(k = firstActiveLink(usedmap); k != 0;
        i++, k = nextActiveLink(usedmap, k)) {
      ii = k + offset;
      if(ii == i)
        continue;
      lp->upbo[i] = lp->upbo[ii];
      lp->orig_upbo[i] = lp->orig_upbo[ii];
      lp->lowbo[i] = lp->lowbo[ii];
      lp->orig_lowbo[i] = lp->orig_lowbo[ii];
      lp->solution[i] = lp->solution[ii];
      lp->best_solution[i] = lp->best_solution[ii];
      lp->is_lower[i] = lp->is_lower[ii];
      if(lp->scalars != NULL)
        lp->scalars[i] = lp->scalars[ii];
    }
    if(isrow) {
      base = lp->rows + 1;
      MEMMOVE(lp->upbo + i, lp->upbo + base, lp->columns);
      MEMMOVE(lp->orig_upbo + i, lp->orig_upbo + base, lp->columns);
      MEMMOVE(lp->lowbo + i, lp->lowbo + base, lp->columns);
      MEMMOVE(lp->orig_lowbo + i, lp->orig_lowbo + base, lp->columns);
      if(lp->model_is_valid) {
        MEMMOVE(lp->solution + i, lp->solution + base, lp->columns);
        MEMMOVE(lp->best_solution + i, lp->best_solution + base, lp->columns);
      }
      MEMMOVE(lp->is_lower + i, lp->is_lower + base, lp->columns);
      if(lp->scalars != NULL)
        MEMMOVE(lp->scalars + i, lp->scalars + base, lp->columns);
    }
  }

  else if(delta < 0) {

    /* First make sure we don't cross the sum count border */
    if(base-delta-1 > lp->sum)
      delta = base - lp->sum - 1;

    /* Shift the data*/
    for(i = base; i <= lp->sum + delta; i++) {
      ii = i - delta;
      lp->upbo[i] = lp->upbo[ii];
      lp->orig_upbo[i] = lp->orig_upbo[ii];
      lp->lowbo[i] = lp->lowbo[ii];
      lp->orig_lowbo[i] = lp->orig_lowbo[ii];
      lp->solution[i] = lp->solution[ii];
      lp->best_solution[i] = lp->best_solution[ii];
      lp->is_lower[i] = lp->is_lower[ii];
      if(lp->scalars != NULL)
        lp->scalars[i] = lp->scalars[ii];
    }

  }

  lp->sum += delta;

  lp->matA->row_end_valid = FALSE;

  return(TRUE);
}

STATIC MYBOOL shift_basis(lprec *lp, int base, int delta, LLrec *usedmap, MYBOOL isrow)
/* Note: Assumes that "lp->sum" and "lp->rows" HAVE NOT been updated to the new counts */
{
  int i, ii;
  MYBOOL Ok = TRUE;

  /* Don't bother to shift the basis if it is not yet ready */
  if(!is_BasisReady(lp))
    return( Ok );

  /* Basis adjustments due to insertions (after actual row/column insertions) */
  if(delta > 0) {

    /* Determine if the basis becomes invalidated */
    if(isrow)
      set_action(&lp->spx_action, ACTION_REBASE | ACTION_REINVERT);

    /* Shift and fix invalid basis references (increment higher order basic variable index) */
    if(base <= lp->sum)
      MEMMOVE(lp->is_basic + base + delta, lp->is_basic + base, lp->sum - base + 1);

    /* Prevent CPU-expensive basis updating if this is the initial model creation */
    if(!lp->model_is_pure || (lp->solvecount > 0))
      for(i = 1; i <= lp->rows; i++) {
        ii = lp->var_basic[i];
        if(ii >= base)
          lp->var_basic[i] += delta;
      }

    /* Update the basis (shift and extend) */
    for(i = 0; i < delta; i++) {
      ii = base + i;
      lp->is_basic[ii] = isrow;
      if(isrow)
        lp->var_basic[lp->rows+1+i] = ii;
    }

  }
  /* Basis adjustments due to deletions (after actual row/column deletions) */
  else {
    int j,k;

    /* Fix invalid basis references (decrement high basic slack variable indexes),
       but reset the entire basis if a deleted variable is found in the basis */
    k = 0;
    for(i = 1; i <= lp->rows; i++) {
      ii = lp->var_basic[i];
      lp->is_basic[ii] = FALSE;
      if(ii >= base) {
       /* Skip to next basis variable if this one is to be deleted */
        if(ii < base-delta) {
          set_action(&lp->spx_action, ACTION_REBASE);
          continue;
        }
       /* Otherwise, update the index of the basic variable for deleted variables */
        ii += delta;
      }
      k++;
      lp->var_basic[k] = ii;
    }

    /* Set the new basis indicators */
    i = k;
    if(isrow)
      i = MIN(k, lp->rows+delta);
    for(; i > 0; i--) {
      j = lp->var_basic[i];
      lp->is_basic[j] = TRUE;
    }

    /* If a column was deleted from the basis then simply add back a non-basic
       slack variable; do two scans, if necessary to avoid adding equality slacks */
    if(!isrow && (k < lp->rows)) {
      for(j = 0; j <= 1; j++)
      for(i = 1; (i <= lp->rows) && (k < lp->rows); i++)
        if(!lp->is_basic[i]) {
          if(!is_constr_type(lp, i, EQ) || (j == 1)) {
            k++;
            lp->var_basic[k] = i;
            lp->is_basic[i] = TRUE;
          }
        }
      k = 0;
    }

    /* We are left with "k" indexes; if no basis variable was deleted, k=rows and the
       inverse is still valid, if k+delta < 0 we do not have a valid
       basis and must create one (in most usage modes this should not happen,
       unless there is a bug) */
    if(k+delta < 0)
      Ok = FALSE;
    if(isrow || (k != lp->rows))
      set_action(&lp->spx_action, ACTION_REINVERT);

  }
  return(Ok);

}

STATIC MYBOOL shift_rowdata(lprec *lp, int base, int delta, LLrec *usedmap)
/* Note: Assumes that "lp->rows" HAS NOT been updated to the new count */
{
  int i, ii;

  /* Shift sparse matrix row data */
  if(lp->matA->is_roworder)
    mat_shiftcols(lp->matA, &base, delta, usedmap);
  else
    mat_shiftrows(lp->matA, &base, delta, usedmap);

  /* Shift data down (insert row), and set default values in positive delta-gap */
  if(delta > 0) {

    /* Shift row data */
    for(ii = lp->rows; ii >= base; ii--) {
      i = ii + delta;
      lp->orig_rhs[i] = lp->orig_rhs[ii];
      lp->rhs[i] = lp->rhs[ii];
      lp->row_type[i] = lp->row_type[ii];
    }

    /* Set defaults (actual basis set in separate procedure) */
    for(i = 0; i < delta; i++) {
      ii = base + i;
      lp->orig_rhs[ii] = 0;
      lp->rhs[ii] = 0;
      lp->row_type[ii] = ROWTYPE_EMPTY;
    }
  }

  /* Shift data up (delete row) */
  else if(usedmap != NULL) {
    for(i = 1, ii = firstActiveLink(usedmap); ii != 0;
        i++, ii = nextActiveLink(usedmap, ii)) {
      if(i == ii)
        continue;
      lp->orig_rhs[i] = lp->orig_rhs[ii];
      lp->rhs[i] = lp->rhs[ii];
      lp->row_type[i] = lp->row_type[ii];
    }
    delta = i - lp->rows - 1;
  }
  else if(delta < 0) {

    /* First make sure we don't cross the row count border */
    if(base-delta-1 > lp->rows)
      delta = base - lp->rows - 1;

    /* Shift row data (don't shift basis indexes here; done in next step) */
    for(i = base; i <= lp->rows + delta; i++) {
      ii = i - delta;
      lp->orig_rhs[i] = lp->orig_rhs[ii];
      lp->rhs[i] = lp->rhs[ii];
      lp->row_type[i] = lp->row_type[ii];
    }
  }

  shift_basis(lp, base, delta, usedmap, TRUE);
  shift_rowcoldata(lp, base, delta, usedmap, TRUE);
  inc_rows(lp, delta);

  return(TRUE);
}

STATIC MYBOOL shift_coldata(lprec *lp, int base, int delta, LLrec *usedmap)
/* Note: Assumes that "lp->columns" has NOT been updated to the new count */
{
  int i, ii;

  if(lp->bb_totalnodes == 0)
    free_duals(lp);

  /* Shift A matrix data */
  if(lp->matA->is_roworder)
    mat_shiftrows(lp->matA, &base, delta, usedmap);
  else
    mat_shiftcols(lp->matA, &base, delta, usedmap);

  /* Shift data right (insert), and set default values in positive delta-gap */
  if(delta > 0) {

    /* Fix variable priority data */
    if((lp->var_priority != NULL) && (base <= lp->columns)) {
      for(i = 0; i < lp->columns; i++)
        if(lp->var_priority[i] >= base)
          lp->var_priority[i] += delta;
    }
    if((lp->sos_priority != NULL) && (base <= lp->columns)) {
      for(i = 0; i < lp->sos_vars; i++)
        if(lp->sos_priority[i] >= base)
          lp->sos_priority[i] += delta;
    }

    /* Fix invalid split variable data */
    if((lp->var_is_free != NULL) && (base <= lp->columns)) {
      for(i = 1; i <= lp->columns; i++)
        if(abs(lp->var_is_free[i]) >= base)
          lp->var_is_free[i] += my_chsign(lp->var_is_free[i] < 0, delta);
    }

    /* Shift column data right */
    for(ii = lp->columns; ii >= base; ii--) {
      i = ii + delta;
      lp->var_type[i] = lp->var_type[ii];
      lp->sc_lobound[i] = lp->sc_lobound[ii];
      lp->orig_obj[i] = lp->orig_obj[ii];
      if(lp->obj != NULL)
        lp->obj[i] = lp->obj[ii];
/*
      if(lp->objfromvalue != NULL)
        lp->objfromvalue[i] = lp->objfromvalue[ii];
      if(lp->objfrom != NULL)
        lp->objfrom[i] = lp->objfrom[ii];
      if(lp->objtill != NULL)
        lp->objtill[i] = lp->objtill[ii];
*/
      if(lp->var_priority != NULL)
        lp->var_priority[i-1] = lp->var_priority[ii-1];
      if(lp->bb_varbranch != NULL)
        lp->bb_varbranch[i-1] = lp->bb_varbranch[ii-1];
      if(lp->var_is_free != NULL)
        lp->var_is_free[i] = lp->var_is_free[ii];
      if(lp->best_solution != NULL)
        lp->best_solution[lp->rows + i] = lp->best_solution[lp->rows + ii];
    }

    /* Set defaults */
    for(i = 0; i < delta; i++) {
      ii = base + i;
      lp->var_type[ii] = ISREAL;
      lp->sc_lobound[ii] = 0;
      lp->orig_obj[ii] = 0;
      if(lp->obj != NULL)
        lp->obj[ii] = 0;
/*
      if(lp->objfromvalue != NULL)
        lp->objfromvalue[ii] = 0;
      if(lp->objfrom != NULL)
        lp->objfrom[ii] = 0;
      if(lp->objtill != NULL)
        lp->objtill[ii] = 0;
*/
      if(lp->var_priority != NULL)
        lp->var_priority[ii-1] = ii;
      if(lp->bb_varbranch != NULL)
        lp->bb_varbranch[ii-1] = BRANCH_DEFAULT;
      if(lp->var_is_free != NULL)
        lp->var_is_free[ii] = 0;
      if(lp->best_solution != NULL)
        lp->best_solution[lp->rows + ii] = 0;
    }
  }

  /* Shift data left (delete) */
  else if(usedmap != NULL) {
    /* Assume there is no need to handle split columns, since we are doing
       this only from presolve, which comes before splitting of columns. */

    /* First update counts */
    if(lp->int_vars + lp->sc_vars > 0)
    for(ii = firstInactiveLink(usedmap); ii != 0; ii = nextInactiveLink(usedmap, ii)) {
      if(is_int(lp, ii)) {
        lp->int_vars--;
        if(SOS_is_member(lp->SOS, 0, ii))
          lp->sos_ints--;
      }
      if(is_semicont(lp, ii))
        lp->sc_vars--;
    }
    /* Shift array members */
    for(i = 1, ii = firstActiveLink(usedmap); ii != 0;
        i++, ii = nextActiveLink(usedmap, ii)) {
      if(i == ii)
        continue;
      lp->var_type[i] = lp->var_type[ii];
      lp->sc_lobound[i] = lp->sc_lobound[ii];
      lp->orig_obj[i] = lp->orig_obj[ii];
      if(lp->obj != NULL)
        lp->obj[i] = lp->obj[ii];
/*
      if(lp->objfromvalue != NULL)
        lp->objfromvalue[i] = lp->objfromvalue[ii];
      if(lp->objfrom != NULL)
        lp->objfrom[i] = lp->objfrom[ii];
      if(lp->objtill != NULL)
        lp->objtill[i] = lp->objtill[ii];
*/
      if(lp->bb_varbranch != NULL)
        lp->bb_varbranch[i-1] = lp->bb_varbranch[ii-1];
      if(lp->var_is_free != NULL)
        lp->var_is_free[i] = lp->var_is_free[ii];
      if(lp->best_solution != NULL)
        lp->best_solution[lp->rows + i] = lp->best_solution[lp->rows + ii];
    }
    /* Shift variable priority data */
    if((lp->var_priority != NULL) || (lp->sos_priority != NULL)) {
      int *colmap = NULL, k;
      allocINT(lp, &colmap, lp->columns + 1, TRUE);
      for(i = 1, ii = 0; i <= lp->columns; i++) {
        if(isActiveLink(usedmap, i)) {
          ii++;
          colmap[i] = ii;
        }
      }
      if(lp->var_priority != NULL) {
        for(i = 0, ii = 0; i < lp->columns; i++) {
          k = colmap[lp->var_priority[i]];
          if(k > 0) {
            lp->var_priority[ii] = k;
            ii++;
          }
        }
      }
      if(lp->sos_priority != NULL) {
        for(i = 0, ii = 0; i < lp->sos_vars; i++) {
          k = colmap[lp->sos_priority[i]];
          if(k > 0) {
            lp->sos_priority[ii] = k;
            ii++;
          }
        }
        lp->sos_vars = ii;
      }
      FREE(colmap);
    }

    delta = i - lp->columns - 1;
  }
  else if(delta < 0) {

    /* Fix invalid split variable data */
    if(lp->var_is_free != NULL) {
      for(i = 1; i <= lp->columns; i++)
        if(abs(lp->var_is_free[i]) >= base)
          lp->var_is_free[i] -= my_chsign(lp->var_is_free[i] < 0, delta);
    }

    /* Shift column data (excluding the basis) */
    for(i = base; i < base-delta; i++) {
      if(is_int(lp, i)) {
        lp->int_vars--;
        if(SOS_is_member(lp->SOS, 0, i))
          lp->sos_ints--;
      }
      if(is_semicont(lp, i))
        lp->sc_vars--;
    }
    for(i = base; i <= lp->columns + delta; i++) {
      ii = i - delta;
      lp->var_type[i] = lp->var_type[ii];
      lp->sc_lobound[i] = lp->sc_lobound[ii];
      lp->orig_obj[i] = lp->orig_obj[ii];
      if(lp->obj != NULL)
        lp->obj[i] = lp->obj[ii];
/*
      if(lp->objfromvalue != NULL)
        lp->objfromvalue[i] = lp->objfromvalue[ii];
      if(lp->objfrom != NULL)
        lp->objfrom[i] = lp->objfrom[ii];
      if(lp->objtill != NULL)
        lp->objtill[i] = lp->objtill[ii];
*/
      if(lp->var_priority != NULL)
        lp->var_priority[i-1] = lp->var_priority[ii-1];
      if(lp->bb_varbranch != NULL)
        lp->bb_varbranch[i-1] = lp->bb_varbranch[ii-1];
      if(lp->var_is_free != NULL)
        lp->var_is_free[i] = lp->var_is_free[ii];
      if(lp->best_solution != NULL)
        lp->best_solution[lp->rows + i] = lp->best_solution[lp->rows + ii];
    }

    /* Fix invalid variable priority data */
    if(lp->var_priority != NULL) {
      for(i = 0, ii = 0; i < lp->columns; i++)
        if(lp->var_priority[i] > base - delta)
          lp->var_priority[ii++] = lp->var_priority[i] + delta;
        else if(lp->var_priority[i] < base)
          lp->var_priority[ii++] = lp->var_priority[i];
    }
    if(lp->sos_priority != NULL) {
      for(i = 0, ii = 0; i < lp->sos_vars; i++) {
        if(lp->sos_priority[i] > base - delta)
          lp->sos_priority[ii++] = lp->sos_priority[i] + delta;
        else if(lp->sos_priority[i] < base)
          lp->sos_priority[ii++] = lp->sos_priority[i];
      }
      lp->sos_vars = ii;
    }

  }

  shift_basis(lp, lp->rows+base, delta, usedmap, FALSE);
  if(SOS_count(lp) > 0)
    SOS_shift_col(lp->SOS, 0, base, delta, usedmap, FALSE);
  shift_rowcoldata(lp, lp->rows+base, delta, usedmap, FALSE);
  inc_columns(lp, delta);

  return( TRUE );
}

/* Utility group for incrementing row and column vector storage space */
STATIC void inc_rows(lprec *lp, int delta)
{
  int i;

  if(lp->names_used && (lp->row_name != NULL))
    for(i = lp->rows + delta; i > lp->rows; i--)
      lp->row_name[i] = NULL;

  lp->rows += delta;
  if(lp->matA->is_roworder)
    lp->matA->columns += delta;
  else
    lp->matA->rows += delta;
}

STATIC void inc_columns(lprec *lp, int delta)
{
  int i;

  if(lp->names_used && (lp->col_name != NULL))
    for(i = lp->columns + delta; i > lp->columns; i--)
      lp->col_name[i] = NULL;

  lp->columns += delta;
  if(lp->matA->is_roworder)
    lp->matA->rows += delta;
  else
    lp->matA->columns += delta;
  if(get_Lrows(lp) > 0)
    lp->matL->columns += delta;
}

STATIC MYBOOL inc_rowcol_space(lprec *lp, int delta, MYBOOL isrows)
{
  int i, oldrowcolalloc, rowcolsum;

  /* Get rid of dual arrays */
  if(lp->solvecount > 0)
    free_duals(lp);

  /* Set constants */
  oldrowcolalloc = lp->sum_alloc;
  lp->sum_alloc += delta;
  rowcolsum = lp->sum_alloc + 1;

  /* Reallocate lp memory */
  if(!allocREAL(lp, &lp->upbo, rowcolsum, AUTOMATIC) ||
     !allocREAL(lp, &lp->orig_upbo, rowcolsum, AUTOMATIC) ||
     !allocREAL(lp, &lp->lowbo, rowcolsum, AUTOMATIC) ||
     !allocREAL(lp, &lp->orig_lowbo, rowcolsum, AUTOMATIC) ||
     !allocREAL(lp, &lp->solution, rowcolsum, AUTOMATIC) ||
     !allocREAL(lp, &lp->best_solution, rowcolsum, AUTOMATIC) ||
     !allocMYBOOL(lp, &lp->is_basic, rowcolsum, AUTOMATIC) ||
     !allocMYBOOL(lp, &lp->is_lower, rowcolsum, AUTOMATIC) ||
     ((lp->scalars != NULL) && !allocREAL(lp, &lp->scalars, rowcolsum, AUTOMATIC)))
    return( FALSE );

  /* Fill in default values, where appropriate */
  for(i = oldrowcolalloc+1; i < rowcolsum; i++) {
    lp->upbo[i] = lp->infinite;
    lp->orig_upbo[i] = lp->upbo[i];
    lp->lowbo[i] = 0;
    lp->orig_lowbo[i] = lp->lowbo[i];
    lp->is_basic[i] = FALSE;
    lp->is_lower[i] = TRUE;
  }

  /* Deal with scalars; the vector can be NULL and also contains Lagrangean information */
  if(lp->scalars != NULL) {
    for(i = oldrowcolalloc+1; i < rowcolsum; i++)
      lp->scalars[i] = 1;
    if(oldrowcolalloc == 0)
      lp->scalars[0] = 1;
  }

  return( inc_presolve_space(lp, delta, isrows) &&
           resizePricer(lp) );
}

STATIC MYBOOL inc_lag_space(lprec *lp, int deltarows, MYBOOL ignoreMAT)
{
  int newsize;

  if(deltarows > 0) {

    newsize = get_Lrows(lp) + deltarows;

    /* Reallocate arrays */
    if(!allocREAL(lp, &lp->lag_rhs, newsize+1, AUTOMATIC) ||
       !allocREAL(lp, &lp->lambda, newsize+1, AUTOMATIC) ||
       !allocINT(lp, &lp->lag_con_type, newsize+1, AUTOMATIC))
      return( FALSE );

    /* Reallocate the matrix (note that the row scalars are stored at index 0) */
    if(!ignoreMAT) {
      if(lp->matL == NULL)
        lp->matL = mat_create(lp, newsize, lp->columns, lp->epsvalue);
      else
        inc_matrow_space(lp->matL, deltarows);
    }
    lp->matL->rows += deltarows;

  }
  /* Handle column count expansion as special case */
  else if(!ignoreMAT) {
    inc_matcol_space(lp->matL, lp->columns_alloc-lp->matL->columns_alloc+1);
  }


  return( TRUE );
}

STATIC MYBOOL inc_row_space(lprec *lp, int deltarows)
{
  int    i, rowsum, oldrowsalloc;
  MYBOOL ok = TRUE;

  /* Adjust lp row structures */
  i = lp->rows_alloc+deltarows;
  if(lp->matA->is_roworder) {
    i -= lp->matA->columns_alloc;
    SETMIN(i, deltarows);
    if(i > 0)
      inc_matcol_space(lp->matA, i);
    rowsum = lp->matA->columns_alloc;
  }
  else {
#if 0
    if((lp->rows_alloc > 0) && (lp->rows + deltarows > lp->rows_alloc))
      i = deltarows; /* peno 25/12/06 */
    else
#endif
      i -= lp->matA->rows_alloc;
    SETMIN(i, deltarows);
    if(i > 0)
      inc_matrow_space(lp->matA, i);
    rowsum = lp->matA->rows_alloc;
  }
  if(lp->rows+deltarows > lp->rows_alloc) {

    rowsum++;
    oldrowsalloc = lp->rows_alloc;
    lp->rows_alloc = rowsum;
    deltarows = rowsum - oldrowsalloc;
    rowsum++;

    if(!allocREAL(lp, &lp->orig_rhs, rowsum, AUTOMATIC) ||
       !allocLREAL(lp, &lp->rhs, rowsum, AUTOMATIC) ||
       !allocINT(lp, &lp->row_type, rowsum, AUTOMATIC) ||
       !allocINT(lp, &lp->var_basic, rowsum, AUTOMATIC))
      return( FALSE );

    if(oldrowsalloc == 0) {
      lp->var_basic[0] = AUTOMATIC; /*TRUE;*/  /* Indicates default basis */
      lp->orig_rhs[0] = 0;
      lp->row_type[0] = ROWTYPE_OFMIN;
    }
    for(i = oldrowsalloc+1; i < rowsum; i++) {
      lp->orig_rhs[i] = 0;
      lp->rhs[i] = 0;
      lp->row_type[i] = ROWTYPE_EMPTY;
      lp->var_basic[i] = i;
    }

    /* Adjust hash name structures */
    if(lp->names_used && (lp->row_name != NULL)) {

      /* First check the hash table */
      if(lp->rowname_hashtab->size < lp->rows_alloc) {
        hashtable *ht;

        ht = copy_hash_table(lp->rowname_hashtab, lp->row_name, lp->rows_alloc + 1);
        if(ht == NULL) {
          lp->spx_status = NOMEMORY;
          return( FALSE );
        }
        free_hash_table(lp->rowname_hashtab);
        lp->rowname_hashtab = ht;
      }

      /* Then the string storage (i.e. pointer to the item's hash structure) */
      lp->row_name = (hashelem **) realloc(lp->row_name, (rowsum) * sizeof(*lp->row_name));
      if(lp->row_name == NULL) {
        lp->spx_status = NOMEMORY;
        return( FALSE );
      }
      for(i = oldrowsalloc + 1; i < rowsum; i++)
        lp->row_name[i] = NULL;
    }

    ok = inc_rowcol_space(lp, deltarows, TRUE);

  }
  return(ok);
}

STATIC MYBOOL inc_col_space(lprec *lp, int deltacols)
{
  int i,colsum, oldcolsalloc;

  i = lp->columns_alloc+deltacols;
  if(lp->matA->is_roworder) {
    i -= lp->matA->rows_alloc;
    SETMIN(i, deltacols);
    if(i > 0)
      inc_matrow_space(lp->matA, i);
    colsum = lp->matA->rows_alloc;
  }
  else {
    i -= lp->matA->columns_alloc;
    SETMIN(i, deltacols);
    if(i > 0)
      inc_matcol_space(lp->matA, i);
    colsum = lp->matA->columns_alloc;
  }

  if(lp->columns+deltacols >= lp->columns_alloc) {

    colsum++;
    oldcolsalloc = lp->columns_alloc;
    lp->columns_alloc = colsum;
    deltacols = colsum - oldcolsalloc;
    colsum++;

    /* Adjust hash name structures */
    if(lp->names_used && (lp->col_name != NULL)) {

      /* First check the hash table */
      if(lp->colname_hashtab->size < lp->columns_alloc) {
        hashtable *ht;

        ht = copy_hash_table(lp->colname_hashtab, lp->col_name, lp->columns_alloc + 1);
        if(ht != NULL) {
          free_hash_table(lp->colname_hashtab);
          lp->colname_hashtab = ht;
        }
      }

      /* Then the string storage (i.e. pointer to the item's hash structure) */
      lp->col_name = (hashelem **) realloc(lp->col_name, (colsum) * sizeof(*lp->col_name));
      for(i = oldcolsalloc+1; i < colsum; i++)
        lp->col_name[i] = NULL;
    }

    if(!allocREAL(lp, &lp->orig_obj, colsum, AUTOMATIC) ||
       !allocMYBOOL(lp, &lp->var_type, colsum, AUTOMATIC) ||
       !allocREAL(lp, &lp->sc_lobound, colsum, AUTOMATIC) ||
       ((lp->obj != NULL) && !allocREAL(lp, &lp->obj, colsum, AUTOMATIC)) ||
       ((lp->var_priority != NULL) && !allocINT(lp, &lp->var_priority, colsum-1, AUTOMATIC)) ||
       ((lp->var_is_free != NULL) && !allocINT(lp, &lp->var_is_free, colsum, AUTOMATIC)) ||
       ((lp->bb_varbranch != NULL) && !allocMYBOOL(lp, &lp->bb_varbranch, colsum-1, AUTOMATIC)))
      return( FALSE );

    /* Make sure that Lagrangean constraints have the same number of columns */
    if(get_Lrows(lp) > 0)
      inc_lag_space(lp, 0, FALSE);

    /* Update column pointers */
    for(i = MIN(oldcolsalloc, lp->columns) + 1; i < colsum; i++) {
      lp->orig_obj[i] = 0;
      if(lp->obj != NULL)
        lp->obj[i] = 0;
      lp->var_type[i] = ISREAL;
      lp->sc_lobound[i] = 0;
      if(lp->var_priority != NULL)
        lp->var_priority[i-1] = i;
    }

    if(lp->var_is_free != NULL) {
      for(i = oldcolsalloc+1; i < colsum; i++)
        lp->var_is_free[i] = 0;
    }

    if(lp->bb_varbranch != NULL) {
      for(i = oldcolsalloc; i < colsum-1; i++)
        lp->bb_varbranch[i] = BRANCH_DEFAULT;
    }

    inc_rowcol_space(lp, deltacols, FALSE);

  }
  return(TRUE);
}

/* Problem manipulation routines */

MYBOOL __WINAPI set_obj(lprec *lp, int colnr, REAL value)
{
  if(colnr <= 0)
    colnr = set_rh(lp, 0, value);
  else
    colnr = set_mat(lp, 0, colnr, value);
  return((MYBOOL) colnr);
}

MYBOOL __WINAPI set_obj_fnex(lprec *lp, int count, REAL *row, int *colno)
{
  MYBOOL chsgn = is_maxim(lp);
  int    i, ix;
  REAL   value;

  if(row == NULL)
    return( FALSE );

  else if(colno == NULL) {
    if(count <= 0)
      count = lp->columns;
    for(i = 1; i <= count; i++) {
      value = row[i];
#ifdef DoMatrixRounding
      value = roundToPrecision(value, lp->matA->epsvalue);
#endif
      lp->orig_obj[i] = my_chsign(chsgn, scaled_mat(lp, value, 0, i));
    }
  }
  else {
    MEMCLEAR(lp->orig_obj, lp->columns+1);
    for(i = 0; i < count; i++) {
      ix = colno[i];
      value = row[i];
#ifdef DoMatrixRounding
      value = roundToPrecision(value, lp->matA->epsvalue);
#endif
      lp->orig_obj[ix] = my_chsign(chsgn, scaled_mat(lp, value, 0, ix));
    }
  }

  return(TRUE);
}

MYBOOL __WINAPI set_obj_fn(lprec *lp, REAL *row)
{
  return( set_obj_fnex(lp, 0, row, NULL) );
}

MYBOOL __WINAPI str_set_obj_fn(lprec *lp, char *row_string)
{
  int    i;
  MYBOOL ret = TRUE;
  REAL   *arow;
  char   *p, *newp;

  allocREAL(lp, &arow, lp->columns + 1, FALSE);
  p = row_string;
  for(i = 1; i <= lp->columns; i++) {
    arow[i] = (REAL) strtod(p, &newp);
    if(p == newp) {
      report(lp, IMPORTANT, "str_set_obj_fn: Bad string %s\n", p);
      lp->spx_status = DATAIGNORED;
      ret = FALSE;
      break;
    }
    else
      p = newp;
  }
  if(lp->spx_status != DATAIGNORED)
    ret = set_obj_fn(lp, arow);
  FREE(arow);
  return( ret );
}

STATIC MYBOOL append_columns(lprec *lp, int deltacolumns)
{
  if(!inc_col_space(lp, deltacolumns))
    return( FALSE );
  varmap_add(lp, lp->sum+1, deltacolumns);
  shift_coldata(lp, lp->columns+1, deltacolumns, NULL);
  return( TRUE );
}

STATIC MYBOOL append_rows(lprec *lp, int deltarows)
{
  if(!inc_row_space(lp, deltarows))
    return( FALSE );
  varmap_add(lp, lp->rows+1, deltarows);
  shift_rowdata(lp, lp->rows+1, deltarows, NULL);

  return( TRUE );
}

MYBOOL __WINAPI set_add_rowmode(lprec *lp, MYBOOL turnon)
{
  if((lp->solvecount == 0) && (turnon ^ lp->matA->is_roworder))
    return( mat_transpose(lp->matA) );
  else
    return( FALSE );
}

MYBOOL __WINAPI is_add_rowmode(lprec *lp)
{
  return(lp->matA->is_roworder);
}

MYBOOL __WINAPI set_row(lprec *lp, int rownr, REAL *row)
{
  if((rownr < 0) || (rownr > lp->rows)) {
    report(lp, IMPORTANT, "set_row: Row %d out of range\n", rownr);
    return( FALSE );
  }
  if(rownr == 0)
    return( set_obj_fn(lp, row) );
  else
    return( mat_setrow(lp->matA, rownr, lp->columns, row, NULL, TRUE, TRUE) );
}

MYBOOL __WINAPI set_rowex(lprec *lp, int rownr, int count, REAL *row, int *colno)
{
  if((rownr < 0) || (rownr > lp->rows)) {
    report(lp, IMPORTANT, "set_rowex: Row %d out of range\n", rownr);
    return( FALSE );
  }
  if(rownr == 0)
    return( set_obj_fnex(lp, count, row, colno) );
  else
    return( mat_setrow(lp->matA, rownr, count, row, colno, TRUE, TRUE) );
}

MYBOOL __WINAPI add_constraintex(lprec *lp, int count, REAL *row, int *colno, int constr_type, REAL rh)
{
  int    n;
  MYBOOL status = FALSE;

  if(!(constr_type == LE || constr_type == GE || constr_type == EQ)) {
    report(lp, IMPORTANT, "add_constraintex: Invalid %d constraint type\n", constr_type);
    return( status );
  }

  /* Prepare for a new row */
  if(!append_rows(lp, 1))
    return( status );

  /* Set constraint parameters, fix the slack */
  if((constr_type & ROWTYPE_CONSTRAINT) == EQ) {
    lp->equalities++;
    lp->orig_upbo[lp->rows] = 0;
    lp->upbo[lp->rows] = 0;
  }
  lp->row_type[lp->rows] = constr_type;

  if(is_chsign(lp, lp->rows) && (rh != 0))
    lp->orig_rhs[lp->rows] = -rh;
  else
    lp->orig_rhs[lp->rows] = rh;

  /* Insert the non-zero constraint values */
  if(colno == NULL && row != NULL)
    n = lp->columns;
  else
    n = count;
  mat_appendrow(lp->matA, n, row, colno, my_chsign(is_chsign(lp, lp->rows), 1.0), TRUE);
  if(!lp->varmap_locked)
    presolve_setOrig(lp, lp->rows, lp->columns);

#ifdef Paranoia
  if(lp->matA->is_roworder)
    n = lp->matA->columns;
  else
    n = lp->matA->rows;
  if(lp->rows != n) {
    report(lp, SEVERE, "add_constraintex: Row count mismatch %d vs %d\n",
                       lp->rows, n);
  }
  else if(is_BasisReady(lp) && !verify_basis(lp))
    report(lp, SEVERE, "add_constraintex: Invalid basis detected for row %d\n", lp->rows);
  else
#endif
  status = TRUE;

  return( status );
}

MYBOOL __WINAPI add_constraint(lprec *lp, REAL *row, int constr_type, REAL rh)
{
  return( add_constraintex(lp, 0, row, NULL, constr_type, rh) );
}

MYBOOL __WINAPI str_add_constraint(lprec *lp, char *row_string, int constr_type, REAL rh)
{
  int    i;
  char   *p, *newp;
  REAL   *aRow;
  MYBOOL status = FALSE;

  allocREAL(lp, &aRow, lp->columns + 1, FALSE);
  p = row_string;

  for(i = 1; i <= lp->columns; i++) {
    aRow[i] = (REAL) strtod(p, &newp);
    if(p == newp) {
      report(lp, IMPORTANT, "str_add_constraint: Bad string '%s'\n", p);
      lp->spx_status = DATAIGNORED;
      break;
    }
    else
      p = newp;
  }
  if(lp->spx_status != DATAIGNORED)
    status = add_constraint(lp, aRow, constr_type, rh);
  FREE(aRow);

  return(status);
}

STATIC MYBOOL del_constraintex(lprec *lp, LLrec *rowmap)
{
  int i;

  if(lp->equalities > 0)
  for(i = firstInactiveLink(rowmap); i != 0; i = nextInactiveLink(rowmap, i)) {
    if(is_constr_type(lp, i, EQ)) {
#ifdef Paranoia
      if(lp->equalities == 0)
        report(lp, SEVERE, "del_constraintex: Invalid count of equality constraints\n");
#endif
       lp->equalities--;
    }
  }

  varmap_delete(lp, 1, -1, rowmap);
  shift_rowdata(lp, 1, -1, rowmap);
  if(!lp->varmap_locked) {
    presolve_setOrig(lp, lp->rows, lp->columns);
    if(lp->names_used)
      del_varnameex(lp, lp->row_name, lp->rows, lp->rowname_hashtab, 0, rowmap);
  }

#ifdef Paranoia
  if(is_BasisReady(lp) && !verify_basis(lp))
    report(lp, SEVERE, "del_constraintex: Invalid basis detected\n");
#endif

  return(TRUE);
}
MYBOOL __WINAPI del_constraint(lprec *lp, int rownr)
{
  MYBOOL preparecompact = (MYBOOL) (rownr < 0);

  if(preparecompact)
    rownr = -rownr;
  if((rownr < 1) || (rownr > lp->rows)) {
    report(lp, IMPORTANT, "del_constraint: Attempt to delete non-existing constraint %d\n", rownr);
    return(FALSE);
  }
  /*
  if(lp->matA->is_roworder) {
    report(lp, IMPORTANT, "del_constraint: Cannot delete constraint while in row entry mode.\n");
    return(FALSE);
  }
  */

  if(is_constr_type(lp, rownr, EQ) && (lp->equalities > 0))
    lp->equalities--;

  varmap_delete(lp, my_chsign(preparecompact, rownr), -1, NULL);
  shift_rowdata(lp, my_chsign(preparecompact, rownr), -1, NULL);

/*
   peno 04.10.07
   Fixes a problem with del_constraint.
   Constraints names were not shifted and reported variable result was incorrect.
   See UnitTest1, UnitTest2

   min: -2 x3;

   c1: +x2 -x1 <= 10;
   c: 0 x3 <= 0;
   c2: +x3 +x2 +x1 <= 20;

   2 <= x3 <= 3;
   x1 <= 30;

   // del_constraint(lp, 2);

   // See write_LP and print_solution result

   // To fix, commented if(!lp->varmap_locked)

*/
  if(!lp->varmap_locked)
  {
    presolve_setOrig(lp, lp->rows, lp->columns);
    if(lp->names_used)
      del_varnameex(lp, lp->row_name, lp->rows, lp->rowname_hashtab, rownr, NULL);
  }

#ifdef Paranoia
  if(is_BasisReady(lp) && !verify_basis(lp))
    report(lp, SEVERE, "del_constraint: Invalid basis detected at row %d\n", rownr);
#endif

  return(TRUE);
}

MYBOOL __WINAPI add_lag_con(lprec *lp, REAL *row, int con_type, REAL rhs)
{
  int  k;
  REAL sign;

  if(con_type == LE || con_type == EQ)
    sign = 1;
  else if(con_type == GE)
    sign = -1;
  else {
    report(lp, IMPORTANT, "add_lag_con: Constraint type %d not implemented\n", con_type);
    return(FALSE);
  }

  inc_lag_space(lp, 1, FALSE);

  k = get_Lrows(lp);
  lp->lag_rhs[k] = rhs * sign;
  mat_appendrow(lp->matL, lp->columns, row, NULL, sign, TRUE);
  lp->lambda[k] = 0;
  lp->lag_con_type[k] = con_type;

  return(TRUE);
}

MYBOOL __WINAPI str_add_lag_con(lprec *lp, char *row_string, int con_type, REAL rhs)
{
  int    i;
  MYBOOL ret = TRUE;
  REAL   *a_row;
  char   *p, *new_p;

  allocREAL(lp, &a_row, lp->columns + 1, FALSE);
  p = row_string;

  for(i = 1; i <= lp->columns; i++) {
    a_row[i] = (REAL) strtod(p, &new_p);
    if(p == new_p) {
      report(lp, IMPORTANT, "str_add_lag_con: Bad string '%s'\n", p);
      lp->spx_status = DATAIGNORED;
      ret = FALSE;
      break;
    }
    else
      p = new_p;
  }
  if(lp->spx_status != DATAIGNORED)
    ret = add_lag_con(lp, a_row, con_type, rhs);
  FREE(a_row);
  return( ret );
}

/* INLINE */ MYBOOL is_splitvar(lprec *lp, int colnr)
/* Two cases handled by var_is_free:

   1) LB:-Inf / UB:<Inf variables
      No helper column created, sign of var_is_free set negative with index to itself.
   2) LB:-Inf / UB: Inf (free) variables
      Sign of var_is_free set positive with index to new helper column,
      helper column created with negative var_is_free with index to the original column.

   This function helps identify the helper column in 2).
*/
{
   return((MYBOOL) ((lp->var_is_free != NULL) &&
                    (lp->var_is_free[colnr] < 0) && (-lp->var_is_free[colnr] != colnr)));
}

void del_splitvars(lprec *lp)
{
  int j, jj, i;

  if(lp->var_is_free != NULL) {
    for(j = lp->columns; j >= 1; j--)
      if(is_splitvar(lp, j)) {
        /* Check if we need to modify the basis */
        jj = lp->rows+abs(lp->var_is_free[j]);
        i = lp->rows+j;
        if(lp->is_basic[i] && !lp->is_basic[jj]) {
          i = findBasisPos(lp, i, NULL);
          set_basisvar(lp, i, jj);
        }
        /* Delete the helper column */
        del_column(lp, j);
      }
    FREE(lp->var_is_free);
  }
}

MYBOOL __WINAPI set_column(lprec *lp, int colnr, REAL *column)
{
  return( mat_setcol(lp->matA, colnr, lp->rows, column, NULL, TRUE, TRUE) );
}

MYBOOL __WINAPI set_columnex(lprec *lp, int colnr, int count, REAL *column, int *rowno)
{
  return( mat_setcol(lp->matA, colnr, count, column, rowno, TRUE, TRUE) );
}

MYBOOL __WINAPI add_columnex(lprec *lp, int count, REAL *column, int *rowno)
/* This function adds a data column to the current model; three cases handled:

    1: Prepare for column data by setting column = NULL
    2: Dense vector indicated by (rowno == NULL) over 0..count+get_Lrows() elements
    3: Sparse vector set over row vectors rowno, over 0..count-1 elements.

   NB! If the column has only one entry, this should be handled as
       a bound, but this currently is not the case  */
{
  MYBOOL status = FALSE;

 /* Prepare and shift column vectors */
  if(!append_columns(lp, 1))
    return( status );

 /* Append sparse regular constraint values */
  if(mat_appendcol(lp->matA, count, column, rowno, 1.0, TRUE) < 0)
    report(lp, SEVERE, "add_columnex: Data column %d supplied in non-ascending row index order.\n",
                       lp->columns);
  else
#ifdef Paranoia
  if(lp->columns != (lp->matA->is_roworder ? lp->matA->rows : lp->matA->columns)) {
    report(lp, SEVERE, "add_columnex: Column count mismatch %d vs %d\n",
                       lp->columns, (lp->matA->is_roworder ? lp->matA->rows : lp->matA->columns));
  }
  else if(is_BasisReady(lp) && (lp->P1extraDim == 0) && !verify_basis(lp))
    report(lp, SEVERE, "add_columnex: Invalid basis detected for column %d\n",
                       lp->columns);
  else
#endif
    status = TRUE;

  if(!lp->varmap_locked)
    presolve_setOrig(lp, lp->rows, lp->columns);

  return( status );
}

MYBOOL __WINAPI add_column(lprec *lp, REAL *column)
{
  del_splitvars(lp);
  return(add_columnex(lp, lp->rows, column, NULL));
}

MYBOOL __WINAPI str_add_column(lprec *lp, char *col_string)
{
  int  i;
  MYBOOL ret = TRUE;
  REAL *aCol;
  char *p, *newp;

  allocREAL(lp, &aCol, lp->rows + 1, FALSE);
  p = col_string;

  for(i = 0; i <= lp->rows; i++) {
    aCol[i] = (REAL) strtod(p, &newp);
    if(p == newp) {
      report(lp, IMPORTANT, "str_add_column: Bad string '%s'\n", p);
      lp->spx_status = DATAIGNORED;
      ret = FALSE;
      break;
    }
    else
      p = newp;
  }
  if(lp->spx_status != DATAIGNORED)
    ret = add_column(lp, aCol);
  FREE(aCol);
  return( ret );
}

STATIC MYBOOL del_varnameex(lprec *lp, hashelem **namelist, int items, hashtable *ht, int varnr, LLrec *varmap)
{
  int i, n;

  /* First drop hash table entries of the deleted variables */
  if(varmap != NULL)
    i = firstInactiveLink(varmap);
  else
    i = varnr;
  while(i > 0) {
    if(namelist[i] != NULL) {
      if(namelist[i]->name != NULL)
        drophash(namelist[i]->name, namelist, ht);
    }
    if(varmap != NULL)
      i = nextInactiveLink(varmap, i);
    else
      i = 0;
  }

  /* Then compress the name list */
  if(varmap != NULL) {
    i = firstInactiveLink(varmap);
    n = nextActiveLink(varmap, i);
    varnr = i;
  }
  else {
    i = varnr;
    n = i + 1;
  }
  while(n != 0) {
    namelist[i] = namelist[n];
    if((namelist[i] != NULL) && (namelist[i]->index > varnr))
      namelist[i]->index -= n - i;
    i++;
    if(varmap != NULL)
      n = nextActiveLink(varmap, i);
    else if(n <= items) /* items has been updated for the new count */
      n++;
    else
      n = 0;
  }

  return( TRUE );
}
STATIC MYBOOL del_columnex(lprec *lp, LLrec *colmap)
{
  varmap_delete(lp, lp->rows+1, -1, colmap);
  shift_coldata(lp, 1, -1, colmap);
  if(!lp->varmap_locked) {
    presolve_setOrig(lp, lp->rows, lp->columns);
    if(lp->names_used)
      del_varnameex(lp, lp->col_name, lp->columns, lp->colname_hashtab, 0, colmap);
  }
#ifdef Paranoia
  if(is_BasisReady(lp) && (lp->P1extraDim == 0) && !verify_basis(lp))
    report(lp, SEVERE, "del_columnex: Invalid basis detected\n");
#endif

  return(TRUE);
}
MYBOOL __WINAPI del_column(lprec *lp, int colnr)
{
  MYBOOL preparecompact = (MYBOOL) (colnr < 0);

  if(preparecompact)
    colnr = -colnr;
  if((colnr > lp->columns) || (colnr < 1)) {
    report(lp, IMPORTANT, "del_column: Column %d out of range\n", colnr);
    return(FALSE);
  }
  /*
  if(lp->matA->is_roworder) {
    report(lp, IMPORTANT, "del_column: Cannot delete column while in row entry mode.\n");
    return(FALSE);
  }
  */

  if((lp->var_is_free != NULL) && (lp->var_is_free[colnr] > 0))
    del_column(lp, lp->var_is_free[colnr]); /* delete corresponding split column (is always after this column) */

  varmap_delete(lp, my_chsign(preparecompact, lp->rows+colnr), -1, NULL);
  shift_coldata(lp, my_chsign(preparecompact, colnr), -1, NULL);
  if(!lp->varmap_locked) {
    presolve_setOrig(lp, lp->rows, lp->columns);
    if(lp->names_used)
      del_varnameex(lp, lp->col_name, lp->columns, lp->colname_hashtab, colnr, NULL);
  }
#ifdef Paranoia
  if(is_BasisReady(lp) && (lp->P1extraDim == 0) && !verify_basis(lp))
    report(lp, SEVERE, "del_column: Invalid basis detected at column %d (%d)\n", colnr, lp->columns);
#endif

  return(TRUE);
}

void __WINAPI set_simplextype(lprec *lp, int simplextype)
{
  lp->simplex_strategy = simplextype;
}

int __WINAPI get_simplextype(lprec *lp)
{
  return(lp->simplex_strategy);
}

void __WINAPI set_preferdual(lprec *lp, MYBOOL dodual)
{
  if(dodual & TRUE)
    lp->simplex_strategy = SIMPLEX_DUAL_DUAL;
  else
    lp->simplex_strategy = SIMPLEX_PRIMAL_PRIMAL;
}

void __WINAPI set_bounds_tighter(lprec *lp, MYBOOL tighten)
{
  lp->tighten_on_set = tighten;
}
MYBOOL __WINAPI get_bounds_tighter(lprec *lp)
{
  return(lp->tighten_on_set);
}

MYBOOL __WINAPI set_upbo(lprec *lp, int colnr, REAL value)
{
  if((colnr > lp->columns) || (colnr < 1)) {
    report(lp, IMPORTANT, "set_upbo: Column %d out of range\n", colnr);
    return(FALSE);
  }

#ifdef DoBorderRounding
  if(fabs(value) < lp->infinite)
    value = my_avoidtiny(value, lp->matA->epsvalue);
#endif
  value = scaled_value(lp, value, lp->rows + colnr);
  if(lp->tighten_on_set) {
    if(value < lp->orig_lowbo[lp->rows + colnr]) {
      report(lp, IMPORTANT, "set_upbo: Upperbound must be >= lowerbound\n");
      return(FALSE);
    }
    if(value < lp->orig_upbo[lp->rows + colnr]) {
      set_action(&lp->spx_action, ACTION_REBASE);
      lp->orig_upbo[lp->rows + colnr] = value;
    }
  }
  else
  {
    set_action(&lp->spx_action, ACTION_REBASE);
    if(value > lp->infinite)
      value = lp->infinite;
    lp->orig_upbo[lp->rows + colnr] = value;
  }
  return(TRUE);
}

REAL __WINAPI get_upbo(lprec *lp, int colnr)
{
  REAL value;

  if((colnr > lp->columns) || (colnr < 1)) {
    report(lp, IMPORTANT, "get_upbo: Column %d out of range\n", colnr);
    return(0);
  }

  value = lp->orig_upbo[lp->rows + colnr];
  value = unscaled_value(lp, value, lp->rows + colnr);
  return(value);
}

MYBOOL __WINAPI set_lowbo(lprec *lp, int colnr, REAL value)
{
  if((colnr > lp->columns) || (colnr < 1)) {
    report(lp, IMPORTANT, "set_lowbo: Column %d out of range\n", colnr);
    return(FALSE);
  }

#ifdef DoBorderRounding
  if(fabs(value) < lp->infinite)
    value = my_avoidtiny(value, lp->matA->epsvalue);
#endif
  value = scaled_value(lp, value, lp->rows + colnr);
  if(lp->tighten_on_set) {
    if(value > lp->orig_upbo[lp->rows + colnr]) {
      report(lp, IMPORTANT, "set_lowbo: Upper bound must be >= lower bound\n");
      return(FALSE);
    }
    if((value < 0) || (value > lp->orig_lowbo[lp->rows + colnr])) {
      set_action(&lp->spx_action, ACTION_REBASE);
      lp->orig_lowbo[lp->rows + colnr] = value;
    }
  }
  else
  {
    set_action(&lp->spx_action, ACTION_REBASE);
    if(value < -lp->infinite)
      value = -lp->infinite;
    lp->orig_lowbo[lp->rows + colnr] = value;
  }
  return(TRUE);
}

REAL __WINAPI get_lowbo(lprec *lp, int colnr)
{
  REAL value;

  if((colnr > lp->columns) || (colnr < 1)) {
    report(lp, IMPORTANT, "get_lowbo: Column %d out of range\n", colnr);
    return(0);
  }

  value = lp->orig_lowbo[lp->rows + colnr];
  value = unscaled_value(lp, value, lp->rows + colnr);
  return(value);
}

MYBOOL __WINAPI set_bounds(lprec *lp, int colnr, REAL lower, REAL upper)
{
  if((colnr > lp->columns) || (colnr < 1)) {
    report(lp, IMPORTANT, "set_bounds: Column %d out of range\n", colnr);
    return(FALSE);
  }
  if(fabs(upper - lower) < lp->epsvalue) {
    if(lower < 0)
      lower = upper;
    else
      upper = lower;
  }
  else if(lower > upper) {
    report(lp, IMPORTANT, "set_bounds: Column %d upper bound must be >= lower bound\n",
                          colnr);
    return( FALSE );
  }

  colnr += lp->rows;

  if(lower < -lp->infinite)
    lower = -lp->infinite;
  else if(lp->scaling_used) {
    lower = scaled_value(lp, lower, colnr);
#ifdef DoBorderRounding
    lower = my_avoidtiny(lower, lp->matA->epsvalue);
#endif
  }

  if(upper > lp->infinite)
    upper = lp->infinite;
  else if(lp->scaling_used) {
    upper = scaled_value(lp, upper, colnr);
#ifdef DoBorderRounding
    upper = my_avoidtiny(upper, lp->matA->epsvalue);
#endif
  }

  lp->orig_lowbo[colnr] = lower;
  lp->orig_upbo[colnr]  = upper;
  set_action(&lp->spx_action, ACTION_REBASE);

  return(TRUE);
}

MYBOOL get_bounds(lprec *lp, int column, REAL *lower, REAL *upper)
{
  if((column > lp->columns) || (column < 1)) {
    report(lp, IMPORTANT, "get_bounds: Column %d out of range", column);
    return(FALSE);
  }

  if(lower != NULL)
    *lower = get_lowbo(lp, column);
  if(upper != NULL)
    *upper = get_upbo(lp, column);

  return(TRUE);
}

MYBOOL __WINAPI set_int(lprec *lp, int colnr, MYBOOL var_type)
{
  if((colnr > lp->columns) || (colnr < 1)) {
    report(lp, IMPORTANT, "set_int: Column %d out of range\n", colnr);
    return(FALSE);
  }

  if((lp->var_type[colnr] & ISINTEGER) != 0) {
    lp->int_vars--;
    lp->var_type[colnr] &= ~ISINTEGER;
  }
  if(var_type) {
    lp->var_type[colnr] |= ISINTEGER;
    lp->int_vars++;
    if(lp->columns_scaled && !is_integerscaling(lp))
      unscale_columns(lp);
  }
  return(TRUE);
}

MYBOOL __WINAPI is_int(lprec *lp, int colnr)
{
  if((colnr > lp->columns) || (colnr < 1)) {
    report(lp, IMPORTANT, "is_int: Column %d out of range\n", colnr);
    return(FALSE);
  }

  return((lp->var_type[colnr] & ISINTEGER) != 0);
}

MYBOOL __WINAPI is_SOS_var(lprec *lp, int colnr)
{
  if((colnr > lp->columns) || (colnr < 1)) {
    report(lp, IMPORTANT, "is_SOS_var: Column %d out of range\n", colnr);
    return(FALSE);
  }

  return((lp->var_type[colnr] & ISSOS) != 0);
}

int __WINAPI add_SOS(lprec *lp, char *name, int sostype, int priority, int count, int *sosvars, REAL *weights)
{
  SOSrec *SOS;
  int    k;

  if((sostype < 1) || (count < 0)) {
    report(lp, IMPORTANT, "add_SOS: Invalid SOS type definition %d\n", sostype);
    return( 0 );
  }

  /* Make sure SOSes of order 3 and higher are properly defined */
  if(sostype > 2) {
    int j;
    for(k = 0; k < count; k++) {
      j = sosvars[k];
      if(!is_int(lp, j) || !is_semicont(lp, j)) {
        report(lp, IMPORTANT, "add_SOS: SOS3+ members all have to be integer or semi-continuous.\n");
        return( 0 );
      }
    }
  }

  /* Make size in the list to handle another SOS record */
  if(lp->SOS == NULL)
    lp->SOS = create_SOSgroup(lp);

  /* Create and append SOS to list */
  SOS = create_SOSrec(lp->SOS, name, sostype, priority, count, sosvars, weights);
  k = append_SOSgroup(lp->SOS, SOS);

  return(k);
}

STATIC int add_GUB(lprec *lp, char *name, int priority, int count, int *gubvars)
{
  SOSrec *GUB;
  int    k;

#ifdef Paranoia
  if(count < 0) {
    report(lp, IMPORTANT, "add_GUB: Invalid GUB member count %d\n", count);
    return(FALSE);
  }
#endif

  /* Make size in the list to handle another GUB record */
  if(lp->GUB == NULL)
    lp->GUB = create_SOSgroup(lp);

  /* Create and append GUB to list */
  GUB = create_SOSrec(lp->GUB, name, 1, priority, count, gubvars, NULL);
  GUB->isGUB = TRUE;
  k = append_SOSgroup(lp->GUB, GUB);

  return(k);
}

MYBOOL __WINAPI set_binary(lprec *lp, int colnr, MYBOOL must_be_bin)
{
  MYBOOL status = FALSE;

  if((colnr > lp->columns) || (colnr < 1)) {
    report(lp, IMPORTANT, "set_binary: Column %d out of range\n", colnr);
    return( status );
  }

  status = set_int(lp, colnr, must_be_bin);
  if(status && must_be_bin)
    status = set_bounds(lp, colnr, 0, 1);
  return( status );
}

MYBOOL __WINAPI is_binary(lprec *lp, int colnr)
{
  if((colnr > lp->columns) || (colnr < 1)) {
    report(lp, IMPORTANT, "is_binary: Column %d out of range\n", colnr);
    return(FALSE);
  }

  return((MYBOOL) (((lp->var_type[colnr] & ISINTEGER) != 0) &&
                    (get_lowbo(lp, colnr) == 0) &&
                    (fabs(get_upbo(lp, colnr) - 1) < lp->epsprimal)));
}

MYBOOL __WINAPI set_unbounded(lprec *lp, int colnr)
{
  if((colnr > lp->columns) || (colnr < 1)) {
    report(lp, IMPORTANT, "set_unbounded: Column %d out of range\n", colnr);
    return( FALSE );
  }

  return( set_bounds(lp, colnr, -lp->infinite, lp->infinite) );
}

MYBOOL __WINAPI is_unbounded(lprec *lp, int colnr)
{
  MYBOOL test;

  if((colnr > lp->columns) || (colnr < 1)) {
    report(lp, IMPORTANT, "is_unbounded: Column %d out of range\n", colnr);
    return(FALSE);
  }

  test = is_splitvar(lp, colnr);
  if(!test) {
    colnr += lp->rows;
    test = (MYBOOL) ((lp->orig_lowbo[colnr] <= -lp->infinite) &&
                     (lp->orig_upbo[colnr] >= lp->infinite));
  }
  return( test );
}

MYBOOL __WINAPI is_negative(lprec *lp, int colnr)
{
  if((colnr > lp->columns) || (colnr < 1)) {
    report(lp, IMPORTANT, "is_negative: Column %d out of range\n", colnr);
    return( FALSE );
  }

  colnr += lp->rows;
  return( (MYBOOL) ((lp->orig_upbo[colnr] <= 0) &&
                    (lp->orig_lowbo[colnr] < 0)) );
}

MYBOOL __WINAPI set_var_weights(lprec *lp, REAL *weights)
{
  if(lp->var_priority != NULL) {
    FREE(lp->var_priority);
  }
  if(weights != NULL) {
    int n;
    allocINT(lp, &lp->var_priority, lp->columns_alloc, FALSE);
    for(n = 0; n < lp->columns; n++) {
      lp->var_priority[n] = n+1;
    }
    n = sortByREAL(lp->var_priority, weights, lp->columns, 0, FALSE);
  }
  return(TRUE);
}

MYBOOL __WINAPI set_var_priority(lprec *lp)
/* Experimental automatic variable ordering/priority setting */
{
  MYBOOL status = FALSE;

  if(is_bb_mode(lp, NODE_AUTOORDER) &&
     (lp->var_priority == NULL) &&
     (SOS_count(lp) == 0)) {

    REAL *rcost = NULL;
    int  i, j, *colorder = NULL;

    allocINT(lp, &colorder, lp->columns+1, FALSE);

    /* Create an "optimal" B&B variable ordering; this MDO-based routine
       returns column indeces in an increasing order of co-dependency.
       It can be argued that arranging the columns in right-to-left
       MDO order should tend to minimize the consequences of choosing the
       wrong variable by reducing the average B&B depth. */
    colorder[0] = lp->columns;
    for(j = 1; j <= lp->columns; j++)
      colorder[j] = lp->rows+j;
    i = getMDO(lp, NULL, colorder, NULL, FALSE);

    /* Map to variable weight */
    allocREAL(lp, &rcost, lp->columns+1, FALSE);
    for(j = lp->columns; j > 0; j--) {
      i = colorder[j]-lp->rows;
      rcost[i] = -j;
    }

   /* Establish the MIP variable priorities */
    set_var_weights(lp, rcost+1);

    FREE(rcost);
    FREE(colorder);
    status = TRUE;
  }

  return( status );
}

int __WINAPI get_var_priority(lprec *lp, int colnr)
{
  if((colnr > lp->columns) || (colnr < 1)) {
    report(lp, IMPORTANT, "get_var_priority: Column %d out of range\n", colnr);
    return(FALSE);
  }

  if(lp->var_priority == NULL)
    return(colnr);
  else
    return(lp->var_priority[colnr - 1]);
}

MYBOOL __WINAPI set_semicont(lprec *lp, int colnr, MYBOOL must_be_sc)
{
  if((colnr > lp->columns) || (colnr < 1)) {
    report(lp, IMPORTANT, "set_semicont: Column %d out of range\n", colnr);
    return(FALSE);
  }

  if(lp->sc_lobound[colnr] != 0) {
    lp->sc_vars--;
    lp->var_type[colnr] &= ~ISSEMI;
  }
  lp->sc_lobound[colnr] = must_be_sc;
  if(must_be_sc) {
    lp->var_type[colnr] |= ISSEMI;
    lp->sc_vars++;
  }
  return(TRUE);
}

MYBOOL __WINAPI is_semicont(lprec *lp, int colnr)
{
  if((colnr > lp->columns) || (colnr < 1)) {
    report(lp, IMPORTANT, "is_semicont: Column %d out of range\n", colnr);
    return(FALSE);
  }

  return((lp->var_type[colnr] & ISSEMI) != 0);
}

MYBOOL __WINAPI set_rh(lprec *lp, int rownr, REAL value)
{
  if((rownr > lp->rows) || (rownr < 0)) {
    report(lp, IMPORTANT, "set_rh: Row %d out of range\n", rownr);
    return(FALSE);
  }

  if(((rownr == 0) && (!is_maxim(lp))) ||
     ((rownr > 0) && is_chsign(lp, rownr)))    /* setting of RHS of OF IS meaningful */
    value = my_flipsign(value);
  if(fabs(value) > lp->infinite) {
    if(value < 0)
      value = -lp->infinite;
    else
      value = lp->infinite;
  }
#ifdef DoBorderRounding
  else
    value = my_avoidtiny(value, lp->matA->epsvalue);
#endif
  value = scaled_value(lp, value, rownr);
  lp->orig_rhs[rownr] = value;
  set_action(&lp->spx_action, ACTION_RECOMPUTE);
  return(TRUE);
}

REAL __WINAPI get_rh(lprec *lp, int rownr)
{
  REAL value;

  if((rownr > lp->rows) || (rownr < 0)) {
    report(lp, IMPORTANT, "get_rh: Row %d out of range", rownr);
    return( 0.0 );
  }

  value = lp->orig_rhs[rownr];
  if (((rownr == 0) && !is_maxim(lp)) ||
      ((rownr > 0) && is_chsign(lp, rownr)))    /* setting of RHS of OF IS meaningful */
    value = my_flipsign(value);
  value = unscaled_value(lp, value, rownr);
  return(value);
}

REAL get_rh_upper(lprec *lp, int rownr)
{
  REAL value, valueR;

  value = lp->orig_rhs[rownr];
  if(is_chsign(lp, rownr)) {
    valueR = lp->orig_upbo[rownr];
    if(is_infinite(lp, valueR))
      return(lp->infinite);
    value = my_flipsign(value);
    value += valueR;
  }
  value = unscaled_value(lp, value, rownr);
  return(value);
}

REAL get_rh_lower(lprec *lp, int rownr)
{
  REAL value, valueR;

  value = lp->orig_rhs[rownr];
  if(is_chsign(lp, rownr))
    value = my_flipsign(value);
  else {
    valueR = lp->orig_upbo[rownr];
    if(is_infinite(lp, valueR))
      return(-lp->infinite);
    value -= valueR;
  }
  value = unscaled_value(lp, value, rownr);
  return(value);
}

MYBOOL set_rh_upper(lprec *lp, int rownr, REAL value)
{
  if(rownr > lp->rows || rownr < 1) {
    report(lp, IMPORTANT, "set_rh_upper: Row %d out of range", rownr);
    return(FALSE);
  }

 /* First scale the value */
  value = scaled_value(lp, value, rownr);

 /* orig_rhs stores the upper bound assuming a < constraint;
    If we have a > constraint, we must adjust the range instead */
  if(is_chsign(lp, rownr)) {
    if(is_infinite(lp, value))
      lp->orig_upbo[rownr] = lp->infinite;
    else {
#ifdef Paranoia
      if(value + lp->orig_rhs[rownr] < 0) {
        report(lp, SEVERE, "set_rh_upper: Invalid negative range in row %d\n",
                           rownr);
        return(FALSE);
      }
#endif
#ifdef DoBorderRounding
      lp->orig_upbo[rownr] = my_avoidtiny(value + lp->orig_rhs[rownr], lp->epsvalue);
#else
      lp->orig_upbo[rownr] = value + lp->orig_rhs[rownr];
#endif
    }
  }
  else {
    /* If there is a constraint range, then this has to be adjusted also */
    if(!is_infinite(lp, lp->orig_upbo[rownr])) {
      lp->orig_upbo[rownr] -= lp->orig_rhs[rownr] - value;
      my_roundzero(lp->orig_upbo[rownr], lp->epsvalue);
      if(lp->orig_upbo[rownr] < 0) {
        report(lp, IMPORTANT, "set_rh_upper: Negative bound set for constraint %d made 0\n", rownr);
        lp->orig_upbo[rownr] = 0;
      }
    }
    lp->orig_rhs[rownr] = value;
  }
  return(TRUE);
}

MYBOOL set_rh_lower(lprec *lp, int rownr, REAL value)
{
  if(rownr > lp->rows || rownr < 1) {
    report(lp, IMPORTANT, "set_rh_lower: Row %d out of range", rownr);
    return(FALSE);
  }

 /* First scale the value */
  value = scaled_value(lp, value, rownr);

 /* orig_rhs stores the upper bound assuming a < constraint;
    If we have a < constraint, we must adjust the range instead */
  if(!is_chsign(lp, rownr)) {
    if(is_infinite(lp, value))
      lp->orig_upbo[rownr] = lp->infinite;
    else {
#ifdef Paranoia
      if(lp->orig_rhs[rownr] - value < 0) {
        report(lp, SEVERE, "set_rh_lower: Invalid negative range in row %d\n",
                           rownr);
        return(FALSE);
      }
#endif
#ifdef DoBorderRounding
      lp->orig_upbo[rownr] = my_avoidtiny(lp->orig_rhs[rownr] - value, lp->epsvalue);
#else
      lp->orig_upbo[rownr] = lp->orig_rhs[rownr] - value;
#endif
    }
  }
  else {
    value = my_flipsign(value);
    /* If there is a constraint range, then this has to be adjusted also */
    if(!is_infinite(lp, lp->orig_upbo[rownr])) {
      lp->orig_upbo[rownr] -= lp->orig_rhs[rownr] - value;
      my_roundzero(lp->orig_upbo[rownr], lp->epsvalue);
      if(lp->orig_upbo[rownr] < 0) {
        report(lp, IMPORTANT, "set_rh_lower: Negative bound set for constraint %d made 0\n", rownr);
        lp->orig_upbo[rownr] = 0;
      }
    }
    lp->orig_rhs[rownr] = value;
  }
  return(TRUE);
}

MYBOOL __WINAPI set_rh_range(lprec *lp, int rownr, REAL deltavalue)
{
  if((rownr > lp->rows) || (rownr < 1)) {
    report(lp, IMPORTANT, "set_rh_range: Row %d out of range", rownr);
    return(FALSE);
  }

  deltavalue = scaled_value(lp, deltavalue, rownr);
  if(deltavalue > lp->infinite)
    deltavalue = lp->infinite;
  else if(deltavalue < -lp->infinite)
    deltavalue = -lp->infinite;
#ifdef DoBorderRounding
  else
    deltavalue = my_avoidtiny(deltavalue, lp->matA->epsvalue);
#endif

  if(fabs(deltavalue) < lp->epsprimal) {
    /* Conversion to EQ */
    set_constr_type(lp, rownr, EQ);
  }
  else if(is_constr_type(lp, rownr, EQ)) {
    /* EQ with a non-zero range */
    if(deltavalue > 0)
      set_constr_type(lp, rownr, GE);
    else
      set_constr_type(lp, rownr, LE);
    lp->orig_upbo[rownr] = fabs(deltavalue);
  }
  else {
    /* Modify GE/LE ranges */
    lp->orig_upbo[rownr] = fabs(deltavalue);
  }

  return(TRUE);
}

REAL __WINAPI get_rh_range(lprec *lp, int rownr)
{
  if((rownr > lp->rows) || (rownr < 0)) {
    report(lp, IMPORTANT, "get_rh_range: row %d out of range\n", rownr);
    return(FALSE);
  }

  if(lp->orig_upbo[rownr] >= lp->infinite)
    return(lp->orig_upbo[rownr]);
  else
    return(unscaled_value(lp, lp->orig_upbo[rownr], rownr));
}

void __WINAPI set_rh_vec(lprec *lp, REAL *rh)
{
  int  i;
  REAL rhi;

  for(i = 1; i <= lp->rows; i++) {
    rhi = rh[i];
#ifdef DoBorderRounding
    rhi = my_avoidtiny(rhi, lp->matA->epsvalue);
#endif
    lp->orig_rhs[i] = my_chsign(is_chsign(lp, i), scaled_value(lp, rhi, i));
  }
  set_action(&lp->spx_action, ACTION_RECOMPUTE);
}

MYBOOL __WINAPI str_set_rh_vec(lprec *lp, char *rh_string)
{
  int  i;
  MYBOOL ret = TRUE;
  REAL *newrh;
  char *p, *newp;

  allocREAL(lp, &newrh, lp->rows + 1, TRUE);
  p = rh_string;

  for(i = 1; i <= lp->rows; i++) {
    newrh[i] = (REAL) strtod(p, &newp);
    if(p == newp) {
      report(lp, IMPORTANT, "str_set_rh_vec: Bad string %s\n", p);
      lp->spx_status = DATAIGNORED;
      ret = FALSE;
      break;
    }
    else
      p = newp;
  }
  if(!(lp->spx_status == DATAIGNORED))
    set_rh_vec(lp, newrh);
  FREE(newrh);
  return( ret );
}

void __WINAPI set_sense(lprec *lp, MYBOOL maximize)
{
  maximize = (MYBOOL) (maximize != FALSE);
  if(is_maxim(lp) != maximize) {
    int i;
    if(is_infinite(lp, lp->bb_heuristicOF))
      lp->bb_heuristicOF = my_chsign(maximize, lp->infinite);
    if(is_infinite(lp, lp->bb_breakOF))
      lp->bb_breakOF = my_chsign(maximize, -lp->infinite);
    lp->orig_rhs[0] = my_flipsign(lp->orig_rhs[0]);
    for(i = 1; i <= lp->columns; i++)
      lp->orig_obj[i] = my_flipsign(lp->orig_obj[i]);
    set_action(&lp->spx_action, ACTION_REINVERT | ACTION_RECOMPUTE);
  }
  if(maximize)
    lp->row_type[0] = ROWTYPE_OFMAX;
  else
    lp->row_type[0] = ROWTYPE_OFMIN;
}

void __WINAPI set_maxim(lprec *lp)
{
  set_sense(lp, TRUE);
}

void __WINAPI set_minim(lprec *lp)
{
  set_sense(lp, FALSE);
}

MYBOOL __WINAPI is_maxim(lprec *lp)
{
  return( (MYBOOL) ((lp->row_type != NULL) &&
                     ((lp->row_type[0] & ROWTYPE_CHSIGN) == ROWTYPE_GE)) );
}

MYBOOL __WINAPI set_constr_type(lprec *lp, int rownr, int con_type)
{
  MYBOOL oldchsign;

  if(rownr > lp->rows+1 || rownr < 1) {
    report(lp, IMPORTANT, "set_constr_type: Row %d out of range\n", rownr);
    return( FALSE );
  }

  /* Prepare for a new row */
  if((rownr > lp->rows) && !append_rows(lp, rownr-lp->rows))
    return( FALSE );

  /* Update the constraint type data */
  if(is_constr_type(lp, rownr, EQ))
    lp->equalities--;

  if((con_type & ROWTYPE_CONSTRAINT) == EQ) {
    lp->equalities++;
    lp->orig_upbo[rownr] = 0;
  }
  else if(((con_type & LE) > 0) || ((con_type & GE) > 0) || (con_type == FR))
    lp->orig_upbo[rownr] = lp->infinite;
  else {
    report(lp, IMPORTANT, "set_constr_type: Constraint type %d not implemented (row %d)\n",
                          con_type, rownr);
    return( FALSE );
  }

  /* Change the signs of the row, if necessary */
  oldchsign = is_chsign(lp, rownr);
  if(con_type == FR)
    lp->row_type[rownr] = LE;
  else
    lp->row_type[rownr] = con_type;
  if(oldchsign != is_chsign(lp, rownr)) {
    MATrec *mat = lp->matA;

    if(mat->is_roworder)
      mat_multcol(mat, rownr, -1, FALSE);
    else
      mat_multrow(mat, rownr, -1);
    if(lp->orig_rhs[rownr] != 0)
      lp->orig_rhs[rownr] *= -1;
    set_action(&lp->spx_action, ACTION_RECOMPUTE);
  }
  if(con_type == FR)
      lp->orig_rhs[rownr] = lp->infinite;

  set_action(&lp->spx_action, ACTION_REINVERT);
  lp->basis_valid = FALSE;

  return( TRUE );
}

/* INLINE */ MYBOOL is_chsign(lprec *lp, int rownr)
{
  return( (MYBOOL) ((lp->row_type[rownr] & ROWTYPE_CONSTRAINT) == ROWTYPE_CHSIGN) );
}

MYBOOL __WINAPI is_constr_type(lprec *lp, int rownr, int mask)
{
  if((rownr < 0) || (rownr > lp->rows)) {
    report(lp, IMPORTANT, "is_constr_type: Row %d out of range\n", rownr);
    return( FALSE );
  }
  return( (MYBOOL) ((lp->row_type[rownr] & ROWTYPE_CONSTRAINT) == mask));
}

int __WINAPI get_constr_type(lprec *lp, int rownr)
{
  if((rownr < 0) || (rownr > lp->rows)) {
    report(lp, IMPORTANT, "get_constr_type: Row %d out of range\n", rownr);
    return(-1);
  }
  return( lp->row_type[rownr] );
}
REAL __WINAPI get_constr_value(lprec *lp, int rownr, int count, REAL *primsolution, int *nzindex)
{
  int    i;
  REAL   value = 0.0;
  MATrec *mat = lp->matA;

  if((rownr < 0) || (rownr > get_Nrows(lp)))
    return( value );

  /* First do validation and initialization of applicable primal solution */
  if(!mat_validate(mat) || ((primsolution == NULL) && (lp->solvecount == 0)))
    return( value );
  i = get_Ncolumns(lp);
  if((primsolution != NULL) && (nzindex == NULL) &&
     ((count <= 0) || (count > i)))
    count = i;
  if(primsolution == NULL) {
    get_ptr_variables(lp, &primsolution);
    primsolution--;
    nzindex = NULL;
    count = i;
  }

  /* Do objective or constraint, as specified */
  if(rownr == 0) {
    value += get_rh(lp, 0);
    if(nzindex != NULL)
      for(i = 0; i < count; i++)
        value += get_mat(lp, 0, nzindex[i]) * primsolution[i];
    else
      for(i = 1; i <= count; i++)
        value += get_mat(lp, 0, i) * primsolution[i];
  }
  else {
    if(nzindex != NULL) {
      for(i = 0; i < count; i++)
        value += get_mat(lp, rownr, nzindex[i]) * primsolution[i];
    }
    else {
      int j;

      for(i = mat->row_end[rownr-1]; i < mat->row_end[rownr]; i++) {
        j = ROW_MAT_COLNR(i);
        value += unscaled_mat(lp, ROW_MAT_VALUE(i), rownr, j) * primsolution[j];
      }
      value = my_chsign(is_chsign(lp, rownr), value);
    }
  }
  return( value );
}

STATIC char *get_str_constr_class(lprec *lp, int con_class)
{
  switch(con_class) {
    case ROWCLASS_Unknown:     return("Unknown");
    case ROWCLASS_Objective:   return("Objective");
    case ROWCLASS_GeneralREAL: return("General REAL");
    case ROWCLASS_GeneralMIP:  return("General MIP");
    case ROWCLASS_GeneralINT:  return("General INT");
    case ROWCLASS_GeneralBIN:  return("General BIN");
    case ROWCLASS_KnapsackINT: return("Knapsack INT");
    case ROWCLASS_KnapsackBIN: return("Knapsack BIN");
    case ROWCLASS_SetPacking:  return("Set packing");
    case ROWCLASS_SetCover:    return("Set cover");
    case ROWCLASS_GUB:         return("GUB");
    default:                   return("Error");
  }
}

STATIC char *get_str_constr_type(lprec *lp, int con_type)
{
  switch(con_type) {
    case FR: return("FR");
    case LE: return("LE");
    case GE: return("GE");
    case EQ: return("EQ");
    default: return("Error");
  }
}

STATIC int get_constr_class(lprec *lp, int rownr)
{
  int    aBIN = 0, aINT = 0, aREAL = 0,
         xBIN = 0, xINT = 0, xREAL = 0;
  int    j, elmnr, elmend, nelm;
  MYBOOL chsign;
  REAL   a;
  MATrec *mat = lp->matA;

  if((rownr < 1) || (rownr > lp->rows)) {
    report(lp, IMPORTANT, "get_constr_class: Row %d out of range\n", rownr);
    return( ROWCLASS_Unknown );
  }
  mat_validate(mat);

  /* Tally counts of constraint variable types and coefficients */
  if(rownr == 0) {
    elmnr = 1;
    elmend = lp->columns;
    nelm = 0;
  }
  else {
    elmnr  = mat->row_end[rownr - 1];
    elmend = mat->row_end[rownr];
    nelm = elmend - elmnr;
  }
  chsign = is_chsign(lp, rownr);
  for(; elmnr < elmend; elmnr++) {
    if(rownr == 0) {
      a = lp->orig_obj[elmnr];
      if(a == 0)
        continue;
      j = elmnr;
    }
    else {
      j = ROW_MAT_COLNR(elmnr);
      a = ROW_MAT_VALUE(elmnr);
    }
    a = unscaled_mat(lp, my_chsign(chsign, a), rownr, j);
    if(is_binary(lp, j))
      xBIN++;
    else if((get_lowbo(lp, j) >= 0) && is_int(lp, j))
      xINT++;
    else
      xREAL++;  /* Includes integer variables with negative lower bound */

    if(fabs(a-1.0) < lp->epsvalue)
      aBIN++;
    else if((a > 0) && (fabs(floor(a+lp->epsvalue)-a) < lp->epsvalue))
      aINT++;
    else
      aREAL++;  /* Includes negative integer-valued coefficients */
  }

  /* Get the constraint type and the RHS */
  if(rownr == 0)
    return( ROWCLASS_Objective );
  j = get_constr_type(lp, rownr);
  a = get_rh(lp, rownr);

  /* Determine the constraint class */
  if((aBIN == nelm) && (xBIN == nelm) && (a >= 1)) {
    if(a > 1)
      j = ROWCLASS_KnapsackBIN;
    else if(j == EQ)
      j = ROWCLASS_GUB;
    else if(j == LE)
      j = ROWCLASS_SetCover;
    else
      j = ROWCLASS_SetPacking;
  }
  else if((aINT == nelm) && (xINT == nelm) && (a >= 1))
    j = ROWCLASS_KnapsackINT;
  else if(xBIN == nelm)
    j = ROWCLASS_GeneralBIN;
  else if(xINT == nelm)
    j = ROWCLASS_GeneralINT;
  else if((xREAL > 0) && (xINT+xBIN > 0))
    j = ROWCLASS_GeneralMIP;
  else
    j = ROWCLASS_GeneralREAL;

  return( j );
}

REAL __WINAPI get_mat(lprec *lp, int rownr, int colnr)
{
  REAL value;
  int  elmnr;
  int colnr1 = colnr, rownr1 = rownr;

  if((rownr < 0) || (rownr > lp->rows)) {
    report(lp, IMPORTANT, "get_mat: Row %d out of range", rownr);
    return(0);
  }
  if((colnr < 1) || (colnr > lp->columns)) {
    report(lp, IMPORTANT, "get_mat: Column %d out of range", colnr);
    return(0);
  }
  if(rownr == 0) {
    value = lp->orig_obj[colnr];
    value = my_chsign(is_chsign(lp, rownr), value);
    value = unscaled_mat(lp, value, rownr, colnr);
  }
  else {
    if(lp->matA->is_roworder)
      swapINT(&colnr1, &rownr1);
    elmnr = mat_findelm(lp->matA, rownr1, colnr1);
    if(elmnr >= 0) {
      MATrec *mat = lp->matA;
      value = my_chsign(is_chsign(lp, rownr), COL_MAT_VALUE(elmnr));
      value = unscaled_mat(lp, value, rownr, colnr);
    }
    else
      value = 0;
  }
  return(value);
}

REAL __WINAPI get_mat_byindex(lprec *lp, int matindex, MYBOOL isrow, MYBOOL adjustsign)
/* Note that this function does not adjust for sign-changed GT constraints! */
{
  int  *rownr, *colnr;
  REAL *value, result;

  mat_get_data(lp, matindex, isrow, &rownr, &colnr, &value);
  if(adjustsign)
    result = (*value) * (is_chsign(lp, *rownr) ? -1 : 1);
  else
    result = *value;
  if(lp->scaling_used)
    return( unscaled_mat(lp, result, *rownr, *colnr) );
  else
    return( result );
}

static int mat_getrow(lprec *lp, int rownr, REAL *row, int *colno)
{
  MYBOOL isnz;
  int    j, countnz = 0;
  REAL   a;

  if((rownr == 0) || !mat_validate(lp->matA)) {
    for(j = 1; j <= lp->columns; j++) {
      a = get_mat(lp,rownr,j);
      isnz = (a != 0);
      if(colno == NULL)
        row[j] = a;
      else if(isnz) {
        row[countnz]   = a;
        colno[countnz] = j;
      }
      if(isnz)
        countnz++;
    }
  }
  else {
    MYBOOL chsign = FALSE;
    int    ie, i;
    MATrec *mat = lp->matA;

    if(colno == NULL)
      MEMCLEAR(row, lp->columns+1);
    if(mat->is_roworder) {
     /* Add the objective function */
      a = get_mat(lp, 0, rownr);
      if(colno == NULL) {
        row[countnz] = a;
        if(a != 0)
          countnz++;
      }
      else if(a != 0) {
        row[countnz] = a;
        colno[countnz] = 0;
        countnz++;
      }
    }
    i = mat->row_end[rownr-1];
    ie = mat->row_end[rownr];
    if(!lp->matA->is_roworder)
      chsign = is_chsign(lp, rownr);
    for(; i < ie; i++) {
      j = ROW_MAT_COLNR(i);
      a = get_mat_byindex(lp, i, TRUE, FALSE);
      if(lp->matA->is_roworder)
        chsign = is_chsign(lp, j);
      a = my_chsign(chsign, a);
      if(colno == NULL)
        row[j] = a;
      else {
        row[countnz]   = a;
        colno[countnz] = j;
      }
      countnz++;
    }
  }
  return( countnz );
}

static int mat_getcolumn(lprec *lp, int colnr, REAL *column, int *nzrow)
{
  int    n = 0, i, ii, ie, *rownr;
  REAL   hold, *value;
  MATrec *mat = lp->matA;

  if(nzrow == NULL)
    MEMCLEAR(column, lp->rows + 1);
  if(!mat->is_roworder) {
     /* Add the objective function */
    hold = get_mat(lp, 0, colnr);
    if(nzrow == NULL) {
      column[n] = hold;
      if(hold != 0)
        n++;
    }
    else if(hold != 0) {
      column[n] = hold;
      nzrow[n] = 0;
      n++;
    }
  }

  i  = lp->matA->col_end[colnr - 1];
  ie = lp->matA->col_end[colnr];
  if(nzrow == NULL)
    n += ie - i;
  rownr = &COL_MAT_ROWNR(i);
  value = &COL_MAT_VALUE(i);
  for(; i < ie;
      i++, rownr += matRowColStep, value += matValueStep) {
    ii = *rownr;

    hold = my_chsign(is_chsign(lp, (mat->is_roworder) ? colnr : ii), *value);
    hold = unscaled_mat(lp, hold, ii, colnr);
    if(nzrow == NULL)
      column[ii] = hold;
    else if(hold != 0) {
      column[n] = hold;
      nzrow[n] = ii;
      n++;
    }
  }
  return( n );
}

int __WINAPI get_columnex(lprec *lp, int colnr, REAL *column, int *nzrow)
{
  if((colnr > lp->columns) || (colnr < 1)) {
    report(lp, IMPORTANT, "get_columnex: Column %d out of range\n", colnr);
    return( -1 );
  }

  if(lp->matA->is_roworder)
    return(mat_getrow(lp, colnr, column, nzrow));
  else
    return(mat_getcolumn(lp, colnr, column, nzrow));
}

MYBOOL __WINAPI get_column(lprec *lp, int colnr, REAL *column)
{
  return( (MYBOOL) (get_columnex(lp, colnr, column, NULL) >= 0) );
}

int __WINAPI get_rowex(lprec *lp, int rownr, REAL *row, int *colno)
{
  if((rownr < 0) || (rownr > lp->rows)) {
    report(lp, IMPORTANT, "get_rowex: Row %d out of range\n", rownr);
    return( -1 );
  }

  if(rownr != 0 && lp->matA->is_roworder)
    return(mat_getcolumn(lp, rownr, row, colno));
  else
    return(mat_getrow(lp, rownr, row, colno));
}

MYBOOL __WINAPI get_row(lprec *lp, int rownr, REAL *row)
{
  return((MYBOOL) (get_rowex(lp, rownr, row, NULL) >= 0) );
}

STATIC void set_OF_override(lprec *lp, REAL *ofVector)
/* The purpose of this function is to set, or clear if NULL, the
   ofVector[0..columns] as the active objective function instead of
   the one stored in the A-matrix. See also lag_solve().*/
{
  lp->obj = ofVector;
}

MYBOOL modifyOF1(lprec *lp, int index, REAL *ofValue, REAL mult)
/* Adjust objective function values for primal/dual phase 1, if appropriate */
{
  MYBOOL accept = TRUE;

  /* Primal simplex: Set user variables to zero or BigM-scaled */
  if(((lp->simplex_mode & SIMPLEX_Phase1_PRIMAL) != 0) && (abs(lp->P1extraDim) > 0)) {
#ifndef Phase1EliminateRedundant
    if(lp->P1extraDim < 0) {
      if(index > lp->sum + lp->P1extraDim)
        accept = FALSE;
    }
    else
#endif
    if((index <= lp->sum - lp->P1extraDim) || (mult == 0)) {
      if((mult == 0) || (lp->bigM == 0))
        accept = FALSE;
      else
        (*ofValue) /= lp->bigM;
    }
  }

  /* Dual simplex: Subtract P1extraVal from objective function values */
  else if(((lp->simplex_mode & SIMPLEX_Phase1_DUAL) != 0) && (index > lp->rows)) {
#if 1  /* This may help increase sparsity of the (extended) basis matrix;
         Can it introduce degeneracy in some cases? */
    if((lp->P1extraVal != 0) && (lp->orig_obj[index - lp->rows] > 0))
      *ofValue = 0;
    else
#endif
    {
      *ofValue -= lp->P1extraVal;
#if 0
      if(is_action(lp->anti_degen, ANTIDEGEN_RHSPERTURB))
        *ofValue -= rand_uniform(lp, lp->epsperturb);
#endif
    }
  }

  /* Do scaling and test for zero */
  if(accept) {
    (*ofValue) *= mult;
    if(fabs(*ofValue) < lp->epsmachine) {
      (*ofValue) = 0;
      accept = FALSE;
    }
  }
  else
    (*ofValue) = 0;

  return( accept );
}

STATIC void set_OF_p1extra(lprec *lp, REAL p1extra)
{
  int  i;
  REAL *value;

  if(lp->spx_trace)
    report(lp, DETAILED, "set_OF_p1extra: Set dual objective offset to %g at iter %.0f.\n",
                          p1extra, (double) get_total_iter(lp));
  lp->P1extraVal = p1extra;
  if(lp->obj == NULL)
    allocREAL(lp, &lp->obj, lp->columns_alloc+1, TRUE);
  for(i = 1, value = lp->obj+1; i <= lp->columns; i++, value++) {
    *value = lp->orig_obj[i];
    modifyOF1(lp, lp->rows + i, value, 1.0);
  }
}

STATIC void unset_OF_p1extra(lprec *lp)
{
  lp->P1extraVal = 0;
  FREE(lp->obj);
}

REAL __WINAPI get_OF_active(lprec *lp, int varnr, REAL mult)
{
  int  colnr = varnr - lp->rows;
  REAL holdOF = 0;

#ifdef Paranoia
  if((colnr <= 0) || (colnr > lp->columns)) {
    report(lp, SEVERE, "get_OF_active: Invalid column index %d supplied\n", colnr);
  }
  else
#endif
  if(lp->obj == NULL) {
    if(colnr > 0)
      holdOF = lp->orig_obj[colnr];
    modifyOF1(lp, varnr, &holdOF, mult);
  }
  else if(colnr > 0)
    holdOF = lp->obj[colnr] * mult;

  return( holdOF );
}

STATIC MYBOOL is_OF_nz(lprec *lp, int colnr)
{
  return( (MYBOOL) (lp->orig_obj[colnr] != 0) );
}

STATIC int singleton_column(lprec *lp, int row_nr, REAL *column, int *nzlist, REAL value, int *maxabs)
{
  int nz = 1;

  if(nzlist == NULL) {
    MEMCLEAR(column, lp->rows + 1);
    column[row_nr] = value;
  }
  else {
    column[nz] = value;
    nzlist[nz] = row_nr;
  }

  if(maxabs != NULL)
    *maxabs = row_nr;
  return( nz );
}

STATIC int expand_column(lprec *lp, int col_nr, REAL *column, int *nzlist, REAL mult, int *maxabs)
{
  int     i, ie, j, maxidx, nzcount;
  REAL    value, maxval;
  MATrec  *mat = lp->matA;
  REAL    *matValue;
  int     *matRownr;

  /* Retrieve a column from the user data matrix A */
  maxval = 0;
  maxidx = -1;
  if(nzlist == NULL) {
    MEMCLEAR(column, lp->rows + 1);
    i  = mat->col_end[col_nr - 1];
    ie = mat->col_end[col_nr];
    matRownr = &COL_MAT_ROWNR(i);
    matValue = &COL_MAT_VALUE(i);
    nzcount = i;
    for(; i < ie;
        i++, matRownr += matRowColStep, matValue += matValueStep) {
      j = *matRownr;
      value = *matValue;
      if(j > 0) {
        value *= mult;
        if(fabs(value) > maxval) {
          maxval = fabs(value);
          maxidx = j;
        }
      }
      column[j] = value;
    }
    nzcount = i - nzcount;

    /* Get the objective as row 0, optionally adjusting the objective for phase 1 */
    if(lp->obj_in_basis) {
      column[0] = get_OF_active(lp, lp->rows+col_nr, mult);
      if(column[0] != 0)
        nzcount++;
    }
  }
  else {
    nzcount = 0;

    /* Get the objective as row 0, optionally adjusting the objective for phase 1 */
    if(lp->obj_in_basis) {
      value = get_OF_active(lp, lp->rows+col_nr, mult);
      if(value != 0) {
        nzcount++;
        nzlist[nzcount] = 0;
        column[nzcount] = value;
      }
    }

    /* Loop over the non-zero column entries */
    i  = mat->col_end[col_nr - 1];
    ie = mat->col_end[col_nr];
    matRownr = &COL_MAT_ROWNR(i);
    matValue = &COL_MAT_VALUE(i);
    for(; i < ie;
        i++, matRownr += matRowColStep, matValue += matValueStep) {
      j = *matRownr;
      value = (*matValue) * mult;
      nzcount++;
      nzlist[nzcount] = j;
      column[nzcount] = value;
      if(fabs(value) > maxval) {
        maxval = fabs(value);
        maxidx = nzcount;
      }
    }
  }

  if(maxabs != NULL)
    *maxabs = maxidx;
  return( nzcount );
}


/* Retrieve a column vector from the data matrix [1..rows, rows+1..rows+columns];
   needs __WINAPI call model since it may be called from BFPs */
int __WINAPI obtain_column(lprec *lp, int varin, REAL *pcol, int *nzlist, int *maxabs)
{
  REAL value = my_chsign(lp->is_lower[varin], -1);
  if(varin > lp->rows) {
    varin -= lp->rows;
    varin = expand_column(lp, varin, pcol, nzlist, value, maxabs);
  }
  else if(lp->obj_in_basis || (varin > 0))
    varin = singleton_column(lp, varin, pcol, nzlist, value, maxabs);
  else
    varin = get_basisOF(lp, NULL, pcol, nzlist);

  return(varin);
}

/* GENERAL INVARIANT CALLBACK FUNCTIONS */
MYBOOL set_callbacks(lprec *lp)
{
  /* Assign API functions to lp structure (mainly for XLIs) */
  lp->add_column              = add_column;
  lp->add_columnex            = add_columnex;
  lp->add_constraint          = add_constraint;
  lp->add_constraintex        = add_constraintex;
  lp->add_lag_con             = add_lag_con;
  lp->add_SOS                 = add_SOS;
  lp->column_in_lp            = column_in_lp;
  lp->copy_lp                 = copy_lp;
  lp->default_basis           = default_basis;
  lp->del_column              = del_column;
  lp->del_constraint          = del_constraint;
  lp->delete_lp               = delete_lp;
  lp->dualize_lp              = dualize_lp;
  lp->free_lp                 = free_lp;
  lp->get_anti_degen          = get_anti_degen;
  lp->get_basis               = get_basis;
  lp->get_basiscrash          = get_basiscrash;
  lp->get_bb_depthlimit       = get_bb_depthlimit;
  lp->get_bb_floorfirst       = get_bb_floorfirst;
  lp->get_bb_rule             = get_bb_rule;
  lp->get_bounds_tighter      = get_bounds_tighter;
  lp->get_break_at_value      = get_break_at_value;
  lp->get_col_name            = get_col_name;
  lp->get_columnex            = get_columnex;
  lp->get_constr_type         = get_constr_type;
  lp->get_constr_value        = get_constr_value;
  lp->get_constraints         = get_constraints;
  lp->get_dual_solution       = get_dual_solution;
  lp->get_epsb                = get_epsb;
  lp->get_epsd                = get_epsd;
  lp->get_epsel               = get_epsel;
  lp->get_epsint              = get_epsint;
  lp->get_epsperturb          = get_epsperturb;
  lp->get_epspivot            = get_epspivot;
  lp->get_improve             = get_improve;
  lp->get_infinite            = get_infinite;
  lp->get_lambda              = get_lambda;
  lp->get_lowbo               = get_lowbo;
  lp->get_lp_index            = get_lp_index;
  lp->get_lp_name             = get_lp_name;
  lp->get_Lrows               = get_Lrows;
  lp->get_mat                 = get_mat;
  lp->get_mat_byindex         = get_mat_byindex;
  lp->get_max_level           = get_max_level;
  lp->get_maxpivot            = get_maxpivot;
  lp->get_mip_gap             = get_mip_gap;
  lp->get_multiprice          = get_multiprice;
  lp->get_nameindex           = get_nameindex;
  lp->get_Ncolumns            = get_Ncolumns;
  lp->get_negrange            = get_negrange;
  lp->get_nonzeros            = get_nonzeros;
  lp->get_Norig_columns       = get_Norig_columns;
  lp->get_Norig_rows          = get_Norig_rows;
  lp->get_Nrows               = get_Nrows;
  lp->get_obj_bound           = get_obj_bound;
  lp->get_objective           = get_objective;
  lp->get_orig_index          = get_orig_index;
  lp->get_origcol_name        = get_origcol_name;
  lp->get_origrow_name        = get_origrow_name;
  lp->get_partialprice        = get_partialprice;
  lp->get_pivoting            = get_pivoting;
  lp->get_presolve            = get_presolve;
  lp->get_presolveloops       = get_presolveloops;
  lp->get_primal_solution     = get_primal_solution;
  lp->get_print_sol           = get_print_sol;
  lp->get_pseudocosts         = get_pseudocosts;
  lp->get_ptr_constraints     = get_ptr_constraints;
  lp->get_ptr_dual_solution   = get_ptr_dual_solution;
  lp->get_ptr_lambda          = get_ptr_lambda;
  lp->get_ptr_primal_solution = get_ptr_primal_solution;
  lp->get_ptr_sensitivity_obj = get_ptr_sensitivity_obj;
  lp->get_ptr_sensitivity_objex = get_ptr_sensitivity_objex;
  lp->get_ptr_sensitivity_rhs = get_ptr_sensitivity_rhs;
  lp->get_ptr_variables       = get_ptr_variables;
  lp->get_rh                  = get_rh;
  lp->get_rh_range            = get_rh_range;
  lp->get_row                 = get_row;
  lp->get_rowex               = get_rowex;
  lp->get_row_name            = get_row_name;
  lp->get_scalelimit          = get_scalelimit;
  lp->get_scaling             = get_scaling;
  lp->get_sensitivity_obj     = get_sensitivity_obj;
  lp->get_sensitivity_objex   = get_sensitivity_objex;
  lp->get_sensitivity_rhs     = get_sensitivity_rhs;
  lp->get_simplextype         = get_simplextype;
  lp->get_solutioncount       = get_solutioncount;
  lp->get_solutionlimit       = get_solutionlimit;
  lp->get_status              = get_status;
  lp->get_statustext          = get_statustext;
  lp->get_timeout             = get_timeout;
  lp->get_total_iter          = get_total_iter;
  lp->get_total_nodes         = get_total_nodes;
  lp->get_upbo                = get_upbo;
  lp->get_var_branch          = get_var_branch;
  lp->get_var_dualresult      = get_var_dualresult;
  lp->get_var_primalresult    = get_var_primalresult;
  lp->get_var_priority        = get_var_priority;
  lp->get_variables           = get_variables;
  lp->get_verbose             = get_verbose;
  lp->get_working_objective   = get_working_objective;
  lp->has_BFP                 = has_BFP;
  lp->has_XLI                 = has_XLI;
  lp->is_add_rowmode          = is_add_rowmode;
  lp->is_anti_degen           = is_anti_degen;
  lp->is_binary               = is_binary;
  lp->is_break_at_first       = is_break_at_first;
  lp->is_constr_type          = is_constr_type;
  lp->is_debug                = is_debug;
  lp->is_feasible             = is_feasible;
  lp->is_unbounded            = is_unbounded;
  lp->is_infinite             = is_infinite;
  lp->is_int                  = is_int;
  lp->is_integerscaling       = is_integerscaling;
  lp->is_lag_trace            = is_lag_trace;
  lp->is_maxim                = is_maxim;
  lp->is_nativeBFP            = is_nativeBFP;
  lp->is_nativeXLI            = is_nativeXLI;
  lp->is_negative             = is_negative;
  lp->is_obj_in_basis         = is_obj_in_basis;
  lp->is_piv_mode             = is_piv_mode;
  lp->is_piv_rule             = is_piv_rule;
  lp->is_presolve             = is_presolve;
  lp->is_scalemode            = is_scalemode;
  lp->is_scaletype            = is_scaletype;
  lp->is_semicont             = is_semicont;
  lp->is_SOS_var              = is_SOS_var;
  lp->is_trace                = is_trace;
  lp->lp_solve_version        = lp_solve_version;
  lp->make_lp                 = make_lp;
  lp->print_constraints       = print_constraints;
  lp->print_debugdump         = print_debugdump;
  lp->print_duals             = print_duals;
  lp->print_lp                = print_lp;
  lp->print_objective         = print_objective;
  lp->print_scales            = print_scales;
  lp->print_solution          = print_solution;
  lp->print_str               = print_str;
  lp->print_tableau           = print_tableau;
  lp->put_abortfunc           = put_abortfunc;
  lp->put_bb_nodefunc         = put_bb_nodefunc;
  lp->put_bb_branchfunc       = put_bb_branchfunc;
  lp->put_logfunc             = put_logfunc;
  lp->put_msgfunc             = put_msgfunc;
  lp->read_LP                 = read_LP;
  lp->read_MPS                = read_MPS;
  lp->read_XLI                = read_XLI;
  lp->read_basis              = read_basis;
  lp->reset_basis             = reset_basis;
  lp->read_params             = read_params;
  lp->reset_params            = reset_params;
  lp->resize_lp               = resize_lp;
  lp->set_action              = set_action;
  lp->set_add_rowmode         = set_add_rowmode;
  lp->set_anti_degen          = set_anti_degen;
  lp->set_basisvar            = set_basisvar;
  lp->set_basis               = set_basis;
  lp->set_basiscrash          = set_basiscrash;
  lp->set_bb_depthlimit       = set_bb_depthlimit;
  lp->set_bb_floorfirst       = set_bb_floorfirst;
  lp->set_bb_rule             = set_bb_rule;
  lp->set_BFP                 = set_BFP;
  lp->set_binary              = set_binary;
  lp->set_bounds              = set_bounds;
  lp->set_bounds_tighter      = set_bounds_tighter;
  lp->set_break_at_first      = set_break_at_first;
  lp->set_break_at_value      = set_break_at_value;
  lp->set_col_name            = set_col_name;
  lp->set_constr_type         = set_constr_type;
  lp->set_debug               = set_debug;
  lp->set_epsb                = set_epsb;
  lp->set_epsd                = set_epsd;
  lp->set_epsel               = set_epsel;
  lp->set_epsint              = set_epsint;
  lp->set_epslevel            = set_epslevel;
  lp->set_epsperturb          = set_epsperturb;
  lp->set_epspivot            = set_epspivot;
  lp->set_unbounded           = set_unbounded;
  lp->set_improve             = set_improve;
  lp->set_infinite            = set_infinite;
  lp->set_int                 = set_int;
  lp->set_lag_trace           = set_lag_trace;
  lp->set_lowbo               = set_lowbo;
  lp->set_lp_name             = set_lp_name;
  lp->set_mat                 = set_mat;
  lp->set_maxim               = set_maxim;
  lp->set_maxpivot            = set_maxpivot;
  lp->set_minim               = set_minim;
  lp->set_mip_gap             = set_mip_gap;
  lp->set_multiprice          = set_multiprice;
  lp->set_negrange            = set_negrange;
  lp->set_obj                 = set_obj;
  lp->set_obj_bound           = set_obj_bound;
  lp->set_obj_fn              = set_obj_fn;
  lp->set_obj_fnex            = set_obj_fnex;
  lp->set_obj_in_basis        = set_obj_in_basis;
  lp->set_outputfile          = set_outputfile;
  lp->set_outputstream        = set_outputstream;
  lp->set_partialprice        = set_partialprice;
  lp->set_pivoting            = set_pivoting;
  lp->set_preferdual          = set_preferdual;
  lp->set_presolve            = set_presolve;
  lp->set_print_sol           = set_print_sol;
  lp->set_pseudocosts         = set_pseudocosts;
  lp->set_rh                  = set_rh;
  lp->set_rh_range            = set_rh_range;
  lp->set_rh_vec              = set_rh_vec;
  lp->set_row                 = set_row;
  lp->set_rowex               = set_rowex;
  lp->set_row_name            = set_row_name;
  lp->set_scalelimit          = set_scalelimit;
  lp->set_scaling             = set_scaling;
  lp->set_semicont            = set_semicont;
  lp->set_sense               = set_sense;
  lp->set_simplextype         = set_simplextype;
  lp->set_solutionlimit       = set_solutionlimit;
  lp->set_timeout             = set_timeout;
  lp->set_trace               = set_trace;
  lp->set_upbo                = set_upbo;
  lp->set_var_branch          = set_var_branch;
  lp->set_var_weights         = set_var_weights;
  lp->set_verbose             = set_verbose;
  lp->set_XLI                 = set_XLI;
  lp->solve                   = solve;
  lp->str_add_column          = str_add_column;
  lp->str_add_constraint      = str_add_constraint;
  lp->str_add_lag_con         = str_add_lag_con;
  lp->str_set_obj_fn          = str_set_obj_fn;
  lp->str_set_rh_vec          = str_set_rh_vec;
  lp->time_elapsed            = time_elapsed;
  lp->unscale                 = unscale;
  lp->write_lp                = write_lp;
  lp->write_LP                = write_LP;
  lp->write_mps               = write_mps;
  lp->write_freemps           = write_freemps;
  lp->write_MPS               = write_MPS;
  lp->write_freeMPS           = write_freeMPS;
  lp->write_XLI               = write_XLI;
  lp->write_basis             = write_basis;
  lp->write_params            = write_params;

  /* Utility functions (mainly for BFPs) */
  lp->userabort               = userabort;
  lp->report                  = report;
  lp->explain                 = explain;
  lp->set_basisvar            = set_basisvar;
  lp->get_lpcolumn            = obtain_column;
  lp->get_basiscolumn         = get_basiscolumn;
  lp->get_OF_active           = get_OF_active;
  lp->getMDO                  = getMDO;
  lp->invert                  = invert;
  lp->set_action              = set_action;
  lp->clear_action            = clear_action;
  lp->is_action               = is_action;

  return( TRUE );
}

/* SUPPORT FUNCTION FOR BASIS FACTORIZATION PACKAGES */
MYBOOL __WINAPI has_BFP(lprec *lp)
{
  return( is_nativeBFP(lp)
#if LoadInverseLib == TRUE
       || (MYBOOL) (lp->hBFP != NULL)
#endif
        );
}

MYBOOL __WINAPI is_nativeBFP(lprec *lp)
{
#ifdef ExcludeNativeInverse
  return( FALSE );
#elif LoadInverseLib == TRUE
  return( (MYBOOL) (lp->hBFP == NULL) );
#else
  return( TRUE );
#endif
}

MYBOOL __WINAPI set_BFP(lprec *lp, char *filename)
/* (Re)mapping of basis factorization variant methods is done here */
{
  int result = LIB_LOADED;

  /* Release the BFP and basis if we are active */
  if(lp->invB != NULL)
    bfp_free(lp);

#if LoadInverseLib == TRUE
  if(lp->hBFP != NULL) {
  #ifdef WIN32
    FreeLibrary(lp->hBFP);
  #else
    dlclose(lp->hBFP);
  #endif
    lp->hBFP = NULL;
  }
#endif

  if(filename == NULL) {
    if(!is_nativeBFP(lp))
      return( FALSE );
#ifndef ExcludeNativeInverse
    lp->bfp_name = bfp_name;
    lp->bfp_compatible = bfp_compatible;
    lp->bfp_free = bfp_free;
    lp->bfp_resize = bfp_resize;
    lp->bfp_nonzeros = bfp_nonzeros;
    lp->bfp_memallocated = bfp_memallocated;
    lp->bfp_restart = bfp_restart;
    lp->bfp_mustrefactorize = bfp_mustrefactorize;
    lp->bfp_preparefactorization = bfp_preparefactorization;
    lp->bfp_factorize = bfp_factorize;
    lp->bfp_finishupdate = bfp_finishupdate;
    lp->bfp_ftran_normal = bfp_ftran_normal;
    lp->bfp_ftran_prepare = bfp_ftran_prepare;
    lp->bfp_btran_normal = bfp_btran_normal;
    lp->bfp_status = bfp_status;
    lp->bfp_implicitslack = bfp_implicitslack;
    lp->bfp_indexbase = bfp_indexbase;
    lp->bfp_rowoffset = bfp_rowoffset;
    lp->bfp_pivotmax = bfp_pivotmax;
    lp->bfp_init = bfp_init;
    lp->bfp_pivotalloc = bfp_pivotalloc;
    lp->bfp_colcount = bfp_colcount;
    lp->bfp_canresetbasis = bfp_canresetbasis;
    lp->bfp_finishfactorization = bfp_finishfactorization;
    lp->bfp_updaterefactstats = bfp_updaterefactstats;
    lp->bfp_prepareupdate = bfp_prepareupdate;
    lp->bfp_pivotRHS = bfp_pivotRHS;
    lp->bfp_btran_double = bfp_btran_double;
    lp->bfp_efficiency = bfp_efficiency;
    lp->bfp_pivotvector = bfp_pivotvector;
    lp->bfp_pivotcount = bfp_pivotcount;
    lp->bfp_refactcount = bfp_refactcount;
    lp->bfp_isSetI = bfp_isSetI;
    lp->bfp_findredundant = bfp_findredundant;
#endif
  }
  else {
#if LoadInverseLib == TRUE
  #ifdef WIN32
   /* Get a handle to the Windows DLL module. */
    lp->hBFP = LoadLibrary(filename);

   /* If the handle is valid, try to get the function addresses. */
    if(lp->hBFP != NULL) {
      lp->bfp_compatible           = (BFPbool_lpintintint *)
                                      GetProcAddress(lp->hBFP, "bfp_compatible");
      if(lp->bfp_compatible == NULL)
        result = LIB_NOINFO;
      else if(lp->bfp_compatible(lp, BFPVERSION, MAJORVERSION, sizeof(REAL))) {

      lp->bfp_name                 = (BFPchar *)
                                      GetProcAddress(lp->hBFP, "bfp_name");
      lp->bfp_free                 = (BFP_lp *)
                                      GetProcAddress(lp->hBFP, "bfp_free");
      lp->bfp_resize               = (BFPbool_lpint *)
                                      GetProcAddress(lp->hBFP, "bfp_resize");
      lp->bfp_nonzeros             = (BFPint_lpbool *)
                                      GetProcAddress(lp->hBFP, "bfp_nonzeros");
      lp->bfp_memallocated         = (BFPint_lp *)
                                      GetProcAddress(lp->hBFP, "bfp_memallocated");
      lp->bfp_restart              = (BFPbool_lp *)
                                      GetProcAddress(lp->hBFP, "bfp_restart");
      lp->bfp_mustrefactorize      = (BFPbool_lp *)
                                      GetProcAddress(lp->hBFP, "bfp_mustrefactorize");
      lp->bfp_preparefactorization = (BFPint_lp *)
                                      GetProcAddress(lp->hBFP, "bfp_preparefactorization");
      lp->bfp_factorize            = (BFPint_lpintintboolbool *)
                                      GetProcAddress(lp->hBFP, "bfp_factorize");
      lp->bfp_finishupdate         = (BFPbool_lpbool *)
                                      GetProcAddress(lp->hBFP, "bfp_finishupdate");
      lp->bfp_ftran_normal         = (BFP_lprealint *)
                                      GetProcAddress(lp->hBFP, "bfp_ftran_normal");
      lp->bfp_ftran_prepare        = (BFP_lprealint *)
                                      GetProcAddress(lp->hBFP, "bfp_ftran_prepare");
      lp->bfp_btran_normal         = (BFP_lprealint *)
                                      GetProcAddress(lp->hBFP, "bfp_btran_normal");
      lp->bfp_status               = (BFPint_lp *)
                                      GetProcAddress(lp->hBFP, "bfp_status");
      lp->bfp_implicitslack        = (BFPbool_lp *)
                                      GetProcAddress(lp->hBFP, "bfp_implicitslack");
      lp->bfp_indexbase            = (BFPint_lp *)
                                      GetProcAddress(lp->hBFP, "bfp_indexbase");
      lp->bfp_rowoffset            = (BFPint_lp *)
                                      GetProcAddress(lp->hBFP, "bfp_rowoffset");
      lp->bfp_pivotmax             = (BFPint_lp *)
                                      GetProcAddress(lp->hBFP, "bfp_pivotmax");
      lp->bfp_init                 = (BFPbool_lpintintchar *)
                                      GetProcAddress(lp->hBFP, "bfp_init");
      lp->bfp_pivotalloc           = (BFPbool_lpint *)
                                      GetProcAddress(lp->hBFP, "bfp_pivotalloc");
      lp->bfp_colcount             = (BFPint_lp *)
                                      GetProcAddress(lp->hBFP, "bfp_colcount");
      lp->bfp_canresetbasis        = (BFPbool_lp *)
                                      GetProcAddress(lp->hBFP, "bfp_canresetbasis");
      lp->bfp_finishfactorization  = (BFP_lp *)
                                      GetProcAddress(lp->hBFP, "bfp_finishfactorization");
      lp->bfp_updaterefactstats    = (BFP_lp *)
                                      GetProcAddress(lp->hBFP, "bfp_updaterefactstats");
      lp->bfp_prepareupdate        = (BFPlreal_lpintintreal *)
                                      GetProcAddress(lp->hBFP, "bfp_prepareupdate");
      lp->bfp_pivotRHS             = (BFPreal_lplrealreal *)
                                      GetProcAddress(lp->hBFP, "bfp_pivotRHS");
      lp->bfp_btran_double         = (BFP_lprealintrealint *)
                                      GetProcAddress(lp->hBFP, "bfp_btran_double");
      lp->bfp_efficiency           = (BFPreal_lp *)
                                      GetProcAddress(lp->hBFP, "bfp_efficiency");
      lp->bfp_pivotvector          = (BFPrealp_lp *)
                                      GetProcAddress(lp->hBFP, "bfp_pivotvector");
      lp->bfp_pivotcount           = (BFPint_lp *)
                                      GetProcAddress(lp->hBFP, "bfp_pivotcount");
      lp->bfp_refactcount          = (BFPint_lpint *)
                                      GetProcAddress(lp->hBFP, "bfp_refactcount");
      lp->bfp_isSetI               = (BFPbool_lp *)
                                      GetProcAddress(lp->hBFP, "bfp_isSetI");
      lp->bfp_findredundant        = (BFPint_lpintrealcbintint *)
                                      GetProcAddress(lp->hBFP, "bfp_findredundant");
      }
      else
        result = LIB_VERINVALID;
    }
  #else
   /* First standardize UNIX .SO library name format. */
    char bfpname[260], *ptr;

    strcpy(bfpname, filename);
    if((ptr = strrchr(filename, '/')) == NULL)
      ptr = filename;
    else
      ptr++;
    bfpname[(int) (ptr - filename)] = 0;
    if(strncmp(ptr, "lib", 3))
      strcat(bfpname, "lib");
    strcat(bfpname, ptr);
    if(strcmp(bfpname + strlen(bfpname) - 3, ".so"))
      strcat(bfpname, ".so");

   /* Get a handle to the module. */
    lp->hBFP = dlopen(bfpname, RTLD_LAZY);

   /* If the handle is valid, try to get the function addresses. */
    if(lp->hBFP != NULL) {
      lp->bfp_compatible           = (BFPbool_lpintintint *)
                                      dlsym(lp->hBFP, "bfp_compatible");
      if(lp->bfp_compatible == NULL)
        result = LIB_NOINFO;
      else if(lp->bfp_compatible(lp, BFPVERSION, MAJORVERSION, sizeof(REAL))) {

      lp->bfp_name                 = (BFPchar *)
                                      dlsym(lp->hBFP, "bfp_name");
      lp->bfp_free                 = (BFP_lp *)
                                      dlsym(lp->hBFP, "bfp_free");
      lp->bfp_resize               = (BFPbool_lpint *)
                                      dlsym(lp->hBFP, "bfp_resize");
      lp->bfp_nonzeros             = (BFPint_lpbool *)
                                      dlsym(lp->hBFP, "bfp_nonzeros");
      lp->bfp_memallocated         = (BFPint_lp *)
                                      dlsym(lp->hBFP, "bfp_memallocated");
      lp->bfp_restart              = (BFPbool_lp *)
                                      dlsym(lp->hBFP, "bfp_restart");
      lp->bfp_mustrefactorize      = (BFPbool_lp *)
                                      dlsym(lp->hBFP, "bfp_mustrefactorize");
      lp->bfp_preparefactorization = (BFPint_lp *)
                                      dlsym(lp->hBFP, "bfp_preparefactorization");
      lp->bfp_factorize            = (BFPint_lpintintboolbool *)
                                      dlsym(lp->hBFP, "bfp_factorize");
      lp->bfp_finishupdate         = (BFPbool_lpbool *)
                                      dlsym(lp->hBFP, "bfp_finishupdate");
      lp->bfp_ftran_normal         = (BFP_lprealint *)
                                      dlsym(lp->hBFP, "bfp_ftran_normal");
      lp->bfp_ftran_prepare        = (BFP_lprealint *)
                                      dlsym(lp->hBFP, "bfp_ftran_prepare");
      lp->bfp_btran_normal         = (BFP_lprealint *)
                                      dlsym(lp->hBFP, "bfp_btran_normal");
      lp->bfp_status               = (BFPint_lp *)
                                      dlsym(lp->hBFP, "bfp_status");
      lp->bfp_implicitslack        = (BFPbool_lp *)
                                      dlsym(lp->hBFP, "bfp_implicitslack");
      lp->bfp_indexbase            = (BFPint_lp *)
                                      dlsym(lp->hBFP, "bfp_indexbase");
      lp->bfp_rowoffset            = (BFPint_lp *)
                                      dlsym(lp->hBFP, "bfp_rowoffset");
      lp->bfp_pivotmax             = (BFPint_lp *)
                                      dlsym(lp->hBFP, "bfp_pivotmax");
      lp->bfp_init                 = (BFPbool_lpintintchar *)
                                      dlsym(lp->hBFP, "bfp_init");
      lp->bfp_pivotalloc           = (BFPbool_lpint *)
                                      dlsym(lp->hBFP, "bfp_pivotalloc");
      lp->bfp_colcount             = (BFPint_lp *)
                                      dlsym(lp->hBFP, "bfp_colcount");
      lp->bfp_canresetbasis        = (BFPbool_lp *)
                                      dlsym(lp->hBFP, "bfp_canresetbasis");
      lp->bfp_finishfactorization  = (BFP_lp *)
                                      dlsym(lp->hBFP, "bfp_finishfactorization");
      lp->bfp_updaterefactstats    = (BFP_lp *)
                                      dlsym(lp->hBFP, "bfp_updaterefactstats");
      lp->bfp_prepareupdate        = (BFPlreal_lpintintreal *)
                                      dlsym(lp->hBFP, "bfp_prepareupdate");
      lp->bfp_pivotRHS             = (BFPreal_lplrealreal *)
                                      dlsym(lp->hBFP, "bfp_pivotRHS");
      lp->bfp_btran_double         = (BFP_lprealintrealint *)
                                      dlsym(lp->hBFP, "bfp_btran_double");
      lp->bfp_efficiency           = (BFPreal_lp *)
                                      dlsym(lp->hBFP, "bfp_efficiency");
      lp->bfp_pivotvector          = (BFPrealp_lp *)
                                      dlsym(lp->hBFP, "bfp_pivotvector");
      lp->bfp_pivotcount           = (BFPint_lp *)
                                      dlsym(lp->hBFP, "bfp_pivotcount");
      lp->bfp_refactcount          = (BFPint_lpint *)
                                      dlsym(lp->hBFP, "bfp_refactcount");
      lp->bfp_isSetI               = (BFPbool_lp *)
                                      dlsym(lp->hBFP, "bfp_isSetI");
      lp->bfp_findredundant        = (BFPint_lpintrealcbintint *)
                                      dlsym(lp->hBFP, "bfp_findredundant");
      }
      else
        result = LIB_VERINVALID;
    }
  #endif
    else
      result = LIB_NOTFOUND;
#endif
    /* Do validation */
    if((result != LIB_LOADED) ||
       ((lp->bfp_name == NULL) ||
        (lp->bfp_compatible == NULL) ||
        (lp->bfp_free == NULL) ||
        (lp->bfp_resize == NULL) ||
        (lp->bfp_nonzeros == NULL) ||
        (lp->bfp_memallocated == NULL) ||
        (lp->bfp_restart == NULL) ||
        (lp->bfp_mustrefactorize == NULL) ||
        (lp->bfp_preparefactorization == NULL) ||
        (lp->bfp_factorize == NULL) ||
        (lp->bfp_finishupdate == NULL) ||
        (lp->bfp_ftran_normal == NULL) ||
        (lp->bfp_ftran_prepare == NULL) ||
        (lp->bfp_btran_normal == NULL) ||
        (lp->bfp_status == NULL) ||
        (lp->bfp_implicitslack == NULL) ||
        (lp->bfp_indexbase == NULL) ||
        (lp->bfp_rowoffset == NULL) ||
        (lp->bfp_pivotmax == NULL) ||
        (lp->bfp_init == NULL) ||
        (lp->bfp_pivotalloc == NULL) ||
        (lp->bfp_colcount == NULL) ||
        (lp->bfp_canresetbasis == NULL) ||
        (lp->bfp_finishfactorization == NULL) ||
        (lp->bfp_updaterefactstats == NULL) ||
        (lp->bfp_prepareupdate == NULL) ||
        (lp->bfp_pivotRHS == NULL) ||
        (lp->bfp_btran_double == NULL) ||
        (lp->bfp_efficiency == NULL) ||
        (lp->bfp_pivotvector == NULL) ||
        (lp->bfp_pivotcount == NULL) ||
        (lp->bfp_refactcount == NULL) ||
        (lp->bfp_isSetI == NULL) ||
        (lp->bfp_findredundant == NULL)
       )) {
      set_BFP(lp, NULL);
      if(result == LIB_LOADED)
        result = LIB_NOFUNCTION;
    }
  }
  if(filename != NULL) {
    char info[LIB_STR_MAXLEN+1];
    switch(result) {
      case LIB_NOTFOUND:   strcpy(info, LIB_STR_NOTFOUND);
                           break;
      case LIB_NOINFO:     strcpy(info, LIB_STR_NOINFO);
                           break;
      case LIB_NOFUNCTION: strcpy(info, LIB_STR_NOFUNCTION);
                           break;
      case LIB_VERINVALID: strcpy(info, LIB_STR_VERINVALID);
                           break;
      default:             strcpy(info, LIB_STR_LOADED);
    }
    report(lp, IMPORTANT, "set_BFP: %s '%s'\n",
                          info, filename);
  }
  return( (MYBOOL) (result == LIB_LOADED));
}


/* External language interface routines */
/* DON'T MODIFY */
lprec * __WINAPI read_XLI(char *xliname, char *modelname, char *dataname, char *options, int verbose)
{
  lprec *lp;

  lp = make_lp(0, 0);
  if(lp != NULL) {
    lp->source_is_file = TRUE;
    lp->verbose = verbose;
    if(!set_XLI(lp, xliname)) {
      free_lp(&lp);
      printf("read_XLI: No valid XLI package selected or available.\n");
    }
    else {
      if(!lp->xli_readmodel(lp, modelname, (dataname != NULL) && (*dataname != 0) ? dataname : NULL, options, verbose))
        free_lp(&lp);
    }
  }
  return( lp );
}

MYBOOL __WINAPI write_XLI(lprec *lp, char *filename, char *options, MYBOOL results)
{
  return( has_XLI(lp) && mat_validate(lp->matA) && lp->xli_writemodel(lp, filename, options, results) );
}

MYBOOL __WINAPI has_XLI(lprec *lp)
{
  return( is_nativeXLI(lp)
#if LoadLanguageLib == TRUE
       || (MYBOOL) (lp->hXLI != NULL)
#endif
        );
}

MYBOOL __WINAPI is_nativeXLI(lprec *lp)
{
#ifdef ExcludeNativeLanguage
  return( FALSE );
#elif LoadLanguageLib == TRUE
  return( (MYBOOL) (lp->hXLI == NULL) );
#else
  return( TRUE );
#endif
}

MYBOOL __WINAPI set_XLI(lprec *lp, char *filename)
/* (Re)mapping of external language interface variant methods is done here */
{
  int result = LIB_LOADED;

#if LoadLanguageLib == TRUE
  if(lp->hXLI != NULL) {
  #ifdef WIN32
    FreeLibrary(lp->hXLI);
  #else
    dlclose(lp->hXLI);
  #endif
    lp->hXLI = NULL;
  }
#endif

  if(filename == NULL) {
    if(!is_nativeXLI(lp))
      return( FALSE );
#ifndef ExcludeNativeLanguage
    lp->xli_name = xli_name;
    lp->xli_compatible = xli_compatible;
    lp->xli_readmodel = xli_readmodel;
    lp->xli_writemodel = xli_writemodel;
#endif
  }
  else {
#if LoadLanguageLib == TRUE
  #ifdef WIN32
   /* Get a handle to the Windows DLL module. */
    lp->hXLI = LoadLibrary(filename);

   /* If the handle is valid, try to get the function addresses. */
    if(lp->hXLI != NULL) {
      lp->xli_compatible           = (XLIbool_lpintintint *)
                                      GetProcAddress(lp->hXLI, "xli_compatible");
      if(lp->xli_compatible == NULL)
        result = LIB_NOINFO;
      else if(lp->xli_compatible(lp, XLIVERSION, MAJORVERSION, sizeof(REAL))) {

        lp->xli_name                 = (XLIchar *)
                                        GetProcAddress(lp->hXLI, "xli_name");
        lp->xli_readmodel            = (XLIbool_lpcharcharcharint *)
                                        GetProcAddress(lp->hXLI, "xli_readmodel");
        lp->xli_writemodel           = (XLIbool_lpcharcharbool *)
                                        GetProcAddress(lp->hXLI, "xli_writemodel");
      }
      else
        result = LIB_VERINVALID;
    }
  #else
   /* First standardize UNIX .SO library name format. */
    char xliname[260], *ptr;

    strcpy(xliname, filename);
    if((ptr = strrchr(filename, '/')) == NULL)
      ptr = filename;
    else
      ptr++;
    xliname[(int) (ptr - filename)] = 0;
    if(strncmp(ptr, "lib", 3))
      strcat(xliname, "lib");
    strcat(xliname, ptr);
    if(strcmp(xliname + strlen(xliname) - 3, ".so"))
      strcat(xliname, ".so");

   /* Get a handle to the module. */
    lp->hXLI = dlopen(xliname, RTLD_LAZY);

   /* If the handle is valid, try to get the function addresses. */
    if(lp->hXLI != NULL) {
      lp->xli_compatible           = (XLIbool_lpintintint *)
                                      dlsym(lp->hXLI, "xli_compatible");
      if(lp->xli_compatible == NULL)
        result = LIB_NOINFO;
      else if(lp->xli_compatible(lp, XLIVERSION, MAJORVERSION, sizeof(REAL))) {

        lp->xli_name                 = (XLIchar *)
                                        dlsym(lp->hXLI, "xli_name");
        lp->xli_readmodel            = (XLIbool_lpcharcharcharint *)
                                        dlsym(lp->hXLI, "xli_readmodel");
        lp->xli_writemodel           = (XLIbool_lpcharcharbool *)
                                        dlsym(lp->hXLI, "xli_writemodel");
      }
      else
        result = LIB_VERINVALID;
    }
  #endif
    else
      result = LIB_NOTFOUND;
#endif
    /* Do validation */
    if((result != LIB_LOADED) ||
       ((lp->xli_name == NULL) ||
        (lp->xli_compatible == NULL) ||
        (lp->xli_readmodel == NULL) ||
        (lp->xli_writemodel == NULL)
       )) {
      set_XLI(lp, NULL);
      if(result == LIB_LOADED)
        result = LIB_NOFUNCTION;
    }
  }
  if(filename != NULL) {
    char info[LIB_STR_MAXLEN+1];
    switch(result) {
      case LIB_NOTFOUND:   strcpy(info, LIB_STR_NOTFOUND);
                           break;
      case LIB_NOINFO:     strcpy(info, LIB_STR_NOINFO);
                           break;
      case LIB_NOFUNCTION: strcpy(info, LIB_STR_NOFUNCTION);
                           break;
      case LIB_VERINVALID: strcpy(info, LIB_STR_VERINVALID);
                           break;
      default:             strcpy(info, LIB_STR_LOADED);
    }
    report(lp, IMPORTANT, "set_XLI: %s '%s'\n",
                          info, filename);
  }
  return( (MYBOOL) (result == LIB_LOADED));
}


STATIC int get_basisOF(lprec *lp, int coltarget[], REAL crow[], int colno[])
/* Fill vector of basic OF values or subtract incoming values from these.
   This function is called twice during reduced cost updates when the basis
   does not contain the basic OF vector as the top row.  The colno[] array
   is filled with the count of non-zero values and the index to those. */
{
  int            i, n = lp->rows, nz = 0;
  REAL           *obj = lp->obj;
  register REAL epsvalue = lp->epsvalue;

  /* Compute offset over the specified objective indeces (step 2) */
  if(coltarget != NULL) {
    register int  ix, m = coltarget[0];
    register REAL value;

    for(i = 1, coltarget++; i <= m; i++, coltarget++) {
      ix = *coltarget;
      /* Finalize the computation of the reduced costs, based on the format that
         duals are computed as negatives, ref description for step 1 above */
      value = crow[ix];
      if(ix > n)
        value += obj[ix - n];
/*      if(value != 0) { */
      if(fabs(value) > epsvalue) {
        nz++;
        if(colno != NULL)
          colno[nz] = ix;
      }
      else
        value = 0.0;
      crow[ix] = value;
    }
  }

  /* Get the basic objective function values (step 1) */
  else {
    register int *basvar = lp->var_basic;

    for(i = 1, crow++, basvar++; i <= n;
         i++, crow++, basvar++) {
      /* Load the objective value of the active basic variable; note that we
         change the sign of the value to maintain computational compatibility with
         the calculation of duals using in-basis storage of the basic OF values */
      if(*basvar <= n)
        *crow = 0;
      else
        *crow = -obj[(*basvar) - n];
      if((*crow) != 0) {
/*      if(fabs(*crow) > epsvalue) { */
        nz++;
        if(colno != NULL)
          colno[nz] = i;
      }
    }
  }
  if(colno != NULL)
    colno[0] = nz;
  return( nz );
}

int __WINAPI get_basiscolumn(lprec *lp, int j, int rn[], double bj[])
/* This routine returns sparse vectors for all basis
   columns, including the OF dummy (index 0) and slack columns.
   NOTE that the index usage is nonstandard for lp_solve, since
   the array offset is 1, not 0. */
{
  int k = lp->bfp_rowoffset(lp),
      matbase = lp->bfp_indexbase(lp);

  /* Do target index adjustment (etaPFI with matbase==0 is special case) */
  if(matbase > 0)
    matbase += k - 1;

 /* Convert index of slack and user columns */
  j -= k;
  if((j > 0) && !lp->bfp_isSetI(lp))
    j = lp->var_basic[j];

 /* Process OF dummy and slack columns (always at lower bound) */
  if(j <= lp->rows) {
    rn[1] = j + matbase;
    bj[1] = 1.0;
    k = 1;
  }
 /* Process user columns (negated if at lower bound) */
  else {
    k = obtain_column(lp, j, bj, rn, NULL);
    if(matbase != 0)
      for(j = 1; j <= k; j++)
        rn[j] += matbase;
  }

  return( k );
}

MYBOOL __WINAPI get_primal_solution(lprec *lp, REAL *pv)
{
  if(lp->spx_status == OPTIMAL)
    ;
  else if(!lp->basis_valid) {
    report(lp, CRITICAL, "get_primal_solution: Not a valid basis");
    return(FALSE);
  }

  MEMCOPY(pv, lp->best_solution, lp->sum + 1);
  return(TRUE);
}

MYBOOL __WINAPI get_ptr_primal_solution(lprec *lp, REAL **pv)
{
  *pv = lp->best_solution;
  return(TRUE);
}

MYBOOL __WINAPI get_dual_solution(lprec *lp, REAL *rc)
{
  REAL *duals;
  MYBOOL ret;

  if(!lp->basis_valid) {
    report(lp, CRITICAL, "get_dual_solution: Not a valid basis");
    return(FALSE);
  }

  ret = get_ptr_sensitivity_rhs(lp, &duals, NULL, NULL);

  if(ret)
    MEMCOPY(rc, duals - 1, lp->sum + 1);
  return(ret);
}

MYBOOL __WINAPI get_ptr_dual_solution(lprec *lp, REAL **rc)
{
  MYBOOL ret = lp->basis_valid;

  /* Just return availability of dual information if rc is NULL */
  if(rc == NULL)
    return( ret && ((MIP_count(lp) == 0) || (lp->bb_totalnodes > 0)) );

  if(!ret) {
    report(lp, CRITICAL, "get_ptr_dual_solution: Not a valid basis");
    return(ret);
  }

  /* Otherwise, get the pointer to the dual information (and optionally produce it) */
  ret = get_ptr_sensitivity_rhs(lp, rc, NULL, NULL);
  if(ret)
    (*rc)--;

  return(ret);
}

MYBOOL __WINAPI get_lambda(lprec *lp, REAL *lambda)
{
  if(!lp->basis_valid || (get_Lrows(lp) == 0)) {
    report(lp, CRITICAL, "get_lambda: Not a valid basis");
    return(FALSE);
  }

  MEMCOPY(lambda, lp->lambda+1, get_Lrows(lp));
  return(TRUE);
}

MYBOOL __WINAPI get_ptr_lambda(lprec *lp, REAL **lambda)
{
  *lambda = lp->lambda;
  return(TRUE);
}

int __WINAPI get_orig_index(lprec *lp, int lp_index)
{
  if(lp->varmap_locked)
    return(lp->presolve_undo->var_to_orig[lp_index]);
  else if(lp_index <= lp->presolve_undo->orig_rows)
    return(lp_index);
  else
    return(lp_index-lp->presolve_undo->orig_rows);
}
int __WINAPI get_lp_index(lprec *lp, int orig_index)
{
  if(lp->varmap_locked)
    return(lp->presolve_undo->orig_to_var[orig_index]);
  else if(orig_index <= lp->presolve_undo->orig_rows)
    return(orig_index);
  else
    return(orig_index-lp->presolve_undo->orig_rows);
}

MYBOOL __WINAPI is_feasible(lprec *lp, REAL *values, REAL threshold)
/* Recommend to use threshold = lp->epspivot */
{
  int     i, j, elmnr, ie;
  REAL    *this_rhs, dist;
  REAL    *value;
  int     *rownr;
  MATrec  *mat = lp->matA;

  for(i = lp->rows + 1; i <= lp->sum; i++) {
    if(values[i - lp->rows] < unscaled_value(lp, lp->orig_lowbo[i], i)
       || values[i - lp->rows] > unscaled_value(lp, lp->orig_upbo[i], i)) {
      if(!((lp->sc_lobound[i - lp->rows]>0) && (values[i - lp->rows]==0)))
        return(FALSE);
    }
  }

  this_rhs = (REAL *) mempool_obtainVector(lp->workarrays, lp->rows+1, sizeof(*this_rhs));
/*  allocREAL(lp, &this_rhs, lp->rows + 1, TRUE); */
  for(j = 1; j <= lp->columns; j++) {
    elmnr = mat->col_end[j - 1];
    ie = mat->col_end[j];
    rownr = &COL_MAT_ROWNR(elmnr);
    value = &COL_MAT_VALUE(elmnr);
    for(; elmnr < ie; elmnr++, rownr += matRowColStep, value += matValueStep) {
      this_rhs[*rownr] += unscaled_mat(lp, *value, *rownr, j);
    }
  }
  for(i = 1; i <= lp->rows; i++) {
    dist = lp->orig_rhs[i] - this_rhs[i];
    my_roundzero(dist, threshold);
    if((lp->orig_upbo[i] == 0 && dist != 0) ||( dist < 0)) {
      FREE(this_rhs);
      return(FALSE);
    }
  }
  mempool_releaseVector(lp->workarrays, (char *) this_rhs, FALSE);
/*  FREE(this_rhs); */
  return(TRUE);
}

int __WINAPI column_in_lp(lprec *lp, REAL *testcolumn)
{
  int    i, j, je, colnr = 0;
  int    nz, ident = 1;
  MATrec *mat = lp->matA;
  int    *matRownr;
  REAL   value, *matValue;

  for(nz = 0, i = 1; i <= lp->rows; i++)
    if(fabs(testcolumn[i]) > lp->epsvalue) nz++;

  for(i = 1; (i <= lp->columns) && (ident); i++) {
    ident = nz;
    value = fabs(get_mat(lp, 0, i)-testcolumn[0]);
    if(value > lp->epsvalue)
      continue;
    j = mat->col_end[i - 1];
    je = mat->col_end[i];
    matRownr = &COL_MAT_ROWNR(j);
    matValue = &COL_MAT_VALUE(j);
    for(; (j < je) && (ident >= 0);
        j++, ident--, matRownr += matRowColStep, matValue += matValueStep) {
      value = *matValue;
      if(is_chsign(lp, *matRownr))
        value = my_flipsign(value);
      value = unscaled_mat(lp, value, *matRownr, i);
      value -= testcolumn[*matRownr];
      if(fabs(value) > lp->epsvalue)
        break;
    }
    if(ident == 0)
      colnr = i;
  }
  return( colnr );
}

MYBOOL __WINAPI set_lp_name(lprec *lp, char *name)
{
  if (name == NULL) {
    FREE(lp->lp_name);
    lp->lp_name = NULL;
  }
  else {
    allocCHAR(lp, &lp->lp_name, (int) (strlen(name) + 1), AUTOMATIC);
    strcpy(lp->lp_name, name);
  }
  return(TRUE);
}

char * __WINAPI get_lp_name(lprec *lp)
{
  return((lp->lp_name != NULL) ? lp->lp_name : (char *) "");
}

STATIC MYBOOL init_rowcol_names(lprec *lp)
{
  if(!lp->names_used) {
    lp->row_name = (hashelem **) calloc(lp->rows_alloc + 1, sizeof(*lp->row_name));
    lp->col_name = (hashelem **) calloc(lp->columns_alloc + 1, sizeof(*lp->col_name));
    lp->rowname_hashtab = create_hash_table(lp->rows_alloc + 1, 0);
    lp->colname_hashtab = create_hash_table(lp->columns_alloc + 1, 1);
    lp->names_used = TRUE;
  }
  return(TRUE);
}

MYBOOL rename_var(lprec *lp, int varindex, char *new_name, hashelem **list, hashtable **ht)
{
  hashelem *hp;
  MYBOOL   newitem;

  hp = list[varindex];
  newitem = (MYBOOL) (hp == NULL);
  if(newitem)
    hp = puthash(new_name, varindex, list, *ht);
  else if((strlen(hp->name) != strlen(new_name)) ||
          (strcmp(hp->name, new_name) != 0)) {
    hashtable *newht, *oldht;

    allocCHAR(lp, &hp->name, (int) (strlen(new_name) + 1), AUTOMATIC);
    strcpy(hp->name, new_name);
    oldht = *ht;
    newht = copy_hash_table(oldht, list, oldht->size);
    *ht = newht;
    free_hash_table(oldht);
  }
  return(newitem);
}

MYBOOL __WINAPI is_use_names(lprec *lp, MYBOOL isrow)
{
  if(isrow)
    return( lp->use_row_names );
  else
    return( lp->use_col_names );
}

void __WINAPI set_use_names(lprec *lp, MYBOOL isrow, MYBOOL use_names)
{
  if(isrow)
    lp->use_row_names = use_names;
  else
    lp->use_col_names = use_names;
}

int __WINAPI get_nameindex(lprec *lp, char *varname, MYBOOL isrow)
{
  if(isrow)
    return( find_row(lp, varname, FALSE) );
  else
    return( find_var(lp, varname, FALSE) );
}

MYBOOL __WINAPI set_row_name(lprec *lp, int rownr, char *new_name)
{
  if((rownr < 0) || (rownr > lp->rows+1)) {
    report(lp, IMPORTANT, "set_row_name: Row %d out of range", rownr);
    return(FALSE);
  }

  /* Prepare for a new row */
  if((rownr > lp->rows) && !append_rows(lp, rownr-lp->rows))
    return( FALSE );
  if(!lp->names_used) {
    if(!init_rowcol_names(lp))
      return(FALSE);
  }
  rename_var(lp, rownr, new_name, lp->row_name, &lp->rowname_hashtab);

  return(TRUE);
}

char * __WINAPI get_row_name(lprec *lp, int rownr)
{
  if((rownr < 0) || (rownr > lp->rows+1)) {
    report(lp, IMPORTANT, "get_row_name: Row %d out of range", rownr);
    return(NULL);
  }

  if((lp->presolve_undo->var_to_orig != NULL) && lp->wasPresolved) {
    if(lp->presolve_undo->var_to_orig[rownr] == 0)
      rownr = -rownr;
    else
      rownr = lp->presolve_undo->var_to_orig[rownr];
  }
  return( get_origrow_name(lp, rownr) );
}

char * __WINAPI get_origrow_name(lprec *lp, int rownr)
{
  MYBOOL newrow;
  char   *ptr;

  newrow = (MYBOOL) (rownr < 0);
  rownr = abs(rownr);
#ifdef Paranoia
  if(((lp->presolve_undo->var_to_orig == NULL) && newrow) ||
     (rownr > MAX(lp->rows, lp->presolve_undo->orig_rows))) {
    report(lp, IMPORTANT, "get_origrow_name: Row %d out of range", rownr);
    return(NULL);
  }
#endif

  if(lp->names_used && lp->use_row_names && (lp->row_name[rownr] != NULL) &&
                            (lp->row_name[rownr]->name != NULL)) {
#ifdef Paranoia
    if(lp->row_name[rownr]->index != rownr)
      report(lp, SEVERE, "get_origrow_name: Inconsistent row ordinal %d vs %d\n",
                         rownr, lp->row_name[rownr]->index);
#endif
    ptr = lp->row_name[rownr]->name;
  }
  else {
    if(lp->rowcol_name == NULL)
      if (!allocCHAR(lp, &lp->rowcol_name, 20, FALSE))
        return(NULL);
    ptr = lp->rowcol_name;
    if(newrow)
      sprintf(ptr, ROWNAMEMASK2, rownr);
    else
      sprintf(ptr, ROWNAMEMASK, rownr);
  }
  return(ptr);
}

MYBOOL __WINAPI set_col_name(lprec *lp, int colnr, char *new_name)
{
  if((colnr > lp->columns+1) || (colnr < 1)) {
    report(lp, IMPORTANT, "set_col_name: Column %d out of range", colnr);
  }

  if((colnr > lp->columns) && !append_columns(lp, colnr-lp->columns))
    return(FALSE);

  if(!lp->names_used)
    init_rowcol_names(lp);
  rename_var(lp, colnr, new_name, lp->col_name, &lp->colname_hashtab);

  return(TRUE);
}

char * __WINAPI get_col_name(lprec *lp, int colnr)
{
  if((colnr > lp->columns+1) || (colnr < 1)) {
    report(lp, IMPORTANT, "get_col_name: Column %d out of range", colnr);
    return(NULL);
  }

  if((lp->presolve_undo->var_to_orig != NULL) && lp->wasPresolved) {
    if(lp->presolve_undo->var_to_orig[lp->rows + colnr] == 0)
      colnr = -colnr;
    else
      colnr = lp->presolve_undo->var_to_orig[lp->rows + colnr];
  }
  return( get_origcol_name(lp, colnr) );
}

char * __WINAPI get_origcol_name(lprec *lp, int colnr)
{
  MYBOOL newcol;
  char   *ptr;

  newcol = (MYBOOL) (colnr < 0);
  colnr = abs(colnr);
#ifdef Paranoia
  if(((lp->presolve_undo->var_to_orig == NULL) && newcol) ||
     (colnr > MAX(lp->columns, lp->presolve_undo->orig_columns))) {
    report(lp, IMPORTANT, "get_origcol_name: Column %d out of range", colnr);
    return(NULL);
  }
#endif

  if(lp->names_used && lp->use_col_names && (lp->col_name[colnr] != NULL) && (lp->col_name[colnr]->name != NULL)) {
#ifdef Paranoia
    if(lp->col_name[colnr]->index != colnr)
      report(lp, SEVERE, "get_origcol_name: Inconsistent column ordinal %d vs %d\n",
                         colnr, lp->col_name[colnr]->index);
#endif
    ptr = lp->col_name[colnr]->name;
  }
  else {
    if(lp->rowcol_name == NULL)
      if (!allocCHAR(lp, &lp->rowcol_name, 20, FALSE))
        return(NULL);
    ptr = lp->rowcol_name;
    if(newcol)
      sprintf(ptr, COLNAMEMASK2, colnr);
    else
      sprintf(ptr, COLNAMEMASK, colnr);
  }
  return(ptr);
}

STATIC int MIP_count(lprec *lp)
{
  return( lp->int_vars+lp->sc_vars+SOS_count(lp) );
}
STATIC int bin_count(lprec *lp, MYBOOL working)
{
  int i, n = 0;
  if(working) {
    for(i = lp->rows+1; i <= lp->sum; i++)
      if(fabs(unscaled_value(lp, lp->upbo[i], i) - 1) < lp->epsvalue)
        n++;
  }
  else {
    for(i = 1; i <= lp->columns; i++)
      if((fabs(get_upbo(lp, i) - 1) < lp->epsvalue) &&
         (fabs(get_lowbo(lp, i) - 0) < lp->epsvalue))
        n++;
  }
  return( n );
}
STATIC int SOS_count(lprec *lp)
{
  if(lp->SOS == NULL)
    return( 0 );
  else
    return( lp->SOS->sos_count );
}
STATIC int GUB_count(lprec *lp)
{
  if(lp->GUB == NULL)
    return( 0 );
  else
    return( lp->GUB->sos_count );
}

STATIC REAL compute_violation(lprec *lp, int row_nr)
/* Returns the bound violation of a given basic variable; the return
   value is negative if it is below is lower bound, it is positive
   if it is greater than the upper bound, and zero otherwise. */
{
  REAL value, test;

  value  = lp->rhs[row_nr];
  row_nr = lp->var_basic[row_nr];
  test = value - my_lowbound(lp->lowbo[row_nr]);
  my_roundzero(test, lp->epsprimal);
  if(test > 0) {
    test = value - lp->upbo[row_nr];
    my_roundzero(test, lp->epsprimal);
    if(test < 0)
      test = 0;
  }
  return( test );
}

STATIC REAL feasibilityOffset(lprec *lp, MYBOOL isdual)
{
  int    i, j;
  REAL   f, Extra;

  Extra = 0;
  if(isdual) {
   /* This section computes a OF offset to ensure that the dual phase 1 is
      feasible.  It is used to compute a primal feasible base that can be
      passed to the primal simplex in phase 2. */
#if 0

   /* This is the legacy (v3.2-) P1extraVal logic that sets Extra to be the
      smallest negative reduced cost. Note that the reduced costs are the
      values of the dual slacks, which are [0..Inf> for feasibility.
      If we have negative reduced costs for bounded non-basic variables, we
      can simply switch the bound to obtain feasibility and possibly avoid
      having to set Extra. */
    if(!isDualFeasible(lp, lp->epsprimal, NULL, NULL, &f)
      Extra = f;

#else
  /* Find the most negative of the objective coefficients. We will subtract this
     value from every element of the objective row, making it non-negative and
     the problem therefore dual feasible. */
    for(i = 1; i <= lp->columns; i++) {
      f = lp->orig_obj[i];
      if(f < Extra)
        Extra = f;
    }
#endif
  }

  else {
  /* Set Extra to be the index of the most negative of the net RHS coefficients;
     this approach can be used in the primal phase 1 followed by the dual phase 2
     and when there are no ranged constraints.  When there are ranged constraints,
     additional artificial variables must be introduced. */
    Extra = 0;
    j = 0;
    Extra = lp->infinite;
    for(i = 1; i <= lp->rows; i++) {
      f = lp->rhs[i];
      if(f < Extra) {
        Extra = f;
        j = i;
      }
    }
    Extra = j;
  }

  return(Extra);

}

STATIC REAL compute_dualslacks(lprec *lp, int target, REAL **dvalues, int **nzdvalues, MYBOOL dosum)
/* Note that this function is similar to the compute_reducedcosts function in lp_price.c */
{
  int    i, varnr,
         *coltarget, **nzduals, *nzvtemp = NULL;
  REAL   d, g = 0, **duals, *vtemp = NULL;
  MYBOOL localREAL = (MYBOOL) (dvalues == NULL),
         localINT  = (MYBOOL) (nzdvalues == NULL);

  if(is_action(lp->spx_action, ACTION_REBASE) ||
     is_action(lp->spx_action, ACTION_REINVERT) || !lp->basis_valid)
    return( g );

  /* Initialize */
  if(!localREAL) {
    duals = dvalues;
    nzduals = nzdvalues;
  }
  else {
    duals = &vtemp;
    nzduals = &nzvtemp;
  }
  if(localINT || (*nzduals == NULL))
    allocINT(lp, nzduals, lp->columns + 1, AUTOMATIC);
  if(localREAL || (*duals == NULL))
    allocREAL(lp, duals, lp->sum + 1, AUTOMATIC);
  if(target == 0)
    target = SCAN_ALLVARS+ USE_NONBASICVARS;

  /* Define variable target list and compute the reduced costs */
  coltarget = (int *) mempool_obtainVector(lp->workarrays, lp->columns+1, sizeof(*coltarget));
  if(!get_colIndexA(lp, target, coltarget, FALSE)) {
    mempool_releaseVector(lp->workarrays, (char *) coltarget, FALSE);
    return(FALSE);
  }
  bsolve(lp, 0, *duals, NULL, lp->epsmachine*DOUBLEROUND, 1.0);
  prod_xA(lp, coltarget, *duals, NULL, lp->epsmachine, 1.0,
                         *duals, *nzduals, MAT_ROUNDDEFAULT | MAT_ROUNDRC);
  mempool_releaseVector(lp->workarrays, (char *) coltarget, FALSE);

  /* Compute sum or maximum infeasibility as specified */
  for(i = 1; i <= (*nzduals)[0]; i++) {
    varnr = (*nzduals)[i];
    d = my_chsign(!lp->is_lower[varnr], (*duals)[varnr]);
    if(d < 0) {
      if(dosum)
        g += -d;         /* Compute sum as a positive number */
      else {
        SETMIN(g, d);    /* Compute gap as a negative number */
      }
    }
  }

  /* Clean up */
  if(localREAL)
    FREE(*duals);
  if(localINT)
    FREE(*nzduals);

  return( g );
}

STATIC REAL compute_feasibilitygap(lprec *lp, MYBOOL isdual, MYBOOL dosum)
{
  REAL f = 0;

  /* This computes the primal feasibility gap (for use with the dual simplex phase 1) */
  if(isdual) {
    int  i;
    REAL g;

    for(i = 1; i <= lp->rows; i++) {
      if(lp->rhs[i] < 0)
        g = lp->rhs[i];
      else if(lp->rhs[i] > lp->upbo[lp->var_basic[i]])
        g = lp->rhs[i] - lp->upbo[lp->var_basic[i]];
      else
        g = 0;
      if(dosum)
        f += g;
      else {
        SETMAX(f, g);
      }
    }
  }
  /* This computes the dual feasibility gap (for use with the primal simplex phase 1) */
  else
    f = compute_dualslacks(lp, SCAN_USERVARS+USE_ALLVARS, NULL, NULL, dosum);

  return( f );
}

/* Find the smallest fractional value in a given row of the OF/constraint matrix */
STATIC int row_decimals(lprec *lp, int rownr, MYBOOL intsonly, REAL *intscalar)
{
  int basi, i, j, ncols = lp->columns;
  REAL f, /* g, */ epsvalue = lp->epsprimal;

  basi = 0;
  for(j = 1; j <= ncols; j++) {
    if(intsonly && !is_int(lp, j)) {
      if(intsonly == TRUE)
        break;
      else
        continue;
    }
    f = fabs(get_mat(lp, rownr, j));
    /* f = fmod(f, 1); */
    f -= floor (f + epsvalue);
/*
    if(f <= epsvalue)
      continue;
    g = f;
*/
    for(i = 0; (i <= MAX_FRACSCALE) && (/* g */ f > epsvalue); i++) {
      f *= 10;
      /* g = fmod(f, 1); */
      f -= floor (f + epsvalue);
    }
    if(i > MAX_FRACSCALE)
      /* i = MAX_FRACSCALE */ break;
    SETMAX(basi, i);
  }
  if(j > ncols)
    *intscalar = pow(10.0, basi);
  else {
    basi = -1;
    *intscalar = 1;
  }
  return( basi );
}

STATIC int row_intstats(lprec *lp, int rownr, int pivcolnr, int *maxndec,
                        int *plucount, int *intcount, int *intval, REAL *valGCD, REAL *pivcolval)
{
  int    jb, je, jj, nn = 0, multA, multB, intGCD = 0;
  REAL   rowval, inthold, intfrac;
  MATrec *mat = lp->matA;

  /* Do we have a valid matrix? */
  if(mat_validate(mat)) {

    /* Get smallest fractional row value */
    *maxndec = row_decimals(lp, rownr, AUTOMATIC, &intfrac);

    /* Get OF row starting and ending positions, as well as the first column index */
    if(rownr == 0) {
      jb = 1;
      je = lp->columns+1;
    }
    else {
      jb = mat->row_end[rownr-1];
      je = mat->row_end[rownr];
    }
    nn = je - jb;
    *pivcolval = 1.0;
    *plucount = 0;
    *intcount = 0;
    *intval   = 0;
    for(; jb < je; jb++) {

      if(rownr == 0) {
        if(lp->orig_obj[jb] == 0) {
          nn--;
          continue;
        }
        jj = jb;
      }
      else
        jj = ROW_MAT_COLNR(jb);

      /* Pick up the value of the pivot column and continue */
      if(jj == pivcolnr) {
        if(rownr == 0)
          *pivcolval = unscaled_mat(lp, lp->orig_obj[jb], 0, jb);
        else
          *pivcolval = get_mat_byindex(lp, jb, TRUE, FALSE);
        continue;
      }
      if(!is_int(lp, jj))
        continue;

      /* Update the count of integer columns */
      (*intcount)++;

      /* Update the count of positive parameter values */
      if(rownr == 0)
        rowval = unscaled_mat(lp, lp->orig_obj[jb], 0, jb);
      else
        rowval = get_mat_byindex(lp, jb, TRUE, FALSE);
      if(rowval > 0)
        (*plucount)++;

      /* Check if the parameter value is integer and update the row's GCD */
      rowval = fabs(rowval) * intfrac;
      rowval += rowval*lp->epsmachine;
      rowval = modf(rowval, &inthold);
      if(rowval < lp->epsprimal) {
        (*intval)++;
        if(*intval == 1)
          intGCD = (int) inthold;
        else
          intGCD = gcd(intGCD, (LLONG) inthold, &multA, &multB);
      }
    }
    *valGCD = intGCD;
    *valGCD /= intfrac;
  }

  return(nn);
}

#if 0
REAL MIP_stepOF(lprec *lp)
/* This function tries to find a non-zero minimum improvement
   if the OF contains all integer variables (logic only applies if we are
   looking for a single solution, not possibly several equal-valued ones).
*/
{
  MYBOOL OFgcd;
  int    colnr, rownr, n, ib, ie, maxndec,
         pluscount, intcount, intval;
  REAL   value, valOF, divOF, valGCD;
  MATrec *mat = lp->matA;

  value = 0;
  if((lp->int_vars > 0) && (lp->solutionlimit == 1) && mat_validate(mat)) {

    /* Get statistics for integer OF variables and compute base stepsize */
    n = row_intstats(lp, 0, -1, &maxndec, &pluscount, &intcount, &intval, &valGCD, &divOF);
    if((n == 0) || (maxndec < 0))
      return( value );
    OFgcd = (MYBOOL) (intval > 0);
    if(OFgcd)
      value = valGCD;

    /* Check non-ints in the OF to see if we can get more info */
    if(n - intcount > 0) {
      int nrv = 0;

      /* See if we have equality constraints */
      ie = lp->rows;
      for(ib = 1; ib <= ie; ib++) {
        if(is_constr_type(lp, ib, EQ))
          break;
      }

      /* If so, there may be a chance to find an improved stepsize */
      if(ib < ie)
      for(colnr = 1; colnr <= lp->columns; colnr++) {

        /* Go directly to the next variable if this is an integer or
          there is no row candidate to explore for hidden bounds for
          real-valued variables (limit scan to one row!) */
        if(is_int(lp, colnr))
          continue;
        nrv++;
        /* Scan equality constraints */
        ib = mat->col_end[colnr-1];
        ie = mat->col_end[colnr];
        while(ib < ie) {
          if(is_constr_type(lp, (rownr = COL_MAT_ROWNR(ib)), EQ)) {

            /* Get "child" row statistics, but break out if we don't
              find enough information, i.e. no integers with coefficients of proper type */
            n = row_intstats(lp, rownr, colnr, &maxndec, &pluscount, &intcount, &intval, &valGCD, &divOF);
            if((intval < n - 1) || (maxndec < 0)) {
              value = 0;
              break;
            }

            /* We can update */
            valOF = unscaled_mat(lp, lp->orig_obj[colnr], 0, colnr);
            valOF = fabs( valOF * (valGCD / divOF) );
            if(OFgcd) {
              SETMIN(value, valOF);
            }
            else {
              OFgcd = TRUE;
              value = valOF;
            }
          }
          ib++;
        }

        /* No point in continuing scan if we failed in current column */
        if(value == 0)
          break;
      }

      /* Check if we found information for any real-valued variable;
         if not, then we must set the iprovement delta to 0 */
      if(nrv == 0)
        value = 0;
    }
  }
  return( value );
}
#else

REAL MIP_stepOF(lprec *lp)
/* This function tries to find a non-zero minimum improvement
   if the OF contains all integer variables (logic only applies if we are
   looking for a single solution, not possibly several equal-valued ones). */
{
  MYBOOL  OFgcd;
  int     colnr, rownr, n, ib, ie,
          pluscount, intcount;
  int     intval, maxndec;
  REAL    value = 0, valOF, divOF, valGCD;
  MATrec  *mat = lp->matA;

  if((lp->int_vars > 0) && (lp->solutionlimit == 1) && mat_validate(mat)) {

    /* Get statistics for integer OF variables and compute base stepsize */
    n = row_intstats(lp, 0, 0, &maxndec, &pluscount, &intcount, &intval, &valGCD, &divOF);
    if((n == 0) || (maxndec < 0))
      return( value );
    OFgcd = (MYBOOL) (intval > 0);
    if(OFgcd)
      value = valGCD;

    /* Check non-ints in the OF to see if we can get more info */
    if(n - intcount > 0) {
      int nrv = n - intcount; /* Number of real variables in the objective */
      int niv = 0;            /* Number of real variables identified as integer */
      int nrows = lp->rows;

      /* See if we have equality constraints */
      for(ib = 1; ib <= nrows; ib++) {
        if(is_constr_type(lp, ib, EQ))
          break;
      }

      /* If so, there may be a chance to find an improved stepsize */
      if(ib < nrows)
      for(colnr = 1; colnr <= lp->columns; colnr++) {

        /* Go directly to the next variable if this is an integer or
          there is no row candidate to explore for hidden bounds for
          real-valued variables (limit scan to one row/no recursion) */
        if((lp->orig_obj[colnr] == 0) || is_int(lp, colnr))
          continue;

        /* Scan equality constraints */
        ib = mat->col_end[colnr-1];
        ie = mat->col_end[colnr];
        while(ib < ie) {
          if(is_constr_type(lp, (rownr = COL_MAT_ROWNR(ib)), EQ)) {

            /* Get "child" row statistics, but break out if we don't
              find enough information, i.e. no integers with coefficients of proper type */
            n = row_intstats(lp, rownr, colnr, &maxndec, &pluscount, &intcount, &intval, &valGCD, &divOF);
            if((intval < n - 1) || (maxndec < 0)) {
              value = 0;
              break;
            }
            niv++;

            /* We can update */
            valOF = unscaled_mat(lp, lp->orig_obj[colnr], 0, colnr);
            valOF = fabs( valOF * (valGCD / divOF) );
            if(OFgcd) {
              SETMIN(value, valOF);
            }
            else {
              OFgcd = TRUE;
              value = valOF;
            }
          }
          ib++;
        }

        /* No point in continuing scan if we failed in current column */
        if(value == 0)
          break;
      }

      /* Check if we found information for any real-valued variable;
         if not, then we must set the improvement delta to 0 */
      if(nrv > niv)
        value = 0;
    }
  }
  return( value );
}

#endif

STATIC MYBOOL isPrimalSimplex(lprec *lp)
{
  return((MYBOOL) (((lp->simplex_mode & SIMPLEX_Phase1_PRIMAL) != 0) ||
                   ((lp->simplex_mode & SIMPLEX_Phase2_PRIMAL) != 0)));
}

STATIC MYBOOL isPhase1(lprec *lp)
{
  return((MYBOOL) (((lp->simplex_mode & SIMPLEX_Phase1_PRIMAL) != 0) ||
                   ((lp->simplex_mode & SIMPLEX_Phase1_DUAL) != 0)));
}

STATIC MYBOOL isP1extra(lprec *lp)
{
  return((MYBOOL) ((lp->P1extraDim > 0) || (lp->P1extraVal != 0)));
}

STATIC MYBOOL feasiblePhase1(lprec *lp, REAL epsvalue)
{
  REAL   gap;
  MYBOOL test;

  gap = fabs(lp->rhs[0] - lp->orig_rhs[0]);
  test = (MYBOOL) (gap < epsvalue);
  return( test) ;
}

STATIC MYBOOL isDegenerateBasis(lprec *lp, int basisvar)
{
  int varindex;

  varindex = lp->var_basic[basisvar];
  if((fabs(lp->rhs[basisvar]) < lp->epsprimal) ||
     (fabs(lp->upbo[varindex]-lp->rhs[basisvar]) < lp->epsprimal))
    return( TRUE );
  else
    return( FALSE );
}

STATIC int findBasicFixedvar(lprec *lp, int afternr, MYBOOL slacksonly)
{
  int varnr, delta = 1;

  if(afternr < 0) {
    delta = -1;
    afternr = -afternr;
  }
  afternr += delta;
  if((afternr < 1) || (afternr > lp->rows))
    return( 0 );

  for(; (afternr > 0) && (afternr <= lp->rows); afternr += delta) {
    varnr = lp->var_basic[afternr];
    if(((varnr <= lp->rows) && is_constr_type(lp, varnr, EQ)) ||
       (!slacksonly && (varnr > lp->rows) && is_fixedvar(lp, varnr)))
      break;
  }

  if(afternr > lp->rows)
    afternr = 0;

  return( afternr );
}

STATIC MYBOOL isBasisVarFeasible(lprec *lp, REAL tol, int basis_row)
{
  int    col;
  REAL   x;
  MYBOOL Ok = TRUE;
  MYBOOL doSC = FALSE;

  col = lp->var_basic[basis_row];
  x = lp->rhs[basis_row];         /* The current solution of basic variables stored here! */
  if((x < -tol) || (x > lp->upbo[col]+tol))
    Ok = FALSE;
  else if(doSC && (col > lp->rows) && (fabs(lp->sc_lobound[col - lp->rows]) > 0)) {
    if((x > tol) && (x < fabs(lp->sc_lobound[col - lp->rows])-tol))
      Ok = FALSE;
  }
  return( Ok );
}
STATIC MYBOOL isPrimalFeasible(lprec *lp, REAL tol, int infeasibles[], REAL *feasibilitygap)
{
  int    i;
  MYBOOL feasible = TRUE;

  /* This is a short-hand call to rowdual() to check for primal infeasibility */

#if 0
  /* Traditional indexing style */
  for(i = 1; i <= lp->rows; i++) {
    feasible = isBasisVarFeasible(lp, tol, i);
#else
  /* Fast array pointer style */
  LREAL *rhsptr;
  int  *idxptr;

  if(infeasibles != NULL)
    infeasibles[0] = 0;
  for(i = 1, rhsptr = lp->rhs+1, idxptr = lp->var_basic+1;
      (i <= lp->rows); i++, rhsptr++, idxptr++) {
    feasible = TRUE;
/*    if(((*rhsptr) < lp->lowbo[*idxptr]-tol) || ((*rhsptr) > lp->upbo[*idxptr]+tol)) */
    if(((*rhsptr) < -tol) || ((*rhsptr) > lp->upbo[*idxptr]+tol))
      feasible = FALSE;
#endif
    if(!feasible) {
      if(infeasibles == NULL)
        break;
      infeasibles[0]++;
      infeasibles[infeasibles[0]] = i;
    }
  }

  /* Compute feasibility gap (could actually do this calculation above) */
  if(feasibilitygap != NULL) {
    if(feasible)
      *feasibilitygap = 0.0;
    else
      *feasibilitygap = feasibilityOffset(lp, FALSE);
  }

  return(feasible);
}

STATIC MYBOOL isDualFeasible(lprec *lp, REAL tol, int *boundflipcount, int infeasibles[], REAL *feasibilitygap)
{
  int    i, varnr,
         n = 0,  /* Number of infeasible duals corrected with bound-swaps */
         m = 0,
         target = SCAN_ALLVARS+USE_NONBASICVARS;
  REAL   f = 0;
  MYBOOL feasible, islower;


  /* The reduced costs are the values of the dual slacks, which
     are [0..Inf> for feasibility.  If we have negative reduced costs
     for bounded non-basic variables, we can simply switch the bound
     of bounded variables to obtain dual feasibility and possibly avoid
     having to use dual simplex phase 1. */
  if((infeasibles != NULL) || (boundflipcount != NULL)) {
    int  *nzdcol = NULL;
    REAL d, *dcol = NULL;

    f = compute_dualslacks(lp, target, &dcol, &nzdcol, FALSE);
    if(nzdcol != NULL)
    for(i = 1; i <= nzdcol[0]; i++) {
      varnr = nzdcol[i];
      islower = lp->is_lower[varnr];
      d = my_chsign(!islower, dcol[varnr]);

      /* Don't bother with uninteresting non-basic variables */
      if((d > -tol) ||                /* Positive reduced costs with a tolerance */
         my_unbounded(lp, varnr) ||   /* Free variables cannot change bound */
         is_fixedvar(lp, varnr))      /* Equality slack or a fixed variable ("type 3") */
        continue;

      /* Check if we have non-flippable bounds, i.e. an unbounded variable
         (types 2+4), or bounded variables (type 3), and if the counter is NULL. */
      if( (boundflipcount == NULL) ||
          ((lp->bb_level <= 1) && (my_rangebo(lp, varnr) > fabs(lp->negrange))) ||
          (islower && my_infinite(lp, lp->upbo[varnr])) ||
          (!islower && my_infinite(lp, my_lowbo(lp, varnr))) ) {
        m++;
        if(infeasibles != NULL)
          infeasibles[m] = varnr;
      }
      /* Only do bound flips if the user-provided counter is non-NULL */
      else {
        lp->is_lower[varnr] = !islower;
        n++;
      }
    }
    if(infeasibles != NULL)
      infeasibles[0] = m;
    FREE(dcol);
    FREE(nzdcol);
    if(n > 0) {
      set_action(&lp->spx_action, ACTION_RECOMPUTE);
      if(m == 0)
        f = 0;
    }
  }
  else
    f = compute_dualslacks(lp, target, NULL, NULL, FALSE);
/*    f = feasibilityOffset(lp, TRUE); */  /* Safe legacy mode */

  /* Do an extra scan to see if there are bounded variables in the OF not present in any constraint;
     Most typically, presolve fixes such cases, so this is rarely encountered. */

  varnr = lp->rows + 1;
  for(i = 1; i <= lp->columns; i++, varnr++) {
    if (mat_collength(lp->matA, i) == 0) {
      islower = lp->is_lower[varnr];
      if((my_chsign(islower, lp->orig_obj[i]) > 0) && !SOS_is_member(lp->SOS, 0, i)) {
        lp->is_lower[varnr] = !islower;
        if((islower && my_infinite(lp,  lp->upbo[varnr] /* lp->orig_upbo[varnr] */)) ||
           (!islower && my_infinite(lp,  my_lowbo(lp, varnr) /* lp->orig_lowbo[varnr] */))) {
          lp->spx_status = UNBOUNDED;
          break;
        }
        /* lp->is_lower[varnr] = !islower; */
        n++;
      }
    }
  }

  /* Return status */

  if(boundflipcount != NULL)
    *boundflipcount = n;
  if(feasibilitygap != NULL) {
    my_roundzero(f, tol);
    *feasibilitygap = f;
  }
  feasible = (MYBOOL) ((f == 0) && (m == 0));

  return(feasible);
}

void __WINAPI default_basis(lprec *lp)
{
  int i;

  /* Set the slack variables to be basic; note that the is_basic[] array
     is a helper array filled in presolve() to match var_basic[]. */
  for(i = 1; i <= lp->rows; i++) {
    lp->var_basic[i] = i;
    lp->is_basic[i] = TRUE;
    lp->is_lower[i] = TRUE;
  }
  lp->var_basic[0] = TRUE; /* Set to signal that this is the default basis */

  /* Set user variables at their lower bound, including the
     dummy slack for the objective "constraint" */
  for(; i <= lp->sum; i++) {
    lp->is_basic[i] = FALSE;
    lp->is_lower[i] = TRUE;
  }
  lp->is_lower[0] = TRUE;

  set_action(&lp->spx_action, ACTION_REBASE | ACTION_REINVERT | ACTION_RECOMPUTE);
  lp->basis_valid = TRUE;  /* Do not re-initialize basis on entering Solve */
}

int __WINAPI get_basiscrash(lprec *lp)
{
  return(lp->crashmode);
}

void __WINAPI set_basiscrash(lprec *lp, int mode)
{
  lp->crashmode = mode;
}

MYBOOL __WINAPI set_basis(lprec *lp, int *bascolumn, MYBOOL nonbasic)   /* Added by KE */
{
  int    i,s,k,n;

  /* Make sure we are consistent */
  if(lp->wasPresolved && ((lp->rows != lp->presolve_undo->orig_rows) ||
                          (lp->columns != lp->presolve_undo->orig_columns)))
    return( FALSE );

 /* Initialize (lp->is_basic is set in preprocess); Note that as of v5 and before
    it is an lp_solve convention that basic variables are at their lower bounds!
    This routine provides for the a possible future case that basic variables
    can be upper-bounded. */
  lp->is_lower[0] = TRUE;
  for(i = 1; i <= lp->sum; i++) {
    lp->is_lower[i] = TRUE;
    lp->is_basic[i] = FALSE;
  }
  for(i = 1; i <= lp->rows; i++)
    lp->var_basic[i] = FALSE;

 /* Set basic and optionally non-basic variables;
    negative index means at lower bound, positive at upper bound */
  if(nonbasic)
    n = lp->sum;
  else
    n = lp->rows;
  for(i = 1; i <= n; i++) {
    s = bascolumn[i];
    k = abs(s);
    if(k <= 0 || k > lp->sum)
      return( FALSE );
    if(i <= lp->rows) {
      lp->var_basic[i] = k;
      lp->is_basic[k] = TRUE;
    }
    else     /* Remove this test if basic variables can be upper-bounded */
    if(s > 0)
      lp->is_lower[k] = FALSE;
  }
  if(!verify_basis(lp))
    return( FALSE );

 /* Invalidate basis */
  set_action(&lp->spx_action, ACTION_REBASE | ACTION_REINVERT | ACTION_RECOMPUTE);
  lp->basis_valid = TRUE;   /* Do not re-initialize basis on entering Solve */
  lp->var_basic[0] = FALSE; /* Set to signal that this is a non-default basis */

  return( TRUE );
}

void __WINAPI reset_basis(lprec *lp)
{
  lp->basis_valid = FALSE;   /* Causes reinversion at next opportunity */
}

MYBOOL __WINAPI get_basis(lprec *lp, int *bascolumn, MYBOOL nonbasic)
{
  int    k, i;

  if(!lp->basis_valid ||
     (lp->rows != lp->presolve_undo->orig_rows) ||
     (lp->columns != lp->presolve_undo->orig_columns))
    return( FALSE );

  *bascolumn = 0;

  /* First save basic variable indexes */
  for(i = 1; i <= lp->rows; i++) {
    k = lp->var_basic[i];
    bascolumn[i] = my_chsign(lp->is_lower[k], k);
  }

  /* Then optionally save non-basic variable indeces */
  if(nonbasic) {
    for(k = 1; (k <= lp->sum) && (i <= lp->sum); k++) {
      if(lp->is_basic[k])
        continue;
      bascolumn[i] = my_chsign(lp->is_lower[k], k);
      i++;
    }
  }
  return( TRUE );
}

STATIC MYBOOL is_BasisReady(lprec *lp)
{
  return( (MYBOOL) (lp->var_basic[0] != AUTOMATIC) );
}

STATIC MYBOOL is_slackbasis(lprec *lp)
{
  int n = 0, err = 0;
  if(lp->basis_valid) {
    int i, k;
    MYBOOL *used = NULL;

    allocMYBOOL(lp, &used, lp->rows+1, TRUE);
    for(i = 1; i <= lp->rows; i++) {
      k = lp->var_basic[i];
      if(k <= lp->rows) {
        if(used[k])
          err++;
        else
          used[k] = TRUE;
        n++;
      }
    }
    FREE(used);
    if(err > 0)
      report(lp, SEVERE, "is_slackbasis: %d inconsistencies found in slack basis\n", err);
  }
  return( (MYBOOL) (n == lp->rows) );
}

STATIC MYBOOL verify_basis(lprec *lp)
{
  int    i, ii, k = 0;
  MYBOOL result = FALSE;

  for(i = 1; i <= lp->rows; i++) {
    ii = lp->var_basic[i];
    if((ii < 1) || (ii > lp->sum) || !lp->is_basic[ii]) {
      k = i;
      ii = 0;
      goto Done;
    }
  }

  ii = lp->rows;
  for(i = 1; i <= lp->sum; i++) {
    if(lp->is_basic[i])
      ii--;
  }
  result = (MYBOOL) (ii == 0);

Done:
#if 0  /* For testing */
  if(!result)
    ii = 0;
#endif
  return(result);
}

int __WINAPI set_basisvar(lprec *lp, int basisPos, int enteringCol)
{
  int leavingCol;

  leavingCol = lp->var_basic[basisPos];

#ifdef Paranoia
  if((basisPos < 1) || (basisPos > lp->rows))
    report(lp, SEVERE, "set_basisvar: Invalid leaving basis position %d specified at iter %.0f\n",
                       basisPos, (double) get_total_iter(lp));
  if((leavingCol < 1) || (leavingCol > lp->sum))
    report(lp, SEVERE, "set_basisvar: Invalid leaving column %d referenced at iter %.0f\n",
                       leavingCol, (double) get_total_iter(lp));
  if((enteringCol < 1) || (enteringCol > lp->sum))
    report(lp, SEVERE, "set_basisvar: Invalid entering column %d specified at iter %.0f\n",
                       enteringCol, (double) get_total_iter(lp));
#endif

#ifdef ParanoiaXY
  if(!lp->is_basic[leavingCol])
    report(lp, IMPORTANT, "set_basisvar: Leaving variable %d is not basic at iter %.0f\n",
                           leavingCol, (double) get_total_iter(lp));
  if(enteringCol > lp->rows && lp->is_basic[enteringCol])
    report(lp, IMPORTANT, "set_basisvar: Entering variable %d is already basic at iter %.0f\n",
                           enteringCol, (double) get_total_iter(lp));
#endif

  lp->var_basic[0]          = FALSE;       /* Set to signal that this is a non-default basis */
  lp->var_basic[basisPos]   = enteringCol;
  lp->is_basic[leavingCol]  = FALSE;
  lp->is_basic[enteringCol] = TRUE;
  if(lp->bb_basis != NULL)
    lp->bb_basis->pivots++;

  return(leavingCol);
}

/* Bounds updating and unloading routines; requires that the
   current values for upbo and lowbo are in the original base. */
STATIC int perturb_bounds(lprec *lp, BBrec *perturbed, MYBOOL doRows, MYBOOL doCols, MYBOOL includeFIXED)
{
  int  i, ii, n = 0;
  REAL new_lb, new_ub, *upbo, *lowbo;

  if(perturbed == NULL)
    return( n );

 /* Map reference bounds to previous state, i.e. cumulate
    perturbations in case of persistent problems */
  upbo  = perturbed->upbo;
  lowbo = perturbed->lowbo;

 /* Set appropriate target variable range */
  i = 1;
  ii = lp->rows;
  if(!doRows)
    i += ii;
  if(!doCols)
    ii = lp->sum;

 /* Perturb (expand) finite variable bounds randomly */
  for(; i <= ii; i++) {

    /* Don't perturb regular slack variables */
    if((i <= lp->rows) && (lowbo[i] == 0) && (upbo[i] >= lp->infinite))
      continue;

    new_lb = lowbo[i];
    new_ub = upbo[i];

    /* Don't perturb fixed variables if not specified */
    if(!includeFIXED && (new_ub == new_lb))
      continue;

    /* Lower bound for variables (consider implementing RHS here w/contentmode== AUTOMATIC) */
    if((i > lp->rows) && (new_lb < lp->infinite)) {
      new_lb = rand_uniform(lp, RANDSCALE) + 1;
      new_lb *= lp->epsperturb;
      lowbo[i] -= new_lb;
      n++;
    }

    /* Upper bound */
    if(new_ub < lp->infinite) {
      new_ub = rand_uniform(lp, RANDSCALE) + 1;
      new_ub *= lp->epsperturb;
      upbo[i] += new_ub;
      n++;
    }
  }

 /* Make sure we start from scratch */
  set_action(&lp->spx_action, ACTION_REBASE);

  return( n );
}

STATIC MYBOOL impose_bounds(lprec *lp, REAL *upbo, REAL *lowbo)
/* Explicitly set working bounds to given vectors without pushing or popping */
{
  MYBOOL ok;

  ok = (MYBOOL) ((upbo != NULL) || (lowbo != NULL));
  if(ok) {
    if((upbo != NULL) && (upbo != lp->upbo))
      MEMCOPY(lp->upbo,  upbo,  lp->sum + 1);
    if((lowbo != NULL) && (lowbo != lp->lowbo))
      MEMCOPY(lp->lowbo, lowbo, lp->sum + 1);
    if(lp->bb_bounds != NULL)
      lp->bb_bounds->UBzerobased = FALSE;
    set_action(&lp->spx_action, ACTION_REBASE);
  }
  set_action(&lp->spx_action, ACTION_RECOMPUTE);
  return( ok );
}

STATIC MYBOOL validate_bounds(lprec *lp, REAL *upbo, REAL *lowbo)
/* Check if all bounds are Explicitly set working bounds to given vectors without pushing or popping */
{
  MYBOOL ok;
  int    i;

  ok = (MYBOOL) ((upbo != NULL) || (lowbo != NULL));
  if(ok) {
    for(i = 1; i <= lp->sum; i++)
      if((lowbo[i] > upbo[i]) || (lowbo[i] < lp->orig_lowbo[i]) || (upbo[i] > lp->orig_upbo[i]))
        break;
    ok = (MYBOOL) (i > lp->sum);
  }
  return( ok );
}

STATIC int unload_BB(lprec *lp)
{
  int levelsunloaded = 0;

  if(lp->bb_bounds != NULL)
    while(pop_BB(lp->bb_bounds))
      levelsunloaded++;
  return( levelsunloaded );
}


#define LowerStorageModel 1
#define BasisStorageModel 1
STATIC basisrec *push_basis(lprec *lp, int *basisvar, MYBOOL *isbasic, MYBOOL *islower)
/* Save the ingoing basis and push it onto the stack */
{
  int sum = lp->sum + 1;
  basisrec *newbasis = NULL;

  newbasis = (basisrec *) calloc(sizeof(*newbasis), 1);
  if((newbasis != NULL) &&
#if LowerStorageModel == 0
    allocMYBOOL(lp, &newbasis->is_lower,  sum,  FALSE) &&
#else
    allocMYBOOL(lp, &newbasis->is_lower,  (sum + 8) / 8,  TRUE) &&
#endif
#if BasisStorageModel == 0
    allocMYBOOL(lp, &newbasis->is_basic,  sum,  FALSE) &&
#endif
    allocINT(lp,    &newbasis->var_basic, lp->rows + 1, FALSE)) {

    if(islower == NULL)
      islower = lp->is_lower;
    if(isbasic == NULL)
      isbasic = lp->is_basic;
    if(basisvar == NULL)
      basisvar = lp->var_basic;

#if LowerStorageModel == 0
    MEMCOPY(newbasis->is_lower,  islower,  sum);
#else
    for(sum = 1; sum <= lp->sum; sum++)
      if(islower[sum])
        set_biton(newbasis->is_lower, sum);
#endif
#if BasisStorageModel == 0
    MEMCOPY(newbasis->is_basic,  isbasic,  lp->sum + 1);
#endif
    MEMCOPY(newbasis->var_basic, basisvar, lp->rows + 1);

    newbasis->previous = lp->bb_basis;
    if(lp->bb_basis == NULL)
      newbasis->level = 0;
    else
      newbasis->level = lp->bb_basis->level + 1;
    newbasis->pivots = 0;

    lp->bb_basis = newbasis;
  }
  return( newbasis );
}

STATIC MYBOOL compare_basis(lprec *lp)
/* Compares the last pushed basis with the currently active basis */
{
  int i, j;
  MYBOOL same_basis = TRUE;

  if(lp->bb_basis == NULL)
    return( FALSE );

  /* Loop over basis variables until a mismatch (order can be different) */
  i = 1;
  while(same_basis && (i <= lp->rows)) {
    j = 1;
    while(same_basis && (j <= lp->rows)) {
      same_basis = (MYBOOL) (lp->bb_basis->var_basic[i] != lp->var_basic[j]);
      j++;
    }
    same_basis = !same_basis;
    i++;
  }
  /* Loop over bound status indicators until a mismatch */
  i = 1;
  while(same_basis && (i <= lp->sum)) {
    same_basis = (lp->bb_basis->is_lower[i] && lp->is_lower[i]);
    i++;
  }

  return( same_basis );
}

STATIC MYBOOL restore_basis(lprec *lp)
/* Restore values from the previously pushed / saved basis without popping it */
{
  MYBOOL ok;
  int    i;

  ok = (MYBOOL) (lp->bb_basis != NULL);
  if(ok) {
    MEMCOPY(lp->var_basic, lp->bb_basis->var_basic, lp->rows + 1);
#if BasisStorageModel == 0
    MEMCOPY(lp->is_basic,  lp->bb_basis->is_basic,  lp->sum + 1);
#else
    MEMCLEAR(lp->is_basic, lp->sum + 1);
    for(i = 1; i <= lp->rows; i++)
      lp->is_basic[lp->var_basic[i]] = TRUE;
#endif
#if LowerStorageModel == 0
    MEMCOPY(lp->is_lower,  lp->bb_basis->is_lower,  lp->sum + 1);
#else
    for(i = 1; i <= lp->sum; i++)
      lp->is_lower[i] = is_biton(lp->bb_basis->is_lower, i);
#endif
    set_action(&lp->spx_action, ACTION_REBASE | ACTION_REINVERT);
  }
  return( ok );
}

STATIC MYBOOL pop_basis(lprec *lp, MYBOOL restore)
/* Pop / free, and optionally restore the previously "pushed" / saved basis */
{
  MYBOOL ok;
  basisrec *oldbasis;

  ok = (MYBOOL) (lp->bb_basis != NULL);
  if(ok) {
    oldbasis = lp->bb_basis;
    if(oldbasis != NULL) {
      lp->bb_basis = oldbasis->previous;
      FREE(oldbasis->var_basic);
#if BasisStorageModel == 0
      FREE(oldbasis->is_basic);
#endif
      FREE(oldbasis->is_lower);
      FREE(oldbasis);
    }
    if(restore && (lp->bb_basis != NULL))
      restore_basis(lp);
  }
  return( ok );
}

STATIC int unload_basis(lprec *lp, MYBOOL restorelast)
{
  int levelsunloaded = 0;

  if(lp->bb_basis != NULL)
    while(pop_basis(lp, restorelast))
      levelsunloaded++;
  return( levelsunloaded );
}


STATIC REAL scaled_floor(lprec *lp, int colnr, REAL value, REAL epsscale)
{
  value = floor(value);
  if(value != 0)
  if(lp->columns_scaled && is_integerscaling(lp)) {
    value = scaled_value(lp, value, colnr);
    if(epsscale != 0)
      value += epsscale*lp->epsmachine;
/*      value += epsscale*lp->epsprimal; */
/*    value = restoreINT(value, lp->epsint); */
  }
  return(value);
}

STATIC REAL scaled_ceil(lprec *lp, int colnr, REAL value, REAL epsscale)
{
  value = ceil(value);
  if(value != 0)
  if(lp->columns_scaled && is_integerscaling(lp)) {
    value = scaled_value(lp, value, colnr);
    if(epsscale != 0)
      value -= epsscale*lp->epsmachine;
/*      value -= epsscale*lp->epsprimal; */
/*    value = restoreINT(value, lp->epsint); */
  }
  return(value);
}

/* Branch and bound variable selection functions */

STATIC MYBOOL is_sc_violated(lprec *lp, int column)
{
  int  varno;
  REAL tmpreal;

  varno = lp->rows+column;
  tmpreal = unscaled_value(lp, lp->sc_lobound[column], varno);
  return( (MYBOOL) ((tmpreal > 0) &&                    /* it is an (inactive) SC variable...    */
                    (lp->solution[varno] < tmpreal) &&  /* ...and the NZ lower bound is violated */
                    (lp->solution[varno] > 0)) );       /* ...and the Z lowerbound is violated   */
}
STATIC int find_sc_bbvar(lprec *lp, int *count)
{
  int    i, ii, n, bestvar;
  int    firstsc, lastsc;
  REAL   hold, holdINT, bestval, OFval, randval, scval;
  MYBOOL reversemode, greedymode, randomizemode,
         pseudocostmode, pseudocostsel;

  bestvar = 0;
  if((lp->sc_vars == 0) || (*count > 0))
    return(bestvar);

  reversemode    = is_bb_mode(lp, NODE_WEIGHTREVERSEMODE);
  greedymode     = is_bb_mode(lp, NODE_GREEDYMODE);
  randomizemode  = is_bb_mode(lp, NODE_RANDOMIZEMODE);
  pseudocostmode = is_bb_mode(lp, NODE_PSEUDOCOSTMODE);
  pseudocostsel  = is_bb_rule(lp, NODE_PSEUDOCOSTSELECT) ||
                   is_bb_rule(lp, NODE_PSEUDONONINTSELECT) ||
                   is_bb_rule(lp, NODE_PSEUDORATIOSELECT);

  bestvar = 0;
  bestval = -lp->infinite;
  hold    = 0;
  randval = 1;
  firstsc = 0;
  lastsc  = lp->columns;

  for(n = 1; n <= lp->columns; n++) {
    ii = get_var_priority(lp, n);
    i = lp->rows + ii;
    if(!lp->bb_varactive[ii] && is_sc_violated(lp, ii) && !SOS_is_marked(lp->SOS, 0, ii)) {

      /* Do tallies */
      (*count)++;
      lastsc = i;
      if(firstsc <= 0)
        firstsc = i;
      scval = get_pseudorange(lp->bb_PseudoCost, ii, BB_SC);

      /* Select default pricing/weighting mode */
      if(pseudocostmode)
        OFval = get_pseudonodecost(lp->bb_PseudoCost, ii, BB_SC, lp->solution[i]);
      else
        OFval = my_chsign(is_maxim(lp), get_mat(lp, 0, ii));

      if(randomizemode)
        randval = exp(rand_uniform(lp, 1.0));

      /* Find the maximum pseudo-cost of a variable (don't apply pseudocostmode here) */
      if(pseudocostsel) {
        if(pseudocostmode)
          hold = OFval;
        else
          hold = get_pseudonodecost(lp->bb_PseudoCost, ii, BB_SC, lp->solution[i]);
        hold *= randval;
        if(greedymode) {
          if(pseudocostmode) /* Override! */
            OFval = my_chsign(is_maxim(lp), get_mat(lp, 0, ii));
          hold *= OFval;
        }
        hold = my_chsign(reversemode, hold);
      }
      else
      /* Find the variable with the largest sc gap (closest to the sc mean) */
      if(is_bb_rule(lp, NODE_FRACTIONSELECT)) {
        hold = modf(lp->solution[i]/scval, &holdINT);
        holdINT = hold-1;
        if(fabs(holdINT) > hold)
          hold = holdINT;
        if(greedymode)
          hold *= OFval;
        hold = my_chsign(reversemode, hold)*scval*randval;
      }
      else
      /* Do first or last violated sc index selection (default) */
      /* if(is_bb_rule(lp, NODE_FIRSTSELECT)) */
      {
        if(reversemode)
          continue;
        else {
          bestvar = i;
          break;
        }
      }

      /* Select better, check for ties, and split by proximity to 0.5*sc_lobound */
      if(hold > bestval) {
        if( (bestvar == 0) ||
            (hold > bestval+lp->epsprimal) ||
            (fabs(modf(lp->solution[i]/scval, &holdINT) - 0.5) <
             fabs(modf(lp->solution[bestvar]/
                       get_pseudorange(lp->bb_PseudoCost, bestvar-lp->rows, BB_SC), &holdINT) - 0.5)) ) {
          bestval = hold;
          bestvar = i;
        }
      }
    }
  }

  if(is_bb_rule(lp, NODE_FIRSTSELECT) && reversemode)
    bestvar = lastsc;

  return(bestvar);
}

STATIC int find_sos_bbvar(lprec *lp, int *count, MYBOOL intsos)
{
  int k, i, j, var;

  var = 0;
  if((lp->SOS == NULL) || (*count > 0))
    return(var);

  /* Check if the SOS'es happen to already be satisified */
  i = SOS_is_satisfied(lp->SOS, 0, lp->solution);
  if((i == SOS_COMPLETE) || (i == SOS_INCOMPLETE))
    return(-1);

  /* Otherwise identify a SOS variable to enter B&B */
  for(k = 0; k < lp->sos_vars; k++) {
    i = lp->sos_priority[k];
#ifdef Paranoia
    if((i < 1) || (i > lp->columns))
      report(lp, SEVERE, "find_sos_bbvar: Invalid SOS variable map %d at %d\n",
                         i, k);
#endif
    j = lp->rows + i;
    if(!SOS_is_marked(lp->SOS, 0, i) && !SOS_is_full(lp->SOS, 0, i, FALSE)) {
/*    if(!SOS_is_marked(lp->SOS, 0, i) && !SOS_is_full(lp->SOS, 0, i, TRUE)) { */
      if(!intsos || is_int(lp, i)) {
        (*count)++;
        if(var == 0) {
          var = j;
          break;
        }
      }
    }
  }
#ifdef Paranoia
  if((var > 0) && !SOS_is_member(lp->SOS, 0, var-lp->rows))
     report(lp, SEVERE, "find_sos_bbvar: Found variable %d, which is not a SOS!\n", var);
#endif
  return(var);
}

STATIC int find_int_bbvar(lprec *lp, int *count, BBrec *BB, MYBOOL *isfeasible)
{
  int    i, ii, n, k, bestvar, depthmax, *nonint = NULL;
  REAL   hold, holdINT, bestval, OFval, randval,
         *lowbo = BB->lowbo, *upbo = BB->upbo;
  MYBOOL reversemode, greedymode, depthfirstmode, breadthfirstmode,
         randomizemode, rcostmode,
         pseudocostmode, pseudocostsel, pseudostrong, isINT, valINT;

  if((lp->int_vars == 0) || (*count > 0))
    return( 0 );
  if(lp->bb_usenode != NULL) {
    i = lp->bb_usenode(lp, lp->bb_nodehandle, BB_INT);
    if(i >= 0) {
      if(i > 0)
        (*count)++;
      return( i );
    }
  }

  reversemode    = is_bb_mode(lp, NODE_WEIGHTREVERSEMODE);
  greedymode     = is_bb_mode(lp, NODE_GREEDYMODE);
  randomizemode  = is_bb_mode(lp, NODE_RANDOMIZEMODE);
  depthfirstmode = is_bb_mode(lp, NODE_DEPTHFIRSTMODE);
  breadthfirstmode = is_bb_mode(lp, NODE_BREADTHFIRSTMODE) &&
                     (MYBOOL) (lp->bb_level <= lp->int_vars);
  rcostmode      = (MYBOOL) /* FALSE */ (BB->lp->solutioncount > 0) && is_bb_mode(lp, NODE_RCOSTFIXING) ; /* 5/2/08 peno disabled NODE_RCOSTFIXING because it results in non-optimal solutions with some models */ /* 15/2/8 peno enabled NODE_RCOSTFIXING again because a fix is found. See lp_simplex.c NODE__RCOSTFIXING fix */
  pseudocostmode = is_bb_mode(lp, NODE_PSEUDOCOSTMODE);
  pseudocostsel  = is_bb_rule(lp, NODE_PSEUDOCOSTSELECT) ||
                   is_bb_rule(lp, NODE_PSEUDONONINTSELECT) ||
                   is_bb_rule(lp, NODE_PSEUDORATIOSELECT);
  pseudostrong   = FALSE &&
                   pseudocostsel && !rcostmode && is_bb_mode(lp, NODE_STRONGINIT);

  /* Fill list of non-ints */
  allocINT(lp, &nonint, lp->columns + 1, FALSE);
  n = 0;
  depthmax = -1;
  if(isfeasible != NULL)
    *isfeasible = TRUE;
  BB->lastrcf = 0;
  for(k = 1; (k <= lp->columns); k++) {
    ii = get_var_priority(lp, k);
    isINT = is_int(lp,ii);
    i  = lp->rows + ii;

    /* Tally reduced cost fixing opportunities for ranged non-basic nonINTs */
    if(!isINT) {
#ifdef UseMilpExpandedRCF
      if(rcostmode) {
        bestvar = rcfbound_BB(BB, i, isINT, NULL, isfeasible);
        if(bestvar != FR)
          BB->lastrcf++;
      }
#endif
    }
    else {

      valINT = solution_is_int(lp, i, FALSE);

      /* Skip already fixed variables */
      if(lowbo[i] == upbo[i]) {

        /* Check for validity */
#ifdef Paranoia
        if(!valINT) {
          report(lp, IMPORTANT,
                 "find_int_bbvar: INT var %d was fixed at %d, but computed as %g at node %.0f\n",
                  ii, (int) lowbo[i], lp->solution[i], (double) lp->bb_totalnodes);
          lp->bb_break = TRUE;
          lp->spx_status = UNKNOWNERROR;
          bestvar = 0;
          goto Done;
        }
#endif
      }

      /* The variable has not yet been fixed */
      else {

        /* Tally reduced cost fixing opportunities (also when the
           variables are integer-valued at the current relaxation) */
        if(rcostmode) {
          bestvar = rcfbound_BB(BB, i, isINT, NULL, isfeasible);
          if(bestvar != FR)
            BB->lastrcf++;
        }
        else
          bestvar = FR;

        /* Only qualify variable as branching node if it is non-integer and
           it will not be subsequently fixed via reduced cost fixing logic */
        if(!valINT && (bestvar >= FR)) {

          n++;
          nonint[n] = ii;
          SETMAX(depthmax, lp->bb_varactive[ii]);
        }
      }

    }
  }

#ifdef UseMilpSlacksRCF
  /* Optionally also tally slacks */
  if(rcostmode) {
    for(i = 1; (i <= lp->rows) && (BB->lastrcf == 0); i++) {
      /* Skip already fixed slacks (equalities) */
      if(lowbo[i] < upbo[i]) {
        bestvar = rcfbound_BB(BB, i, FALSE, NULL, isfeasible);
        if(bestvar != FR)
          BB->lastrcf++;
      }
    }
  }
#endif
  nonint[0] = n;
  *count    = n;
  bestvar   = 0;
  if(n == 0)     /* No non-integers found */
    goto Done;

  bestval  = -lp->infinite;
  hold     = 0;
  randval  = 1;

  /* Sort non-ints by depth in case we have breadthfirst or depthfirst modes */
  if((lp->bb_level > 1) && (depthmax > 0) && (depthfirstmode || breadthfirstmode)) {
    int *depths = NULL;

    /* Fill attribute array and make sure ordinal order breaks ties during sort */
    allocINT(lp, &depths, n + 1, FALSE);
    for(i = 1; i <= n; i++)
      depths[i] = (depthfirstmode ? n+1-i : i) + (n+1)*lp->bb_varactive[nonint[i]];
    hpsortex(depths, n, 1, sizeof(*nonint), depthfirstmode, compareINT, nonint);
    FREE(depths);
  }

  /* Do simple firstselect handling */
  if(is_bb_rule(lp, NODE_FIRSTSELECT)) {
    if(reversemode)
      bestvar = lp->rows + nonint[nonint[0]];
    else
      bestvar = lp->rows + nonint[1];
  }

  else for(n = 1; n <= nonint[0]; n++) {
    ii = nonint[n];
    i = lp->rows + ii;

    /* Do the naive detection */
    if(n == 1)
      bestvar = i;

    /* Should we do a "strong" pseudo-cost initialization or an incremental update? */
    if(pseudostrong &&
       (MAX(lp->bb_PseudoCost->LOcost[ii].rownr,
            lp->bb_PseudoCost->UPcost[ii].rownr) < lp->bb_PseudoCost->updatelimit) &&
       (MAX(lp->bb_PseudoCost->LOcost[ii].colnr,
            lp->bb_PseudoCost->UPcost[ii].colnr) < 5*lp->bb_PseudoCost->updatelimit)) {
      strongbranch_BB(lp, BB, ii, BB_INT, nonint[0]);
    }

    /* Select default pricing/weighting mode */
    if(pseudocostmode)
      OFval = get_pseudonodecost(lp->bb_PseudoCost, ii, BB_INT, lp->solution[i]);
    else
      OFval = my_chsign(is_maxim(lp), get_mat(lp, 0, ii));

    if(randomizemode)
      randval = exp(rand_uniform(lp, 1.0));

    /* Find the maximum pseudo-cost of a variable (don't apply pseudocostmode here) */
    if(pseudocostsel) {
      if(pseudocostmode)
        hold = OFval;
      else
        hold = get_pseudonodecost(lp->bb_PseudoCost, ii, BB_INT, lp->solution[i]);
      hold *= randval;
      if(greedymode) {
        if(pseudocostmode) /* Override! */
          OFval = my_chsign(is_maxim(lp), get_mat(lp, 0, ii));
        hold *= OFval;
      }
      hold = my_chsign(reversemode, hold);
    }
    else
    /* Find the variable with the largest gap to its bounds (distance from being fixed) */
    if(is_bb_rule(lp, NODE_GAPSELECT)) {
      hold = lp->solution[i];
      holdINT = hold-unscaled_value(lp, upbo[i], i);
      hold -= unscaled_value(lp, lowbo[i], i);
      if(fabs(holdINT) > hold)
        hold = holdINT;
      if(greedymode)
        hold *= OFval;
      hold = my_chsign(reversemode, hold)*randval;
    }
    else
    /* Find the variable with the largest integer gap (closest to 0.5) */
    if(is_bb_rule(lp, NODE_FRACTIONSELECT)) {
      hold = modf(lp->solution[i], &holdINT);
      holdINT = hold-1;
      if(fabs(holdINT) > hold)
        hold = holdINT;
      if(greedymode)
        hold *= OFval;
      hold = my_chsign(reversemode, hold)*randval;
    }
    else
    /* Find the "range", most flexible variable */
    if(is_bb_rule(lp, NODE_RANGESELECT)) {
      hold = unscaled_value(lp, upbo[i]-lowbo[i], i);
      if(greedymode)
        hold *= OFval;
      hold = my_chsign(reversemode, hold)*randval;
    }

    /* Select better, check for ties, and split by proximity to 0.5 */
    if(hold > bestval) {
      if( (hold > bestval+lp->epsprimal) ||
          (fabs(modf(lp->solution[i], &holdINT) - 0.5) <
           fabs(modf(lp->solution[bestvar], &holdINT) - 0.5)) ) {
        bestval = hold;
        bestvar = i;
      }
    }
  }

Done:
  FREE(nonint);
  return(bestvar);
}

STATIC BBPSrec *init_pseudocost(lprec *lp, int pseudotype)
{
  int     i;
  REAL    PSinitUP, PSinitLO;
  BBPSrec *newitem;
  MYBOOL  isPSCount;

  /* Allocate memory */
  newitem = (BBPSrec*) malloc(sizeof(*newitem));
  newitem->lp = lp;
  newitem->LOcost = (MATitem*) malloc((lp->columns+1) * sizeof(*newitem->LOcost));
  newitem->UPcost = (MATitem*) malloc((lp->columns+1) * sizeof(*newitem->UPcost));
  newitem->secondary = NULL;

  /* Initialize with OF values */
  newitem->pseodotype = (pseudotype & NODE_STRATEGYMASK);
  isPSCount = ((pseudotype & NODE_PSEUDONONINTSELECT) != 0);
  for(i = 1; i <= lp->columns; i++) {
    newitem->LOcost[i].rownr = 1; /* Actual updates */
    newitem->LOcost[i].colnr = 1; /* Attempted updates */
    newitem->UPcost[i].rownr = 1;
    newitem->UPcost[i].colnr = 1;

    /* Initialize with the plain OF value as conventional usage suggests, or
       override in case of pseudo-nonint count strategy */
    PSinitUP = my_chsign(is_maxim(lp), get_mat(lp, 0, i));
    PSinitLO = -PSinitUP;
    if(isPSCount) {
      /* Set default assumed reduction in the number of non-ints by choosing this variable;
         KE changed from 0 on 30 June 2004 and made two-sided selectable.  Note that the
         typical value range is <0..1>, with a positive bias for an "a priori" assumed
         fast-converging (low "MIP-complexity") model. Very hard models may require
         negative initialized values for one or both. */
      PSinitUP = 0.1*0;
#if 0
      PSinitUP = my_chsign(PSinitUP < 0, PSinitUP);
      PSinitLO = -PSinitUP;
#else
      PSinitLO = PSinitUP;
#endif
    }
    newitem->UPcost[i].value = PSinitUP;
    newitem->LOcost[i].value = PSinitLO;
  }
  newitem->updatelimit     = lp->bb_PseudoUpdates;
  newitem->updatesfinished = 0;
  newitem->restartlimit    = DEF_PSEUDOCOSTRESTART;

  /* Let the user get an opportunity to initialize pseudocosts */
  if(userabort(lp, MSG_INITPSEUDOCOST))
    lp->spx_status = USERABORT;

  return( newitem );
}

STATIC MYBOOL free_pseudoclass(BBPSrec **PseudoClass)
{
  BBPSrec *target = *PseudoClass;

  FREE(target->LOcost);
  FREE(target->UPcost);
  target = target->secondary;
  FREE(*PseudoClass);
  *PseudoClass = target;

  return( (MYBOOL) (target != NULL) );
}

STATIC void free_pseudocost(lprec *lp)
{
  if((lp != NULL) && (lp->bb_PseudoCost != NULL)) {
    while(free_pseudoclass(&(lp->bb_PseudoCost)) );
  }
}

MYBOOL __WINAPI set_pseudocosts(lprec *lp, REAL *clower, REAL *cupper, int *updatelimit)
{
  int i;

  if((lp->bb_PseudoCost == NULL) || ((clower == NULL) && (cupper == NULL)))
    return(FALSE);
  for(i = 1; i <= lp->columns; i++) {
    if(clower != NULL)
      lp->bb_PseudoCost->LOcost[i].value = clower[i];
    if(cupper != NULL)
      lp->bb_PseudoCost->UPcost[i].value = cupper[i];
  }
  if(updatelimit != NULL)
    lp->bb_PseudoCost->updatelimit = *updatelimit;
  return(TRUE);
}

MYBOOL __WINAPI get_pseudocosts(lprec *lp, REAL *clower, REAL *cupper, int *updatelimit)
{
  int i;

  if((lp->bb_PseudoCost == NULL) || ((clower == NULL) && (cupper == NULL)))
    return(FALSE);
  for(i = 1; i <= lp->columns; i++) {
    if(clower != NULL)
      clower[i] = lp->bb_PseudoCost->LOcost[i].value;
    if(cupper != NULL)
      cupper[i] = lp->bb_PseudoCost->UPcost[i].value;
  }
  if(updatelimit != NULL)
    *updatelimit = lp->bb_PseudoCost->updatelimit;
  return(TRUE);
}

STATIC REAL get_pseudorange(BBPSrec *pc, int mipvar, int varcode)
{
  if(varcode == BB_SC)
    return( unscaled_value(pc->lp, pc->lp->sc_lobound[mipvar], pc->lp->rows+mipvar) );
  else
    return( 1.0 );
}

STATIC void update_pseudocost(BBPSrec *pc, int mipvar, int varcode, MYBOOL capupper, REAL varsol)
{
  REAL     OFsol, uplim;
  MATitem  *PS;
  MYBOOL   nonIntSelect = is_bb_rule(pc->lp, NODE_PSEUDONONINTSELECT);

  /* Establish input values;
     Note: The pseudocosts are normalized to the 0-1 range! */
  uplim = get_pseudorange(pc, mipvar, varcode);
  varsol = modf(varsol/uplim, &OFsol);

  /* Set reference value according to pseudocost mode */
  if(nonIntSelect)
    OFsol = pc->lp->bb_bounds->lastvarcus;    /* The count of MIP infeasibilities */
  else
    OFsol = pc->lp->solution[0];              /* The problem's objective function value */

  if(isnan(varsol)) {
    pc->lp->bb_parentOF = OFsol;
    return;
  }

  /* Point to the applicable (lower or upper) bound and increment attempted update count */
  if(capupper) {
    PS = &pc->LOcost[mipvar];
  }
  else {
    PS = &pc->UPcost[mipvar];
    varsol = 1-varsol;
  }
  PS->colnr++;

  /* Make adjustment to divisor if we are using the ratio pseudo-cost approach */
  if(is_bb_rule(pc->lp, NODE_PSEUDORATIOSELECT))
    varsol *= capupper;

  /* Compute the update (consider weighting in favor of most recent) */
  mipvar = pc->updatelimit;
  if(((mipvar <= 0) || (PS->rownr < mipvar)) &&
     (fabs(varsol) > pc->lp->epspivot)) {
    /* We are interested in the change in the MIP measure (contribution to increase
       or decrease, as the case may be) and not its last value alone. */
    PS->value = PS->value*PS->rownr + (pc->lp->bb_parentOF-OFsol) / (varsol*uplim);
    PS->rownr++;
    PS->value /= PS->rownr;
    /* Check if we have enough information to restart */
    if(PS->rownr == mipvar) {
      pc->updatesfinished++;
      if(is_bb_mode(pc->lp, NODE_RESTARTMODE) &&
        (pc->updatesfinished/(2.0*pc->lp->int_vars) >
         pc->restartlimit)) {
        pc->lp->bb_break = AUTOMATIC;
        pc->restartlimit *= 2.681;  /* KE: Who can figure this one out? */
        if(pc->restartlimit > 1)
          pc->lp->bb_rule -= NODE_RESTARTMODE;
        report(pc->lp, NORMAL, "update_pseudocost: Restarting with updated pseudocosts\n");
      }
    }
  }
  pc->lp->bb_parentOF = OFsol;
}

STATIC REAL get_pseudobranchcost(BBPSrec *pc, int mipvar, MYBOOL dofloor)
{
  if(dofloor)
    return( pc->LOcost[mipvar].value );
  else
    return( pc->UPcost[mipvar].value );
}

STATIC REAL get_pseudonodecost(BBPSrec *pc, int mipvar, int vartype, REAL varsol)
{
  REAL hold, uplim;

  uplim = get_pseudorange(pc, mipvar, vartype);
  varsol = modf(varsol/uplim, &hold);
  if(isnan(varsol))
    varsol = 0;

  hold = pc->LOcost[mipvar].value*varsol +
         pc->UPcost[mipvar].value*(1-varsol);

  return( hold*uplim );
}

STATIC int compute_theta(lprec *lp, int rownr, LREAL *theta, int isupbound, REAL HarrisScalar, MYBOOL primal)
/* The purpose of this routine is to compute the non-basic bound state / value of
   the leaving variable. Note that the incoming theta is "d" in Chvatal-terminology */
{
  int             colnr = lp->var_basic[rownr];
  register LREAL x     = lp->rhs[rownr];
  REAL            lb    = 0,  /* Put lower bound here when the fully bounded version is implemented */
                  ub    = lp->upbo[colnr],
                  eps   = lp->epsprimal;  /* Primal feasibility tolerance */

  /* Compute theta for the primal simplex */
  HarrisScalar *= eps;
  if(primal) {

    if(*theta > 0)
      x -= lb - HarrisScalar;   /* A positive number */
    else if(ub < lp->infinite)
      x -= ub + HarrisScalar;   /* A negative number */
    else {
      *theta = -lp->infinite;
      return( colnr );
    }
  }
  /* Compute theta for the dual simplex */
  else {

    if(isupbound)
      *theta = -(*theta);

    /* Current value is below or equal to its lower bound */
    if(x < lb+eps)
      x -= lb - HarrisScalar;

    /* Current value is above or equal to its upper bound */
    else if(x > ub-eps) {
      if(ub >= lp->infinite) {
        *theta = lp->infinite * my_sign(*theta);
        return( colnr );
      }
      else
        x -= ub + HarrisScalar;
    }
  }
  my_roundzero(x, lp->epsmachine);
  *theta = x / *theta;

#ifdef EnforcePositiveTheta
  /* Check if we have negative theta due to rounding or an internal error */
  if(*theta < 0) {
    if(primal && (ub == lb))
      lp->rhs[rownr] = lb;
    else
#ifdef Paranoia
    if(*theta < -eps) {
      report(lp, DETAILED, "compute_theta: Negative theta (%g) not allowed in base-0 version of lp_solve\n",
                            *theta);
    }
#endif
    *theta = 0;
  }
#endif

  return( colnr );
}

STATIC MYBOOL check_degeneracy(lprec *lp, REAL *pcol, int *degencount)
/* Check if the entering column Pi=Inv(B)*a is likely to produce improvement;
   (cfr. Istvan Maros: CTOTSM p. 233) */
{
  int  i, ndegen;
  REAL *rhs, sdegen, epsmargin = lp->epsprimal;

  sdegen = 0;
  ndegen = 0;
  rhs    = lp->rhs;
  for(i = 1; i <= lp->rows; i++) {
    rhs++;
    pcol++;
    if(fabs(*rhs) < epsmargin) {
      sdegen += *pcol;
      ndegen++;
    }
    else if(fabs((*rhs)-lp->upbo[lp->var_basic[i]]) < epsmargin) {
      sdegen -= *pcol;
      ndegen++;
    }
  }
  if(degencount != NULL)
    *degencount = ndegen;
/*  sdegen += epsmargin*ndegen; */
  return( (MYBOOL) (sdegen <= 0) );
}

STATIC MYBOOL performiteration(lprec *lp, int rownr, int varin, LREAL theta, MYBOOL primal, MYBOOL allowminit,
                               REAL *prow, int *nzprow, REAL *pcol, int *nzpcol, int *boundswaps)
{
  int    varout;
  REAL   pivot, epsmargin, leavingValue, leavingUB, enteringUB;
  MYBOOL leavingToUB = FALSE, enteringFromUB, enteringIsFixed, leavingIsFixed;
  MYBOOL *islower = &(lp->is_lower[varin]);
  MYBOOL minitNow = FALSE, minitStatus = ITERATE_MAJORMAJOR;
  LREAL  deltatheta = theta;

  if(userabort(lp, MSG_ITERATION))
    return( minitNow );

#ifdef Paranoia
  if(rownr > lp->rows) {
    if (lp->spx_trace)
      report(lp, IMPORTANT, "performiteration: Numeric instability encountered!\n");
    lp->spx_status = NUMFAILURE;
    return( FALSE );
  }
#endif
  varout = lp->var_basic[rownr];
#ifdef Paranoia
  if(!lp->is_lower[varout])
    report(lp, SEVERE, "performiteration: Leaving variable %d was at its upper bound at iter %.0f\n",
                        varout, (double) get_total_iter(lp));
#endif

  /* Theta is the largest change possible (strictest constraint) for the entering
     variable (Theta is Chvatal's "t", ref. Linear Programming, pages 124 and 156) */
  lp->current_iter++;

  /* Test if it is possible to do a cheap "minor iteration"; i.e. set entering
     variable to its opposite bound, without entering the basis - which is
     obviously not possible for fixed variables! */
  epsmargin = lp->epsprimal;
  enteringFromUB = !(*islower);
  enteringUB = lp->upbo[varin];
  leavingUB  = lp->upbo[varout];
  enteringIsFixed = (MYBOOL) (fabs(enteringUB) < epsmargin);
  leavingIsFixed  = (MYBOOL) (fabs(leavingUB) < epsmargin);
#if defined _PRICE_NOBOUNDFLIP
  allowminit     &= !ISMASKSET(lp->piv_strategy, PRICE_NOBOUNDFLIP);
#endif
#ifdef Paranoia
  if(enteringUB < 0)
    report(lp, SEVERE, "performiteration: Negative range for entering variable %d at iter %.0f\n",
                        varin, (double) get_total_iter(lp));
  if(leavingUB < 0)
    report(lp, SEVERE, "performiteration: Negative range for leaving variable %d at iter %.0f\n",
                        varout, (double) get_total_iter(lp));
#endif

  /* Handle batch bound swaps with the dual long-step algorithm;
     Loop over specified bound swaps; update RHS and Theta for bound swaps */
  if((boundswaps != NULL) && (boundswaps[0] > 0)) {

    int   i, boundvar;
    REAL  *hold;

    /* Allocate and initialize accumulation array */
    allocREAL(lp, &hold, lp->rows + 1, TRUE);

    /* Accumulate effective bound swaps and update flag */
    for(i = 1; i <= boundswaps[0]; i++) {
      boundvar = boundswaps[i];
      deltatheta = my_chsign(!lp->is_lower[boundvar], lp->upbo[boundvar]);
      mat_multadd(lp->matA, hold, boundvar, deltatheta);
      lp->is_lower[boundvar] = !lp->is_lower[boundvar];
    }
    lp->current_bswap += boundswaps[0];
    lp->current_iter  += boundswaps[0];

    /* Solve for bound flip update vector (note that this does not
       overwrite the stored update vector for the entering variable) */
    ftran(lp, hold, NULL, lp->epsmachine);
    if(!lp->obj_in_basis)
      hold[0] = 0; /* The correct reduced cost goes here (adjusted for bound state) ****** */

    /* Update the RHS / basic variable values and set revised thetas */
    pivot = lp->bfp_pivotRHS(lp, 1, hold);
    deltatheta = multi_enteringtheta(lp->longsteps);
    theta = deltatheta;

    FREE(hold);
  }

  /* Otherwise to traditional check for single bound swap */
  else if(allowminit &&
           !enteringIsFixed) {

/*    pivot = epsmargin; */
    pivot = lp->epsdual;
/* #define v51mode */ /* Enable this for v5.1 operation mode */
#ifdef v51mode
    if(((lp->simplex_mode & SIMPLEX_Phase1_DUAL) == 0) ||
       !is_constr_type(lp, rownr, EQ))                      /* *** DEBUG CODE KE */
#endif
    if(enteringUB - theta < -pivot) {

#ifndef v51mode
      if(fabs(enteringUB - theta) < pivot)
        minitStatus = ITERATE_MINORMAJOR;
      else
#endif
        minitStatus = ITERATE_MINORRETRY;
      minitNow    = (MYBOOL) (minitStatus != ITERATE_MAJORMAJOR);
    }
  }

  /* Process for traditional style single minor iteration */
  if(minitNow) {

   /* Set the new values (note that theta is set to always be positive) */
    theta = MIN(fabs(theta), enteringUB);

    /* Update the RHS / variable values and do bound-swap */
    pivot = lp->bfp_pivotRHS(lp, theta, NULL);
    *islower = !(*islower);

    lp->current_bswap++;

  }

  /* Process for major iteration */
  else {

    /* Update the active pricer for the current pivot */
    updatePricer(lp, rownr, varin, lp->bfp_pivotvector(lp), prow, nzprow);

    /* Update the current basic variable values */
    pivot = lp->bfp_pivotRHS(lp, theta, NULL);

    /* See if the leaving variable goes directly to its upper bound. */
    leavingValue = lp->rhs[rownr];
    leavingToUB = (MYBOOL) (leavingValue > 0.5*leavingUB);
    lp->is_lower[varout] = leavingIsFixed || !leavingToUB;

    /* Set the value of the entering varible (theta always set to be positive) */
    if(enteringFromUB) {
      lp->rhs[rownr] = enteringUB - deltatheta;
      *islower = TRUE;
    }
    else
      lp->rhs[rownr] = deltatheta;
    my_roundzero(lp->rhs[rownr], epsmargin);

   /* Update basis indeces */
    varout = set_basisvar(lp, rownr, varin);

   /* Finalize the update in preparation for next major iteration */
    lp->bfp_finishupdate(lp, enteringFromUB);

  }

  /* Show pivot tracking information, if specified */
  if((lp->verbose > NORMAL) && (MIP_count(lp) == 0) &&
     ((lp->current_iter % MAX(2, lp->rows / 10)) == 0))
    report(lp, NORMAL, "Objective value " RESULTVALUEMASK " at iter %10.0f.\n",
                       lp->rhs[0], (double) get_total_iter(lp));

#if 0
  if(verify_solution(lp, FALSE, my_if(minitNow, "MINOR", "MAJOR")) >= 0) {
    if(minitNow)
      pivot = get_obj_active(lp, varin);
    else
      pivot = get_obj_active(lp, varout);
  }
#endif
#if 0
  if((lp->longsteps != NULL) && (boundswaps[0] > 0) && lp->longsteps->objcheck &&
    ((pivot = fabs(my_reldiff(lp->rhs[0], lp->longsteps->obj_last))) > lp->epssolution)) {
    report(lp, IMPORTANT, "performiteration: Objective value gap %8.6f found at iter %6.0f (%d bound flips, %d)\n",
                          pivot, (double) get_total_iter(lp), boundswaps[0], enteringFromUB);
  }
#endif

  if(lp->spx_trace) {
    if(minitNow)
      report(lp, NORMAL, "I:%5.0f - minor - %5d ignored,          %5d flips  from %s with THETA=%g and OBJ=%g\n",
                         (double) get_total_iter(lp), varout, varin, (enteringFromUB ? "UPPER" : "LOWER"), theta, lp->rhs[0]);
    else
      report(lp, NORMAL, "I:%5.0f - MAJOR - %5d leaves to %s,  %5d enters from %s with THETA=%g and OBJ=%g\n",
                         (double) get_total_iter(lp), varout, (leavingToUB    ? "UPPER" : "LOWER"),
                                           varin,  (enteringFromUB ? "UPPER" : "LOWER"), theta, lp->rhs[0]);
    if(minitNow) {
      if(!lp->is_lower[varin])
        report(lp, DETAILED,
        "performiteration: Variable %d changed to its lower bound at iter %.0f (from %g)\n",
        varin, (double) get_total_iter(lp), enteringUB);
      else
        report(lp, DETAILED,
        "performiteration: Variable %d changed to its upper bound at iter %.0f (to %g)\n",
        varin, (double) get_total_iter(lp), enteringUB);
    }
    else
      report(lp, NORMAL,
          "performiteration: Variable %d entered basis at iter %.0f at " RESULTVALUEMASK "\n",
          varin, (double) get_total_iter(lp), lp->rhs[rownr]);
    if(!primal) {
      pivot = compute_feasibilitygap(lp, (MYBOOL)!primal, TRUE);
      report(lp, NORMAL, "performiteration: Feasibility gap at iter %.0f is " RESULTVALUEMASK "\n",
                         (double) get_total_iter(lp), pivot);
    }
    else
      report(lp, NORMAL,
          "performiteration: Current objective function value at iter %.0f is " RESULTVALUEMASK "\n",
          (double) get_total_iter(lp), lp->rhs[0]);
  }

  return( minitStatus );

} /* performiteration */

STATIC REAL get_refactfrequency(lprec *lp, MYBOOL final)
{
  COUNTER iters;
  int     refacts;

  /* Get numerator and divisor information */
  iters   = (lp->total_iter+lp->current_iter) - (lp->total_bswap+lp->current_bswap);
  refacts = lp->bfp_refactcount(lp, BFP_STAT_REFACT_TOTAL);

  /* Return frequency for different cases:
      1) Actual frequency in case final statistic is desired
      2) Dummy if we are in a B&B process
      3) Frequency with added initialization offsets which
         are diluted in course of the solution process */
  if(final)
    return( (REAL) (iters) / MAX(1,refacts) );
  else if(lp->bb_totalnodes > 0)
    return( (REAL) lp->bfp_pivotmax(lp) );
  else
    return( (REAL) (lp->bfp_pivotmax(lp)+iters) / (1+refacts) );
}

#if 0
/* INLINE */ MYBOOL is_fixedvar(lprec *lp, int variable)
{
  if((lp->bb_bounds != NULL && lp->bb_bounds->UBzerobased) || (variable <= lp->rows))
    return( (MYBOOL) (lp->upbo[variable] < lp->epsprimal) );
  else
    return( (MYBOOL) (lp->upbo[variable]-lp->lowbo[variable] < lp->epsprimal) );
} /* is_fixedvar */
#else
MYBOOL is_fixedvar(lprec *lp, int varnr)
{
  if(lp->bb_bounds == NULL) {
    if(varnr <= lp->rows)
      return( (MYBOOL) (lp->orig_upbo[varnr] < lp->epsmachine) );
    else
      return( (MYBOOL) (lp->orig_upbo[varnr]-lp->orig_lowbo[varnr] < lp->epsmachine) );
  }
  else if((varnr <= lp->rows) || (lp->bb_bounds->UBzerobased == TRUE))
    return( (MYBOOL) (lp->upbo[varnr] < lp->epsvalue) );
  else
    return( (MYBOOL) (lp->upbo[varnr]-lp->lowbo[varnr] < lp->epsvalue) );
}
#endif

STATIC MYBOOL solution_is_int(lprec *lp, int index, MYBOOL checkfixed)
{
#if 1
  return( (MYBOOL) (isINT(lp, lp->solution[index]) && (!checkfixed || is_fixedvar(lp, index))) );
#else
  if(isINT(lp, lp->solution[index])) {
    if(checkfixed)
      return(is_fixedvar(lp, index));
    else
      return(TRUE);
  }
  return(FALSE);
#endif
} /* solution_is_int */


MYBOOL __WINAPI set_multiprice(lprec *lp, int multiblockdiv)
{
  /* See if we are resetting multiply priced column structures */
  if(multiblockdiv != lp->multiblockdiv) {
    if(multiblockdiv < 1)
      multiblockdiv = 1;
    lp->multiblockdiv = multiblockdiv;
    multi_free(&(lp->multivars));
  }
  return( TRUE );
}

int __WINAPI get_multiprice(lprec *lp, MYBOOL getabssize)
{
  if((lp->multivars == NULL) || (lp->multivars->used == 0))
    return( 0 );
  if(getabssize)
    return( lp->multivars->size );
  else
    return( lp->multiblockdiv );
}

MYBOOL __WINAPI set_partialprice(lprec *lp, int blockcount, int *blockstart, MYBOOL isrow)
{
  int        ne, i, items;
  partialrec **blockdata;

  /* Determine partial target (rows or columns) */
  if(isrow)
    blockdata = &(lp->rowblocks);
  else
    blockdata = &(lp->colblocks);

  /* See if we are resetting partial blocks */
  ne = 0;
  items = IF(isrow, lp->rows, lp->columns);
  if(blockcount == 1)
    partial_freeBlocks(blockdata);

  /* Set a default block count if this was not specified */
  else if(blockcount <= 0) {
    blockstart = NULL;
    if(items < DEF_PARTIALBLOCKS*DEF_PARTIALBLOCKS)
      blockcount = items / DEF_PARTIALBLOCKS + 1;
    else
      blockcount = DEF_PARTIALBLOCKS;
    ne = items / blockcount;
    if(ne * blockcount < items)
      ne++;
  }

  /* Fill partial block arrays;
     Note: These will be modified during preprocess to reflect
           presolved columns and the handling of slack variables. */
  if(blockcount > 1) {
    MYBOOL     isNew = (MYBOOL) (*blockdata == NULL);

    /* Provide for extra block with slack variables in the column mode */
    i = 0;
    if(!isrow)
      i++;

    /* (Re)-allocate memory */
    if(isNew)
      *blockdata = partial_createBlocks(lp, isrow);
    allocINT(lp, &((*blockdata)->blockend), blockcount+i+1, AUTOMATIC);
    allocINT(lp, &((*blockdata)->blockpos), blockcount+i+1, AUTOMATIC);

    /* Copy the user-provided block start positions */
    if(blockstart != NULL) {
      MEMCOPY((*blockdata)->blockend+i, blockstart, blockcount+i+1);
      if(!isrow) {
        blockcount++;
        (*blockdata)->blockend[0] = 1;
        for(i = 1; i < blockcount; i++)
          (*blockdata)->blockend[i] += lp->rows;
      }
    }

    /* Fill the block ending positions if they were not specified */
    else {
      (*blockdata)->blockend[0] = 1;
      (*blockdata)->blockpos[0] = 1;
      if(ne == 0) {
        ne = items / blockcount;
        /* Increase the block size if we have a fractional value */
        while(ne * blockcount < items)
          ne++;
      }
      i = 1;
      if(!isrow) {
        (*blockdata)->blockend[i] = (*blockdata)->blockend[i-1]+lp->rows;
        blockcount++;
        i++;
        items += lp->rows;
      }
      for(; i < blockcount; i++)
        (*blockdata)->blockend[i] = (*blockdata)->blockend[i-1]+ne;

      /* Let the last block handle the "residual" */
      (*blockdata)->blockend[blockcount] = items+1;
    }

    /* Fill starting positions (used in multiple partial pricing) */
    for(i = 1; i <= blockcount; i++)
      (*blockdata)->blockpos[i] = (*blockdata)->blockend[i-1];

  }

  /* Update block count */
  (*blockdata)->blockcount = blockcount;


  return( TRUE );
} /* set_partialprice */

void __WINAPI get_partialprice(lprec *lp, int *blockcount, int *blockstart, MYBOOL isrow)
{
  partialrec *blockdata;

  /* Determine partial target (rows or columns) */
  if(isrow)
    blockdata = lp->rowblocks;
  else
    blockdata = lp->colblocks;

  *blockcount = partial_countBlocks(lp, isrow);
  if((blockdata != NULL) && (blockstart != NULL)) {
    int i = 0, k = *blockcount;
    if(!isrow)
      i++;
    MEMCOPY(blockstart, blockdata->blockend + i, k - i);
    if(!isrow) {
      k -= i;
      for(i = 0; i < k; i++)
        blockstart[i] -= lp->rows;
    }
  }
}


/* Solution-related functions */
STATIC MYBOOL bb_better(lprec *lp, int target, int mode)
/* Must handle four modes (logic assumes Min!):
      -----|--.--|----->
   1  ++++++-----------  LHS exclusive test point is better
   2  +++++++++--------  LHS inclusive
   3  ++++++-----++++++  LHS+RHS exclusive
   4  --------+++++++++  RHS inclusive
   5  -----------++++++  RHS exclusive
*/
{
  REAL   epsvalue, offset = lp->epsprimal,
         refvalue = lp->infinite, testvalue = lp->solution[0];
  MYBOOL ismax = is_maxim(lp),
         relgap = is_action(mode, OF_TEST_RELGAP),
         fcast  = is_action(target, OF_PROJECTED),
         delta  = is_action(target, OF_DELTA);

  if(relgap) {
    epsvalue = lp->mip_relgap;
    clear_action(&mode, OF_TEST_RELGAP);
  }
  else
    epsvalue = lp->mip_absgap;

  if(delta)
    clear_action(&target, OF_DELTA);
  if(fcast)
    clear_action(&target, OF_PROJECTED);
#ifdef Paranoia
  if((mode < OF_TEST_BT) || (mode > OF_TEST_WT))
    report(lp, SEVERE, "bb_better: Passed invalid mode '%d'\n", mode);
#endif

  switch(target) {
    case OF_RELAXED:   refvalue = lp->real_solution;
                       break;
    case OF_INCUMBENT: refvalue = lp->best_solution[0];
                       break;
    case OF_WORKING:  refvalue = my_chsign(!ismax, lp->bb_workOF /* unscaled_value(lp, lp->bb_workOF, 0) */ );
                       if(fcast)
                         testvalue = my_chsign(!ismax, lp->longsteps->obj_last) - epsvalue;
                       else
                         testvalue = my_chsign(!ismax, lp->rhs[0] /* unscaled_value(lp, lp->rhs[0], 0) */);
                       break;
    case OF_USERBREAK: refvalue = lp->bb_breakOF;
                       break;
    case OF_HEURISTIC: refvalue = lp->bb_heuristicOF;
                       break;
    case OF_DUALLIMIT: refvalue = lp->bb_limitOF;
                       break;
    default         :  report(lp, SEVERE, "bb_better: Passed invalid test target '%d'\n", target);
                       return( FALSE );
  }

  /* Adjust the test value for the desired acceptability window */
  if(delta) {
    SETMAX(epsvalue, lp->bb_deltaOF - epsvalue);
  }
  else
    epsvalue = my_chsign(target >= OF_USERBREAK, epsvalue); /* *** This seems Ok, but should be verified */
  testvalue += my_chsign(ismax, epsvalue);

  /* Compute the raw test value */
  if(relgap)
    testvalue = my_reldiff(testvalue, refvalue);
  else
    testvalue -= refvalue;

  /* Make test value adjustment based on the selected option */
  if(mode == OF_TEST_NE)
    relgap = (MYBOOL) (fabs(testvalue) >= offset);
  else {
    testvalue = my_chsign(mode > OF_TEST_NE, testvalue);
    testvalue = my_chsign(ismax, testvalue);
    relgap = (MYBOOL) (testvalue < offset);
  }
  return( relgap );
}

STATIC void construct_solution(lprec *lp, REAL *target)
{
  int     i, j, basi;
  REAL    f, epsvalue = lp->epsprimal;
  REAL    *solution;
  REAL    *value;
  int     *rownr;
  MATrec  *mat = lp->matA;

  if(target == NULL)
    solution = lp->solution;
  else
    solution = target;

  /* Initialize OF and slack variables. */
  for(i = 0; i <= lp->rows; i++) {
#ifdef LegacySlackDefinition
    if(i == 0)
      f = unscaled_value(lp, -lp->orig_rhs[i], i);
    else {
      j = lp->presolve_undo->var_to_orig[i];
      if(j > 0) {
        f = lp->presolve_undo->fixed_rhs[j];
        f = unscaled_value(lp, f, i);
      }
      else
        f = 0;
    }
#else
    f = lp->orig_rhs[i];
    if((i > 0) && !lp->is_basic[i] && !lp->is_lower[i])
#ifdef SlackInitMinusInf
      f -= my_chsign(is_chsign(lp, i), fabs(lp->upbo[i]));
#else
      f -= my_chsign(is_chsign(lp, i), fabs(lp->lowbo[i] + lp->upbo[i]));
#endif
    f = unscaled_value(lp, -f, i);
#endif
    solution[i] = f;
  }

  /* Initialize user variables to their lower bounds. */
  for(i = lp->rows+1; i <= lp->sum; i++)
    solution[i] = lp->lowbo[i];

  /* Add values of user basic variables. */
  for(i = 1; i <= lp->rows; i++) {
    basi = lp->var_basic[i];
    if(basi > lp->rows) {
      solution[basi] += lp->rhs[i];
    }
  }

  /* 1. Adjust non-basic variables at their upper bounds,
     2. Unscale all user variables,
     3. Optionally do precision management. */
  for(i = lp->rows + 1; i <= lp->sum; i++) {
    if(!lp->is_basic[i] && !lp->is_lower[i])
      solution[i] += lp->upbo[i];
    solution[i] = unscaled_value(lp, solution[i], i);
#ifdef xImproveSolutionPrecision
    if(is_int(lp, i-lp->rows))
      solution[i] = restoreINT(solution[i], lp->epsint);
    else
      solution[i] = restoreINT(solution[i], lp->epsprimal);
#endif
  }

  /* Compute the OF and slack values "in extentio" */
  for(j = 1; j <= lp->columns; j++) {
    f = solution[lp->rows + j];
    if(f != 0) {
      solution[0] += f * unscaled_mat(lp, lp->orig_obj[j], 0, j);
      i = mat->col_end[j-1];
      basi = mat->col_end[j];
      rownr = &COL_MAT_ROWNR(i);
      value = &COL_MAT_VALUE(i);
      for(; i < basi;
          i++, rownr += matRowColStep, value += matValueStep)
        solution[*rownr] += f * unscaled_mat(lp, *value, *rownr, j);
    }
  }

  /* Do slack precision management and sign reversal if necessary */
  for(i = 0; i <= lp->rows; i++) {
#ifdef ImproveSolutionPrecision
    my_roundzero(solution[i], epsvalue);
#endif
    if(is_chsign(lp, i))
      solution[i] = my_flipsign(solution[i]);
  }

 /* Record the best real-valued solution and compute a simple MIP solution limit */
  if(target == NULL) {
    if(is_infinite(lp, lp->real_solution)) {
      lp->bb_workOF = lp->rhs[0];
      lp->real_solution = solution[0];
      if(is_infinite(lp, lp->bb_limitOF))
        lp->bb_limitOF = lp->real_solution;
      else {
        if(is_maxim(lp)) {
          SETMIN(lp->bb_limitOF, lp->real_solution);
        }
        else {
          SETMAX(lp->bb_limitOF, lp->real_solution);
        }
      }

      /* Do MIP-related tests and computations */
      if((lp->int_vars > 0) && mat_validate(lp->matA) /* && !lp->wasPresolved */) { /* && !lp->wasPresolved uncommented by findings of William H. Patton. The code was never executed when the test was there. The code has effect in an integer model with all integer objective coeff. to cut-off optimization and thus make it faster */
        REAL fixedOF = unscaled_value(lp, lp->orig_rhs[0], 0);

        /* Check if we have an all-integer OF */
        basi = lp->columns;
        for(j = 1; j <= basi; j++) {
          f = fabs(get_mat(lp, 0, j)) + lp->epsint / 2;
          if(f > lp->epsint) { /* If coefficient is 0 then it doesn't influence OF, even it variable is not integer */
            if(!is_int(lp, j) || (fmod(f, 1) > lp->epsint))
              break;
          }
        }

        /* If so, we can round up the fractional OF */
        if(j > basi) {
          f = my_chsign(is_maxim(lp), lp->real_solution) + fixedOF;
          f = floor(f+(1-epsvalue));
          f = my_chsign(is_maxim(lp), f - fixedOF);
          if(is_infinite(lp, lp->bb_limitOF))
            lp->bb_limitOF = f;
          else if(is_maxim(lp)) {
            SETMIN(lp->bb_limitOF, f);
          }
          else {
            SETMAX(lp->bb_limitOF, f);
          }
        }
      }

      /* Check that a user limit on the OF is feasible */
      if((lp->int_vars > 0) &&
         (my_chsign(is_maxim(lp), my_reldiff(lp->best_solution[0],lp->bb_limitOF)) < -epsvalue)) {
        lp->spx_status = INFEASIBLE;
        lp->bb_break = TRUE;
      }
    }
  }

} /* construct_solution */

STATIC int check_solution(lprec *lp, int  lastcolumn, REAL *solution,
                          REAL *upbo, REAL *lowbo, REAL tolerance)
{
/*#define UseMaxValueInCheck*/
  MYBOOL isSC;
  REAL   test, value, hold, diff, maxdiff = 0.0, maxerr = 0.0, *matValue,
#ifdef UseMaxValueInCheck
         *maxvalue = NULL,
#else
         *plusum = NULL, *negsum = NULL;
#endif
  int    i,j,n, errlevel = IMPORTANT, errlimit = 10, *matRownr, *matColnr;
  MATrec *mat = lp->matA;

  report(lp, NORMAL, " \n");
  if(MIP_count(lp) > 0)
    report(lp, NORMAL, "%s solution  " RESULTVALUEMASK " after %10.0f iter, %9.0f nodes (gap %.1f%%).\n",
                       my_if(lp->bb_break && !bb_better(lp, OF_DUALLIMIT, OF_TEST_BE) && bb_better(lp, OF_RELAXED, OF_TEST_NE), "Subopt.", "Optimal"),
                       solution[0], (double) lp->total_iter, (double) lp->bb_totalnodes,
                       100.0*fabs(my_reldiff(solution[0], lp->bb_limitOF)));
  else
    report(lp, NORMAL, "Optimal solution  " RESULTVALUEMASK " after %10.0f iter.\n",
                       solution[0], (double) lp->total_iter);

 /* Find the signed sums and the largest absolute product in the matrix (exclude the OF for speed) */
#ifdef UseMaxValueInCheck
  allocREAL(lp, &maxvalue, lp->rows + 1, FALSE);
  for(i = 0; i <= lp->rows; i++)
    maxvalue[i] = fabs(get_rh(lp, i));
#else
  allocREAL(lp, &plusum, lp->rows + 1, TRUE);
  allocREAL(lp, &negsum, lp->rows + 1, TRUE);
#endif
  n = get_nonzeros(lp);
  matRownr = &COL_MAT_ROWNR(0);
  matColnr = &COL_MAT_COLNR(0);
  matValue = &COL_MAT_VALUE(0);
  for(i = 0; i < n; i++, matRownr += matRowColStep,
                         matColnr += matRowColStep,
                         matValue += matValueStep) {
    test = unscaled_mat(lp, *matValue, *matRownr, *matColnr);
    test *= solution[lp->rows + (*matColnr)];
#ifdef UseMaxValueInCheck
    test = fabs(test);
    if(test > maxvalue[*matRownr])
      maxvalue[*matRownr] = test;
#else
    if(test > 0)
      plusum[*matRownr] += test;
    else
      negsum[*matRownr] += test;
#endif
  }


 /* Check if solution values are within the bounds; allowing a margin for numeric errors */
  n = 0;
  for(i = lp->rows + 1; i <= lp->rows+lastcolumn; i++) {

    value = solution[i];

    /* Check for case where we are testing an intermediate solution
       (variables shifted to the origin) */
    if(lowbo == NULL)
      test = 0;
    else
      test = unscaled_value(lp, lowbo[i], i);

    isSC = is_semicont(lp, i - lp->rows);
    diff = my_reldiff(value, test);
    if(diff < 0) {
      if(isSC && (value < test/2))
        test = 0;
      SETMAX(maxerr, fabs(value-test));
      SETMAX(maxdiff, fabs(diff));
    }
    if((diff < -tolerance) && !isSC)  {
      if(n < errlimit)
      report(lp, errlevel,
        "check_solution: Variable   %s = " RESULTVALUEMASK " is below its lower bound " RESULTVALUEMASK "\n",
         get_col_name(lp, i-lp->rows), value, test);
      n++;
    }

    test = unscaled_value(lp, upbo[i], i);
    diff = my_reldiff(value, test);
    if(diff > 0) {
      SETMAX(maxerr, fabs(value-test));
      SETMAX(maxdiff, fabs(diff));
    }
    if(diff > tolerance) {
      if(n < errlimit)
      report(lp, errlevel,
         "check_solution: Variable   %s = " RESULTVALUEMASK " is above its upper bound " RESULTVALUEMASK "\n",
         get_col_name(lp, i-lp->rows), value, test);
      n++;
    }
  }

 /* Check if constraint values are within the bounds; allowing a margin for numeric errors */
  for(i = 1; i <= lp->rows; i++) {

    test = lp->orig_rhs[i];
    if(is_infinite(lp, test))
      continue;

#ifdef LegacySlackDefinition
    j = lp->presolve_undo->var_to_orig[i];
    if(j != 0) {
      if(is_infinite(lp, lp->presolve_undo->fixed_rhs[j]))
        continue;
      test += lp->presolve_undo->fixed_rhs[j];
    }
#endif

    if(is_chsign(lp, i)) {
      test = my_flipsign(test);
      test += fabs(upbo[i]);
    }
    value = solution[i];
    test = unscaled_value(lp, test, i);
#ifndef LegacySlackDefinition
    value += test;
#endif
/*    diff = my_reldiff(value, test); */
#ifdef UseMaxValueInCheck
    hold = maxvalue[i];
#else
    hold = plusum[i] - negsum[i];
#endif
    if(hold < lp->epsvalue)
      hold = 1;
    diff = my_reldiff((value+1)/hold, (test+1)/hold);
    if(diff > 0) {
      SETMAX(maxerr, fabs(value-test));
      SETMAX(maxdiff, fabs(diff));
    }
    if(diff > tolerance) {
      if(n < errlimit)
      report(lp, errlevel,
        "check_solution: Constraint %s = " RESULTVALUEMASK " is above its %s " RESULTVALUEMASK "\n",
        get_row_name(lp, i), value,
        (is_constr_type(lp, i, EQ) ? "equality of" : "upper bound"), test);
      n++;
    }

    test = lp->orig_rhs[i];
#ifdef LegacySlackDefinition
    j = lp->presolve_undo->var_to_orig[i];
    if(j != 0) {
      if(is_infinite(lp, lp->presolve_undo->fixed_rhs[j]))
        continue;
      test += lp->presolve_undo->fixed_rhs[j];
    }
#endif

    value = solution[i];
    if(is_chsign(lp, i))
      test = my_flipsign(test);
    else {
      if(is_infinite(lp, upbo[i]))
        continue;
      test -= fabs(upbo[i]);
#ifndef LegacySlackDefinition
      value = fabs(upbo[i]) - value;
#endif
    }
    test = unscaled_value(lp, test, i);
#ifndef LegacySlackDefinition
    value += test;
#endif
/*    diff = my_reldiff(value, test); */
#ifdef UseMaxValueInCheck
    hold = maxvalue[i];
#else
    hold = plusum[i] - negsum[i];
#endif
    if(hold < lp->epsvalue)
      hold = 1;
    diff = my_reldiff((value+1)/hold, (test+1)/hold);
    if(diff < 0) {
      SETMAX(maxerr, fabs(value-test));
      SETMAX(maxdiff, fabs(diff));
    }
    if(diff < -tolerance) {
      if(n < errlimit)
      report(lp, errlevel,
        "check_solution: Constraint %s = " RESULTVALUEMASK " is below its %s " RESULTVALUEMASK "\n",
        get_row_name(lp, i), value,
        (is_constr_type(lp, i, EQ) ? "equality of" : "lower bound"), test);
      n++;
    }
  }

#ifdef UseMaxValueInCheck
  FREE(maxvalue);
#else
  FREE(plusum);
  FREE(negsum);
#endif

  if(n > 0) {
    report(lp, IMPORTANT, "\nSeriously low accuracy found ||*|| = %g (rel. error %g)\n",
               maxerr, maxdiff);
    return(NUMFAILURE);
  }
  else {
    if(maxerr > 1.0e-7)
      report(lp, NORMAL, "\nMarginal numeric accuracy ||*|| = %g (rel. error %g)\n",
                 maxerr, maxdiff);
    else if(maxerr > 1.0e-9)
      report(lp, NORMAL, "\nReasonable numeric accuracy ||*|| = %g (rel. error %g)\n",
                 maxerr, maxdiff);
    else if(maxerr > 1.0e11)
      report(lp, NORMAL, "\nVery good numeric accuracy ||*|| = %g\n", maxerr);
    else
      report(lp, NORMAL, "\nExcellent numeric accuracy ||*|| = %g\n", maxerr);

    return(OPTIMAL);
  }

} /* check_solution */

STATIC void transfer_solution_var(lprec *lp, int uservar)
{
  if(lp->varmap_locked && (MYBOOL) ((lp->do_presolve & PRESOLVE_LASTMASKMODE) != PRESOLVE_NONE)) {
    uservar += lp->rows;
    lp->full_solution[lp->presolve_undo->orig_rows +
                      lp->presolve_undo->var_to_orig[uservar]] = lp->best_solution[uservar];
  }
}
STATIC void transfer_solution(lprec *lp, MYBOOL dofinal)
{
  int i, ii;

  MEMCOPY(lp->best_solution, lp->solution, lp->sum + 1);

  /* Round integer solution values to actual integers */
  if(is_integerscaling(lp) && (lp->int_vars > 0))
    for(i = 1; i <= lp->columns; i++) {
      if(is_int(lp, i)) {
        ii = lp->rows + i;
        lp->best_solution[ii] = floor(lp->best_solution[ii] + 0.5);
      }
    }

  /* Transfer to full solution vector in the case of presolved eliminations */
  if(dofinal && lp->varmap_locked &&
     (MYBOOL) ((lp->do_presolve & PRESOLVE_LASTMASKMODE) != PRESOLVE_NONE)) {
    presolveundorec *psundo = lp->presolve_undo;

    lp->full_solution[0] = lp->best_solution[0];
    for(i = 1; i <= lp->rows; i++) {
      ii = psundo->var_to_orig[i];
#ifdef Paranoia
      if((ii < 0) || (ii > lp->presolve_undo->orig_rows))
        report(lp, SEVERE, "transfer_solution: Invalid mapping of row index %d to original index '%d'\n",
                            i, ii);
#endif
      lp->full_solution[ii] = lp->best_solution[i];
    }
    for(i = 1; i <= lp->columns; i++) {
      ii = psundo->var_to_orig[lp->rows+i];
#ifdef Paranoia
      if((ii < 0) || (ii > lp->presolve_undo->orig_columns))
        report(lp, SEVERE, "transfer_solution: Invalid mapping of column index %d to original index '%d'\n",
                            i, ii);
#endif
      lp->full_solution[psundo->orig_rows+ii] = lp->best_solution[lp->rows+i];
    }
  }

}

STATIC MYBOOL construct_duals(lprec *lp)
{
  int  i, n, *coltarget;
  REAL scale0, value, dualOF;

  if(lp->duals != NULL)
    free_duals(lp);

  if(is_action(lp->spx_action, ACTION_REBASE) ||
     is_action(lp->spx_action, ACTION_REINVERT) || (!lp->basis_valid) ||
     !allocREAL(lp, &(lp->duals), lp->sum + 1, AUTOMATIC))
    return(FALSE);

  /* Initialize */
  coltarget = (int *) mempool_obtainVector(lp->workarrays, lp->columns+1, sizeof(*coltarget));
  if(!get_colIndexA(lp, SCAN_USERVARS+USE_NONBASICVARS, coltarget, FALSE)) {
    mempool_releaseVector(lp->workarrays, (char *) coltarget, FALSE);
    return(FALSE);
  }
  bsolve(lp, 0, lp->duals, NULL, lp->epsmachine*DOUBLEROUND, 1.0);
  prod_xA(lp, coltarget, lp->duals, NULL, lp->epsmachine, 1.0,
                         lp->duals, NULL, MAT_ROUNDDEFAULT | MAT_ROUNDRC);
  mempool_releaseVector(lp->workarrays, (char *) coltarget, FALSE);


  /* The (Lagrangean) dual values are the reduced costs of the primal slacks;
     when the slack is at its upper bound, change the sign. */
  n = lp->rows;
  for(i = 1; i <= n; i++) {
    if(lp->is_basic[i])
      lp->duals[i] = 0;
    /* Added a test if variable is different from 0 because sometime you get -0 and this
       is different from 0 on for example INTEL processors (ie 0 != -0 on INTEL !) PN */
    else if((is_chsign(lp, 0) == is_chsign(lp, i)) && lp->duals[i])
      lp->duals[i] = my_flipsign(lp->duals[i]);
  }
  if(is_maxim(lp)) {
    n = lp->sum;
    for(i = lp->rows + 1; i <= n; i++)
      lp->duals[i] = my_flipsign(lp->duals[i]);
  }

  /* If we presolved, then reconstruct the duals */
  n = lp->presolve_undo->orig_sum;
  if(((lp->do_presolve & PRESOLVE_LASTMASKMODE) != PRESOLVE_NONE) &&
      allocREAL(lp, &(lp->full_duals), n + 1, TRUE)) {
    int ix, ii = lp->presolve_undo->orig_rows;

    n = lp->sum;
    for(ix = 1; ix <= n; ix++) {
      i = lp->presolve_undo->var_to_orig[ix];
      if(ix > lp->rows)
        i += ii;
#ifdef Paranoia
      /* Check for index out of range due to presolve */
      if(i > lp->presolve_undo->orig_sum)
        report(lp, SEVERE, "construct_duals: Invalid presolve variable mapping found\n");
#endif
      lp->full_duals[i] = lp->duals[ix];
    }
    presolve_rebuildUndo(lp, FALSE);
  }

  /* Calculate the dual OF and do scaling adjustments to the duals */
  if(lp->scaling_used)
    scale0 = lp->scalars[0];
  else
    scale0 = 1;
  dualOF = my_chsign(is_maxim(lp), lp->orig_rhs[0]) / scale0;
  for(i = 1; i <= lp->sum; i++) {
    value = scaled_value(lp, lp->duals[i] / scale0, i);
    my_roundzero(value, lp->epsprimal);
    lp->duals[i] = value;
    if(i <= lp->rows)
      dualOF += value * lp->solution[i];
  }

#if 0
  /* See if we can make use of the dual OF;
     note that we do not currently adjust properly for presolve */
  if(lp->rows == lp->presolve_undo->orig_rows)
  if(MIP_count(lp) > 0) {
    if(is_maxim(lp)) {
      SETMIN(lp->bb_limitOF, dualOF);
    }
    else {
      SETMAX(lp->bb_limitOF, dualOF);
    }
  }
  else if(fabs(my_reldiff(dualOF, lp->solution[0])) > lp->epssolution)
    report(lp, IMPORTANT, "calculate_duals: Check for possible suboptimal solution!\n");
#endif

  return(TRUE);
} /* construct_duals */

/* Calculate sensitivity duals */
STATIC MYBOOL construct_sensitivity_duals(lprec *lp)
{
  int  k,varnr, ok = TRUE;
  int  *workINT = NULL;
  REAL *pcol,a,infinite,epsvalue,from,till,objfromvalue;

  /* one column of the matrix */
  FREE(lp->objfromvalue);
  FREE(lp->dualsfrom);
  FREE(lp->dualstill);
  if(!allocREAL(lp, &pcol, lp->rows + 1, TRUE) ||
     !allocREAL(lp, &lp->objfromvalue, lp->columns + 1, AUTOMATIC) ||
     !allocREAL(lp, &lp->dualsfrom, lp->sum + 1, AUTOMATIC) ||
     !allocREAL(lp, &lp->dualstill, lp->sum + 1, AUTOMATIC)) {
    FREE(pcol);
    FREE(lp->objfromvalue);
    FREE(lp->dualsfrom);
    FREE(lp->dualstill);
    ok = FALSE;
  }
  else {
    infinite=lp->infinite;
    epsvalue=lp->epsmachine;
    for(varnr=1; varnr<=lp->sum; varnr++) {
      from=infinite;
      till=infinite;
      objfromvalue=infinite;
      if (!lp->is_basic[varnr]) {
        if (!fsolve(lp, varnr, pcol, workINT, epsvalue, 1.0, FALSE)) {  /* construct one column of the tableau */
          ok = FALSE;
          break;
        }
        /* Search for the rows(s) which first result in further iterations */
        for (k=1; k<=lp->rows; k++) {
          if (fabs(pcol[k])>epsvalue) {
            a = lp->rhs[k]/pcol[k];
            if((varnr > lp->rows) && (fabs(lp->solution[varnr]) <= epsvalue) && (a < objfromvalue) && (a >= lp->lowbo[varnr]))
              objfromvalue = a;
            if ((a<=0.0) && (pcol[k]<0.0) && (-a<from)) from=my_flipsign(a);
            if ((a>=0.0) && (pcol[k]>0.0) && ( a<till)) till= a;
            if (lp->upbo[lp->var_basic[k]] < infinite) {
              a = (REAL) ((lp->rhs[k]-lp->upbo[lp->var_basic[k]])/pcol[k]);
              if((varnr > lp->rows) && (fabs(lp->solution[varnr]) <= epsvalue) && (a < objfromvalue) && (a >= lp->lowbo[varnr]))
                objfromvalue = a;
              if ((a<=0.0) && (pcol[k]>0.0) && (-a<from)) from=my_flipsign(a);
              if ((a>=0.0) && (pcol[k]<0.0) && ( a<till)) till= a;
            }
          }
        }

        if (!lp->is_lower[varnr]) {
          a=from;
          from=till;
          till=a;
        }
        if ((varnr<=lp->rows) && (!is_chsign(lp, varnr))) {
          a=from;
          from=till;
          till=a;
        }
      }

      if (from!=infinite)
        lp->dualsfrom[varnr]=lp->solution[varnr]-unscaled_value(lp, from, varnr);
      else
        lp->dualsfrom[varnr]=-infinite;
      if (till!=infinite)
        lp->dualstill[varnr]=lp->solution[varnr]+unscaled_value(lp, till, varnr);
      else
        lp->dualstill[varnr]=infinite;

      if (varnr > lp->rows) {
        if (objfromvalue != infinite) {
          if ((!sensrejvar) || (lp->upbo[varnr] != 0.0)) {
            if (!lp->is_lower[varnr])
              objfromvalue = lp->upbo[varnr] - objfromvalue;
            if ((lp->upbo[varnr] < infinite) && (objfromvalue > lp->upbo[varnr]))
              objfromvalue = lp->upbo[varnr];
          }
          objfromvalue += lp->lowbo[varnr];
          objfromvalue = unscaled_value(lp, objfromvalue, varnr);
        }
        else
          objfromvalue = -infinite;
        lp->objfromvalue[varnr - lp->rows] = objfromvalue;
      }

    }
    FREE(pcol);
  }
  return((MYBOOL) ok);
} /* construct_sensitivity_duals */

/* Calculate sensitivity objective function */
STATIC MYBOOL construct_sensitivity_obj(lprec *lp)
{
  int  i, l, varnr, row_nr, ok = TRUE;
  REAL *OrigObj = NULL, *drow = NULL, *prow = NULL,
       sign, a, min1, min2, infinite, epsvalue, from, till;

  /* objective function */
  FREE(lp->objfrom);
  FREE(lp->objtill);
  if(!allocREAL(lp, &drow, lp->sum + 1, TRUE) ||
     !allocREAL(lp, &OrigObj, lp->columns + 1, FALSE) ||
     !allocREAL(lp, &prow, lp->sum + 1, TRUE) ||
     !allocREAL(lp, &lp->objfrom, lp->columns + 1, AUTOMATIC) ||
     !allocREAL(lp, &lp->objtill, lp->columns + 1, AUTOMATIC)) {
Abandon:
    FREE(drow);
    FREE(OrigObj);
    FREE(prow);
    FREE(lp->objfrom);
    FREE(lp->objtill);
    ok = FALSE;
  }
  else {
    int *coltarget;

    infinite=lp->infinite;
    epsvalue=lp->epsmachine;

    coltarget = (int *) mempool_obtainVector(lp->workarrays, lp->columns+1, sizeof(*coltarget));
    if(!get_colIndexA(lp, SCAN_USERVARS+USE_NONBASICVARS, coltarget, FALSE)) {
      mempool_releaseVector(lp->workarrays, (char *) coltarget, FALSE);
      goto Abandon;
    }
    bsolve(lp, 0, drow, NULL, epsvalue*DOUBLEROUND, 1.0);
    prod_xA(lp, coltarget, drow, NULL, epsvalue, 1.0,
                           drow, NULL, MAT_ROUNDDEFAULT | MAT_ROUNDRC);

    /* original (unscaled) objective function */
    get_row(lp, 0, OrigObj);
    for(i = 1; i <= lp->columns; i++) {
      from=-infinite;
      till= infinite;
      varnr = lp->rows + i;
      if(!lp->is_basic[varnr]) {
      /* only the coeff of the objective function of column i changes. */
        a = unscaled_mat(lp, drow[varnr], 0, i);
        if(is_maxim(lp))
          a = -a;
        if ((!sensrejvar) && (lp->upbo[varnr] == 0.0))
          /* ignore, because this case doesn't results in further iterations */ ;
        else if(((lp->is_lower[varnr] != 0) == (is_maxim(lp) == FALSE)) && (a > -epsvalue))
          from = OrigObj[i] - a; /* less than this value gives further iterations */
        else
          till = OrigObj[i] - a; /* bigger than this value gives further iterations */
      }
      else {
      /* all the coeff of the objective function change. Search the minimal change needed for further iterations */
        for(row_nr=1;
            (row_nr<=lp->rows) && (lp->var_basic[row_nr]!=varnr); row_nr++)
          /* Search on which row the variable exists in the basis */ ;
        if(row_nr<=lp->rows) {       /* safety test; should always be found ... */
          /* Construct one row of the tableau */
          bsolve(lp, row_nr, prow, NULL, epsvalue*DOUBLEROUND, 1.0);
          prod_xA(lp, coltarget, prow, NULL, epsvalue, 1.0,
                                 prow, NULL, MAT_ROUNDDEFAULT);
          /* sign = my_chsign(is_chsign(lp, row_nr), -1); */
          sign = my_chsign(lp->is_lower[row_nr], -1);
          min1=infinite;
          min2=infinite;
          for(l=1; l<=lp->sum; l++)   /* search for the column(s) which first results in further iterations */
            if ((!lp->is_basic[l]) && (lp->upbo[l]>0.0) &&
                (fabs(prow[l])>epsvalue) && (drow[l]*(lp->is_lower[l] ? -1 : 1)<epsvalue)) {
              a = unscaled_mat(lp, fabs(drow[l] / prow[l]), 0, i);
              if(prow[l]*sign*(lp->is_lower[l] ? 1 : -1) < 0.0) {
                if(a < min1)
                  min1 = a;
              }
              else {
                if(a < min2)
                  min2 = a;
              }
            }
          if ((lp->is_lower[varnr] == 0) == (is_maxim(lp) == FALSE)) {
            a = min1;
            min1 = min2;
            min2 = a;
          }
          if (min1<infinite)
            from = OrigObj[i]-min1;
          if (min2<infinite)
            till = OrigObj[i]+min2;
          a = lp->solution[varnr];
          if (is_maxim(lp)) {
            if (a - lp->lowbo[varnr] < epsvalue)
              from = -infinite; /* if variable is at lower bound then decrementing objective coefficient will not result in extra iterations because it would only extra decrease the value, but since it is at its lower bound ... */
            else if (((!sensrejvar) || (lp->upbo[varnr] != 0.0)) && (lp->lowbo[varnr] + lp->upbo[varnr] - a < epsvalue))
              till = infinite;  /* if variable is at upper bound then incrementing objective coefficient will not result in extra iterations because it would only extra increase the value, but since it is at its upper bound ... */
          }
          else {
            if (a - lp->lowbo[varnr] < epsvalue)
              till = infinite;  /* if variable is at lower bound then incrementing objective coefficient will not result in extra iterations because it would only extra decrease the value, but since it is at its lower bound ... */
            else if (((!sensrejvar) || (lp->upbo[varnr] != 0.0)) && (lp->lowbo[varnr] + lp->upbo[varnr] - a < epsvalue))
              from = -infinite; /* if variable is at upper bound then decrementing objective coefficient will not result in extra iterations because it would only extra increase the value, but since it is at its upper bound ... */
          }
        }
      }
      lp->objfrom[i]=from;
      lp->objtill[i]=till;
    }
    mempool_releaseVector(lp->workarrays, (char *) coltarget, FALSE);
  }
  FREE(prow);
  FREE(OrigObj);
  FREE(drow);

  return((MYBOOL) ok);
} /* construct_sensitivity_obj */

STATIC MYBOOL refactRecent(lprec *lp)
{
  int pivcount = lp->bfp_pivotcount(lp);
  if(pivcount == 0)
    return( AUTOMATIC );
  else if (pivcount < 2*DEF_MAXPIVOTRETRY)
    return( TRUE );
  else
    return( FALSE );
}

STATIC MYBOOL check_if_less(lprec *lp, REAL x, REAL y, int variable)
{
  if(y < x-scaled_value(lp, lp->epsint, variable)) {
    if(lp->bb_trace)
      report(lp, NORMAL, "check_if_less: Invalid new bound %g should be < %g for %s\n",
                         x, y, get_col_name(lp, variable));
    return(FALSE);
  }
  else
    return(TRUE);
}

/* Various basis utility routines */

STATIC int findNonBasicSlack(lprec *lp, MYBOOL *is_basic)
{
  int i;

  for(i = lp->rows; i > 0; i--)
    if(!is_basic[i])
      break;
  return( i );
}

STATIC int findBasisPos(lprec *lp, int notint, int *var_basic)
{
  int i;

  if(var_basic == NULL)
    var_basic = lp->var_basic;
  for(i = lp->rows; i > 0; i--)
    if(var_basic[i] == notint)
      break;
  return( i );
}

STATIC void replaceBasisVar(lprec *lp, int rownr, int var, int *var_basic, MYBOOL *is_basic)
{
  int out;

  out = var_basic[rownr];
  var_basic[rownr] = var;
  is_basic[out] = FALSE;
  is_basic[var] = TRUE;
}

STATIC void free_duals(lprec *lp)
{
  FREE(lp->duals);
  FREE(lp->full_duals);
  FREE(lp->dualsfrom);
  FREE(lp->dualstill);
  FREE(lp->objfromvalue);
  FREE(lp->objfrom);
  FREE(lp->objtill);
}

/* Transform RHS by adjusting for the bound state of variables;
   optionally rebase upper bound, and account for this in later calls */
STATIC void initialize_solution(lprec *lp, MYBOOL shiftbounds)
{
  int     i, k1, k2, *matRownr, colnr;
  LREAL   theta;
  REAL    value, *matValue, loB, upB;
  MATrec  *mat = lp->matA;

  /* Set bounding status indicators */
  if(lp->bb_bounds != NULL) {
    if(shiftbounds == INITSOL_SHIFTZERO) {
      if(lp->bb_bounds->UBzerobased)
        report(lp, SEVERE, "initialize_solution: The upper bounds are already zero-based at refactorization %d\n",
                           lp->bfp_refactcount(lp, BFP_STAT_REFACT_TOTAL));
      lp->bb_bounds->UBzerobased = TRUE;
    }
    else if(!lp->bb_bounds->UBzerobased)
        report(lp, SEVERE, "initialize_solution: The upper bounds are not zero-based at refactorization %d\n",
                           lp->bfp_refactcount(lp, BFP_STAT_REFACT_TOTAL));
  }

  /* Initialize the working RHS/basic variable solution vector */
  i = is_action(lp->anti_degen, ANTIDEGEN_RHSPERTURB) && (lp->monitor != NULL) && lp->monitor->active;
  if(sizeof(*lp->rhs) == sizeof(*lp->orig_rhs) && !i) {
    MEMCOPY(lp->rhs, lp->orig_rhs, lp->rows+1);
  }
  else if(i) {
    lp->rhs[0] = lp->orig_rhs[0];
    for(i = 1; i <= lp->rows; i++) {
      if(is_constr_type(lp, i, EQ))
        theta = rand_uniform(lp, lp->epsvalue);
      else {
        theta = rand_uniform(lp, lp->epsperturb);
/*        if(lp->orig_upbo[i] < lp->infinite)
          lp->orig_upbo[i] += theta; */
      }
      lp->rhs[i] = lp->orig_rhs[i] + theta;
    }
  }
  else
    for(i = 0; i <= lp->rows; i++)
      lp->rhs[i] = lp->orig_rhs[i];

/* Adjust active RHS for variables at their active upper/lower bounds */
  for(i = 1; i <= lp->sum; i++) {

    upB = lp->upbo[i];
    loB = lp->lowbo[i];

    /* Shift to "ranged" upper bound, tantamount to defining zero-based variables */
    if(shiftbounds == INITSOL_SHIFTZERO) {
      if((loB > -lp->infinite) && (upB < lp->infinite))
        lp->upbo[i] -= loB;
      if(lp->upbo[i] < 0)
        report(lp, SEVERE, "initialize_solution: Invalid rebounding; variable %d at refact %d, iter %.0f\n",
                           i, lp->bfp_refactcount(lp, BFP_STAT_REFACT_TOTAL), (double) get_total_iter(lp));
    }

    /* Use "ranged" upper bounds */
    else if(shiftbounds == INITSOL_USEZERO) {
      if((loB > -lp->infinite) && (upB < lp->infinite))
        upB += loB;
    }

    /* Shift upper bound back to original value */
    else if(shiftbounds == INITSOL_ORIGINAL) {
      if((loB > -lp->infinite) && (upB < lp->infinite)) {
        lp->upbo[i] += loB;
        upB += loB;
      }
      continue;
    }
    else
      report(lp, SEVERE, "initialize_solution: Invalid option value '%d'\n",
                         shiftbounds);

    /* Set the applicable adjustment */
    if(lp->is_lower[i])
      theta = loB;
    else
      theta = upB;


    /* Check if we need to pass through the matrix;
       remember that basis variables are always lower-bounded */
    if(theta == 0)
      continue;

    /* Do user and artificial variables */
    if(i > lp->rows) {

      /* Get starting and ending indeces in the NZ vector */
      colnr = i - lp->rows;
      k1 = mat->col_end[colnr - 1];
      k2 = mat->col_end[colnr];
      matRownr = &COL_MAT_ROWNR(k1);
      matValue = &COL_MAT_VALUE(k1);

      /* Get the objective as row 0, optionally adjusting the objective for phase 1 */
      value = get_OF_active(lp, i, theta);
      lp->rhs[0] -= value;

      /* Do the normal case */
      for(; k1 < k2;
          k1++, matRownr += matRowColStep, matValue += matValueStep) {
        lp->rhs[*matRownr] -= theta * (*matValue);
      }
    }

    /* Do slack variables (constraint "bounds")*/
    else {
      lp->rhs[i] -= theta;
    }

  }

  /* Do final pass to get the maximum value */
  i = idamax(lp->rows /* +1 */, lp->rhs, 1);
  lp->rhsmax = fabs(lp->rhs[i]);

  if(shiftbounds == INITSOL_SHIFTZERO)
    clear_action(&lp->spx_action, ACTION_REBASE);

}

/* This routine recomputes the basic variables using the full inverse */
STATIC void recompute_solution(lprec *lp, MYBOOL shiftbounds)
{
  /* Compute RHS = b - A(n)*x(n) */
  initialize_solution(lp, shiftbounds);

  /* Compute x(b) = Inv(B)*RHS (Ref. lp_solve inverse logic and Chvatal p. 121) */
  lp->bfp_ftran_normal(lp, lp->rhs, NULL);
  if(!lp->obj_in_basis) {
    int i, ib, n = lp->rows;
    for(i = 1; i <= n; i++) {
      ib = lp->var_basic[i];
      if(ib > n)
        lp->rhs[0] -= get_OF_active(lp, ib, lp->rhs[i]);
    }
  }

 /* Round the values (should not be greater than the factor used in bfp_pivotRHS) */
  roundVector(lp->rhs, lp->rows, lp->epsvalue);

  clear_action(&lp->spx_action, ACTION_RECOMPUTE);
}

/* This routine compares an existing basic solution to a recomputed one;
   Note that the routine must provide for the possibility that the order of the
   basis variables can be changed by the inversion engine. */
STATIC int verify_solution(lprec *lp, MYBOOL reinvert, char *info)
{
  int  i, ii, n, *oldmap, *newmap, *refmap = NULL;
  REAL *oldrhs, err, errmax;

  allocINT(lp, &oldmap, lp->rows+1, FALSE);
  allocINT(lp, &newmap, lp->rows+1, FALSE);
  allocREAL(lp, &oldrhs, lp->rows+1, FALSE);

  /* Get sorted mapping of the old basis */
  for(i = 0; i <= lp->rows; i++)
    oldmap[i] = i;
  if(reinvert) {
    allocINT(lp, &refmap, lp->rows+1, FALSE);
    MEMCOPY(refmap, lp->var_basic, lp->rows+1);
    sortByINT(oldmap, refmap, lp->rows, 1, TRUE);
  }

  /* Save old and calculate the new RHS vector */
  MEMCOPY(oldrhs, lp->rhs, lp->rows+1);
  if(reinvert)
    invert(lp, INITSOL_USEZERO, FALSE);
  else
    recompute_solution(lp, INITSOL_USEZERO);

  /* Get sorted mapping of the new basis */
  for(i = 0; i <= lp->rows; i++)
    newmap[i] = i;
  if(reinvert) {
    MEMCOPY(refmap, lp->var_basic, lp->rows+1);
    sortByINT(newmap, refmap, lp->rows, 1, TRUE);
  }

  /* Identify any gap */
  errmax = 0;
  ii = -1;
  n = 0;
  for(i = lp->rows; i > 0; i--) {
    err = fabs(my_reldiff(oldrhs[oldmap[i]], lp->rhs[newmap[i]]));
    if(err > lp->epsprimal) {
      n++;
      if(err > errmax) {
        ii = i;
        errmax = err;
      }
    }
  }
  err = fabs(my_reldiff(oldrhs[i], lp->rhs[i]));
  if(err < lp->epspivot) {
    i--;
    err = 0;
  }
  else {
    n++;
    if(ii < 0) {
      ii = 0;
      errmax = err;
    }
  }
  if(n > 0) {
    report(lp, IMPORTANT, "verify_solution: Iter %.0f %s - %d errors; OF %g, Max @row %d %g\n",
                           (double) get_total_iter(lp), my_if(info == NULL, "", info), n, err, newmap[ii], errmax);
  }
  /* Copy old results back (not possible for inversion) */
  if(!reinvert)
    MEMCOPY(lp->rhs, oldrhs, lp->rows+1);

  FREE(oldmap);
  FREE(newmap);
  FREE(oldrhs);
  if(reinvert)
    FREE(refmap);

  return( ii );

}

/* Preprocessing and postprocessing functions */
STATIC int identify_GUB(lprec *lp, MYBOOL mark)
{
  int    i, j, jb, je, k, knint, srh;
  REAL   rh, mv, tv, bv;
  MATrec *mat = lp->matA;

  if((lp->equalities == 0) || !mat_validate(mat))
    return( 0 );

  k = 0;
  for(i = 1; i <= lp->rows; i++) {

    /* Check if it is an equality constraint */
    if(!is_constr_type(lp, i, EQ))
      continue;

    rh = get_rh(lp, i);
    srh = my_sign(rh);
    knint = 0;
    je = mat->row_end[i];
    for(jb = mat->row_end[i-1]; jb < je; jb++) {
      j = ROW_MAT_COLNR(jb);

      /* Check for validity of the equation elements */
      if(!is_int(lp, j))
        knint++;
      if(knint > 1)
        break;

      mv = get_mat_byindex(lp, jb, TRUE, FALSE);
      if(fabs(my_reldiff(mv, rh)) > lp->epsprimal)
        break;

      tv = mv*get_upbo(lp, j);
      bv = get_lowbo(lp, j);
#if 0 /* Requires 1 as upper bound */
      if((fabs(my_reldiff(tv, rh)) > lp->epsprimal) || (bv != 0))
#else /* Can handle any upper bound >= 1 */
      if((srh*(tv-rh) < -lp->epsprimal) || (bv != 0))
#endif
        break;
    }

    /* Update GUB count and optionally mark the GUB */
    if(jb == je) {
      k++;
      if(mark == TRUE)
        lp->row_type[i] |= ROWTYPE_GUB;
      else if(mark == AUTOMATIC)
        break;
    }

  }
  return( k );
}

STATIC int prepare_GUB(lprec *lp)
{
  int    i, j, jb, je, k, *members = NULL;
  REAL   rh;
  char   GUBname[16];
  MATrec *mat = lp->matA;

  if((lp->equalities == 0) ||
     !allocINT(lp, &members, lp->columns+1, TRUE) ||
     !mat_validate(mat))
    return( 0 );

  for(i = 1; i <= lp->rows; i++) {

    /* Check if it has been marked as a GUB */
    if(!(lp->row_type[i] & ROWTYPE_GUB))
      continue;

    /* Pick up the GUB column indeces */
    k = 0;
    je = mat->row_end[i];
    for(jb = mat->row_end[i-1], k = 0; jb < je; jb++) {
      members[k] = ROW_MAT_COLNR(jb);
      k++;
    }

    /* Add the GUB */
    j = GUB_count(lp) + 1;
    sprintf(GUBname, "GUB_%d", i);
    add_GUB(lp, GUBname, j, k, members);

    /* Unmark the GUBs */
    clear_action(&(lp->row_type[i]), ROWTYPE_GUB);

    /* Standardize coefficients to 1 if necessary */
    rh = get_rh(lp, i);
    if(fabs(my_reldiff(rh, 1)) > lp->epsprimal) {
      set_rh(lp, i, 1);
      for(jb = mat->row_end[i-1]; jb < je; jb++) {
        j = ROW_MAT_COLNR(jb);
        set_mat(lp, i,j, 1);
      }
    }

  }
  FREE(members);
  return(GUB_count(lp));
}

/* Pre- and post processing functions, i.a. splitting free variables */
STATIC MYBOOL pre_MIPOBJ(lprec *lp)
{
#ifdef MIPboundWithOF
  if(MIP_count(lp) > 0) {
    int i = 1;
    while((i <= lp->rows) && !mat_equalRows(lp->matA, 0, i) && !is_constr_type(lp, i, EQ))
      i++;
    if(i <= lp->rows)
      lp->constraintOF = i;
  }
#endif
  lp->bb_deltaOF = MIP_stepOF(lp);
  return( TRUE );
}
STATIC MYBOOL post_MIPOBJ(lprec *lp)
{
#ifdef MIPboundWithOF
/*
  if(lp->constraintOF) {
    del_constraint(lp, lp->rows);
    if(is_BasisReady(lp) && !verify_basis(lp))
      return( FALSE );
  }
*/
#endif
  return( TRUE );
}

int preprocess(lprec *lp)
{
  int    i, j, k, ok = TRUE, *new_index = NULL;
  REAL   hold, *new_column = NULL;
  MYBOOL scaled, primal1, primal2;

 /* do not process if already preprocessed */
  if(lp->wasPreprocessed)
    return( ok );

  /* Write model statistics and optionally initialize partial pricing structures */
  if(lp->lag_status != RUNNING) {
    MYBOOL doPP;

    /* Extract the user-specified simplex strategy choices */
    primal1 = (MYBOOL) (lp->simplex_strategy & SIMPLEX_Phase1_PRIMAL);
    primal2 = (MYBOOL) (lp->simplex_strategy & SIMPLEX_Phase2_PRIMAL);

    /* Initialize partial pricing structures */
    doPP = is_piv_mode(lp, PRICE_PARTIAL | PRICE_AUTOPARTIAL);
/*    doPP &= (MYBOOL) (lp->columns / 2 > lp->rows); */
    if(doPP) {
      i = partial_findBlocks(lp, FALSE, FALSE);
      if(i < 4)
        i = (int) (5 * log((REAL) lp->columns / lp->rows));
      report(lp, NORMAL, "The model is %s to have %d column blocks/stages.\n",
                         (i > 1 ? "estimated" : "set"), i);
      set_partialprice(lp, i, NULL, FALSE);
    }
/*    doPP &= (MYBOOL) (lp->rows / 4 > lp->columns); */
    if(doPP) {
      i = partial_findBlocks(lp, FALSE, TRUE);
      if(i < 4)
        i = (int) (5 * log((REAL) lp->rows / lp->columns));
      report(lp, NORMAL, "The model is %s to have %d row blocks/stages.\n",
                         (i > 1 ? "estimated" : "set"), i);
      set_partialprice(lp, i, NULL, TRUE);
    }

    /* Check for presence of valid pricing blocks if partial pricing
      is defined, but not autopartial is not set */
    if(!doPP && is_piv_mode(lp, PRICE_PARTIAL)) {
      if((lp->rowblocks == NULL) || (lp->colblocks == NULL)) {
        report(lp, IMPORTANT, "Ignoring partial pricing, since block structures are not defined.\n");
        clear_action(&lp->piv_strategy, PRICE_PARTIAL);
      }
    }

    /* Initialize multiple pricing block divisor */
#if 0
    if(primal1 || primal2)
      lp->piv_strategy |= PRICE_MULTIPLE | PRICE_AUTOMULTIPLE;
#endif
    if(is_piv_mode(lp, PRICE_MULTIPLE) && (primal1 || primal2)) {
      doPP = is_piv_mode(lp, PRICE_AUTOMULTIPLE);
      if(doPP) {
        i = (int) (2.5*log((REAL) lp->sum));
        SETMAX( i, 1);
        set_multiprice(lp, i);
      }
      if(lp->multiblockdiv > 1)
      report(lp, NORMAL, "Using %d-candidate primal simplex multiple pricing block.\n",
                          lp->columns / lp->multiblockdiv);
    }
    else
      set_multiprice(lp, 1);

    report(lp, NORMAL, "Using %s simplex for phase 1 and %s simplex for phase 2.\n",
                       my_if(primal1, "PRIMAL", "DUAL"), my_if(primal2, "PRIMAL", "DUAL"));
    i = get_piv_rule(lp);
    if((i == PRICER_STEEPESTEDGE) && is_piv_mode(lp, PRICE_PRIMALFALLBACK))
      report(lp, NORMAL, "The pricing strategy is set to '%s' for the dual and '%s' for the primal.\n",
                       get_str_piv_rule(i), get_str_piv_rule(i-1));
    else
      report(lp, NORMAL, "The primal and dual simplex pricing strategy set to '%s'.\n",
                       get_str_piv_rule(i));

    report(lp, NORMAL, " \n");
  }

  /* Compute a minimum step improvement step requirement */
  pre_MIPOBJ(lp);

 /* First create extra columns for FR variables or flip MI variables */
  for (j = 1; j <= lp->columns; j++) {

#ifdef Paranoia
    if((lp->rows != lp->matA->rows) || (lp->columns != lp->matA->columns))
      report(lp, SEVERE, "preprocess: Inconsistent variable counts found\n");
#endif

   /* First handle sign-flipping of variables:
       1) ... with a finite upper bound and a negative Inf-bound (since basis variables are lower-bounded)
       2) ... with bound assymetry within negrange limits (for stability reasons) */
    i = lp->rows + j;
    hold = lp->orig_upbo[i];
/*
    if((hold <= 0) || (!is_infinite(lp, lp->negrange) &&
                       (hold < -lp->negrange) &&
                       (lp->orig_lowbo[i] <= lp->negrange)) ) {
*/
#define fullybounded FALSE
    if( ((hold < lp->infinite) && my_infinite(lp, lp->orig_lowbo[i])) ||
        (!fullybounded && !my_infinite(lp, lp->negrange) &&
         (hold < -lp->negrange) && (lp->orig_lowbo[i] <= lp->negrange)) ) {
      /* Delete split sibling variable if one existed from before */
      if((lp->var_is_free != NULL) && (lp->var_is_free[j] > 0))
        del_column(lp, lp->var_is_free[j]);
      /* Negate the column / flip to the positive range */
      mat_multcol(lp->matA, j, -1, TRUE);
      if(lp->var_is_free == NULL) {
        if(!allocINT(lp, &lp->var_is_free, MAX(lp->columns, lp->columns_alloc) + 1, TRUE))
          return(FALSE);
      }
      lp->var_is_free[j] = -j; /* Indicator UB and LB are switched, with no helper variable added */
      lp->orig_upbo[i] = my_flipsign(lp->orig_lowbo[i]);
      lp->orig_lowbo[i] = my_flipsign(hold);
      /* Check for presence of negative ranged SC variable */
      if(lp->sc_lobound[j] > 0) {
        lp->sc_lobound[j] = lp->orig_lowbo[i];
        lp->orig_lowbo[i] = 0;
      }
    }
   /* Then deal with -+, full-range/FREE variables by creating a helper variable */
    else if((lp->orig_lowbo[i] <= lp->negrange) && (hold >= -lp->negrange)) {
      if(lp->var_is_free == NULL) {
        if(!allocINT(lp, &lp->var_is_free, MAX(lp->columns,lp->columns_alloc) + 1, TRUE))
          return(FALSE);
      }
      if(lp->var_is_free[j] <= 0) { /* If this variable wasn't split yet ... */
        if(SOS_is_member(lp->SOS, 0, i - lp->rows)) {   /* Added */
          report(lp, IMPORTANT, "preprocess: Converted negative bound for SOS variable %d to zero",
                                i - lp->rows);
          lp->orig_lowbo[i] = 0;
          continue;
        }
        if(new_column == NULL) {
          if(!allocREAL(lp, &new_column, lp->rows + 1, FALSE) ||
             !allocINT(lp, &new_index, lp->rows + 1, FALSE)) {
            ok = FALSE;
            break;
          }
        }
       /* Avoid precision loss by turning off unscaling and rescaling */
       /* in get_column and add_column operations; also make sure that */
       /* full scaling information is preserved */
        scaled = lp->scaling_used;
        lp->scaling_used = FALSE;
        k = get_columnex(lp, j, new_column, new_index);
        if(!add_columnex(lp, k, new_column, new_index)) {
          ok = FALSE;
          break;
        }
        mat_multcol(lp->matA, lp->columns, -1, TRUE);
        if(scaled)
          lp->scalars[lp->rows+lp->columns] = lp->scalars[i];
        lp->scaling_used = (MYBOOL) scaled;
        /* Only create name if we are not clearing a pre-used item, since this
           variable could have been deleted by presolve but the name is required
           for solution reconstruction. */
        if(lp->names_used && (lp->col_name[j] == NULL)) {
          char fieldn[50];

          sprintf(fieldn, "__AntiBodyOf(%d)__", j);
          if(!set_col_name(lp, lp->columns, fieldn)) {
/*          if (!set_col_name(lp, lp->columns, get_col_name(lp, j))) { */
            ok = FALSE;
            break;
          }
        }
        /* Set (positive) index to the original column's split / helper and back */
        lp->var_is_free[j] = lp->columns;
      }
      lp->orig_upbo[lp->rows + lp->var_is_free[j]] = my_flipsign(lp->orig_lowbo[i]);
      lp->orig_lowbo[i] = 0;

      /* Negative index indicates x is split var and -var_is_free[x] is index of orig var */
      lp->var_is_free[lp->var_is_free[j]] = -j;
      lp->var_type[lp->var_is_free[j]] = lp->var_type[j];
    }
   /* Check for positive ranged SC variables */
    else if(lp->sc_lobound[j] > 0) {
      lp->sc_lobound[j] = lp->orig_lowbo[i];
      lp->orig_lowbo[i] = 0;
    }

   /* Tally integer variables in SOS'es */
    if(SOS_is_member(lp->SOS, 0, j) && is_int(lp, j))
      lp->sos_ints++;
  }

  FREE(new_column);
  FREE(new_index);

  /* Fill lists of GUB constraints, if appropriate */
  if((MIP_count(lp) > 0) && is_bb_mode(lp, NODE_GUBMODE) && (identify_GUB(lp, AUTOMATIC) > 0))
    prepare_GUB(lp);

  /* (Re)allocate reduced cost arrays */
  ok = allocREAL(lp, &(lp->drow), lp->sum+1, AUTOMATIC) &&
       allocINT(lp, &(lp->nzdrow), lp->sum+1, AUTOMATIC);
  if(ok)
    lp->nzdrow[0] = 0;

  /* Minimize memory usage */
  memopt_lp(lp, 0, 0, 0);

  lp->wasPreprocessed = TRUE;

  return(ok);
}

void postprocess(lprec *lp)
{
  int i,ii,j;
  REAL hold;

 /* Check if the problem actually was preprocessed */
  if(!lp->wasPreprocessed)
    return;

 /* Must compute duals here in case we have free variables; note that in
    this case sensitivity analysis is not possible unless done here */
  if((lp->bb_totalnodes == 0) && (lp->var_is_free == NULL)) {
    if(is_presolve(lp, PRESOLVE_DUALS))
      construct_duals(lp);
    if(is_presolve(lp, PRESOLVE_SENSDUALS))
      if(!construct_sensitivity_duals(lp) || !construct_sensitivity_obj(lp))
        report(lp, IMPORTANT, "postprocess: Unable to allocate working memory for duals.\n");
  }

 /* Loop over all columns */
  for (j = 1; j <= lp->columns; j++) {
    i = lp->rows + j;
   /* Reconstruct strictly negative values */
    if((lp->var_is_free != NULL) && (lp->var_is_free[j] < 0)) {
      /* Check if we have the simple case where the UP and LB are negated and switched */
      if(-lp->var_is_free[j] == j) {
        mat_multcol(lp->matA, j, -1, TRUE);
        hold = lp->orig_upbo[i];
        lp->orig_upbo[i] = my_flipsign(lp->orig_lowbo[i]);
        lp->orig_lowbo[i] = my_flipsign(hold);
        lp->best_solution[i] = my_flipsign(lp->best_solution[i]);
        transfer_solution_var(lp, j);

        /* hold = lp->objfrom[j];
        lp->objfrom[j] = my_flipsign(lp->objtill[j]);
        lp->objtill[j] = my_flipsign(hold); */ /* under investigation <peno> */

        /* lp->duals[i] = my_flipsign(lp->duals[i]);
        hold = lp->dualsfrom[i];
        lp->dualsfrom[i] = my_flipsign(lp->dualstill[i]);
        lp->dualstill[i] = my_flipsign(hold); */ /* under investigation <peno> */
       /* Bound switch undone, so clear the status */
        lp->var_is_free[j] = 0;
       /* Adjust negative ranged SC */
        if(lp->sc_lobound[j] > 0)
          lp->orig_lowbo[lp->rows + j] = -lp->sc_lobound[j];
      }
      /* Ignore the split / helper columns (will be deleted later) */
    }
   /* Condense values of extra columns of quasi-free variables split in two */
    else if((lp->var_is_free != NULL) && (lp->var_is_free[j] > 0)) {
      ii = lp->var_is_free[j]; /* Index of the split helper var */
      /* if(lp->objfrom[j] == -lp->infinite)
        lp->objfrom[j] = -lp->objtill[ii];
      lp->objtill[ii] = lp->infinite;
      if(lp->objtill[j] == lp->infinite)
        lp->objtill[j] = my_flipsign(lp->objfrom[ii]);
      lp->objfrom[ii] = -lp->infinite; */ /* under investigation <peno> */

      ii += lp->rows;
      lp->best_solution[i] -= lp->best_solution[ii]; /* join the solution again */
      transfer_solution_var(lp, j);
      lp->best_solution[ii] = 0;

      /* if(lp->duals[i] == 0)
        lp->duals[i] = my_flipsign(lp->duals[ii]);
      lp->duals[ii] = 0;
      if(lp->dualsfrom[i] == -lp->infinite)
        lp->dualsfrom[i] = my_flipsign(lp->dualstill[ii]);
      lp->dualstill[ii] = lp->infinite;
      if(lp->dualstill[i] == lp->infinite)
        lp->dualstill[i] = my_flipsign(lp->dualsfrom[ii]);
      lp->dualsfrom[ii] = -lp->infinite; */ /* under investigation <peno> */

      /* Reset to original bound */
      lp->orig_lowbo[i] = my_flipsign(lp->orig_upbo[ii]);
    }
   /* Adjust for semi-continuous variables */
    else if(lp->sc_lobound[j] > 0) {
      lp->orig_lowbo[i] = lp->sc_lobound[j];
    }
  }

  /* Remove any split column helper variables */
  del_splitvars(lp);
  post_MIPOBJ(lp);

  /* Do extended reporting, if specified */
  if(lp->verbose > NORMAL) {
    REPORT_extended(lp);

  }

  lp->wasPreprocessed = FALSE;
}

