2025年11月28日金曜日

COPT Revised OSI implementaion

 Next, we move on to the OSI implementation that enables COPT to be used not only as an LPSolver but also as a MIPSolver. To use COPT as a MIPSolver, it must be explicitly instructed, and for that purpose, we have added a mode "mip" since the previous update. One note is we restricted one thread during mip mode.


#ifdef COPT

#include "constraint_function.h"

#include 
static copt_env* env = NULL;

int OsiCOPTSolverInterface::error_handling(int errcode) const{
    char errmsg[COPT_BUFFSIZE];

    COPT_GetRetcodeMsg(errcode, errmsg, COPT_BUFFSIZE);
    string str = errmsg;
    str+="\n";
    //printf("ERROR %d: %s\n", errcode, errmsg);
    send_status_to_gui(str);
    return 0;
}
OsiCOPTSolverInterface::OsiCOPTSolverInterface()
{
    lpmethod = 2;//barrier
    int errcode = COPT_CreateEnv(&env);
    if (errcode) {
        error_handling(errcode);

    }
    else {
        errcode = COPT_CreateProb(env, &prob);
        

        if (errcode) {
            error_handling(errcode);
        }
        errcode = COPT_SetIntParam(prob, COPT_INTPARAM_LOGTOCONSOLE, 0);// COPT_INTPARAM_LOGGING, 0);
        if (errcode) {
            error_handling(errcode);
        }
        errcode=COPT_SetIntParam(prob, COPT_INTPARAM_CROSSOVER, 0);//crossover 禁止
        if (errcode) {
            error_handling(errcode);
        }
        errcode= COPT_SetIntParam(prob, COPT_INTPARAM_LPMETHOD, lpmethod);//barrier
        if (errcode) {
            error_handling(errcode);
        }

    }
    //*get_model() = env.CreateModel("lp_ex1");
    mip_obj = DBL_MAX;
    running = false;
    crossover = true;
    log_cnt = 0;
    mip = false;

}
OsiCOPTSolverInterface&
OsiCOPTSolverInterface::operator=(const OsiCOPTSolverInterface& rhs)
{

    int errcode=COPT_CreateCopy(rhs.get_prob(), &prob);
    objOffset = rhs.objOffset;

    running = rhs.running;
    crossover = rhs.crossover;

    col_lower_vec = rhs.col_lower_vec;
    col_upper_vec=rhs.col_upper_vec;

    row_lower_vec = rhs.row_lower_vec;
    row_upper_vec =rhs.row_upper_vec;
    col_cost_vec=rhs.col_cost_vec;
    lpmethod = rhs.lpmethod;
    mip = rhs.mip;

    errcode = COPT_SetIntParam(prob, COPT_INTPARAM_LOGTOCONSOLE, 0);// COPT_INTPARAM_LOGGING, 0);
    if (errcode) {
        error_handling(errcode);
    }
    

    return *this;


}

OsiCOPTSolverInterface::OsiCOPTSolverInterface(const OsiCOPTSolverInterface& original) {
    *this = original;
   
}
OsiCOPTSolverInterface::~OsiCOPTSolverInterface()
{
    // Delete problem and environment
    if (prob) {
        COPT_DeleteProb(&prob);
    }
    if (env) {
        COPT_DeleteEnv(&env);
    }
    mip_obj = DBL_MAX;
    running = false;
    crossover = true;
    log_cnt = 0;


}
void OsiCOPTSolverInterface::set_mip() {
    mip = true;
    int errcode = COPT_SetIntParam(prob, COPT_INTPARAM_THREADS,1);

    if (errcode) {
        error_handling(errcode);
    }
}

