/* $Id: CoinWarmStartBasis.cpp 2083 2019-01-06 19:38:09Z unxusr $ */
// Copyright (C) 2000, International Business Machines
// Corporation and others.  All Rights Reserved.
// This code is licensed under the terms of the Eclipse Public License (EPL).

#if defined(_MSC_VER)
// Turn off compiler warning about long names
#pragma warning(disable : 4786)
#endif

#include "CoinUtilsConfig.h"
#include <cassert>

#include "CoinWarmStartBasis.hpp"
#include "CoinHelperFunctions.hpp"
#include <cmath>
#include <iostream>

//#############################################################################

void CoinWarmStartBasis::setSize(int ns, int na)
{
  // Round all so arrays multiple of 4
  int nintS = (ns + 15) >> 4;
  int nintA = (na + 15) >> 4;
  int size = nintS + nintA;
  if (size) {
    if (size > maxSize_) {
      delete[] structuralStatus_;
      maxSize_ = size + 10;
      structuralStatus_ = new char[4 * maxSize_];
    }
    memset(structuralStatus_, 0, (4 * nintS) * sizeof(char));
    artificialStatus_ = structuralStatus_ + 4 * nintS;
    memset(artificialStatus_, 0, (4 * nintA) * sizeof(char));
  } else {
    artificialStatus_ = NULL;
  }
  numArtificial_ = na;
  numStructural_ = ns;
}

void CoinWarmStartBasis::assignBasisStatus(int ns, int na, char *&sStat,
  char *&aStat)
{
  // Round all so arrays multiple of 4
  int nintS = (ns + 15) >> 4;
  int nintA = (na + 15) >> 4;
  int size = nintS + nintA;
  if (size) {
    if (size > maxSize_) {
      delete[] structuralStatus_;
      maxSize_ = size + 10;
      structuralStatus_ = new char[4 * maxSize_];
    }
    CoinMemcpyN(sStat, (4 * nintS), structuralStatus_);
    artificialStatus_ = structuralStatus_ + 4 * nintS;
    CoinMemcpyN(aStat, (4 * nintA), artificialStatus_);
  } else {
    artificialStatus_ = NULL;
  }
  numStructural_ = ns;
  numArtificial_ = na;
  delete[] sStat;
  delete[] aStat;
  sStat = NULL;
  aStat = NULL;
}
CoinWarmStartBasis::CoinWarmStartBasis(int ns, int na,
  const char *sStat, const char *aStat)
  : numStructural_(ns)
  , numArtificial_(na)
  , structuralStatus_(NULL)
  , artificialStatus_(NULL)
{
  // Round all so arrays multiple of 4
  int nintS = ((ns + 15) >> 4);
  int nintA = ((na + 15) >> 4);
  maxSize_ = nintS + nintA;
  if (maxSize_ > 0) {
    structuralStatus_ = new char[4 * maxSize_];
    if (nintS > 0) {
      structuralStatus_[4 * nintS - 3] = 0;
      structuralStatus_[4 * nintS - 2] = 0;
      structuralStatus_[4 * nintS - 1] = 0;
      CoinMemcpyN(sStat, ((ns + 3) / 4), structuralStatus_);
    }
    artificialStatus_ = structuralStatus_ + 4 * nintS;
    if (nintA > 0) {
      artificialStatus_[4 * nintA - 3] = 0;
      artificialStatus_[4 * nintA - 2] = 0;
      artificialStatus_[4 * nintA - 1] = 0;
      CoinMemcpyN(aStat, ((na + 3) / 4), artificialStatus_);
    }
  }
}

