text: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  /*                                                                       */
  /*    This file is part of the HiGHS linear optimization suite           */
  /*                                                                       */
  /*    Written and engineered 2008-2021 at the University of Edinburgh    */
  /*                                                                       */
  /*    Available as open-source under the MIT License                     */
  /*                                                                       */
  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  /**@file interfaces/OsiHiGHSInterface.cpp
   * @brief Osi/HiGHS interface implementation
   * @author Julian Hall, Ivet Galabova, Qi Huangfu and Michael Feldmeier
   */
  #include "OsiHiGHSSolverInterface.hpp"
  
  #include <cmath>
  
  #include "CoinWarmStartBasis.hpp"
  #include "Highs.h"
  #include "HighsLp.h"
  #include "HighsOptions.h"
  #include "HighsStatus.h"
  #include "io/FilereaderMps.h"
  #include "io/HighsIO.h"
  #include "lp_data/HConst.h"
  
  static void printtomessagehandler(int level, const char* msg,
                                    void* msgcb_data) {
    assert(msgcb_data != NULL);
  
    CoinMessageHandler* handler = (CoinMessageHandler*)msgcb_data;
  
    int len = strlen(msg);
    if (len > 0 && msg[len - 1] == '\n') {
      const_cast<char*>(msg)[len - 1] = '\0';
      handler->message(0, "HiGHS", msg, ' ') << CoinMessageEol;
      const_cast<char*>(msg)[len - 1] = '\n';
    } else
      handler->message(0, "HiGHS", msg, ' ');
  }
  
  static void logtomessagehandler(HighsMessageType type, const char* msg,
                                  void* msgcb_data) {
    assert(msgcb_data != NULL);
  
    CoinMessageHandler* handler = (CoinMessageHandler*)msgcb_data;
  
    // we know log message end with a newline, replace by coin-eol
    int len = strlen(msg);
    assert(len > 0);
    assert(msg[len - 1] == '\n');
    const_cast<char*>(msg)[len - 1] = '\0';
  
    handler->message(0, "HiGHS", msg, ' ') << CoinMessageEol;
  
    const_cast<char*>(msg)[len - 1] = '\n';
  }
  
  OsiHiGHSSolverInterface::OsiHiGHSSolverInterface()
      //  : status(HighsStatus::Init) {
      : status(HighsStatus::OK) {
    HighsSetMessageCallback(printtomessagehandler, logtomessagehandler,
                            (void*)handler_);
  
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(
        options.output, options.message_level, ML_ALWAYS,
        "Calling OsiHiGHSSolverInterface::OsiHiGHSSolverInterface()\n");
    this->highs = new Highs();
    this->dummy_solution = new HighsSolution;
  
    // because HiGHS calls HiGHSSetIO with the Options, which overwrites
    // the previous setting
    this->highs->options_.printmsgcb = printtomessagehandler;
    this->highs->options_.logmsgcb = logtomessagehandler;
    this->highs->options_.msgcb_data = (void*)handler_;
  
    setStrParam(OsiSolverName, "HiGHS");
  }
  
  OsiHiGHSSolverInterface::OsiHiGHSSolverInterface(
      const OsiHiGHSSolverInterface& original)
      : OsiSolverInterface(original),
        //      status(HighsStatus::Init)
        status(HighsStatus::OK) {
    HighsSetMessageCallback(printtomessagehandler, logtomessagehandler,
                            (void*)handler_);
  
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(
        options.output, options.message_level, ML_ALWAYS,
        "Calling OsiHiGHSSolverInterface::OsiHiGHSSolverInterface()\n");
    this->highs = new Highs();
    this->dummy_solution = new HighsSolution;
  
    // because HiGHS calls HiGHSSetIO with the Options, whichoverwrites the
    // previous setting
    this->highs->options_.printmsgcb = printtomessagehandler;
    this->highs->options_.logmsgcb = logtomessagehandler;
    this->highs->options_.msgcb_data = (void*)handler_;
  
    this->highs->passModel(original.highs->getLp());
    setStrParam(OsiSolverName, "HiGHS");
  }
  
  OsiHiGHSSolverInterface::~OsiHiGHSSolverInterface() {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(
        options.output, options.message_level, ML_ALWAYS,
        "Calling OsiHiGHSSolverInterface::~OsiHiGHSSolverInterface()\n");
  
    HighsSetMessageCallback(NULL, NULL, NULL);
  
    delete this->highs;
  
    if (this->rowRange != NULL) {
      delete[] this->rowRange;
    }
  
    if (this->rhs != NULL) {
      delete[] this->rhs;
    }
  
    if (this->rowSense != NULL) {
      delete[] this->rowSense;
    }
  
    if (this->matrixByCol != NULL) {
      delete this->matrixByCol;
    }
  }
  
  OsiSolverInterface* OsiHiGHSSolverInterface::clone(bool copyData) const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::clone()\n");
    if (!copyData) {
      OsiHiGHSSolverInterface* cln = new OsiHiGHSSolverInterface();
      return cln;
  
    } else {
      OsiHiGHSSolverInterface* cln = new OsiHiGHSSolverInterface(*this);
      cln->objOffset = this->objOffset;
      return cln;
    }
  }
  
  bool OsiHiGHSSolverInterface::setIntParam(OsiIntParam key, int value) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::setIntParam()\n");
    switch (key) {
      case OsiMaxNumIteration:
      case OsiMaxNumIterationHotStart:
        this->highs->options_.simplex_iteration_limit = value;
        return true;
      case OsiNameDiscipline:
        // TODO
        return false;
      case OsiLastIntParam:
      default:
        return false;
    }
  }
  
  bool OsiHiGHSSolverInterface::setDblParam(OsiDblParam key, double value) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::setDblParam()\n");
    switch (key) {
      case OsiDualObjectiveLimit:
        this->highs->options_.dual_objective_value_upper_bound = value;
        return true;
      case OsiPrimalObjectiveLimit:
        return false;
      case OsiDualTolerance:
        this->highs->options_.dual_feasibility_tolerance = value;
        return true;
      case OsiPrimalTolerance:
        this->highs->options_.primal_feasibility_tolerance = value;
        return true;
      case OsiObjOffset:
        this->objOffset = value;
        return true;
      case OsiLastDblParam:
      default:
        return false;
    }
  }
  
  bool OsiHiGHSSolverInterface::setStrParam(OsiStrParam key,
                                            const std::string& value) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::setStrParam(%d, %s)\n",
                      key, value.c_str());
    switch (key) {
      case OsiProbName:
        return OsiSolverInterface::setStrParam(key, value);
      case OsiSolverName:
        return OsiSolverInterface::setStrParam(key, value);
      case OsiLastStrParam:
      default:
        return false;
    }
  }
  
  bool OsiHiGHSSolverInterface::getIntParam(OsiIntParam key, int& value) const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getIntParam()\n");
    switch (key) {
      case OsiMaxNumIteration:
      case OsiMaxNumIterationHotStart:
        value = this->highs->options_.simplex_iteration_limit;
        return true;
      case OsiNameDiscipline:
        // TODO
        return false;
      case OsiLastIntParam:
      default:
        return false;
    }
  }
  
  bool OsiHiGHSSolverInterface::getDblParam(OsiDblParam key,
                                            double& value) const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getDblParam()\n");
    switch (key) {
      case OsiDualObjectiveLimit:
        value = this->highs->options_.dual_objective_value_upper_bound;
        return true;
      case OsiPrimalObjectiveLimit:
        return false;
      case OsiDualTolerance:
        value = this->highs->options_.dual_feasibility_tolerance;
        return true;
      case OsiPrimalTolerance:
        value = this->highs->options_.primal_feasibility_tolerance;
        return true;
      case OsiObjOffset:
        value = this->objOffset;
        return true;
      case OsiLastDblParam:
      default:
        return false;
    }
  }
  
  bool OsiHiGHSSolverInterface::getStrParam(OsiStrParam key,
                                            std::string& value) const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getStrParam(%d, %s)\n",
                      key, value.c_str());
    switch (key) {
      case OsiProbName:
        return OsiSolverInterface::getStrParam(key, value);
      case OsiSolverName:
        return OsiSolverInterface::getStrParam(key, value);
      case OsiLastStrParam:
      default:
        return false;
    }
  }
  
  void OsiHiGHSSolverInterface::initialSolve() {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::initialSolve()\n");
    this->status = this->highs->run();
  }
  
  bool OsiHiGHSSolverInterface::isAbandoned() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::isAbandoned()\n");
    //  return this->status == HighsStatus::NumericalDifficulties;
    return false;
  }
  
  bool OsiHiGHSSolverInterface::isProvenOptimal() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::isProvenOptimal()\n");
    //  return (this->status == HighsStatus::Optimal) ||
    //         (this->status == HighsStatus::OK);
    return false;
  }
  
  bool OsiHiGHSSolverInterface::isProvenPrimalInfeasible() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(
        options.output, options.message_level, ML_ALWAYS,
        "Calling OsiHiGHSSolverInterface::isProvenPrimalInfeasible()\n");
    //  return this->status == HighsStatus::Infeasible;
    return false;
  }
  
  bool OsiHiGHSSolverInterface::isProvenDualInfeasible() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(
        options.output, options.message_level, ML_ALWAYS,
        "Calling OsiHiGHSSolverInterface::isProvenDualInfeasible()\n");
    //  return this->status == HighsStatus::Unbounded;
    return false;
  }
  
  bool OsiHiGHSSolverInterface::isPrimalObjectiveLimitReached() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(
        options.output, options.message_level, ML_ALWAYS,
        "Calling OsiHiGHSSolverInterface::isPrimalObjectiveLimitReached()\n");
    return false;
  }
  
  bool OsiHiGHSSolverInterface::isDualObjectiveLimitReached() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(
        options.output, options.message_level, ML_ALWAYS,
        "Calling OsiHiGHSSolverInterface::isDualObjectiveLimitReached()\n");
    //  return this->status == HighsStatus::ReachedDualObjectiveUpperBound;
    return false;
  }
  
  bool OsiHiGHSSolverInterface::isIterationLimitReached() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(
        options.output, options.message_level, ML_ALWAYS,
        "Calling OsiHiGHSSolverInterface::isIterationLimitReached()\n");
    //  return this->status == HighsStatus::ReachedIterationLimit;
    return false;
  }
  
  int OsiHiGHSSolverInterface::getNumCols() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getNumCols()\n");
    return this->highs->lp_.numCol_;
  }
  
  int OsiHiGHSSolverInterface::getNumRows() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getNumRows()\n");
    return this->highs->lp_.numRow_;
  }
  
  int OsiHiGHSSolverInterface::getNumElements() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getNumElements()\n");
    return this->highs->lp_.Astart_[this->highs->lp_.numCol_];
  }
  
  const double* OsiHiGHSSolverInterface::getColLower() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getColLower()\n");
    return &(this->highs->lp_.colLower_[0]);
  }
  
  const double* OsiHiGHSSolverInterface::getColUpper() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getColUpper()\n");
    return &(this->highs->lp_.colUpper_[0]);
  }
  
  const double* OsiHiGHSSolverInterface::getRowLower() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getRowLower()\n");
    return &(this->highs->lp_.rowLower_[0]);
  }
  
  const double* OsiHiGHSSolverInterface::getRowUpper() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getRowUpper()\n");
    return &(this->highs->lp_.rowUpper_[0]);
  }
  
  const double* OsiHiGHSSolverInterface::getObjCoefficients() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getObjCoefficients()\n");
    return &(this->highs->lp_.colCost_[0]);
  }
  
  // TODO: review: 10^20?
  double OsiHiGHSSolverInterface::getInfinity() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_NONE,
                      "Calling OsiHiGHSSolverInterface::getInfinity()\n");
    return HIGHS_CONST_INF;
  }
  
  const double* OsiHiGHSSolverInterface::getRowRange() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getRowRange()\n");
    if (this->rowRange != NULL) {
      delete[] this->rowRange;
    }
  
    int nrows = this->getNumRows();
  
    if (nrows == 0) {
      return this->rowRange;
    }
  
    this->rowRange = new double[nrows];
  
    for (int i = 0; i < nrows; i++) {
      // compute range for row i
      double lo = this->highs->lp_.rowLower_[i];
      double hi = this->highs->lp_.rowUpper_[i];
      double t1;
      char t2;
      this->convertBoundToSense(lo, hi, t2, t1, this->rowRange[i]);
    }
  
    return this->rowRange;
  }
  
  const double* OsiHiGHSSolverInterface::getRightHandSide() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getRightHandSide()\n");
    if (this->rhs != NULL) {
      delete[] this->rhs;
    }
  
    int nrows = this->getNumRows();
  
    if (nrows == 0) {
      return this->rhs;
    }
  
    this->rhs = new double[nrows];
  
    for (int i = 0; i < nrows; i++) {
      // compute rhs for row i
      double lo = this->highs->lp_.rowLower_[i];
      double hi = this->highs->lp_.rowUpper_[i];
      double t1;
      char t2;
      this->convertBoundToSense(lo, hi, t2, this->rhs[i], t1);
    }
  
    return this->rhs;
  }
  
  const char* OsiHiGHSSolverInterface::getRowSense() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getRowSense()\n");
    if (this->rowSense != NULL) {
      delete[] this->rowSense;
    }
  
    int nrows = this->getNumRows();
  
    if (nrows == 0) {
      return this->rowSense;
    }
  
    this->rowSense = new char[nrows];
  
    for (int i = 0; i < nrows; i++) {
      // compute sense for row i
      double lo = this->highs->lp_.rowLower_[i];
      double hi = this->highs->lp_.rowUpper_[i];
      double t1, t2;
      this->convertBoundToSense(lo, hi, this->rowSense[i], t1, t2);
    }
  
    return this->rowSense;
  }
  
  const CoinPackedMatrix* OsiHiGHSSolverInterface::getMatrixByCol() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getMatrixByCol()\n");
    if (this->matrixByCol != NULL) {
      delete this->matrixByCol;
    }
  
    int nrows = this->getNumRows();
    int ncols = this->getNumCols();
    int nelements = this->getNumElements();
  
    int* len = new int[ncols];
    int* start = new int[ncols + 1];
    int* index = new int[nelements];
    double* value = new double[nelements];
  
    // copy data
    memcpy(start, &(this->highs->lp_.Astart_[0]), (ncols + 1) * sizeof(int));
    memcpy(index, &(this->highs->lp_.Aindex_[0]), nelements * sizeof(int));
    memcpy(value, &(this->highs->lp_.Avalue_[0]), nelements * sizeof(double));
  
    for (int i = 0; i < ncols; i++) {
      len[i] = start[i + 1] - start[i];
    }
  
    this->matrixByCol = new CoinPackedMatrix();
  
    this->matrixByCol->assignMatrix(true, nrows, ncols, nelements, value, index,
                                    start, len);
    assert(this->matrixByCol->getNumCols() == ncols);
    assert(this->matrixByCol->getNumRows() == nrows);
  
    return this->matrixByCol;
  }
  
  const CoinPackedMatrix* OsiHiGHSSolverInterface::getMatrixByRow() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getMatrixByRow()\n");
    if (this->matrixByRow != NULL) {
      delete this->matrixByRow;
    }
    this->matrixByRow = new CoinPackedMatrix();
    this->matrixByRow->reverseOrderedCopyOf(*this->getMatrixByCol());
  
    return this->matrixByRow;
  }
  
  double OsiHiGHSSolverInterface::getObjSense() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getObjSense()\n");
    return (double)this->highs->lp_.sense_;
  }
  
  void OsiHiGHSSolverInterface::setObjSense(double s) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::setObjSense()\n");
    ObjSense pass_sense = ObjSense::MINIMIZE;
    if (s == (double)ObjSense::MAXIMIZE) pass_sense = ObjSense::MAXIMIZE;
    this->highs->changeObjectiveSense(pass_sense);
  }
  
  void OsiHiGHSSolverInterface::addRow(const CoinPackedVectorBase& vec,
                                       const double rowlb, const double rowub) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::addRow()\n");
    bool success = this->highs->addRow(rowlb, rowub, vec.getNumElements(),
                                       vec.getIndices(), vec.getElements());
    assert(success);
    if (!success) {
      HighsPrintMessage(
          options.output, options.message_level, ML_ALWAYS,
          "Return from OsiHiGHSSolverInterface::addRow() is false\n");
    }
  }
  
  void OsiHiGHSSolverInterface::addRow(const CoinPackedVectorBase& vec,
                                       const char rowsen, const double rowrhs,
                                       const double rowrng) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::addRow()\n");
    // Assign arbitrary values so that compilation is clean
    double lb = 0;
    double ub = 1e200;
    this->convertSenseToBound(rowsen, rowrhs, rowrng, lb, ub);
    this->addRow(vec, lb, ub);
  }
  
  void OsiHiGHSSolverInterface::addCol(const CoinPackedVectorBase& vec,
                                       const double collb, const double colub,
                                       const double obj) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::addCol()\n");
    bool success = this->highs->addCol(obj, collb, colub, vec.getNumElements(),
                                       vec.getIndices(), vec.getElements());
    assert(success);
    if (!success) {
      HighsPrintMessage(
          options.output, options.message_level, ML_ALWAYS,
          "Return from OsiHiGHSSolverInterface::addCol() is false\n");
    }
  }
  
  void OsiHiGHSSolverInterface::deleteCols(const int num, const int* colIndices) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::deleteCols()\n");
    this->highs->deleteCols(num, colIndices);
  }
  
  void OsiHiGHSSolverInterface::deleteRows(const int num, const int* rowIndices) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::deleteRows()\n");
    this->highs->deleteRows(num, rowIndices);
  }
  
  void OsiHiGHSSolverInterface::assignProblem(CoinPackedMatrix*& matrix,
                                              double*& collb, double*& colub,
                                              double*& obj, double*& rowlb,
                                              double*& rowub) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::assignProblem()\n");
    loadProblem(*matrix, collb, colub, obj, rowlb, rowub);
    delete matrix;
    matrix = 0;
    delete[] collb;
    collb = 0;
    delete[] colub;
    colub = 0;
    delete[] obj;
    obj = 0;
    delete[] rowlb;
    rowlb = 0;
    delete[] rowub;
    rowub = 0;
  }
  
  void OsiHiGHSSolverInterface::loadProblem(const CoinPackedMatrix& matrix,
                                            const double* collb,
                                            const double* colub,
                                            const double* obj, const char* rowsen,
                                            const double* rowrhs,
                                            const double* rowrng) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::loadProblem()\n");
    int numRow = matrix.getNumRows();
  
    double* rowlb = new double[numRow];
    double* rowub = new double[numRow];
  
    char* myrowsen = (char*)rowsen;
    bool rowsennull = false;
    double* myrowrhs = (double*)rowrhs;
    bool rowrhsnull = false;
    double* myrowrng = (double*)rowrng;
    bool rowrngnull = false;
  
    if (rowsen == NULL) {
      rowsennull = true;
      myrowsen = new char[numRow];
      for (int i = 0; i < numRow; i++) {
        myrowsen[i] = 'G';
      }
    }
  
    if (rowrhs == NULL) {
      rowsennull = true;
      myrowrhs = new double[numRow];
      for (int i = 0; i < numRow; i++) {
        myrowrhs[i] = 0.0;
      }
    }
  
    if (rowrng == NULL) {
      rowrngnull = true;
      myrowrng = new double[numRow];
      for (int i = 0; i < numRow; i++) {
        myrowrng[i] = 0.0;
      }
    }
  
    for (int i = 0; i < numRow; i++) {
      this->convertSenseToBound(myrowsen[i], myrowrhs[i], myrowrng[i], rowlb[i],
                                rowub[i]);
    }
  
    this->loadProblem(matrix, collb, colub, obj, rowlb, rowub);
  
    delete[] rowlb;
    delete[] rowub;
  
    if (rowsennull) {
      delete[] myrowsen;
    }
  
    if (rowrhsnull) {
      delete[] myrowrhs;
    }
  
    if (rowrngnull) {
      delete[] myrowrng;
    }
  }
  
  void OsiHiGHSSolverInterface::assignProblem(CoinPackedMatrix*& matrix,
                                              double*& collb, double*& colub,
                                              double*& obj, char*& rowsen,
                                              double*& rowrhs, double*& rowrng) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::assignProblem()\n");
    loadProblem(*matrix, collb, colub, obj, rowsen, rowrhs, rowrng);
    delete matrix;
    matrix = 0;
    delete[] collb;
    collb = 0;
    delete[] colub;
    colub = 0;
    delete[] obj;
    obj = 0;
    delete[] rowsen;
    rowsen = 0;
    delete[] rowrhs;
    rowrhs = 0;
    delete[] rowrng;
    rowrng = 0;
  }
  
  void OsiHiGHSSolverInterface::loadProblem(
      const int numcols, const int numrows, const CoinBigIndex* start,
      const int* index, const double* value, const double* collb,
      const double* colub, const double* obj, const double* rowlb,
      const double* rowub) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::loadProblem()\n");
    double oldObjSense = this->getObjSense();
  
    HighsLp lp;
  
    lp.numRow_ = numrows;
    lp.numCol_ = numcols;
  
    // setup HighsLp data structures
    lp.colCost_.resize(numcols);
    lp.colUpper_.resize(numcols);
    lp.colLower_.resize(numcols);
  
    lp.rowLower_.resize(numrows);
    lp.rowUpper_.resize(numrows);
  
    lp.Astart_.resize(numcols + 1);
    lp.Aindex_.resize(start[numcols]);
    lp.Avalue_.resize(start[numcols]);
  
    // copy data
    if (obj != NULL) {
      lp.colCost_.assign(obj, obj + numcols);
    } else {
      lp.colCost_.assign(numcols, 0.0);
    }
  
    if (collb != NULL) {
      lp.colLower_.assign(collb, collb + numcols);
    } else {
      lp.colLower_.assign(numcols, 0.0);
    }
  
    if (colub != NULL) {
      lp.colUpper_.assign(colub, colub + numcols);
    } else {
      lp.colUpper_.assign(numcols, HIGHS_CONST_INF);
    }
  
    if (rowlb != NULL) {
      lp.rowLower_.assign(rowlb, rowlb + numrows);
    } else {
      lp.rowLower_.assign(numrows, -HIGHS_CONST_INF);
    }
  
    if (rowub != NULL) {
      lp.rowUpper_.assign(rowub, rowub + numrows);
    } else {
      lp.rowUpper_.assign(numrows, HIGHS_CONST_INF);
    }
  
    lp.Astart_.assign(start, start + numcols + 1);
    lp.Aindex_.assign(index, index + start[numcols]);
    lp.Avalue_.assign(value, value + start[numcols]);
    this->highs->passModel(lp);
    this->setObjSense(oldObjSense);
  }
  
  void OsiHiGHSSolverInterface::loadProblem(
      const int numcols, const int numrows, const CoinBigIndex* start,
      const int* index, const double* value, const double* collb,
      const double* colub, const double* obj, const char* rowsen,
      const double* rowrhs, const double* rowrng) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::loadProblem()\n");
    double* rowlb = new double[numrows];
    double* rowub = new double[numrows];
  
    for (int i = 0; i < numrows; i++) {
      this->convertSenseToBound(rowsen[i], rowrhs[i], rowrng[i], rowlb[i],
                                rowub[i]);
    }
  
    this->loadProblem(numcols, numrows, start, index, value, collb, colub, obj,
                      rowlb, rowub);
  
    delete[] rowlb;
    delete[] rowub;
  }
  
  void OsiHiGHSSolverInterface::loadProblem(
      const CoinPackedMatrix& matrix, const double* collb, const double* colub,
      const double* obj, const double* rowlb, const double* rowub) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::loadProblem()\n");
    bool transpose = false;
    if (!matrix.isColOrdered()) {
      transpose = true;
      // ToDo: remove this hack
      //((CoinPackedMatrix *)&matrix)->transpose();
      ((CoinPackedMatrix*)&matrix)->reverseOrdering();
    }
  
    int numCol = matrix.getNumCols();
    int numRow = matrix.getNumRows();
    int num_nz = matrix.getNumElements();
  
    int* start = new int[numCol + 1];
    int* index = new int[num_nz];
    double* value = new double[num_nz];
  
    // get matrix data
    // const CoinBigIndex *vectorStarts = matrix.getVectorStarts();
    const int* vectorLengths = matrix.getVectorLengths();
    const double* elements = matrix.getElements();
    const int* indices = matrix.getIndices();
  
    // set matrix in HighsLp
    start[0] = 0;
    int nz = 0;
    for (int i = 0; i < numCol; i++) {
      start[i + 1] = start[i] + vectorLengths[i];
      CoinBigIndex first = matrix.getVectorFirst(i);
      for (int j = 0; j < vectorLengths[i]; j++) {
        index[nz] = indices[first + j];
        value[nz] = elements[first + j];
        nz++;
      }
    }
    assert(num_nz == nz);
  
    this->loadProblem(numCol, numRow, start, index, value, collb, colub, obj,
                      rowlb, rowub);
  
    if (transpose) {
      //((CoinPackedMatrix)matrix).transpose();
      ((CoinPackedMatrix*)&matrix)->reverseOrdering();
    }
  
    delete[] start;
    delete[] index;
    delete[] value;
  }
  
  /// Read a problem in MPS format from the given filename.
  // int OsiHiGHSSolverInterface::readMps(const char *filename,
  //   const char *extension)
  // {
  //   HighsOptions& options = this->highs->options_;
  //   HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
  //                     "Calling OsiHiGHSSolverInterface::readMps()\n");
  
  //   HighsLp lp;
  
  //   highs->options_.filename = std::string(filename) + "." +
  //   std::string(extension);
  
  //   FilereaderRetcode rc = FilereaderMps().readModelFromFile(highs->options_,
  //   lp); if (rc != FilereaderRetcode::OK)
  // 	  return (int)rc;
  //   this->setDblParam(OsiDblParam::OsiObjOffset, lp.offset_);
  //   highs->passModel(lp);
  
  //   return 0;
  // }
  
  /// Write the problem into an mps file of the given filename.
  void OsiHiGHSSolverInterface::writeMps(const char* filename,
                                         const char* extension,
                                         double objSense) const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::writeMps()\n");
  
    std::string fullname = std::string(filename) + "." + std::string(extension);
  
    if (objSense != 0.0) {
      // HiGHS doesn't do funny stuff with the objective sense, so use Osi's
      // method if something strange is requested
      OsiSolverInterface::writeMpsNative(fullname.c_str(), NULL, NULL, 0, 2,
                                         objSense);
      return;
    }
  
    FilereaderMps frmps;
    HighsStatus rc =
        frmps.writeModelToFile(highs->options_, fullname, highs->lp_);
  
    if (rc != HighsStatus::OK)
      throw CoinError("Creating MPS file failed", "writeMps",
                      "OsiHiGHSSolverInterface", __FILE__, __LINE__);
  }
  
  void OsiHiGHSSolverInterface::passInMessageHandler(
      CoinMessageHandler* handler) {
    OsiSolverInterface::passInMessageHandler(handler);
  
    HighsSetMessageCallback(printtomessagehandler, logtomessagehandler,
                            (void*)handler);
  
    // because HiGHS calls HiGHSSetIO with the Options, whichoverwrites the
    // previous setting
    this->highs->options_.printmsgcb = printtomessagehandler;
    this->highs->options_.logmsgcb = logtomessagehandler;
    this->highs->options_.msgcb_data = (void*)handler_;
  }
  
  const double* OsiHiGHSSolverInterface::getColSolution() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getColSolution()\n");
    if (!highs) {
      return nullptr;
    } else {
      if (highs->solution_.col_value.size() == 0) {
        double num_cols = highs->lp_.numCol_;
        this->dummy_solution->col_value.resize(num_cols);
        for (int col = 0; col < highs->lp_.numCol_; col++) {
          if (highs->lp_.colLower_[col] <= 0 && highs->lp_.colUpper_[col] >= 0)
            dummy_solution->col_value[col] = 0;
          else if (std::fabs(highs->lp_.colLower_[col] <
                             std::fabs(highs->lp_.colUpper_[col])))
            dummy_solution->col_value[col] = highs->lp_.colLower_[col];
          else
            dummy_solution->col_value[col] = highs->lp_.colUpper_[col];
        }
        return &dummy_solution->col_value[0];
      }
    }
  
    return &highs->solution_.col_value[0];
  }
  
  const double* OsiHiGHSSolverInterface::getRowPrice() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getRowPrice()\n");
    if (!highs)
      return nullptr;
    else {
      if (highs->solution_.row_dual.size() == 0) {
        double num_cols = highs->lp_.numCol_;
        this->dummy_solution->row_dual.resize(num_cols);
        for (int col = 0; col < highs->lp_.numCol_; col++) {
          if (highs->lp_.colLower_[col] <= 0 && highs->lp_.colUpper_[col] >= 0)
            dummy_solution->row_dual[col] = 0;
          else if (std::fabs(highs->lp_.colLower_[col] <
                             std::fabs(highs->lp_.colUpper_[col])))
            dummy_solution->row_dual[col] = highs->lp_.colLower_[col];
          else
            dummy_solution->row_dual[col] = highs->lp_.colUpper_[col];
        }
        return &dummy_solution->row_dual[0];
      }
    }
  
    return &highs->solution_.row_dual[0];
  }
  
  const double* OsiHiGHSSolverInterface::getReducedCost() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getReducedCost()\n");
    if (!highs)
      return nullptr;
    else {
      if (highs->solution_.col_dual.size() == 0) {
        const HighsLp& lp = highs->lp_;
        double num_cols = lp.numCol_;
        this->dummy_solution->col_dual.resize(num_cols);
        for (int col = 0; col < num_cols; col++) {
          dummy_solution->col_dual[col] = lp.colCost_[col];
          for (int i = lp.Astart_[col]; i < lp.Astart_[col + 1]; i++) {
            const int row = lp.Aindex_[i];
            assert(row >= 0);
            assert(row < lp.numRow_);
  
            dummy_solution->col_dual[col] +=
                dummy_solution->row_dual[row] * lp.Avalue_[i];
          }
        }
        return &dummy_solution->col_dual[0];
      }
    }
  
    return &highs->solution_.col_dual[0];
  }
  
  const double* OsiHiGHSSolverInterface::getRowActivity() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getRowActivity()\n");
    if (!highs)
      return nullptr;
    else {
      if (highs->solution_.row_value.size() == 0) {
        double num_cols = highs->lp_.numCol_;
        this->dummy_solution->row_value.resize(num_cols);
        for (int col = 0; col < highs->lp_.numCol_; col++) {
          if (highs->lp_.colLower_[col] <= 0 && highs->lp_.colUpper_[col] >= 0)
            dummy_solution->row_value[col] = 0;
          else if (std::fabs(highs->lp_.colLower_[col] <
                             std::fabs(highs->lp_.colUpper_[col])))
            dummy_solution->row_value[col] = highs->lp_.colLower_[col];
          else
            dummy_solution->row_value[col] = highs->lp_.colUpper_[col];
        }
        return &dummy_solution->row_value[0];
      }
    }
  
    return &highs->solution_.row_value[0];
  }
  
  double OsiHiGHSSolverInterface::getObjValue() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getObjValue()\n");
    double objVal = 0.0;
    if (true || highs->solution_.col_value.size() == 0) {
      const double* sol = this->getColSolution();
      const double* cost = this->getObjCoefficients();
      int ncols = this->getNumCols();
  
      objVal = -this->objOffset;
      for (int i = 0; i < ncols; i++) {
        objVal += sol[i] * cost[i];
      }
    } else {
      this->highs->getHighsInfoValue("objective_function_value", objVal);
    }
  
    return objVal;
  }
  
  int OsiHiGHSSolverInterface::getIterationCount() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getIterationCount()\n");
    if (!highs) {
      return 0;
    }
    int iteration_count;
    this->highs->getHighsInfoValue("simplex_iteration_count", iteration_count);
    return iteration_count;
  }
  
  void OsiHiGHSSolverInterface::setRowPrice(const double* rowprice) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
  
                      "Calling OsiHiGHSSolverInterface::setRowPrice()\n");
    if (!rowprice) return;
    HighsSolution solution;
    solution.row_dual.resize(highs->lp_.numRow_);
    for (int row = 0; row < highs->lp_.numRow_; row++)
      solution.row_dual[row] = rowprice[row];
  
    /*HighsStatus result =*/highs->setSolution(solution);
  }
  
  void OsiHiGHSSolverInterface::setColSolution(const double* colsol) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::setColSolution()\n");
    if (!colsol) return;
    HighsSolution solution;
    solution.col_value.resize(highs->lp_.numCol_);
    for (int col = 0; col < highs->lp_.numCol_; col++)
      solution.col_value[col] = colsol[col];
  
    /*HighsStatus result =*/highs->setSolution(solution);
  }
  
  void OsiHiGHSSolverInterface::applyRowCut(const OsiRowCut& rc) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::applyRowCut()\n");
  }
  
  void OsiHiGHSSolverInterface::applyColCut(const OsiColCut& cc) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::applyColCut()\n");
  }
  
  void OsiHiGHSSolverInterface::setContinuous(int index) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::setContinuous()\n");
  }
  
  void OsiHiGHSSolverInterface::setInteger(int index) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::setInteger()\n");
  }
  
  bool OsiHiGHSSolverInterface::isContinuous(int colNumber) const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::isContinuous()\n");
    return true;
  }
  
  void OsiHiGHSSolverInterface::setRowType(int index, char sense,
                                           double rightHandSide, double range) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::setRowType()\n");
    // Assign arbitrary values so that compilation is clean
    double lo = 0;
    double hi = 1e200;
    this->convertSenseToBound(sense, rightHandSide, range, lo, hi);
    this->setRowBounds(index, lo, hi);
  }
  
  void OsiHiGHSSolverInterface::setRowLower(int elementIndex,
                                            double elementValue) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::setRowLower()\n");
  
    double upper = this->getRowUpper()[elementIndex];
  
    this->highs->changeRowBounds(elementIndex, elementValue, upper);
  }
  
  void OsiHiGHSSolverInterface::setRowUpper(int elementIndex,
                                            double elementValue) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::setRowUpper()\n");
    double lower = this->getRowLower()[elementIndex];
    this->highs->changeRowBounds(elementIndex, lower, elementValue);
  }
  
  void OsiHiGHSSolverInterface::setColLower(int elementIndex,
                                            double elementValue) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::setColLower()\n");
    double upper = this->getColUpper()[elementIndex];
    this->highs->changeColBounds(elementIndex, elementValue, upper);
  }
  
  void OsiHiGHSSolverInterface::setColUpper(int elementIndex,
                                            double elementValue) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::setColUpper()\n");
    double lower = this->getColLower()[elementIndex];
    this->highs->changeColBounds(elementIndex, lower, elementValue);
  }
  
  void OsiHiGHSSolverInterface::setObjCoeff(int elementIndex,
                                            double elementValue) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::setObjCoeff()\n");
    this->highs->changeColCost(elementIndex, elementValue);
  }
  
  std::vector<double*> OsiHiGHSSolverInterface::getDualRays(int maxNumRays,
                                                            bool fullRay) const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getDualRays()\n");
    return std::vector<double*>(0);
  }
  
  std::vector<double*> OsiHiGHSSolverInterface::getPrimalRays(
      int maxNumRays) const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getPrimalRays()\n");
    return std::vector<double*>(0);
  }
  
  CoinWarmStart* OsiHiGHSSolverInterface::getEmptyWarmStart() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getEmptyWarmStart()\n");
    return (dynamic_cast<CoinWarmStart*>(new CoinWarmStartBasis()));
  }
  
  CoinWarmStart* OsiHiGHSSolverInterface::getWarmStart() const {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::getWarmStart()\n");
    if (!highs) return NULL;
  
    if (highs->basis_.col_status.size() == 0 ||
        highs->basis_.row_status.size() == 0)
      return NULL;
  
    int num_cols = highs->lp_.numCol_;
    int num_rows = highs->lp_.numRow_;
  
    int* cstat = new int[num_cols];
    int* rstat = new int[num_rows];
  
    getBasisStatus(cstat, rstat);
  
    CoinWarmStartBasis* warm_start = new CoinWarmStartBasis();
    warm_start->setSize(num_cols, num_rows);
  
    for (int i = 0; i < num_rows; ++i)
      warm_start->setArtifStatus(i, CoinWarmStartBasis::Status(rstat[i]));
    for (int i = 0; i < num_cols; ++i)
      warm_start->setStructStatus(i, CoinWarmStartBasis::Status(cstat[i]));
  
    return warm_start;
  }
  
  bool OsiHiGHSSolverInterface::setWarmStart(const CoinWarmStart* warmstart) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::setWarmStart()\n");
    return false;
  }
  
  void OsiHiGHSSolverInterface::resolve() {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::resolve()\n");
    this->status = this->highs->run();
  }
  
  void OsiHiGHSSolverInterface::setRowBounds(int elementIndex, double lower,
                                             double upper) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::setRowBounds()\n");
  
    this->highs->changeRowBounds(elementIndex, lower, upper);
  }
  
  void OsiHiGHSSolverInterface::setColBounds(int elementIndex, double lower,
                                             double upper) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::setColBounds()\n");
  
    this->highs->changeColBounds(elementIndex, lower, upper);
  }
  
  void OsiHiGHSSolverInterface::setRowSetBounds(const int* indexFirst,
                                                const int* indexLast,
                                                const double* boundList) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::setRowSetBounds()\n");
    OsiSolverInterface::setRowSetBounds(indexFirst, indexLast - 1, boundList);
  }
  
  void OsiHiGHSSolverInterface::setColSetBounds(const int* indexFirst,
                                                const int* indexLast,
                                                const double* boundList) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::setColSetBounds()\n");
    OsiSolverInterface::setColSetBounds(indexFirst, indexLast - 1, boundList);
  }
  
  void OsiHiGHSSolverInterface::branchAndBound() {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::branchAndBound()\n");
    // TODO
  }
  
  void OsiHiGHSSolverInterface::setObjCoeffSet(const int* indexFirst,
                                               const int* indexLast,
                                               const double* coeffList) {
    HighsOptions& options = this->highs->options_;
    HighsPrintMessage(options.output, options.message_level, ML_ALWAYS,
                      "Calling OsiHiGHSSolverInterface::setObjCoeffSet()\n");
    OsiSolverInterface::setObjCoeffSet(indexFirst, indexLast - 1, coeffList);
  }
  
  int OsiHiGHSSolverInterface::canDoSimplexInterface() const { return 0; }
  
  /* Osi return codes:
  0: free
  1: basic
  2: upper
  3: lower
  */
  void OsiHiGHSSolverInterface::getBasisStatus(int* cstat, int* rstat) const {
    if (!highs) return;
  
    if (highs->basis_.col_status.size() == 0 ||
        highs->basis_.row_status.size() == 0)
      return;
  
    for (size_t i = 0; i < highs->basis_.col_status.size(); ++i)
      switch (highs->basis_.col_status[i]) {
        case HighsBasisStatus::BASIC:
          cstat[i] = 1;
          break;
        case HighsBasisStatus::LOWER:
          cstat[i] = 3;
          break;
        case HighsBasisStatus::UPPER:
          cstat[i] = 2;
          break;
        case HighsBasisStatus::SUPER:
          cstat[i] = 0;
          break;
        case HighsBasisStatus::ZERO:
          cstat[i] = 0;
          break;
        case HighsBasisStatus::NONBASIC:
          cstat[i] = 3;
          break;
      }
  
    for (size_t i = 0; i < highs->basis_.row_status.size(); ++i)
      switch (highs->basis_.row_status[i]) {
        case HighsBasisStatus::BASIC:
          rstat[i] = 1;
          break;
        case HighsBasisStatus::LOWER:
          rstat[i] = 3;
          break;
        case HighsBasisStatus::UPPER:
          rstat[i] = 2;
          break;
        case HighsBasisStatus::SUPER:
          rstat[i] = 0;
          break;
        case HighsBasisStatus::ZERO:
          rstat[i] = 0;
          break;
        case HighsBasisStatus::NONBASIC:
          rstat[i] = 3;
          break;
      }
  }
  
  void OsiHiGHSSolverInterface ::setRowNames(OsiNameVec& srcNames, int srcStart,
                                             int len, int tgtStart) {}
  
  void OsiHiGHSSolverInterface ::setColNames(OsiNameVec& srcNames, int srcStart,
                                             int len, int tgtStart) {}
  
  void OsiSolverInterfaceMpsUnitTest(
      const std::vector<OsiSolverInterface*>& vecSiP, const std::string& mpsDir) {
  }
  