/// Get objective function sense (1 for min (default), -1 for max)
double OsiCOPTSolverInterface::getObjSense() const {
    return 1;//min
}
void OsiCOPTSolverInterface::set_time_limit(int sec) {
    //HighsStatus hs = this->highs->setOptionValue("time_limit", sec);
    int errcode = COPT_SetDblParam(prob, COPT_DBLPARAM_TIMELIMIT, sec);
    if (errcode) {
        error_handling(errcode);
    }
}
void OsiCOPTSolverInterface::setObjSense(double s) {

    ObjSense pass_sense = ObjSense::kMinimize;
    if (s == (double)ObjSense::kMaximize) pass_sense = ObjSense::kMaximize;
    if (pass_sense == ObjSense::kMinimize) {
        int errcode=COPT_SetObjSense(prob, COPT_MINIMIZE);
        if (errcode) {
            error_handling(errcode);
        }
    }
    else {
        int errcode = COPT_SetObjSense(prob, COPT_MAXIMIZE);
        if (errcode) {
            error_handling(errcode);
        }
    }
}
void OsiCOPTSolverInterface::writeMps(const char* filename, const char* extension, double objSense) const
{
    std::string fullname = std::string(filename) + "." + std::string(extension);
    int errcode=COPT_WriteMps( prob, fullname.c_str());
    if (errcode) {
        error_handling(errcode);
    }

}
void OsiCOPTSolverInterface::writeLp(const char* filename, const char* extension, double objSense) const
{
    std::string fullname = std::string(filename) + "." + std::string(extension);
    int errcode = COPT_WriteLp(prob, fullname.c_str());
    if (errcode) {
        error_handling(errcode);
    }

}
void OsiCOPTSolverInterface::setRowType(HighsInt index, char sense,
    double rightHandSide, double range) {
    // 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 OsiCOPTSolverInterface::setObjCoeff(HighsInt elementIndex,
    double elementValue) {

    int errcode=COPT_SetColObj(prob, 1,&elementIndex, &elementValue);
    if (errcode) {
        error_handling(errcode);
    }
    //this->highs->changeColCost(elementIndex, elementValue);
}
void OsiCOPTSolverInterface::setObjCoeffSet(const int* indexFirst, const int* indexLast, const double* coeffList) {

    OsiSolverInterface::setObjCoeffSet(indexFirst, indexLast - 1, coeffList);

}
void OsiCOPTSolverInterface::setColSetBounds(const HighsInt* indexFirst,
    const HighsInt* indexLast,
    const double* boundList) {

    OsiSolverInterface::setColSetBounds(indexFirst, indexLast - 1, boundList);
}
void OsiCOPTSolverInterface::setRowBounds(HighsInt elementIndex, double lower,
    double upper) {

    int errcode=COPT_SetRowLower(prob, 1, &elementIndex, &lower);
    if (errcode) {
        error_handling(errcode);
    }
    errcode = COPT_SetRowUpper(prob, 1, &elementIndex, &upper);
    if (errcode) {
        error_handling(errcode);
    }
    
}
void OsiCOPTSolverInterface::setColBounds(HighsInt elementIndex, double lower,
    double upper) {

    int errcode = COPT_SetColLower(prob, 1, &elementIndex, &lower);
    if (errcode) {
        error_handling(errcode);
    }
    errcode = COPT_SetColUpper(prob, 1, &elementIndex, &upper);
    if (errcode) {
        error_handling(errcode);
    }

}
void OsiCOPTSolverInterface::setRowSetBounds(const HighsInt* indexFirst,
    const HighsInt* indexLast,
    const double* boundList) {

    OsiSolverInterface::setRowSetBounds(indexFirst, indexLast - 1, boundList);
}