CoinWarmStartBasis::CoinWarmStartBasis(const CoinWarmStartBasis &ws)
  : numStructural_(ws.numStructural_)
  , numArtificial_(ws.numArtificial_)
  , structuralStatus_(NULL)
  , artificialStatus_(NULL)
{
  // Round all so arrays multiple of 4
  int nintS = (numStructural_ + 15) >> 4;
  int nintA = (numArtificial_ + 15) >> 4;
  maxSize_ = nintS + nintA;
  if (maxSize_ > 0) {
    structuralStatus_ = new char[4 * maxSize_];
    CoinMemcpyN(ws.structuralStatus_, (4 * nintS), structuralStatus_);
    artificialStatus_ = structuralStatus_ + 4 * nintS;
    CoinMemcpyN(ws.artificialStatus_, (4 * nintA), artificialStatus_);
  }
}

CoinWarmStartBasis &
CoinWarmStartBasis::operator=(const CoinWarmStartBasis &rhs)
{
  if (this != &rhs) {
    numStructural_ = rhs.numStructural_;
    numArtificial_ = rhs.numArtificial_;
    // Round all so arrays multiple of 4
    int nintS = (numStructural_ + 15) >> 4;
    int nintA = (numArtificial_ + 15) >> 4;
    int size = nintS + nintA;
    if (size > maxSize_) {
      delete[] structuralStatus_;
      maxSize_ = size + 10;
      structuralStatus_ = new char[4 * maxSize_];
    }
    if (size > 0) {
      CoinMemcpyN(rhs.structuralStatus_, (4 * nintS), structuralStatus_);
      artificialStatus_ = structuralStatus_ + 4 * nintS;
      CoinMemcpyN(rhs.artificialStatus_, (4 * nintA), artificialStatus_);
    } else {
      artificialStatus_ = NULL;
    }
  }
  return *this;
}

// Resizes
void CoinWarmStartBasis::resize(int newNumberRows, int newNumberColumns)
{
  int i, nCharNewS, nCharOldS, nCharNewA, nCharOldA;
  if (newNumberRows != numArtificial_ || newNumberColumns != numStructural_) {
    nCharOldS = 4 * ((numStructural_ + 15) >> 4);
    int nIntS = (newNumberColumns + 15) >> 4;
    nCharNewS = 4 * nIntS;
    nCharOldA = 4 * ((numArtificial_ + 15) >> 4);
    int nIntA = (newNumberRows + 15) >> 4;
    nCharNewA = 4 * nIntA;
    int size = nIntS + nIntA;
    // Do slowly if number of columns increases or need new array
    if (newNumberColumns > numStructural_ || size > maxSize_) {
      if (size > maxSize_)
        maxSize_ = size + 10;
      char *array = new char[4 * maxSize_];
      // zap all for clarity and zerofault etc
      memset(array, 0, 4 * maxSize_ * sizeof(char));
      CoinMemcpyN(structuralStatus_, (nCharOldS > nCharNewS) ? nCharNewS : nCharOldS, array);
      CoinMemcpyN(artificialStatus_, (nCharOldA > nCharNewA) ? nCharNewA : nCharOldA,
        array + nCharNewS);
      delete[] structuralStatus_;
      structuralStatus_ = array;
      artificialStatus_ = array + nCharNewS;
      for (i = numStructural_; i < newNumberColumns; i++)
        setStructStatus(i, atLowerBound);
      for (i = numArtificial_; i < newNumberRows; i++)
        setArtifStatus(i, basic);
    } else {
      // can do faster
      if (newNumberColumns != numStructural_) {
        memmove(structuralStatus_ + nCharNewS, artificialStatus_,
          (nCharOldA > nCharNewA) ? nCharNewA : nCharOldA);
        artificialStatus_ = structuralStatus_ + 4 * nIntS;
      }
      for (i = numArtificial_; i < newNumberRows; i++)
        setArtifStatus(i, basic);
    }
    numStructural_ = newNumberColumns;
    numArtificial_ = newNumberRows;
  }
}

/*
  compressRows takes an ascending list of target indices without duplicates
  and removes them, compressing the artificialStatus_ array in place. It will
  fail spectacularly if the indices are not sorted. Use deleteRows if you
  need to preprocess the target indices to satisfy the conditions.
*/
void CoinWarmStartBasis::compressRows(int tgtCnt, const int *tgts)
{
  int i, keep, t, blkStart, blkEnd;
  /*
  Depending on circumstances, constraint indices may be larger than the size
  of the basis. Check for that now. Scan from top, betting that in most cases
  the majority of indices will be valid.
*/
  for (t = tgtCnt - 1; t >= 0 && tgts[t] >= numArtificial_; t--)
    ;
  // temporary trap to make sure that scan from top is correct choice.
  // if ((t+1) < tgtCnt/2)
  // { printf("CWSB: tgtCnt %d, t %d; BAD CASE",tgtCnt,t+1) ; }
  if (t < 0)
    return;
  tgtCnt = t + 1;
  Status stati;

#ifdef COIN_DEBUG
  /*
  If we're debugging, scan to see if we're deleting nonbasic artificials.
  (In other words, are we deleting tight constraints?) Easiest to just do this
  up front as opposed to integrating it with the loops below.
*/
  int nbCnt = 0;
  for (t = 0; t < tgtCnt; t++) {
    i = tgts[t];
    stati = getStatus(artificialStatus_, i);
    if (stati != CoinWarmStartBasis::basic) {
      nbCnt++;
    }
  }
  if (nbCnt > 0) {
    std::cout << nbCnt << " nonbasic artificials deleted." << std::endl;
  }
#endif

  /*
  Preserve all entries before the first target. Skip across consecutive
  target indices to establish the start of the first block to be retained.
*/
  keep = tgts[0];
  for (t = 0; t < tgtCnt - 1 && tgts[t] + 1 == tgts[t + 1]; t++)
    ;
  blkStart = tgts[t] + 1;
  /*
  Outer loop works through the indices to be deleted. Inner loop copies runs
  of indices to keep.
*/
  while (t < tgtCnt - 1) {
    blkEnd = tgts[t + 1] - 1;
    for (i = blkStart; i <= blkEnd; i++) {
      stati = getStatus(artificialStatus_, i);
      setStatus(artificialStatus_, keep++, stati);
    }
    for (t++; t < tgtCnt - 1 && tgts[t] + 1 == tgts[t + 1]; t++)
      ;
    blkStart = tgts[t] + 1;
  }
  /*
  Finish off by copying from last deleted index to end of status array.
*/
  for (i = blkStart; i < numArtificial_; i++) {
    stati = getStatus(artificialStatus_, i);
    setStatus(artificialStatus_, keep++, stati);
  }

  numArtificial_ -= tgtCnt;

  return;
}

/*
  deleteRows takes an unordered list of target indices with duplicates and
  removes them from the basis. The strategy is to preprocesses the list into
  an ascending list without duplicates, suitable for compressRows.
*/
void CoinWarmStartBasis::deleteRows(int rawTgtCnt, const int *rawTgts)
{
  if (rawTgtCnt <= 0)
    return;

  int i;
  int last = -1;
  bool ordered = true;
  for (i = 0; i < rawTgtCnt; i++) {
    int iRow = rawTgts[i];
    if (iRow > last) {
      last = iRow;
    } else {
      ordered = false;
      break;
    }
  }
  if (ordered) {
    compressRows(rawTgtCnt, rawTgts);
  } else {
    int *tgts = new int[rawTgtCnt];
    CoinMemcpyN(rawTgts, rawTgtCnt, tgts);
    int *first = &tgts[0];
    int *last = &tgts[rawTgtCnt];
    int *endUnique;
    std::sort(first, last);
    endUnique = std::unique(first, last);
    int tgtCnt = static_cast< int >(endUnique - first);
    compressRows(tgtCnt, tgts);
    delete[] tgts;
  }
  return;
}