void OsiCOPTSolverInterface::branchAndBound() {
    
    // TODO
}
void OsiCOPTSolverInterface::set_lpmethod(int m,double d)
{
    lpmethod = m;
    if (lpmethod == 6) {
        send_status_to_gui("\t\tPDLP is selected.\n");
        int errcode = COPT_SetDblParam(prob, COPT_DBLPARAM_PDLPTOL, d);//Barrier
        if (errcode) {
            error_handling(errcode);
        }
        errcode = COPT_SetIntParam(prob, COPT_INTPARAM_GPUMODE, 1);//GPU mode=1
        if (errcode) {
            error_handling(errcode);
        }
    }
    else if (lpmethod == 2) {
        send_status_to_gui("\t\tBarrier is selected.\n");
        int errcode = COPT_SetIntParam(prob, COPT_INTPARAM_GPUMODE, 0);//GPU mode=0
        if (errcode) {
            error_handling(errcode);
        }
        //errcode = COPT_SetIntParam(prob, COPT_INTPARAM_GPUMODE, 1);//GPU mode=1
    }

}
void OsiCOPTSolverInterface::initialSolve() {
    if (mip) {
        int errcode = COPT_Solve(prob);
        if (errcode) {
            error_handling(errcode);
        }
        int lpstat = COPT_MIPSTATUS_UNSTARTED;
        errcode = COPT_GetIntAttr(prob, COPT_INTATTR_MIPSTATUS, &lpstat);
        if (errcode) {
            error_handling(errcode);
        }
        if (lpstat == COPT_MIPSTATUS_OPTIMAL) {
            sol.col_value.resize(getNumCols());
            int errcode = COPT_GetSolution(prob, &sol.col_value[0]);// 
            //int COPT_GetLpSolution(copt_prob * prob, double* value, double * slack(activity of constraints), double* rowDual(row price), double* redCost)
            if (errcode) {
                error_handling(errcode);
            }
        }
        return;
    }
    set_running(true);
    int errcode = COPT_SetIntParam(prob, COPT_INTPARAM_LPMETHOD, lpmethod);//Barrier
    if (errcode) {
        error_handling(errcode);
    }
Restart:
    errcode = COPT_SolveLp(prob);
    if (errcode) {
        error_handling(errcode);
    }
    int lpstat = COPT_LPSTATUS_UNSTARTED;
    double lpobjval;
    double* lpsol = NULL;
    int* colstat = NULL;
    errcode = COPT_GetIntAttr(prob, COPT_INTATTR_LPSTATUS, &lpstat);
    if (errcode) {
         error_handling(errcode);
    }
    if (lpstat == COPT_LPSTATUS_OPTIMAL) {
        sol.col_value.resize(getNumCols());
        sol.col_dual.resize(getNumCols());
        sol.row_dual.resize(getNumRows());
        sol.row_value.resize(getNumRows()); //getRowActivity
        int errcode = COPT_GetLpSolution(prob, &sol.col_value[0], &sol.row_value[0], &sol.row_dual[0], &sol.col_dual[0]);// 
        //int COPT_GetLpSolution(copt_prob * prob, double* value, double * slack(activity of constraints), double* rowDual(row price), double* redCost)
        if (errcode) {
            error_handling(errcode);
        }
    }
    else if (lpstat == COPT_LPSTATUS_NUMERICAL) {
        
        string str = "Numarical trouble encounterd.\n";
        send_status_to_gui(str);
        //writeMps("copt_trouble1");
        errcode = COPT_SetIntParam(prob, COPT_INTPARAM_LPMETHOD,0);//Simplex
        if (errcode) {
            error_handling(errcode);
        }
        goto Restart;

        
        errcode = COPT_SetIntParam(prob, COPT_INTPARAM_LPMETHOD, lpmethod);//Barrier
        if (errcode) {
            error_handling(errcode);
        }
    }
    else
        assert(0);
    errcode = COPT_SetIntParam(prob, COPT_INTPARAM_LPMETHOD, lpmethod);//Barrier
    if (errcode) {
        error_handling(errcode);
    }
    //this->status = this->highs->run();
    //const HighsSolution const_sol = this->highs->getSolution();
    //sol = const_sol;
    set_running(false);
}
void OsiCOPTSolverInterface::resolve() {

    initialSolve();
}
const double* OsiCOPTSolverInterface::getRowRange() const {

    if (this->rowRange != NULL) {
        delete[] this->rowRange;
    }

    HighsInt nrows = this->getNumRows();

    if (nrows == 0) {
        return this->rowRange;
    }

    this->rowRange = new double[nrows];

    for (HighsInt i = 0; i < nrows; i++) {
        // compute range for row i
        double lo = this->getRowLower()[i];
        double hi = this->getRowUpper()[i];
        double t1;
        char t2;
        this->convertBoundToSense(lo, hi, t2, t1, this->rowRange[i]);
    }

    return this->rowRange;
}
const double* OsiCOPTSolverInterface::getRightHandSide() const {
#
    if (this->rhs != NULL) {
        delete[] this->rhs;
    }

    HighsInt nrows = this->getNumRows();

    if (nrows == 0) {
        return this->rhs;
    }

    this->rhs = new double[nrows];

    for (HighsInt i = 0; i < nrows; i++) {
        // compute rhs for row i
        double lo = this->getRowLower()[i];
        double hi = this->getRowUpper()[i];
        double t1;
        char t2;
        this->convertBoundToSense(lo, hi, t2, this->rhs[i], t1);
    }

    return this->rhs;
}
const char* OsiCOPTSolverInterface::getRowSense() const {


    if (this->rowSense != NULL) {
        delete[] this->rowSense;
    }

    HighsInt nrows = this->getNumRows();

    if (nrows == 0) {
        return this->rowSense;
    }

    this->rowSense = new char[nrows];

    for (HighsInt i = 0; i < nrows; i++) {
        // compute sense for row i
        double lo = this->getRowLower()[i];
        double hi = this->getRowUpper()[i];
        double t1, t2;
        this->convertBoundToSense(lo, hi, this->rowSense[i], t1, t2);
    }

    return this->rowSense;
}
void OsiCOPTSolverInterface::make_crossover() {
    double d1 = getObjValue();
    {
        if (d1 == 0) {
            resolve();
        }

        int errcode = COPT_SetIntParam(prob, COPT_INTPARAM_CROSSOVER, 1);//crossover Enable
        if (errcode) {
            error_handling(errcode);
        }
        errcode = COPT_SetIntParam(prob, COPT_INTPARAM_LPMETHOD, 3);//crossover
        if (errcode) {
            error_handling(errcode);
        }
    }
    /*
    1: Dual simplex.
        2 : Barrier.
        3 : Crossover.
        4 : Concurrent(Use simplex and barrier simultaneously).
        5 : Choose between simplex and barrier automatically(Based on features such
            as sparsity and /or coefficients ranges).
        6 : First - order method(PDLP)
    */
    resolve();
    double d2 = getObjValue();
    if (d1) {
       // assert(fabs(d1 - d2) <= 1e-3);
    } {
        int errcode = COPT_SetIntParam(prob, COPT_INTPARAM_CROSSOVER, 0);//crossover 禁止
        if (errcode) {
            error_handling(errcode);
        }
        errcode = COPT_SetIntParam(prob, COPT_INTPARAM_LPMETHOD, lpmethod);//barrier
        if (errcode) {
            error_handling(errcode);
        }
    }
}

const CoinPackedMatrix* OsiCOPTSolverInterface::getMatrixByCol() const {

    if (this->matrixByCol != NULL) {
        delete this->matrixByCol;
    }

    HighsInt nrows = this->getNumRows();
    HighsInt ncols = this->getNumCols();
    HighsInt nelements = this->getNumElements();

    HighsInt* len = new int[ncols];
    HighsInt* start = new int[ncols + 1];
    HighsInt* index = new int[nelements];
    double* value = new double[nelements];

    int pReqSize = 0;
    /*
    int errcode = COPT_GetCols(prob, ncols,
        0,//const int* list,
        0,//int* colMatBeg,
        0,//int* colMatCnt,
        0,// int* colMatIdx,
        0,//double* colMatElem,
        nelements,
        &pReqSize);*/
    //vector list;
    //for (auto i = 0; i < ncols; i++) {
    //   list.push_back(i);
    //}
    int errcode = COPT_GetCols(prob, ncols,
        0,//const int* list,
        start,//int* colMatBeg,
        0,// lenは0で渡すFORMATにする,//int* colMatCnt,
        index,// int* colMatIdx,
        value,//double* colMatElem,
        nelements,
        &pReqSize);
    // copy data

    //assert(0);//TODO
    /*
    memcpy(start, &(this->highs->getLp().a_matrix_.start_[0]),
        (ncols + 1) * sizeof(HighsInt));
    memcpy(index, &(this->highs->getLp().a_matrix_.index_[0]),
        nelements * sizeof(HighsInt));
    memcpy(value, &(this->highs->getLp().a_matrix_.value_[0]),
        nelements * sizeof(double));
        */
    if (errcode) {
        error_handling(errcode);
    }
    for (HighsInt i = 0; i < ncols; i++) {//
        assert(start[i + 1] >= 0);
        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* OsiCOPTSolverInterface::getMatrixByRow() const {

    if (this->matrixByRow != NULL) {
        delete this->matrixByRow;
    }
    this->matrixByRow = new CoinPackedMatrix();
    this->matrixByRow->reverseOrderedCopyOf(*this->getMatrixByCol());

    return this->matrixByRow;
}
void OsiCOPTSolverInterface::assignProblem(CoinPackedMatrix*& matrix,
    double*& collb, double*& colub,
    double*& obj, double*& rowlb,
    double*& rowub) {

    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 OsiCOPTSolverInterface::loadProblem(const CoinPackedMatrix& matrix,
    const double* collb,
    const double* colub,
    const double* obj, const char* rowsen,
    const double* rowrhs,
    const double* rowrng) {

    HighsInt 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 (HighsInt i = 0; i < numRow; i++) {
            myrowsen[i] = 'G';
        }
    }

    if (rowrhs == NULL) {
        rowsennull = true;
        myrowrhs = new double[numRow];
        for (HighsInt i = 0; i < numRow; i++) {
            myrowrhs[i] = 0.0;
        }
    }

    if (rowrng == NULL) {
        rowrngnull = true;
        myrowrng = new double[numRow];
        for (HighsInt i = 0; i < numRow; i++) {
            myrowrng[i] = 0.0;
        }
    }

    for (HighsInt 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 OsiCOPTSolverInterface::assignProblem(CoinPackedMatrix*& matrix,
    double*& collb, double*& colub,
    double*& obj, char*& rowsen,
    double*& rowrhs, double*& rowrng) {

    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 OsiCOPTSolverInterface::loadProblem(
    const HighsInt numcols, const HighsInt numrows, const CoinBigIndex* start,
    const HighsInt* index, const double* value, const double* collb,
    const double* colub, const double* obj, const double* rowlb,
    const double* rowub) {

    double oldObjSense = this->getObjSense();
   
    //obj
    if (obj == 0) {
        col_cost_vec.clear();
    }
    else {
        col_cost_vec.resize(numcols);
        for (auto i = 0; i < numcols; i++) {
            col_cost_vec[i] = obj[i];
        }
    }
    //col
    col_lower_vec.resize(numcols);
    col_upper_vec.resize(numcols);
    for (auto i = 0; i < numcols; i++) {
        col_lower_vec[i] = collb[i];
        col_upper_vec[i] = colub[i];
    }
    //row
    row_lower_vec.resize(numrows);
    row_upper_vec.resize(numrows);
    for (auto i = 0; i < numrows; i++) {
        row_lower_vec[i] = rowlb[i];
        row_upper_vec[i] = rowub[i];
    }


    int errcode = COPT_LoadProb(prob,
        numcols,
        numrows,
        COPT_MINIMIZE,//The optimization sense, either COPT_MAXIMIZE or COPT_MINIMIZE.
        objOffset,//The constant part of the objective function.
        obj,//Objective coefficients of variables
        start,
        0,//const int* colMatCnt, //If colMatCnt is NULL, colMatBeg will need to have length of nCol+1,and the begin and end pointers to the i - th matrix column coefficients are defined using colMatBeg[i] and colMatBeg[i + 1]
        index,//const int* colMatIdx,
        value,//const double* colMatElem,
        0,//const char* colType, //If colType is NULL, all variables will be continuous.
        collb, // const double* colLower,
        colub,//const double* colUpper,
        0,//const char* rowSense,//If rowSense is NULL, then rowBound and rowUpper will be treated as lower  and upper bounds for constraints.T
        rowlb,//const double* rowBound,
        rowub,// double* rowUpper,
        0,//char const* const* colNames,//
        0);// char const* const* rowNames);Names of variables and constraints. Can be NULL
    
    if (errcode) {
        error_handling(errcode);
    }
    
}
void OsiCOPTSolverInterface::loadProblem(
    const HighsInt numcols, const HighsInt numrows, const CoinBigIndex* start,
    const HighsInt* index, const double* value, const double* collb,
    const double* colub, const double* obj, const char* rowsen,
    const double* rowrhs, const double* rowrng) {

    double* rowlb = new double[numrows];
    double* rowub = new double[numrows];

    for (HighsInt 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 OsiCOPTSolverInterface::loadProblem(
    const CoinPackedMatrix& matrix, const double* collb, const double* colub,
    const double* obj, const double* rowlb, const double* rowub) {

    bool transpose = false;
    if (!matrix.isColOrdered()) {
        transpose = true;
        // ToDo: remove this hack
        //((CoinPackedMatrix *)&matrix)->transpose();
        ((CoinPackedMatrix*)&matrix)->reverseOrdering();
    }

    HighsInt numCol = matrix.getNumCols();
    HighsInt numRow = matrix.getNumRows();
    HighsInt num_nz = matrix.getNumElements();

    HighsInt* start = new int[numCol + 1];
    HighsInt* index = new int[num_nz];
    double* value = new double[num_nz];

    // get matrix data
    // const CoinBigIndex *vectorStarts = matrix.getVectorStarts();
    const HighsInt* vectorLengths = matrix.getVectorLengths();
    const double* elements = matrix.getElements();
    const HighsInt* indices = matrix.getIndices();

    // set matrix in HighsLp
    start[0] = 0;
    HighsInt nz = 0;
    for (HighsInt i = 0; i < numCol; i++) {
        start[i + 1] = start[i] + vectorLengths[i];
        CoinBigIndex first = matrix.getVectorFirst(i);
        for (HighsInt 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;
}
void OsiCOPTSolverInterface::addRow(const CoinPackedVectorBase& vec,
    const double rowlb, const double rowub) {


    int errcode = COPT_AddRow(prob,  vec.getNumElements(), vec.getIndices(), vec.getElements(), 0, rowlb, rowub, 0);
    if (errcode) {
        error_handling(errcode);
    }
    else {
        row_lower_vec.push_back(rowlb);
        row_upper_vec.push_back(rowub);
    }

 
}

void OsiCOPTSolverInterface::addRow(const CoinPackedVectorBase& vec,
    const char rowsen, const double rowrhs,
    const double rowrng) {

    // 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 OsiCOPTSolverInterface::addCol(const CoinPackedVectorBase& vec,
    const double collb, const double colub,
    const double obj) {

    int elements = vec.getNumElements();
    const int* index_ptr = vec.getIndices();
    const double* val_ptr = vec.getElements();
    
    
    int errcode = COPT_AddCol(prob, obj, elements, index_ptr,val_ptr, COPT_CONTINUOUS, collb, colub, 0);//Variable Type: 'C'
    if (errcode) {
        error_handling(errcode);
    }
    else {
        col_cost_vec.push_back(obj);
        col_lower_vec.push_back(collb);
        col_upper_vec.push_back(colub);
    }
    
}

void OsiCOPTSolverInterface::deleteCols(const HighsInt num,
    const HighsInt* colIndices) {
    int originalcols = getNumCols();
    assert(col_cost_vec.size() == getNumCols());

    int errcode = COPT_DelCols(prob, num, colIndices);
    if (errcode) {
        error_handling(errcode);
    }
    else {
        getColLowerCOPT();
        getColUpperCOPT();
        getObjCoefficientsCOPT();
        /*
        set del_set;
        for (int i = 0; i < num; i++) {
            int ind = colIndices[i];
            del_set.insert(ind);
        }
        vector new_col_cost_vec;
        vector new_col_upper, new_col_lower;
        for (int i = 0; i < originalcols; i++) {
            auto iter = del_set.find(i);
            if (iter == del_set.end()) {
                new_col_cost_vec.push_back(col_cost_vec[i]);
                new_col_lower.push_back(col_lower_vec[i]);
                new_col_upper.push_back(col_upper_vec[i]);
            }
        }
        assert(num == del_set.size());
        assert(col_cost_vec.size() == new_col_cost_vec.size() + del_set.size());
        
        col_cost_vec = new_col_cost_vec;
        col_lower_vec = new_col_lower;
        col_upper_vec = new_col_upper;
        assert(col_cost_vec.size() == col_lower_vec.size());
        assert(col_cost_vec.size() == col_upper_vec.size());
        assert(col_cost_vec.size() == getNumCols());
        */
    }

}

void OsiCOPTSolverInterface::deleteRows(const HighsInt num,
    const HighsInt* rowIndices) {
    int originalrows = getNumRows();
    int errcode = COPT_DelRows(prob, num, rowIndices);
    if (errcode) {
        error_handling(errcode);
    } else {
        getRowLowerCOPT();
        getRowUpperCOPT();
        /*
        set del_set;
        for (int i = 0; i < num; i++) {
            int ind = rowIndices[i];
            del_set.insert(ind);
        }
        
        vector new_row_upper, new_row_lower;
        for (int i = 0; i < originalrows; i++) {
            auto iter = del_set.find(i);
            if (iter == del_set.end()) {
                
                new_row_lower.push_back(row_lower_vec[i]);
                new_row_upper.push_back(row_upper_vec[i]);
            }
        }
        assert(num == del_set.size());
        assert(row_lower_vec.size() == new_row_lower.size() + del_set.size());

        
        row_lower_vec = new_row_lower;
        row_upper_vec = new_row_upper;
        assert(row_lower_vec.size() == getNumRows());
        */
    }
    
}

bool OsiCOPTSolverInterface::isContinuous(int colNumber) const
{
    char b;
    int errcode=COPT_GetColType(prob,1, &colNumber, &b);
    if (errcode) {
        error_handling(errcode);
    }


    return b== COPT_CONTINUOUS;
}
double OsiCOPTSolverInterface::getObjValue() const
{
    double lpobjval;
    if (mip) {
        int errcode = COPT_GetDblAttr(prob, COPT_DBLATTR_BESTOBJ, &lpobjval);
        if (errcode) {
            error_handling(errcode);
        }
        return lpobjval;
    }
    int errcode = COPT_GetDblAttr(prob, COPT_DBLATTR_LPOBJVAL, &lpobjval);
    if (errcode) {
        error_handling(errcode);
    }
    return lpobjval;
}
bool OsiCOPTSolverInterface::isAbandoned() const {

    return false;
}

bool OsiCOPTSolverInterface::isProvenOptimal() const {
    if (mip) {
        int lpstat = 0;
        int errcode = COPT_GetIntAttr(prob, COPT_INTATTR_MIPSTATUS, &lpstat);
        if (errcode) {
            error_handling(errcode);
        }
        if (lpstat == COPT_MIPSTATUS_OPTIMAL) {
            return true;
        }
        assert(0);
        return false;
    }
    int* colstat = NULL;
    int lpstat = 0;
    int errcode = COPT_GetIntAttr(prob, COPT_INTATTR_LPSTATUS, &lpstat);
    if (errcode) {
        error_handling(errcode);
    }
    return lpstat== COPT_LPSTATUS_OPTIMAL;
}

bool OsiCOPTSolverInterface::isProvenPrimalInfeasible() const {
    if (mip) {
        int lpstat = 0;
        int errcode = COPT_GetIntAttr(prob, COPT_INTATTR_MIPSTATUS, &lpstat);
        if (errcode) {
            error_handling(errcode);
        }
        if (lpstat == COPT_MIPSTATUS_INFEASIBLE) {
            return true;
        }
        
        return false;
    }
    int* colstat = NULL;
    int lpstat = 0;
    int errcode = COPT_GetIntAttr(prob, COPT_INTATTR_LPSTATUS, &lpstat);
    if (errcode) {
        error_handling(errcode);
    }
    return lpstat == COPT_LPSTATUS_INFEASIBLE;

    
}

bool OsiCOPTSolverInterface::isProvenDualInfeasible() const {
    assert(!mip);
    int* colstat = NULL;
    int lpstat = 0;
    int errcode = COPT_GetIntAttr(prob, COPT_INTATTR_LPSTATUS, &lpstat);
    if (errcode) {
        error_handling(errcode);
    }
    return lpstat == COPT_LPSTATUS_INFEASIBLE;
    
}

bool OsiCOPTSolverInterface::isPrimalObjectiveLimitReached() const {

    return false;
}

bool OsiCOPTSolverInterface::isDualObjectiveLimitReached() const {
   

    return false;
}

bool OsiCOPTSolverInterface::isIterationLimitReached() const {
    int* colstat = NULL;
    int lpstat = 0;
    int errcode = COPT_GetIntAttr(prob, COPT_INTATTR_LPSTATUS, &lpstat);
    if (errcode) {
        error_handling(errcode);
    }
    return lpstat == COPT_LPSTATUS_ITERLIMIT;
    
}
HighsInt OsiCOPTSolverInterface::getIterationCount() const {

    
    int iteration_count = 0;
    int errcode = COPT_GetIntAttr(prob, COPT_INTATTR_BARRIERITER, &iteration_count);
    if (errcode) {
        error_handling(errcode);
    }

    
    return iteration_count;
}

HighsInt OsiCOPTSolverInterface::getNumCols() const {
    int elems = 0;
    int errcode = COPT_GetIntAttr(prob, COPT_INTATTR_COLS, &elems);
    if (errcode) {
        error_handling(errcode);
    }
    return elems;
}

HighsInt OsiCOPTSolverInterface::getNumRows() const {
    int elems = 0;
    int errcode = COPT_GetIntAttr(prob, COPT_INTATTR_ROWS, &elems);
    if (errcode) {
        error_handling(errcode);
    }
    return elems;
}

HighsInt OsiCOPTSolverInterface::getNumElements() const {
    int elems = 0;
    int errcode = COPT_GetIntAttr(prob, COPT_INTATTR_ELEMS, &elems);
    if (errcode) {
        error_handling(errcode);
    }
    return elems;
}
void OsiCOPTSolverInterface::setRowLower(HighsInt elementIndex,
    double elementValue) {
    int errcode = COPT_SetRowLower(prob, 1, &elementIndex, &elementValue);
    if (errcode) {
        error_handling(errcode);
    }
    else {
        assert(elementIndex < row_lower_vec.size());
        row_lower_vec[elementIndex] = elementValue;
    }
   
}

void OsiCOPTSolverInterface::setRowUpper(HighsInt elementIndex,
    double elementValue) {

    int errcode = COPT_SetRowUpper(prob, 1, &elementIndex, &elementValue);
    if (errcode) {
        error_handling(errcode);
    }
    else {
        assert(elementIndex < row_upper_vec.size());
        row_upper_vec[elementIndex] = elementValue;
    }

}

void OsiCOPTSolverInterface::setColLower(HighsInt elementIndex,
    double elementValue) {
    int errcode = COPT_SetColLower(prob, 1, &elementIndex, &elementValue);
    if (errcode) {
        error_handling(errcode);
    }
    else {
        assert(elementIndex < col_lower_vec.size());
        col_lower_vec[elementIndex] = elementValue;
    }

}

void OsiCOPTSolverInterface::setColUpper(HighsInt elementIndex,
    double elementValue) {
    int errcode = COPT_SetColUpper(prob, 1, &elementIndex, &elementValue);
    if (errcode) {
        error_handling(errcode);
    }
    else {
        assert(elementIndex < col_upper_vec.size());
        col_upper_vec[elementIndex] = elementValue;
    }
}
void OsiCOPTSolverInterface::setContinuous(int index) {
    const char b = COPT_CONTINUOUS;
    int errcode=COPT_SetColType(prob, 1, &index, &b);
    if (errcode) {
        error_handling(errcode);
    }

}

/// Set the index-th variable to be an integer variable
void OsiCOPTSolverInterface::setInteger(int index) {
    const char b = COPT_INTEGER;
    int errcode = COPT_SetColType(prob, 1, &index, &b);
    if (errcode) {
        error_handling(errcode);
    }
}

const double* OsiCOPTSolverInterface::getColLower() const {
        
    assert(col_lower_vec.size());
    return &col_lower_vec[0];
}
const double* OsiCOPTSolverInterface::getColLowerCOPT() {

    col_lower_vec.resize(getNumCols(),0);

    int errcode = COPT_GetColInfo(prob, COPT_DBLINFO_LB, getNumCols(),
        0, &col_lower_vec[0]);
    if (errcode) {
        error_handling(errcode);
    }
    return &col_lower_vec[0];
}

const double* OsiCOPTSolverInterface::getColUpper() const {
    assert(col_upper_vec.size());
    return &col_upper_vec[0];
}

const double* OsiCOPTSolverInterface::getColUpperCOPT() {
    
    //assert(col_upper_vec.size() == getNumCols());
    col_upper_vec.resize(getNumCols(), 0);
    int errcode = COPT_GetColInfo(prob, COPT_DBLINFO_UB, getNumCols(),
        0, &col_upper_vec[0]);
    if (errcode) {
        error_handling(errcode);
    }
    return &col_upper_vec[0];
}
const double* OsiCOPTSolverInterface::getRowLowerCOPT() {
    //assert(row_lower_vec.size()==getNumRows());
    row_lower_vec.resize(getNumRows(), 0);
    int errcode = COPT_GetRowInfo(prob, COPT_DBLINFO_LB, getNumRows(),
        0, &row_lower_vec[0]);
    if (errcode) {
        error_handling(errcode);
    }


    return &row_lower_vec[0];
}
bool  OsiCOPTSolverInterface::compare( OsiCOPTSolverInterface& copt)
{
    if (getNumCols() != copt.getNumCols()) {
        return false;
    }
    if (getNumRows() != copt.getNumRows()) {
        return false;
    }

    getObjCoefficientsCOPT();
    copt.getObjCoefficientsCOPT();

    getColUpperCOPT();
    copt.getColUpperCOPT();
    
    getColLowerCOPT();
    copt.getColLowerCOPT();
    
    getRowUpperCOPT();
    copt.getRowUpperCOPT();
    
    getRowLowerCOPT();
    copt.getRowLowerCOPT();
    const CoinPackedMatrix* cp = getMatrixByCol();
    const CoinPackedMatrix* cp1 = copt.getMatrixByCol();
    bool identical2 = cp->isEquivalent(*cp1);
    if (!identical2) {
        assert(0);
        return false;
    }
    for (auto i = 0; i < getNumRows(); i++) {

        double obj1 = getRowLower()[i];
        double obj2 = copt.getRowLower()[i];
        if (fabs(obj1 - obj2) >= 1e-3) {
            assert(0);
            return false;
        }
        obj1 = getRowUpper()[i];
        obj2 = copt.getRowUpper()[i];
        if (fabs(obj1 - obj2) >= 1e-3) {
            assert(0);
            return false;
        }
    }


    for (auto i = 0; i < getNumCols(); i++) {
        double obj1 = getObjCoefficients()[i];
        double obj2 = copt.getObjCoefficients()[i];
        if (fabs(obj1 - obj2) >= 1e-3) {
            assert(0);
            return false;
        }
        obj1 = getColLower()[i];
        obj2 = copt.getColLower()[i];
        if (fabs(obj1 - obj2) >= 1e-3) {
            assert(0);
            return false;
        }
        obj1 = getColUpper()[i];
        obj2 = copt.getColUpper()[i];
        if (obj1 >= 1e30 && obj2 >= 1e30) {
            continue;
        }
        if (fabs(obj1 - obj2) >= 1e-3) {
            assert(0);
            return false;
        }
    }
    
    return true;

}
const double* OsiCOPTSolverInterface::getRowUpperCOPT()  {

    row_upper_vec.resize(getNumRows(), 0);
    //assert(row_upper_vec.size() == getNumRows());
    int errcode = COPT_GetRowInfo(prob, COPT_DBLINFO_UB, getNumRows(),
        0, &row_upper_vec[0]);
    if (errcode) {
        error_handling(errcode);
    }

    return &row_upper_vec[0];
}

const double* OsiCOPTSolverInterface::getObjCoefficientsCOPT() {
   // assert(col_cost_vec.size());
    //assert(col_cost_vec.size() == getNumCols());
    col_cost_vec.resize(getNumCols(), 0);
    int errcode = COPT_GetColInfo(prob, COPT_DBLINFO_OBJ, getNumCols(),
        0, &col_cost_vec[0]);
    if (errcode) {
        error_handling(errcode);
    }
    return &col_cost_vec[0];

    
}
const double* OsiCOPTSolverInterface::getRowLower() const {
    assert(row_lower_vec.size());
    return &row_lower_vec[0];
}

const double* OsiCOPTSolverInterface::getRowUpper() const {
    assert(row_upper_vec.size());
    return &row_upper_vec[0];
}

const double* OsiCOPTSolverInterface::getObjCoefficients() const {
    assert(col_cost_vec.size());
    return &col_cost_vec[0];
}

// TODO: review: 10^20?
double OsiCOPTSolverInterface::getInfinity() const {
    
    return kHighsInf;
}
const double* OsiCOPTSolverInterface::getColSolution() const {

    const double* ptr = &sol.col_value[0];
    
    return ptr;
}

const double* OsiCOPTSolverInterface::getRowPrice() const {

    return &sol.row_dual[0];
}

const double* OsiCOPTSolverInterface::getReducedCost() const {

    return &sol.col_dual[0];
}

const double* OsiCOPTSolverInterface::getRowActivity() const {


    return &sol.row_value[0];
}
int OsiCOPTSolverInterface::setBasisStatus(const int*colbasis, const int*rowbasis) {
    
    int errcode = COPT_SetBasis(prob, colbasis, rowbasis);
    if (errcode) {
        error_handling(errcode);
    }
    return 0;
}

void OsiCOPTSolverInterface::getBasisStatus(HighsInt* cstat,
    HighsInt* rstat) const {
    
    int errcode=COPT_GetBasis(prob,cstat,rstat);
    if (errcode) {
        error_handling(errcode);
    }


}

OsiSolverInterface* OsiCOPTSolverInterface::clone(bool copyData) const {

    if (!copyData) {
        OsiCOPTSolverInterface* cln = new OsiCOPTSolverInterface();
        return cln;

    }
    else {
        OsiCOPTSolverInterface* cln = new OsiCOPTSolverInterface(*this);
        

        return cln;
    }
}
void OsiCOPTSolverInterface::setRowPrice(const double* rowprice) {
    assert(getNumRows() == sol.row_dual.size());
    for (auto i = 0; i < getNumRows(); i++) {
        sol.row_value[i] = rowprice[i];
    }
    int errcode = COPT_SetLpSolution(prob, &sol.col_value[0], &sol.row_value[0], &sol.row_dual[0], &sol.col_dual[0]);// 
    //int COPT_GetLpSolution(copt_prob * prob, double* value, double * slack(activity of constraints), double* rowDual(row price), double* redCost)
    if (errcode) {
        error_handling(errcode);
    }
}

void OsiCOPTSolverInterface::setColSolution(const double* colsol) {
    assert(getNumCols() == sol.col_value.size());
    for (auto i = 0; i < getNumCols(); i++) {
        sol.col_value[i] = colsol[i];
    }
    int errcode = COPT_SetLpSolution(prob, &sol.col_value[0], &sol.row_value[0], &sol.row_dual[0], &sol.col_dual[0]);// 
    //int COPT_GetLpSolution(copt_prob * prob, double* value, double * slack(activity of constraints), double* rowDual(row price), double* redCost)
    if (errcode) {
        error_handling(errcode);
    }
   
}

std::vector OsiCOPTSolverInterface::getDualRays(HighsInt maxNumRays,
    bool fullRay) const {
    assert(0);
    return std::vector(0);
}

std::vector OsiCOPTSolverInterface::getPrimalRays(
    HighsInt maxNumRays) const {
    assert(0);
    return std::vector(0);
}

CoinWarmStart* OsiCOPTSolverInterface::getEmptyWarmStart() const {
    return 0;
}

CoinWarmStart* OsiCOPTSolverInterface::getWarmStart() const {
    return 0;
}

bool OsiCOPTSolverInterface::setWarmStart(const CoinWarmStart* warmstart) {
    //const HighsOptions& options = this->highs->getOptions();
    //highsLogDev(options.log_options, HighsLogType::kInfo,
    //    "Calling OsiHiGHSSolverInterface::setWarmStart()\n");
    return false;
}
#endif

0 件のコメント:

コメントを投稿