// Deletes columns
void CoinWarmStartBasis::deleteColumns(int number, const int *which)
{
  int i;
  char *deleted = new char[numStructural_];
  int numberDeleted = 0;
  memset(deleted, 0, numStructural_ * sizeof(char));
  for (i = 0; i < number; i++) {
    int j = which[i];
    if (j >= 0 && j < numStructural_ && !deleted[j]) {
      numberDeleted++;
      deleted[j] = 1;
    }
  }
  int nCharNewS = 4 * ((numStructural_ - numberDeleted + 15) >> 4);
  int nCharNewA = 4 * ((numArtificial_ + 15) >> 4);
  char *array = new char[4 * maxSize_];
#ifdef ZEROFAULT
  memset(array, 0, (4 * maxSize_ * sizeof(char)));
#endif
  CoinMemcpyN(artificialStatus_, nCharNewA, array + nCharNewS);
  int put = 0;
#ifdef COIN_DEBUG
  int numberBasic = 0;
#endif
  for (i = 0; i < numStructural_; i++) {
    Status status = getStructStatus(i);
    if (!deleted[i]) {
      setStatus(array, put, status);
      put++;
    }
#ifdef COIN_DEBUG
    else if (status == CoinWarmStartBasis::basic) {
      numberBasic++;
    }
#endif
  }
  delete[] structuralStatus_;
  structuralStatus_ = array;
  artificialStatus_ = structuralStatus_ + nCharNewS;
  delete[] deleted;
  numStructural_ -= numberDeleted;
#ifdef COIN_DEBUG
  if (numberBasic)
    std::cout << numberBasic << " basic structurals deleted" << std::endl;
#endif
}

/*
  Merge the specified entries from the source basis (src) into the target
  basis (this). For each entry in xferCols, xferRows, first is the source index,
  second is the target index, and third is the run length.
  
  This routine was originally created to solve the problem of correctly
  expanding an existing basis but can be used in a general context to merge
  two bases.

  If the xferRows (xferCols) vector is missing, no row (column) information
  will be transferred from src to tgt.
*/

void CoinWarmStartBasis::mergeBasis(const CoinWarmStartBasis *src,
  const XferVec *xferRows,
  const XferVec *xferCols)

{
  assert(src);
  int srcCols = src->getNumStructural();
  int srcRows = src->getNumArtificial();
  /*
  Merge the structural variable status.
*/
  if (srcCols > 0 && xferCols != NULL) {
    XferVec::const_iterator xferSpec = xferCols->begin();
    XferVec::const_iterator xferEnd = xferCols->end();
    for (; xferSpec != xferEnd; xferSpec++) {
      int srcNdx = (*xferSpec).first;
      int tgtNdx = (*xferSpec).second;
      int runLen = (*xferSpec).third;
      assert(srcNdx >= 0 && srcNdx + runLen <= srcCols);
      assert(tgtNdx >= 0 && tgtNdx + runLen <= getNumStructural());
      for (int i = 0; i < runLen; i++) {
        CoinWarmStartBasis::Status stat = src->getStructStatus(srcNdx + i);
        setStructStatus(tgtNdx + i, stat);
      }
    }
  }
  /*
  Merge the row (artificial variable) status.
*/
  if (srcRows > 0 && xferRows != NULL) {
    XferVec::const_iterator xferSpec = xferRows->begin();
    XferVec::const_iterator xferEnd = xferRows->end();
    for (; xferSpec != xferEnd; xferSpec++) {
      int srcNdx = (*xferSpec).first;
      int tgtNdx = (*xferSpec).second;
      int runLen = (*xferSpec).third;
      assert(srcNdx >= 0 && srcNdx + runLen <= srcRows);
      assert(tgtNdx >= 0 && tgtNdx + runLen <= getNumArtificial());
      for (int i = 0; i < runLen; i++) {
        CoinWarmStartBasis::Status stat = src->getArtifStatus(srcNdx + i);
        setArtifStatus(tgtNdx + i, stat);
      }
    }
  }

  return;
}

// Prints in readable format (for debug)
void CoinWarmStartBasis::print() const
{
  int i;
  int numberBasic = 0;
  for (i = 0; i < numStructural_; i++) {
    Status status = getStructStatus(i);
    if (status == CoinWarmStartBasis::basic)
      numberBasic++;
  }
  int numberStructBasic = numberBasic;
  for (i = 0; i < numArtificial_; i++) {
    Status status = getArtifStatus(i);
    if (status == CoinWarmStartBasis::basic)
      numberBasic++;
  }
  std::cout << "Basis " << this << " has " << numArtificial_ << " rows and "
            << numStructural_ << " columns, "
            << numberBasic << " basic, of which " << numberStructBasic
            << " were columns" << std::endl;
  std::cout << "Rows:" << std::endl;
  char type[] = { 'F', 'B', 'U', 'L' };

  for (i = 0; i < numArtificial_; i++)
    std::cout << type[getArtifStatus(i)];
  std::cout << std::endl;
  std::cout << "Columns:" << std::endl;

  for (i = 0; i < numStructural_; i++)
    std::cout << type[getStructStatus(i)];
  std::cout << std::endl;
}
CoinWarmStartBasis::CoinWarmStartBasis()
{

  numStructural_ = 0;
  numArtificial_ = 0;
  maxSize_ = 0;
  structuralStatus_ = NULL;
  artificialStatus_ = NULL;
}
CoinWarmStartBasis::~CoinWarmStartBasis()
{
  delete[] structuralStatus_;
}
// Returns number of basic structurals
int CoinWarmStartBasis::numberBasicStructurals() const
{
  int i;
  int numberBasic = 0;
  for (i = 0; i < numStructural_; i++) {
    Status status = getStructStatus(i);
    if (status == CoinWarmStartBasis::basic)
      numberBasic++;
  }
  return numberBasic;
}
// Returns true if full basis (for debug)
bool CoinWarmStartBasis::fullBasis() const
{
  int i;
  int numberBasic = 0;
  for (i = 0; i < numStructural_; i++) {
    Status status = getStructStatus(i);
    if (status == CoinWarmStartBasis::basic)
      numberBasic++;
  }
  for (i = 0; i < numArtificial_; i++) {
    Status status = getArtifStatus(i);
    if (status == CoinWarmStartBasis::basic)
      numberBasic++;
  }
#ifdef COIN_DEVELOP
  if (numberBasic != numArtificial_)
    printf("mismatch - basis has %d rows, %d basic\n",
      numArtificial_, numberBasic);
#endif
  return numberBasic == numArtificial_;
}
// Returns true if full basis and fixes up (for debug)
bool CoinWarmStartBasis::fixFullBasis()
{
  int i;
  int numberBasic = 0;
  for (i = 0; i < numStructural_; i++) {
    Status status = getStructStatus(i);
    if (status == CoinWarmStartBasis::basic)
      numberBasic++;
  }
  for (i = 0; i < numArtificial_; i++) {
    Status status = getArtifStatus(i);
    if (status == CoinWarmStartBasis::basic)
      numberBasic++;
  }
#ifdef COIN_DEVELOP
  if (numberBasic != numArtificial_)
    printf("mismatch - basis has %d rows, %d basic\n",
      numArtificial_, numberBasic);
#endif
  bool returnCode = (numberBasic == numArtificial_);
  if (numberBasic > numArtificial_) {
    for (i = 0; i < numStructural_; i++) {
      Status status = getStructStatus(i);
      if (status == CoinWarmStartBasis::basic) {
        setStructStatus(i, atLowerBound);
        numberBasic--;
        if (numberBasic == numArtificial_)
          break;
      }
    }
  } else if (numberBasic < numArtificial_) {
    for (i = 0; i < numArtificial_; i++) {
      Status status = getArtifStatus(i);
      if (status != CoinWarmStartBasis::basic) {
        setArtifStatus(i, basic);
        numberBasic++;
        if (numberBasic == numArtificial_)
          break;
      }
    }
  }
  return returnCode;
}
/*
  Generate a diff that'll convert oldCWS into the basis pointed to by this.

  This routine is a bit of a hack, for efficiency's sake. Rather than work
  with individual status vector entries, we're going to treat the vectors as
  int's --- in effect, we create one diff entry for each block of 16 status
  entries. Diffs for logicals are tagged with 0x80000000.
*/

CoinWarmStartDiff *
CoinWarmStartBasis::generateDiff(const CoinWarmStart *const oldCWS) const
{
  /*
  Make sure the parameter is CoinWarmStartBasis or derived class.
*/
  const CoinWarmStartBasis *oldBasis = dynamic_cast< const CoinWarmStartBasis * >(oldCWS);
#ifndef NDEBUG
  if (!oldBasis) {
    throw CoinError("Old basis not derived from CoinWarmStartBasis.",
      "generateDiff", "CoinWarmStartBasis");
  }
#endif
  const CoinWarmStartBasis *newBasis = this;
  /*
  Make sure newBasis is equal or bigger than oldBasis. Calculate the worst case
  number of diffs and allocate vectors to hold them.
*/
  const int oldArtifCnt = oldBasis->getNumArtificial();
  const int oldStructCnt = oldBasis->getNumStructural();
  const int newArtifCnt = newBasis->getNumArtificial();
  const int newStructCnt = newBasis->getNumStructural();

  assert(newArtifCnt >= oldArtifCnt);
  assert(newStructCnt >= oldStructCnt);

  int sizeOldArtif = (oldArtifCnt + 15) >> 4;
  int sizeNewArtif = (newArtifCnt + 15) >> 4;
  int sizeOldStruct = (oldStructCnt + 15) >> 4;
  int sizeNewStruct = (newStructCnt + 15) >> 4;
  int maxBasisLength = sizeNewArtif + sizeNewStruct;

  unsigned int *diffNdx = new unsigned int[2 * maxBasisLength];
  unsigned int *diffVal = diffNdx + maxBasisLength;
  /*
  Ok, setup's over. Now scan the logicals (aka artificials, standing in for
  constraints). For the portion of the status arrays which overlap, create
  diffs. Then add any additional status from newBasis.

  I removed the following bit of code & comment:

    if (sizeNew == sizeOld) sizeOld--; // make sure all taken

  I assume this is meant to trap cases where oldBasis does not occupy all of
  the final int, but I can't see where it's necessary.
*/
  const unsigned int *oldStatus = reinterpret_cast< const unsigned int * >(oldBasis->getArtificialStatus());
  const unsigned int *newStatus = reinterpret_cast< const unsigned int * >(newBasis->getArtificialStatus());
  int numberChanged = 0;
  int i;
  for (i = 0; i < sizeOldArtif; i++) {
    if (oldStatus[i] != newStatus[i]) {
      diffNdx[numberChanged] = i | 0x80000000;
      diffVal[numberChanged++] = newStatus[i];
    }
  }
  for (; i < sizeNewArtif; i++) {
    diffNdx[numberChanged] = i | 0x80000000;
    diffVal[numberChanged++] = newStatus[i];
  }
  /*
  Repeat for structural variables.
*/
  oldStatus = reinterpret_cast< const unsigned int * >(oldBasis->getStructuralStatus());
  newStatus = reinterpret_cast< const unsigned int * >(newBasis->getStructuralStatus());
  for (i = 0; i < sizeOldStruct; i++) {
    if (oldStatus[i] != newStatus[i]) {
      diffNdx[numberChanged] = i;
      diffVal[numberChanged++] = newStatus[i];
    }
  }
  for (; i < sizeNewStruct; i++) {
    diffNdx[numberChanged] = i;
    diffVal[numberChanged++] = newStatus[i];
  }
  /*
  Create the object of our desire.
*/
  CoinWarmStartBasisDiff *diff;
  if ((numberChanged * 2 < maxBasisLength + 1 || !newStructCnt) && true)
    diff = new CoinWarmStartBasisDiff(numberChanged, diffNdx, diffVal);
  else
    diff = new CoinWarmStartBasisDiff(newBasis);
  /*
  Clean up and return.
*/
  delete[] diffNdx;

  return (static_cast< CoinWarmStartDiff * >(diff));
}

/*
  Apply a diff to the basis pointed to by this.  It's assumed that the
  allocated capacity of the basis is sufficiently large.
*/
void CoinWarmStartBasis::applyDiff(const CoinWarmStartDiff *const cwsdDiff)
{
  /*
  Make sure we have a CoinWarmStartBasisDiff
*/
  const CoinWarmStartBasisDiff *diff = dynamic_cast< const CoinWarmStartBasisDiff * >(cwsdDiff);
#ifndef NDEBUG
  if (!diff) {
    throw CoinError("Diff not derived from CoinWarmStartBasisDiff.",
      "applyDiff", "CoinWarmStartBasis");
  }
#endif
  /*
  Application is by straighforward replacement of words in the status arrays.
  Index entries for logicals (aka artificials) are tagged with 0x80000000.
*/
  const int numberChanges = diff->sze_;
  unsigned int *structStatus = reinterpret_cast< unsigned int * >(this->getStructuralStatus());
  unsigned int *artifStatus = reinterpret_cast< unsigned int * >(this->getArtificialStatus());
  if (numberChanges >= 0) {
    const unsigned int *diffNdxs = diff->difference_;
    const unsigned int *diffVals = diffNdxs + numberChanges;

    for (int i = 0; i < numberChanges; i++) {
      unsigned int diffNdx = diffNdxs[i];
      unsigned int diffVal = diffVals[i];
      if ((diffNdx & 0x80000000) == 0) {
        structStatus[diffNdx] = diffVal;
      } else {
        artifStatus[diffNdx & 0x7fffffff] = diffVal;
      }
    }
  } else {
    // just replace
    const unsigned int *diffA = diff->difference_ - 1;
    const int artifCnt = static_cast< int >(diffA[0]);
    const int structCnt = -numberChanges;
    int sizeArtif = (artifCnt + 15) >> 4;
    int sizeStruct = (structCnt + 15) >> 4;
    CoinMemcpyN(diffA + 1, sizeStruct, structStatus);
    CoinMemcpyN(diffA + 1 + sizeStruct, sizeArtif, artifStatus);
  }
  return;
}

const char *statusName(CoinWarmStartBasis::Status status)
{
  switch (status) {
  case CoinWarmStartBasis::isFree: {
    return ("NBFR");
  }
  case CoinWarmStartBasis::basic: {
    return ("B");
  }
  case CoinWarmStartBasis::atUpperBound: {
    return ("NBUB");
  }
  case CoinWarmStartBasis::atLowerBound: {
    return ("NBLB");
  }
  case CoinWarmStartBasis::superBasic: {
    return ("SB");
  }
  default: {
    return ("INVALID!");
  }
  }
}
char statusToChar(CoinWarmStartBasis::Status status)
{
  switch (status) {
  case CoinWarmStartBasis::isFree: {
    return ('F');
  }
  case CoinWarmStartBasis::basic: {
    return ('B');
  }
  case CoinWarmStartBasis::atUpperBound: {
    return ('U');
  }
  case CoinWarmStartBasis::atLowerBound: {
    return ('L');
  }
  case CoinWarmStartBasis::superBasic: {
    return ('S');
  }
  default: {
    return ('I');
  } // invalid!
  }
}
CoinWarmStartBasis::Status charToStatus(char status)
{
  switch (status) {
  case 'F': {
    return (CoinWarmStartBasis::isFree);
  }
  case 'B': {
    return (CoinWarmStartBasis::basic);
  }
  case 'U': {
    return (CoinWarmStartBasis::atUpperBound);
  }
  case 'L': {
    return (CoinWarmStartBasis::atLowerBound);
  }
  case 'S': {
    return (CoinWarmStartBasis::superBasic);
  }
  case 'X': {
    return (CoinWarmStartBasis::atLowerBound);
  } // fixed
  default: {
    abort();
  } // invalid!
  }
}

/* Routines for CoinWarmStartBasisDiff */

/*
  Constructor given diff data.
*/
CoinWarmStartBasisDiff::CoinWarmStartBasisDiff(int sze,
  const unsigned int *const diffNdxs, const unsigned int *const diffVals)
  : sze_(sze)
  , difference_(NULL)

{
  if (sze > 0) {
    difference_ = new unsigned int[2 * sze];
    CoinMemcpyN(diffNdxs, sze, difference_);
    CoinMemcpyN(diffVals, sze, difference_ + sze_);
  }

  return;
}
/*
  Constructor when full is smaller than diff!
*/
CoinWarmStartBasisDiff::CoinWarmStartBasisDiff(const CoinWarmStartBasis *rhs)
  : sze_(0)
  , difference_(0)
{
  const int artifCnt = rhs->getNumArtificial();
  const int structCnt = rhs->getNumStructural();
  int sizeArtif = (artifCnt + 15) >> 4;
  int sizeStruct = (structCnt + 15) >> 4;
  int maxBasisLength = sizeArtif + sizeStruct;
  assert(maxBasisLength && structCnt);
  sze_ = -structCnt;
  difference_ = new unsigned int[maxBasisLength + 1];
  difference_[0] = artifCnt;
  difference_++;
  CoinMemcpyN(reinterpret_cast< const unsigned int * >(rhs->getStructuralStatus()), sizeStruct,
    difference_);
  CoinMemcpyN(reinterpret_cast< const unsigned int * >(rhs->getArtificialStatus()), sizeArtif,
    difference_ + sizeStruct);
}

/*
  Copy constructor.
*/

CoinWarmStartBasisDiff::CoinWarmStartBasisDiff(const CoinWarmStartBasisDiff &rhs)
  : sze_(rhs.sze_)
  , difference_(0)
{
  if (sze_ > 0) {
    difference_ = CoinCopyOfArray(rhs.difference_, 2 * sze_);
  } else if (sze_ < 0) {
    const unsigned int *diff = rhs.difference_ - 1;
    const int artifCnt = static_cast< int >(diff[0]);
    const int structCnt = -sze_;
    int sizeArtif = (artifCnt + 15) >> 4;
    int sizeStruct = (structCnt + 15) >> 4;
    int maxBasisLength = sizeArtif + sizeStruct;
    difference_ = CoinCopyOfArray(diff, maxBasisLength + 1);
    difference_++;
  }

  return;
}

/*
  Assignment --- for convenience when assigning objects containing
  CoinWarmStartBasisDiff objects.
*/
CoinWarmStartBasisDiff &
CoinWarmStartBasisDiff::operator=(const CoinWarmStartBasisDiff &rhs)

{
  if (this != &rhs) {
    if (sze_ > 0) {
      delete[] difference_;
    } else if (sze_ < 0) {
      unsigned int *diff = difference_ - 1;
      delete[] diff;
    }
    sze_ = rhs.sze_;
    if (sze_ > 0) {
      difference_ = CoinCopyOfArray(rhs.difference_, 2 * sze_);
    } else if (sze_ < 0) {
      const unsigned int *diff = rhs.difference_ - 1;
      const int artifCnt = static_cast< int >(diff[0]);
      const int structCnt = -sze_;
      int sizeArtif = (artifCnt + 15) >> 4;
      int sizeStruct = (structCnt + 15) >> 4;
      int maxBasisLength = sizeArtif + sizeStruct;
      difference_ = CoinCopyOfArray(diff, maxBasisLength + 1);
      difference_++;
    } else {
      difference_ = 0;
    }
  }

  return (*this);
}
/*brief Destructor */
CoinWarmStartBasisDiff::~CoinWarmStartBasisDiff()
{
  if (sze_ > 0) {
    delete[] difference_;
  } else if (sze_ < 0) {
    unsigned int *diff = difference_ - 1;
    delete[] diff;
  }
}

/* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2
*/
