OsiSolverInterface *
expandKnapsack(CoinModel & model, int * whichColumn, int * knapsackStart,
               int * knapsackRow, int &numberKnapsack,
               CglStored & stored, int logLevel,
               int fixedPriority, int SOSPriority, CoinModel & tightenedModel)
{
    int maxTotal = numberKnapsack;
    // load from coin model
    OsiSolverLink *si = new OsiSolverLink();
    OsiSolverInterface * finalModel = NULL;
    si->setDefaultMeshSize(0.001);
    // need some relative granularity
    si->setDefaultBound(100.0);
    si->setDefaultMeshSize(0.01);
    si->setDefaultBound(100000.0);
    si->setIntegerPriority(1000);
    si->setBiLinearPriority(10000);
    si->load(model, true, logLevel);
    // get priorities
    const int * priorities = model.priorities();
    int numberColumns = model.numberColumns();
    if (priorities) {
        OsiObject ** objects = si->objects();
        int numberObjects = si->numberObjects();
        for (int iObj = 0; iObj < numberObjects; iObj++) {
            int iColumn = objects[iObj]->columnNumber();
            if (iColumn >= 0 && iColumn < numberColumns) {
#ifndef NDEBUG
                OsiSimpleInteger * obj =
                    dynamic_cast <OsiSimpleInteger *>(objects[iObj]) ;
#endif
                assert (obj);
                int iPriority = priorities[iColumn];
                if (iPriority > 0)
                    objects[iObj]->setPriority(iPriority);
            }
        }
        if (fixedPriority > 0) {
            si->setFixedPriority(fixedPriority);
        }
        if (SOSPriority < 0)
            SOSPriority = 100000;
    }
    CoinModel coinModel = *si->coinModel();
    assert(coinModel.numberRows() > 0);
    tightenedModel = coinModel;
    int numberRows = coinModel.numberRows();
    // Mark variables
    int * whichKnapsack = new int [numberColumns];
    int iRow, iColumn;
    for (iColumn = 0; iColumn < numberColumns; iColumn++)
        whichKnapsack[iColumn] = -1;
    int kRow;
    bool badModel = false;
    // analyze
    if (logLevel > 1) {
        for (iRow = 0; iRow < numberRows; iRow++) {
            /* Just obvious one at first
            positive non unit coefficients
            all integer
            positive rowUpper
            for now - linear (but further down in code may use nonlinear)
            column bounds should be tight
            */
            //double lower = coinModel.getRowLower(iRow);
            double upper = coinModel.getRowUpper(iRow);
            if (upper < 1.0e10) {
                CoinModelLink triple = coinModel.firstInRow(iRow);
                bool possible = true;
                int n = 0;
                int n1 = 0;
                while (triple.column() >= 0) {
                    int iColumn = triple.column();
                    const char *  el = coinModel.getElementAsString(iRow, iColumn);
                    if (!strcmp("Numeric", el)) {
                        if (coinModel.columnLower(iColumn) == coinModel.columnUpper(iColumn)) {
                            triple = coinModel.next(triple);
                            continue; // fixed
                        }
                        double value = coinModel.getElement(iRow, iColumn);
                        if (value < 0.0) {
                            possible = false;
                        } else {
                            n++;
                            if (value == 1.0)
                                n1++;
                            if (coinModel.columnLower(iColumn) < 0.0)
                                possible = false;
                            if (!coinModel.isInteger(iColumn))
                                possible = false;
                            if (whichKnapsack[iColumn] >= 0)
                                possible = false;
                        }
                    } else {
                        possible = false; // non linear
                    }
                    triple = coinModel.next(triple);
                }
                if (n - n1 > 1 && possible) {
                    double lower = coinModel.getRowLower(iRow);
                    double upper = coinModel.getRowUpper(iRow);
                    CoinModelLink triple = coinModel.firstInRow(iRow);
                    while (triple.column() >= 0) {
                        int iColumn = triple.column();
                        lower -= coinModel.columnLower(iColumn) * triple.value();
                        upper -= coinModel.columnLower(iColumn) * triple.value();
                        triple = coinModel.next(triple);
                    }
                    printf("%d is possible %g <=", iRow, lower);
                    // print
                    triple = coinModel.firstInRow(iRow);
                    while (triple.column() >= 0) {
                        int iColumn = triple.column();
                        if (coinModel.columnLower(iColumn) != coinModel.columnUpper(iColumn))
                            printf(" (%d,el %g up %g)", iColumn, triple.value(),
                                   coinModel.columnUpper(iColumn) - coinModel.columnLower(iColumn));
                        triple = coinModel.next(triple);
                    }
                    printf(" <= %g\n", upper);
                }
            }
        }
    }
    numberKnapsack = 0;
    for (kRow = 0; kRow < numberRows; kRow++) {
        iRow = kRow;
        /* Just obvious one at first
           positive non unit coefficients
           all integer
           positive rowUpper
           for now - linear (but further down in code may use nonlinear)
           column bounds should be tight
        */
        //double lower = coinModel.getRowLower(iRow);
        double upper = coinModel.getRowUpper(iRow);
        if (upper < 1.0e10) {
            CoinModelLink triple = coinModel.firstInRow(iRow);
            bool possible = true;
            int n = 0;
            int n1 = 0;
            while (triple.column() >= 0) {
                int iColumn = triple.column();
                const char *  el = coinModel.getElementAsString(iRow, iColumn);
                if (!strcmp("Numeric", el)) {
                    if (coinModel.columnLower(iColumn) == coinModel.columnUpper(iColumn)) {
                        triple = coinModel.next(triple);
                        continue; // fixed
                    }
                    double value = coinModel.getElement(iRow, iColumn);
                    if (value < 0.0) {
                        possible = false;
                    } else {
                        n++;
                        if (value == 1.0)
                            n1++;
                        if (coinModel.columnLower(iColumn) < 0.0)
                            possible = false;
                        if (!coinModel.isInteger(iColumn))
                            possible = false;
                        if (whichKnapsack[iColumn] >= 0)
                            possible = false;
                    }
                } else {
                    possible = false; // non linear
                }
                triple = coinModel.next(triple);
            }
            if (n - n1 > 1 && possible) {
                // try
                CoinModelLink triple = coinModel.firstInRow(iRow);
                while (triple.column() >= 0) {
                    int iColumn = triple.column();
                    if (coinModel.columnLower(iColumn) != coinModel.columnUpper(iColumn))
                        whichKnapsack[iColumn] = numberKnapsack;
                    triple = coinModel.next(triple);
                }
                knapsackRow[numberKnapsack++] = iRow;
            }
        }
    }
    if (logLevel > 0)
        printf("%d out of %d candidate rows are possible\n", numberKnapsack, numberRows);
    // Check whether we can get rid of nonlinearities
    /* mark rows
       -2 in knapsack and other variables
       -1 not involved
       n only in knapsack n
    */
    int * markRow = new int [numberRows];
    for (iRow = 0; iRow < numberRows; iRow++)
        markRow[iRow] = -1;
    int canDo = 1; // OK and linear
    for (iColumn = 0; iColumn < numberColumns; iColumn++) {
        CoinModelLink triple = coinModel.firstInColumn(iColumn);
        int iKnapsack = whichKnapsack[iColumn];
        bool linear = true;
        // See if quadratic objective
        const char * expr = coinModel.getColumnObjectiveAsString(iColumn);
        if (strcmp(expr, "Numeric")) {
            linear = false;
        }
        while (triple.row() >= 0) {
            int iRow = triple.row();
            if (iKnapsack >= 0) {
                if (markRow[iRow] == -1) {
                    markRow[iRow] = iKnapsack;
                } else if (markRow[iRow] != iKnapsack) {
                    markRow[iRow] = -2;
                }
            }
            const char * expr = coinModel.getElementAsString(iRow, iColumn);
            if (strcmp(expr, "Numeric")) {
                linear = false;
            }
            triple = coinModel.next(triple);
        }
        if (!linear) {
            if (whichKnapsack[iColumn] < 0) {
                canDo = 0;
                break;
            } else {
                canDo = 2;
            }
        }
    }
    int * markKnapsack = NULL;
    double * coefficient = NULL;
    double * linear = NULL;
    int * whichRow = NULL;
    int * lookupRow = NULL;
    badModel = (canDo == 0);
    if (numberKnapsack && canDo) {
        /* double check - OK if
           no nonlinear
           nonlinear only on columns in knapsack
           nonlinear only on columns in knapsack * ONE other - same for all in knapsack
           AND that is only row connected to knapsack
           (theoretically could split knapsack if two other and small numbers)
           also ONE could be ONE expression - not just a variable
        */
        int iKnapsack;
        markKnapsack = new int [numberKnapsack];
        coefficient = new double [numberKnapsack];
        linear = new double [numberColumns];
        for (iKnapsack = 0; iKnapsack < numberKnapsack; iKnapsack++)
            markKnapsack[iKnapsack] = -1;
        if (canDo == 2) {
            for (iRow = -1; iRow < numberRows; iRow++) {
                int numberOdd;
                CoinPackedMatrix * row = coinModel.quadraticRow(iRow, linear, numberOdd);
                if (row) {
                    // see if valid
                    const double * element = row->getElements();
                    const int * column = row->getIndices();
                    const CoinBigIndex * columnStart = row->getVectorStarts();
                    const int * columnLength = row->getVectorLengths();
                    int numberLook = row->getNumCols();
                    for (int i = 0; i < numberLook; i++) {
                        int iKnapsack = whichKnapsack[i];
                        if (iKnapsack < 0) {
                            // might be able to swap - but for now can't have knapsack in
                            for (int j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) {
                                int iColumn = column[j];
                                if (whichKnapsack[iColumn] >= 0) {
                                    canDo = 0; // no good
                                    badModel = true;
                                    break;
                                }
                            }
                        } else {
                            // OK if in same knapsack - or maybe just one
                            int marked = markKnapsack[iKnapsack];
                            for (int j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) {
                                int iColumn = column[j];
                                if (whichKnapsack[iColumn] != iKnapsack && whichKnapsack[iColumn] >= 0) {
                                    canDo = 0; // no good
                                    badModel = true;
                                    break;
                                } else if (marked == -1) {
                                    markKnapsack[iKnapsack] = iColumn;
                                    marked = iColumn;
                                    coefficient[iKnapsack] = element[j];
                                    coinModel.associateElement(coinModel.columnName(iColumn), 1.0);
                                } else if (marked != iColumn) {
                                    badModel = true;
                                    canDo = 0; // no good
                                    break;
                                } else {
                                    // could manage with different coefficients - but for now ...
                                    assert(coefficient[iKnapsack] == element[j]);
                                }
                            }
                        }
                    }
                    delete row;
                }
            }
        }
        if (canDo) {
            // for any rows which are cuts
            whichRow = new int [numberRows];
            lookupRow = new int [numberRows];
            bool someNonlinear = false;
            double maxCoefficient = 1.0;
            for (iKnapsack = 0; iKnapsack < numberKnapsack; iKnapsack++) {
                if (markKnapsack[iKnapsack] >= 0) {
                    someNonlinear = true;
                    int iColumn = markKnapsack[iKnapsack];
                    maxCoefficient = CoinMax(maxCoefficient, fabs(coefficient[iKnapsack] * coinModel.columnUpper(iColumn)));
                }
            }
            if (someNonlinear) {
                // associate all columns to stop possible error messages
                for (iColumn = 0; iColumn < numberColumns; iColumn++) {
                    coinModel.associateElement(coinModel.columnName(iColumn), 1.0);
                }
            }
            ClpSimplex tempModel;
            tempModel.loadProblem(coinModel);
            // Create final model - first without knapsacks
            int nCol = 0;
            int nRow = 0;
            for (iRow = 0; iRow < numberRows; iRow++) {
                if (markRow[iRow] < 0) {
                    lookupRow[iRow] = nRow;
                    whichRow[nRow++] = iRow;
                } else {
                    lookupRow[iRow] = -1;
                }
            }
            for (iColumn = 0; iColumn < numberColumns; iColumn++) {
                if (whichKnapsack[iColumn] < 0)
                    whichColumn[nCol++] = iColumn;
            }
            ClpSimplex finalModelX(&tempModel, nRow, whichRow, nCol, whichColumn, false, false, false);
            OsiClpSolverInterface finalModelY(&finalModelX, true);
            finalModel = finalModelY.clone();
            finalModelY.releaseClp();
            // Put back priorities
            const int * priorities = model.priorities();
            if (priorities) {
                finalModel->findIntegers(false);
                OsiObject ** objects = finalModel->objects();
                int numberObjects = finalModel->numberObjects();
                for (int iObj = 0; iObj < numberObjects; iObj++) {
                    int iColumn = objects[iObj]->columnNumber();
                    if (iColumn >= 0 && iColumn < nCol) {
#ifndef NDEBUG
                        OsiSimpleInteger * obj =
                            dynamic_cast <OsiSimpleInteger *>(objects[iObj]) ;
#endif
                        assert (obj);
                        int iPriority = priorities[whichColumn[iColumn]];
                        if (iPriority > 0)
                            objects[iObj]->setPriority(iPriority);
                    }
                }
            }
            for (iRow = 0; iRow < numberRows; iRow++) {
                whichRow[iRow] = iRow;
            }
            int numberOther = finalModel->getNumCols();
            int nLargest = 0;
            int nelLargest = 0;
            int nTotal = 0;
            for (iKnapsack = 0; iKnapsack < numberKnapsack; iKnapsack++) {
                iRow = knapsackRow[iKnapsack];
                int nCreate = maxTotal;
                int nelCreate = coinModel.expandKnapsack(iRow, nCreate, NULL, NULL, NULL, NULL);
                if (nelCreate < 0)
                    badModel = true;
                nTotal += nCreate;
                nLargest = CoinMax(nLargest, nCreate);
                nelLargest = CoinMax(nelLargest, nelCreate);
            }
            if (nTotal > maxTotal)
                badModel = true;
            if (!badModel) {
                // Now arrays for building
                nelLargest = CoinMax(nelLargest, nLargest) + 1;
                double * buildObj = new double [nLargest];
                double * buildElement = new double [nelLargest];
                int * buildStart = new int[nLargest+1];
                int * buildRow = new int[nelLargest];
                // alow for integers in knapsacks
                OsiObject ** object = new OsiObject * [numberKnapsack+nTotal];
                int nSOS = 0;
                int nObj = numberKnapsack;
                for (iKnapsack = 0; iKnapsack < numberKnapsack; iKnapsack++) {
                    knapsackStart[iKnapsack] = finalModel->getNumCols();
                    iRow = knapsackRow[iKnapsack];
                    int nCreate = 10000;
                    coinModel.expandKnapsack(iRow, nCreate, buildObj, buildStart, buildRow, buildElement);
                    // Redo row numbers
                    for (iColumn = 0; iColumn < nCreate; iColumn++) {
                        for (int j = buildStart[iColumn]; j < buildStart[iColumn+1]; j++) {
                            int jRow = buildRow[j];
                            jRow = lookupRow[jRow];
                            assert (jRow >= 0 && jRow < nRow);
                            buildRow[j] = jRow;
                        }
                    }
                    finalModel->addCols(nCreate, buildStart, buildRow, buildElement, NULL, NULL, buildObj);
                    int numberFinal = finalModel->getNumCols();
                    for (iColumn = numberOther; iColumn < numberFinal; iColumn++) {
                        if (markKnapsack[iKnapsack] < 0) {
                            finalModel->setColUpper(iColumn, maxCoefficient);
                            finalModel->setInteger(iColumn);
                        } else {
                            finalModel->setColUpper(iColumn, maxCoefficient + 1.0);
                            finalModel->setInteger(iColumn);
                        }
                        OsiSimpleInteger * sosObject = new OsiSimpleInteger(finalModel, iColumn);
                        sosObject->setPriority(1000000);
                        object[nObj++] = sosObject;
                        buildRow[iColumn-numberOther] = iColumn;
                        buildElement[iColumn-numberOther] = 1.0;
                    }
                    if (markKnapsack[iKnapsack] < 0) {
                        // convexity row
                        finalModel->addRow(numberFinal - numberOther, buildRow, buildElement, 1.0, 1.0);
                    } else {
                        int iColumn = markKnapsack[iKnapsack];
                        int n = numberFinal - numberOther;
                        buildRow[n] = iColumn;
                        buildElement[n++] = -fabs(coefficient[iKnapsack]);
                        // convexity row (sort of)
                        finalModel->addRow(n, buildRow, buildElement, 0.0, 0.0);
                        OsiSOS * sosObject = new OsiSOS(finalModel, n - 1, buildRow, NULL, 1);
                        sosObject->setPriority(iKnapsack + SOSPriority);
                        // Say not integral even if is (switch off heuristics)
                        sosObject->setIntegerValued(false);
                        object[nSOS++] = sosObject;
                    }
                    numberOther = numberFinal;
                }
                finalModel->addObjects(nObj, object);
                for (iKnapsack = 0; iKnapsack < nObj; iKnapsack++)
                    delete object[iKnapsack];
                delete [] object;
                // Can we move any rows to cuts
                const int * cutMarker = coinModel.cutMarker();
                if (cutMarker && 0) {
                    printf("AMPL CUTS OFF until global cuts fixed\n");
                    cutMarker = NULL;
                }
                if (cutMarker) {
                    // Row copy
                    const CoinPackedMatrix * matrixByRow = finalModel->getMatrixByRow();
                    const double * elementByRow = matrixByRow->getElements();
                    const int * column = matrixByRow->getIndices();
                    const CoinBigIndex * rowStart = matrixByRow->getVectorStarts();
                    const int * rowLength = matrixByRow->getVectorLengths();

                    const double * rowLower = finalModel->getRowLower();
                    const double * rowUpper = finalModel->getRowUpper();
                    int nDelete = 0;
                    for (iRow = 0; iRow < numberRows; iRow++) {
                        if (cutMarker[iRow] && lookupRow[iRow] >= 0) {
                            int jRow = lookupRow[iRow];
                            whichRow[nDelete++] = jRow;
                            int start = rowStart[jRow];
                            stored.addCut(rowLower[jRow], rowUpper[jRow],
                                          rowLength[jRow], column + start, elementByRow + start);
                        }
                    }
                    finalModel->deleteRows(nDelete, whichRow);
                }
                knapsackStart[numberKnapsack] = finalModel->getNumCols();
                delete [] buildObj;
                delete [] buildElement;
                delete [] buildStart;
                delete [] buildRow;
                finalModel->writeMps("full");
            }
        }
    }
    delete [] whichKnapsack;
    delete [] markRow;
    delete [] markKnapsack;
    delete [] coefficient;
    delete [] linear;
    delete [] whichRow;
    delete [] lookupRow;
    delete si;
    si = NULL;
    if (!badModel && finalModel) {
        finalModel->setDblParam(OsiObjOffset, coinModel.objectiveOffset());
        return finalModel;
    } else {
        delete finalModel;
        printf("can't make knapsacks - did you set fixedPriority (extra1)\n");
        return NULL;
    }
}
//--------------------------------------------------------------------------
void OsiGlpkSolverInterfaceUnitTest(const std::string & mpsDir, const std::string & netlibDir)
{
    // Test default constructor
    {
        OsiGlpkSolverInterface m;
        OSIUNITTEST_ASSERT_ERROR(m.obj_         == NULL, {}, "glpk", "default constructor");
        OSIUNITTEST_ASSERT_ERROR(m.collower_    == NULL, {}, "glpk", "default constructor");
        OSIUNITTEST_ASSERT_ERROR(m.colupper_    == NULL, {}, "glpk", "default constructor");
        OSIUNITTEST_ASSERT_ERROR(m.ctype_       == NULL, {}, "glpk", "default constructor");
        OSIUNITTEST_ASSERT_ERROR(m.rowsense_    == NULL, {}, "glpk", "default constructor");
        OSIUNITTEST_ASSERT_ERROR(m.rhs_         == NULL, {}, "glpk", "default constructor");
        OSIUNITTEST_ASSERT_ERROR(m.rowrange_    == NULL, {}, "glpk", "default constructor");
        OSIUNITTEST_ASSERT_ERROR(m.rowlower_    == NULL, {}, "glpk", "default constructor");
        OSIUNITTEST_ASSERT_ERROR(m.rowupper_    == NULL, {}, "glpk", "default constructor");
        OSIUNITTEST_ASSERT_ERROR(m.colsol_      == NULL, {}, "glpk", "default constructor");
        OSIUNITTEST_ASSERT_ERROR(m.rowsol_      == NULL, {}, "glpk", "default constructor");
        OSIUNITTEST_ASSERT_ERROR(m.matrixByRow_ == NULL, {}, "glpk", "default constructor");
        OSIUNITTEST_ASSERT_ERROR(m.matrixByCol_ == NULL, {}, "glpk", "default constructor");
        OSIUNITTEST_ASSERT_ERROR(m.getApplicationData() == NULL, {}, "glpk", "default constructor");
        int i=2346;
        m.setApplicationData(&i);
        OSIUNITTEST_ASSERT_ERROR(*((int *)(m.getApplicationData())) == i, {}, "glpk", "default constructor");
    }


    {
        CoinRelFltEq eq;
        OsiGlpkSolverInterface m;
        std::string fn = mpsDir+"exmip1";
        m.readMps(fn.c_str(),"mps");

        {
            OsiGlpkSolverInterface im;

            OSIUNITTEST_ASSERT_ERROR(im.getNumCols()  == 0,    {}, "glpk", "default constructor");
            OSIUNITTEST_ASSERT_ERROR(im.getModelPtr() != NULL, {}, "glpk", "default constructor");

            // Test reset
            im.reset();
            OSIUNITTEST_ASSERT_ERROR(m.obj_         == NULL, {}, "glpk", "reset");
            OSIUNITTEST_ASSERT_ERROR(m.collower_    == NULL, {}, "glpk", "reset");
            OSIUNITTEST_ASSERT_ERROR(m.colupper_    == NULL, {}, "glpk", "reset");
            OSIUNITTEST_ASSERT_ERROR(m.ctype_       == NULL, {}, "glpk", "reset");
            OSIUNITTEST_ASSERT_ERROR(m.rowsense_    == NULL, {}, "glpk", "reset");
            OSIUNITTEST_ASSERT_ERROR(m.rhs_         == NULL, {}, "glpk", "reset");
            OSIUNITTEST_ASSERT_ERROR(m.rowrange_    == NULL, {}, "glpk", "reset");
            OSIUNITTEST_ASSERT_ERROR(m.rowlower_    == NULL, {}, "glpk", "reset");
            OSIUNITTEST_ASSERT_ERROR(m.rowupper_    == NULL, {}, "glpk", "reset");
            OSIUNITTEST_ASSERT_ERROR(m.colsol_      == NULL, {}, "glpk", "reset");
            OSIUNITTEST_ASSERT_ERROR(m.rowsol_      == NULL, {}, "glpk", "reset");
            OSIUNITTEST_ASSERT_ERROR(m.matrixByRow_ == NULL, {}, "glpk", "reset");
            OSIUNITTEST_ASSERT_ERROR(m.matrixByCol_ == NULL, {}, "glpk", "reset");
            OSIUNITTEST_ASSERT_ERROR(m.getApplicationData() == NULL, {}, "glpk", "reset");
        }

        // Test copy constructor and assignment operator
        {
            OsiGlpkSolverInterface lhs;
            {
                OsiGlpkSolverInterface im(m);

                OsiGlpkSolverInterface imC1(im);
                OSIUNITTEST_ASSERT_ERROR(imC1.getModelPtr() != im.getModelPtr(), {}, "glpk", "copy constructor");
                OSIUNITTEST_ASSERT_ERROR(imC1.getNumCols()  == im.getNumCols(),  {}, "glpk", "copy constructor");
                OSIUNITTEST_ASSERT_ERROR(imC1.getNumRows()  == im.getNumRows(),  {}, "glpk", "copy constructor");

                OsiGlpkSolverInterface imC2(im);
                OSIUNITTEST_ASSERT_ERROR(imC2.getModelPtr() != im.getModelPtr(), {}, "glpk", "copy constructor");
                OSIUNITTEST_ASSERT_ERROR(imC2.getNumCols()  == im.getNumCols(),  {}, "glpk", "copy constructor");
                OSIUNITTEST_ASSERT_ERROR(imC2.getNumRows()  == im.getNumRows(),  {}, "glpk", "copy constructor");

                OSIUNITTEST_ASSERT_ERROR(imC1.getModelPtr() != imC2.getModelPtr(), {}, "glpk", "copy constructor");

                lhs = imC2;
            }

            // Test that lhs has correct values even though rhs has gone out of scope
            OSIUNITTEST_ASSERT_ERROR(lhs.getModelPtr() != m.getModelPtr(), {}, "glpk", "assignment operator");
            OSIUNITTEST_ASSERT_ERROR(lhs.getNumCols()  == m.getNumCols(),  {}, "glpk", "copy constructor");
            OSIUNITTEST_ASSERT_ERROR(lhs.getNumRows()  == m.getNumRows(),  {}, "glpk", "copy constructor");
        }

        // Test clone
        {
            OsiGlpkSolverInterface glpkSi(m);
            OsiSolverInterface * siPtr = &glpkSi;
            OsiSolverInterface * siClone = siPtr->clone();
            OsiGlpkSolverInterface * glpkClone = dynamic_cast<OsiGlpkSolverInterface*>(siClone);
            OSIUNITTEST_ASSERT_ERROR(glpkClone != NULL, {}, "glpk", "clone");
            OSIUNITTEST_ASSERT_ERROR(glpkClone->getModelPtr() != glpkSi.getModelPtr(), {}, "glpk", "clone");
            OSIUNITTEST_ASSERT_ERROR(glpkClone->getNumRows() == glpkSi.getNumRows(), {}, "glpk", "clone");
            OSIUNITTEST_ASSERT_ERROR(glpkClone->getNumCols() == glpkSi.getNumCols(), {}, "glpk", "clone");

            delete siClone;
        }

        // test infinity
        {
            OsiGlpkSolverInterface si;
            OSIUNITTEST_ASSERT_ERROR(si.getInfinity() == COIN_DBL_MAX, {}, "glpk", "infinity");
        }

#if 0
        // ??? These index error 'throw's aren't in OsiGlpk

        // Test some catches
        {
            OsiGlpkSolverInterface solver;
            try {
                solver.setObjCoeff(0,0.0);
            }
            catch (CoinError e) {
                std::cout<<"Correct throw"<<std::endl;
            }
            std::string fn = mpsDir+"exmip1";
            solver.readMps(fn.c_str(),"mps");
            try {
                solver.setObjCoeff(0,0.0);
            }
            catch (CoinError e) {
                std::cout<<"** Incorrect throw"<<std::endl;
                abort();
            }
            try {
                int index[]= {0,20};
                double value[]= {0.0,0.0,0.0,0.0};
                solver.setColSetBounds(index,index+2,value);
            }
            catch (CoinError e) {
                std::cout<<"Correct throw"<<std::endl;
            }
        }
#endif

        {
            OsiGlpkSolverInterface glpkSi(m);
            int nc = glpkSi.getNumCols();
            int nr = glpkSi.getNumRows();
            const double * cl = glpkSi.getColLower();
            const double * cu = glpkSi.getColUpper();
            const double * rl = glpkSi.getRowLower();
            const double * ru = glpkSi.getRowUpper();
            OSIUNITTEST_ASSERT_ERROR(nc == 8, return, "glpk", "read and copy exmip1");
            OSIUNITTEST_ASSERT_ERROR(nr == 5, return, "glpk", "read and copy exmip1");
            OSIUNITTEST_ASSERT_ERROR(eq(cl[0],2.5), {}, "glpk", "read and copy exmip1");
            OSIUNITTEST_ASSERT_ERROR(eq(cl[1],0.0), {}, "glpk", "read and copy exmip1");
            OSIUNITTEST_ASSERT_ERROR(eq(cu[1],4.1), {}, "glpk", "read and copy exmip1");
            OSIUNITTEST_ASSERT_ERROR(eq(cu[2],1.0), {}, "glpk", "read and copy exmip1");
            OSIUNITTEST_ASSERT_ERROR(eq(rl[0],2.5), {}, "glpk", "read and copy exmip1");
            OSIUNITTEST_ASSERT_ERROR(eq(rl[4],3.0), {}, "glpk", "read and copy exmip1");
            OSIUNITTEST_ASSERT_ERROR(eq(ru[1],2.1), {}, "glpk", "read and copy exmip1");
            OSIUNITTEST_ASSERT_ERROR(eq(ru[4],15.), {}, "glpk", "read and copy exmip1");

            const double * cs = glpkSi.getColSolution();
            OSIUNITTEST_ASSERT_ERROR(eq(cs[0],2.5), {}, "glpk", "read and copy exmip1");
            OSIUNITTEST_ASSERT_ERROR(eq(cs[7],0.0), {}, "glpk", "read and copy exmip1");

            OSIUNITTEST_ASSERT_ERROR(!eq(cl[3],1.2345), {}, "glpk", "set col lower");
            glpkSi.setColLower( 3, 1.2345 );
            OSIUNITTEST_ASSERT_ERROR( eq(cl[3],1.2345), {}, "glpk", "set col lower");

            OSIUNITTEST_ASSERT_ERROR(!eq(glpkSi.getColUpper()[4],10.2345), {}, "glpk", "set col upper");
            glpkSi.setColUpper( 4, 10.2345 );
            OSIUNITTEST_ASSERT_ERROR( eq(glpkSi.getColUpper()[4],10.2345), {}, "glpk", "set col upper");

            double objValue = glpkSi.getObjValue();
            OSIUNITTEST_ASSERT_ERROR(eq(objValue,3.5), {}, "glpk", "getObjValue() before solve");

            OSIUNITTEST_ASSERT_ERROR(eq(glpkSi.getObjCoefficients()[0], 1.0), {}, "glpk", "read and copy exmip1");
            OSIUNITTEST_ASSERT_ERROR(eq(glpkSi.getObjCoefficients()[1], 0.0), {}, "glpk", "read and copy exmip1");
            OSIUNITTEST_ASSERT_ERROR(eq(glpkSi.getObjCoefficients()[2], 0.0), {}, "glpk", "read and copy exmip1");
            OSIUNITTEST_ASSERT_ERROR(eq(glpkSi.getObjCoefficients()[3], 0.0), {}, "glpk", "read and copy exmip1");
            OSIUNITTEST_ASSERT_ERROR(eq(glpkSi.getObjCoefficients()[4], 2.0), {}, "glpk", "read and copy exmip1");
            OSIUNITTEST_ASSERT_ERROR(eq(glpkSi.getObjCoefficients()[5], 0.0), {}, "glpk", "read and copy exmip1");
            OSIUNITTEST_ASSERT_ERROR(eq(glpkSi.getObjCoefficients()[6], 0.0), {}, "glpk", "read and copy exmip1");
            OSIUNITTEST_ASSERT_ERROR(eq(glpkSi.getObjCoefficients()[7],-1.0), {}, "glpk", "read and copy exmip1");
        }

        // Test matrixByRow method
        {
            const OsiGlpkSolverInterface si(m);
            const CoinPackedMatrix * smP = si.getMatrixByRow();

            OSIUNITTEST_ASSERT_ERROR(smP->getMajorDim()    ==  5, return, "glpk", "getMatrixByRow: major dim");
            OSIUNITTEST_ASSERT_ERROR(smP->getNumElements() == 14, return, "glpk", "getMatrixByRow: num elements");

            CoinRelFltEq eq;
            const double * ev = smP->getElements();

            // GLPK returns each row in reverse order. This is consistent with
            // the sparse matrix format but is not what most solvers do.  That's
            // why this section is different.
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4], 3.0), {}, "glpk", "getMatrixByRow: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3], 1.0), {}, "glpk", "getMatrixByRow: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2],-2.0), {}, "glpk", "getMatrixByRow: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1],-1.0), {}, "glpk", "getMatrixByRow: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0],-1.0), {}, "glpk", "getMatrixByRow: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6], 2.0), {}, "glpk", "getMatrixByRow: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 1.1), {}, "glpk", "getMatrixByRow: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8], 1.0), {}, "glpk", "getMatrixByRow: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 1.0), {}, "glpk", "getMatrixByRow: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[10], 2.8), {}, "glpk", "getMatrixByRow: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9],-1.2), {}, "glpk", "getMatrixByRow: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 5.6), {}, "glpk", "getMatrixByRow: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "glpk", "getMatrixByRow: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 1.9), {}, "glpk", "getMatrixByRow: elements");

            const CoinBigIndex * mi = smP->getVectorStarts();
            OSIUNITTEST_ASSERT_ERROR(mi[0] ==  0, {}, "glpk", "getMatrixByRow: vector starts");
            OSIUNITTEST_ASSERT_ERROR(mi[1] ==  5, {}, "glpk", "getMatrixByRow: vector starts");
            OSIUNITTEST_ASSERT_ERROR(mi[2] ==  7, {}, "glpk", "getMatrixByRow: vector starts");
            OSIUNITTEST_ASSERT_ERROR(mi[3] ==  9, {}, "glpk", "getMatrixByRow: vector starts");
            OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "glpk", "getMatrixByRow: vector starts");
            OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "glpk", "getMatrixByRow: vector starts");

            const int * ei = smP->getIndices();
            OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 0, {}, "glpk", "getMatrixByRow: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 1, {}, "glpk", "getMatrixByRow: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "glpk", "getMatrixByRow: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 4, {}, "glpk", "getMatrixByRow: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 7, {}, "glpk", "getMatrixByRow: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 1, {}, "glpk", "getMatrixByRow: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 2, {}, "glpk", "getMatrixByRow: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 2, {}, "glpk", "getMatrixByRow: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 5, {}, "glpk", "getMatrixByRow: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[10] == 3, {}, "glpk", "getMatrixByRow: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 6, {}, "glpk", "getMatrixByRow: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[13] == 0, {}, "glpk", "getMatrixByRow: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "glpk", "getMatrixByRow: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[11] == 7, {}, "glpk", "getMatrixByRow: indices");
        }

        // Test adding several cuts
        {
            OsiGlpkSolverInterface fim;
            std::string fn = mpsDir+"exmip1";
            fim.readMps(fn.c_str(),"mps");
            // exmip1.mps has 2 integer variables with index 2 & 3
            fim.initialSolve();
            OsiRowCut cuts[3];

            // Generate one ineffective cut plus two trivial cuts
            int c;
            int nc = fim.getNumCols();
            int *inx = new int[nc];
            for (c=0; c<nc; c++) inx[c]=c;
            double *el = new double[nc];
            for (c=0; c<nc; c++) el[c]=1.0e-50+((double)c)*((double)c);

            cuts[0].setRow(nc,inx,el);
            cuts[0].setLb(-100.);
            cuts[0].setUb(500.);
            cuts[0].setEffectiveness(22);
            el[4]=0.0; // to get inf later

            for (c=2; c<4; c++) {
                el[0]=1.0;
                inx[0]=c;
                cuts[c-1].setRow(1,inx,el);
                cuts[c-1].setLb(1.);
                cuts[c-1].setUb(100.);
                cuts[c-1].setEffectiveness(c);
            }
            fim.writeMps("x1.mps");
            fim.applyRowCuts(3,cuts);
            fim.writeMps("x2.mps");
            // resolve - should get message about zero elements
            fim.resolve();
            fim.writeMps("x3.mps");
            // check integer solution
            const double * cs = fim.getColSolution();
            CoinRelFltEq eq;
            OSIUNITTEST_ASSERT_ERROR(eq(cs[2], 1.0), {}, "glpk", "add cuts");
            OSIUNITTEST_ASSERT_ERROR(eq(cs[3], 1.0), {}, "glpk", "add cuts");
#if 0  // ??? Not working for some reason.
            // check will find invalid matrix
            el[0]=1.0/el[4];
            inx[0]=0;
            cuts[0].setRow(nc,inx,el);
            cuts[0].setLb(-100.);
            cuts[0].setUb(500.);
            cuts[0].setEffectiveness(22);
            fim.applyRowCut(cuts[0]);
            // resolve - should get message about zero elements
            fim.resolve();
            OSIUNITTEST_ASSERT_WARNING(fim.isAbandoned(), {}, "glpk", "add cuts");
#endif
            delete[]el;
            delete[]inx;
        }

        // Test matrixByCol method
        {
            const OsiGlpkSolverInterface si(m);
            const CoinPackedMatrix * smP = si.getMatrixByCol();

            OSIUNITTEST_ASSERT_ERROR(smP->getMajorDim()    ==  8, return, "glpk", "getMatrixByCol: major dim");
            OSIUNITTEST_ASSERT_ERROR(smP->getMinorDim()    ==  5, return, "glpk", "getMatrixByCol: minor dim");
            OSIUNITTEST_ASSERT_ERROR(smP->getNumElements() == 14, return, "glpk", "getMatrixByCol: number of elements");
            OSIUNITTEST_ASSERT_ERROR(smP->getSizeVectorStarts() == 9, return, "glpk", "getMatrixByCol: vector starts size");

            CoinRelFltEq eq;
            const double * ev = smP->getElements();
            // Unlike row-ordered matrices, GLPK does column-ordered the "normal" way
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0], 3.0), {}, "glpk", "getMatrixByCol: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1], 5.6), {}, "glpk", "getMatrixByCol: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2], 1.0), {}, "glpk", "getMatrixByCol: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3], 2.0), {}, "glpk", "getMatrixByCol: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4], 1.1), {}, "glpk", "getMatrixByCol: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 1.0), {}, "glpk", "getMatrixByCol: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6],-2.0), {}, "glpk", "getMatrixByCol: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 2.8), {}, "glpk", "getMatrixByCol: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8],-1.0), {}, "glpk", "getMatrixByCol: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9], 1.0), {}, "glpk", "getMatrixByCol: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[10], 1.0), {}, "glpk", "getMatrixByCol: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[11],-1.2), {}, "glpk", "getMatrixByCol: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[12],-1.0), {}, "glpk", "getMatrixByCol: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "glpk", "getMatrixByCol: elements");

            const CoinBigIndex * mi = smP->getVectorStarts();
            OSIUNITTEST_ASSERT_ERROR(mi[0] ==  0, {}, "glpk", "getMatrixByCol: vector starts");
            OSIUNITTEST_ASSERT_ERROR(mi[1] ==  2, {}, "glpk", "getMatrixByCol: vector starts");
            OSIUNITTEST_ASSERT_ERROR(mi[2] ==  4, {}, "glpk", "getMatrixByCol: vector starts");
            OSIUNITTEST_ASSERT_ERROR(mi[3] ==  6, {}, "glpk", "getMatrixByCol: vector starts");
            OSIUNITTEST_ASSERT_ERROR(mi[4] ==  8, {}, "glpk", "getMatrixByCol: vector starts");
            OSIUNITTEST_ASSERT_ERROR(mi[5] == 10, {}, "glpk", "getMatrixByCol: vector starts");
            OSIUNITTEST_ASSERT_ERROR(mi[6] == 11, {}, "glpk", "getMatrixByCol: vector starts");
            OSIUNITTEST_ASSERT_ERROR(mi[7] == 12, {}, "glpk", "getMatrixByCol: vector starts");
            OSIUNITTEST_ASSERT_ERROR(mi[8] == 14, {}, "glpk", "getMatrixByCol: vector starts");

            const int * ei = smP->getIndices();
            OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "glpk", "getMatrixByCol: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 4, {}, "glpk", "getMatrixByCol: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 0, {}, "glpk", "getMatrixByCol: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 1, {}, "glpk", "getMatrixByCol: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 1, {}, "glpk", "getMatrixByCol: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 2, {}, "glpk", "getMatrixByCol: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 0, {}, "glpk", "getMatrixByCol: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 3, {}, "glpk", "getMatrixByCol: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 0, {}, "glpk", "getMatrixByCol: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 4, {}, "glpk", "getMatrixByCol: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[10] == 2, {}, "glpk", "getMatrixByCol: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[11] == 3, {}, "glpk", "getMatrixByCol: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[12] == 0, {}, "glpk", "getMatrixByCol: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[13] == 4, {}, "glpk", "getMatrixByCol: indices");
        }
        //--------------
        // Test rowsense, rhs, rowrange, matrixByRow
        {
            OsiGlpkSolverInterface lhs;
            {
#if 0  // FIXME ??? these won't work because the copy constructor changes the values in m
                OSIUNITTEST_ASSERT_ERROR(m.rowrange_ == NULL, {}, "glpk", "???");
                OSIUNITTEST_ASSERT_ERROR(m.rowsense_ == NULL, {}, "glpk", "???");
                OSIUNITTEST_ASSERT_ERROR(m.rhs_ == NULL, {}, "glpk", "???");
                OSIUNITTEST_ASSERT_ERROR(m.matrixByRow_ == NULL, {}, "glpk", "???");
#endif

                OsiGlpkSolverInterface siC1(m);
                OSIUNITTEST_ASSERT_WARNING(siC1.rowrange_ == NULL, {}, "glpk", "row range");
                OSIUNITTEST_ASSERT_WARNING(siC1.rowsense_ == NULL, {}, "glpk", "row sense");
                OSIUNITTEST_ASSERT_WARNING(siC1.rhs_ == NULL, {}, "glpk", "right hand side");
                OSIUNITTEST_ASSERT_WARNING(siC1.matrixByRow_ == NULL, {}, "glpk", "matrix by row");

                const char   * siC1rs  = siC1.getRowSense();
                OSIUNITTEST_ASSERT_ERROR(siC1rs[0] == 'G', {}, "glpk", "row sense");
                OSIUNITTEST_ASSERT_ERROR(siC1rs[1] == 'L', {}, "glpk", "row sense");
                OSIUNITTEST_ASSERT_ERROR(siC1rs[2] == 'E', {}, "glpk", "row sense");
                OSIUNITTEST_ASSERT_ERROR(siC1rs[3] == 'R', {}, "glpk", "row sense");
                OSIUNITTEST_ASSERT_ERROR(siC1rs[4] == 'R', {}, "glpk", "row sense");

                const double * siC1rhs = siC1.getRightHandSide();
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[0],2.5), {}, "glpk", "right hand side");
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[1],2.1), {}, "glpk", "right hand side");
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[2],4.0), {}, "glpk", "right hand side");
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[3],5.0), {}, "glpk", "right hand side");
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[4],15.), {}, "glpk", "right hand side");

                const double * siC1rr  = siC1.getRowRange();
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[0],0.0), {}, "glpk", "row range");
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[1],0.0), {}, "glpk", "row range");
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[2],0.0), {}, "glpk", "row range");
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[3],5.0-1.8), {}, "glpk", "row range");
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[4],15.0-3.0), {}, "glpk", "row range");

                const CoinPackedMatrix * siC1mbr = siC1.getMatrixByRow();
                OSIUNITTEST_ASSERT_ERROR(siC1mbr != NULL, {}, "glpk", "matrix by row");
                OSIUNITTEST_ASSERT_ERROR(siC1mbr->getMajorDim()    ==  5, return, "glpk", "matrix by row: major dim");
                OSIUNITTEST_ASSERT_ERROR(siC1mbr->getNumElements() == 14, return, "glpk", "matrix by row: num elements");

                const double * ev = siC1mbr->getElements();
                OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4], 3.0), {}, "glpk", "matrix by row: elements");
                OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3], 1.0), {}, "glpk", "matrix by row: elements");
                OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2],-2.0), {}, "glpk", "matrix by row: elements");
                OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1],-1.0), {}, "glpk", "matrix by row: elements");
                OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0],-1.0), {}, "glpk", "matrix by row: elements");
                OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6], 2.0), {}, "glpk", "matrix by row: elements");
                OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 1.1), {}, "glpk", "matrix by row: elements");
                OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8], 1.0), {}, "glpk", "matrix by row: elements");
                OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 1.0), {}, "glpk", "matrix by row: elements");
                OSIUNITTEST_ASSERT_ERROR(eq(ev[10], 2.8), {}, "glpk", "matrix by row: elements");
                OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9],-1.2), {}, "glpk", "matrix by row: elements");
                OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 5.6), {}, "glpk", "matrix by row: elements");
                OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "glpk", "matrix by row: elements");
                OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 1.9), {}, "glpk", "matrix by row: elements");

                const CoinBigIndex * mi = siC1mbr->getVectorStarts();
                OSIUNITTEST_ASSERT_ERROR(mi[0] ==  0, {}, "glpk", "matrix by row: vector starts");
                OSIUNITTEST_ASSERT_ERROR(mi[1] ==  5, {}, "glpk", "matrix by row: vector starts");
                OSIUNITTEST_ASSERT_ERROR(mi[2] ==  7, {}, "glpk", "matrix by row: vector starts");
                OSIUNITTEST_ASSERT_ERROR(mi[3] ==  9, {}, "glpk", "matrix by row: vector starts");
                OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "glpk", "matrix by row: vector starts");
                OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "glpk", "matrix by row: vector starts");

                const int * ei = siC1mbr->getIndices();
                OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 0, {}, "glpk", "matrix by row: indices");
                OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 1, {}, "glpk", "matrix by row: indices");
                OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "glpk", "matrix by row: indices");
                OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 4, {}, "glpk", "matrix by row: indices");
                OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 7, {}, "glpk", "matrix by row: indices");
                OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 1, {}, "glpk", "matrix by row: indices");
                OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 2, {}, "glpk", "matrix by row: indices");
                OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 2, {}, "glpk", "matrix by row: indices");
                OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 5, {}, "glpk", "matrix by row: indices");
                OSIUNITTEST_ASSERT_ERROR(ei[10] == 3, {}, "glpk", "matrix by row: indices");
                OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 6, {}, "glpk", "matrix by row: indices");
                OSIUNITTEST_ASSERT_ERROR(ei[13] == 0, {}, "glpk", "matrix by row: indices");
                OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "glpk", "matrix by row: indices");
                OSIUNITTEST_ASSERT_ERROR(ei[11] == 7, {}, "glpk", "matrix by row: indices");

                OSIUNITTEST_ASSERT_WARNING(siC1rs  == siC1.getRowSense(), {}, "glpk", "row sense");
                OSIUNITTEST_ASSERT_WARNING(siC1rhs == siC1.getRightHandSide(), {}, "glpk", "right hand side");
                OSIUNITTEST_ASSERT_WARNING(siC1rr  == siC1.getRowRange(), {}, "glpk", "row range");

                // Change glpk Model by adding free row
                OsiRowCut rc;
                rc.setLb(-COIN_DBL_MAX);
                rc.setUb( COIN_DBL_MAX);
                OsiCuts cuts;
                cuts.insert(rc);
                siC1.applyCuts(cuts);

                // Since model was changed, test that cached data is now freed.
                OSIUNITTEST_ASSERT_ERROR(siC1.rowrange_ == NULL, {}, "glpk", "free cached data after adding row");
                OSIUNITTEST_ASSERT_ERROR(siC1.rowsense_ == NULL, {}, "glpk", "free cached data after adding row");
                OSIUNITTEST_ASSERT_ERROR(siC1.rhs_ == NULL, {}, "glpk", "free cached data after adding row");
                OSIUNITTEST_ASSERT_ERROR(siC1.matrixByRow_ == NULL, {}, "glpk", "free cached data after adding row");

                siC1rs  = siC1.getRowSense();
                OSIUNITTEST_ASSERT_ERROR(siC1rs[0] == 'G', {}, "glpk", "row sense after adding row");
                OSIUNITTEST_ASSERT_ERROR(siC1rs[1] == 'L', {}, "glpk", "row sense after adding row");
                OSIUNITTEST_ASSERT_ERROR(siC1rs[2] == 'E', {}, "glpk", "row sense after adding row");
                OSIUNITTEST_ASSERT_ERROR(siC1rs[3] == 'R', {}, "glpk", "row sense after adding row");
                OSIUNITTEST_ASSERT_ERROR(siC1rs[4] == 'R', {}, "glpk", "row sense after adding row");
                OSIUNITTEST_ASSERT_ERROR(siC1rs[5] == 'N', {}, "glpk", "row sense after adding row");

                siC1rhs = siC1.getRightHandSide();
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[0],2.5), {}, "glpk", "right hand side after adding row");
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[1],2.1), {}, "glpk", "right hand side after adding row");
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[2],4.0), {}, "glpk", "right hand side after adding row");
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[3],5.0), {}, "glpk", "right hand side after adding row");
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[4],15.), {}, "glpk", "right hand side after adding row");
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[5],0.0), {}, "glpk", "right hand side after adding row");

                siC1rr  = siC1.getRowRange();
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[0],0.0), {}, "glpk", "row range after adding row");
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[1],0.0), {}, "glpk", "row range after adding row");
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[2],0.0), {}, "glpk", "row range after adding row");
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[3],5.0-1.8), {}, "glpk", "row range after adding row");
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[4],15.0-3.0), {}, "glpk", "row range after adding row");
                OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[5],0.0), {}, "glpk", "row range after adding row");

                lhs = siC1;
            }
            // Test that lhs has correct values even though siC1 has gone out of scope
            OSIUNITTEST_ASSERT_ERROR(lhs.rowrange_ == NULL, {}, "glpk", "freed origin after assignment");
            OSIUNITTEST_ASSERT_ERROR(lhs.rowsense_ == NULL, {}, "glpk", "freed origin after assignment");
            OSIUNITTEST_ASSERT_ERROR(lhs.rhs_ == NULL, {}, "glpk", "freed origin after assignment");
            OSIUNITTEST_ASSERT_ERROR(lhs.matrixByRow_ == NULL, {}, "glpk", "freed origin after assignment");

            const char * lhsrs  = lhs.getRowSense();
            OSIUNITTEST_ASSERT_ERROR(lhsrs[0] == 'G', {}, "glpk", "row sense after assignment");
            OSIUNITTEST_ASSERT_ERROR(lhsrs[1] == 'L', {}, "glpk", "row sense after assignment");
            OSIUNITTEST_ASSERT_ERROR(lhsrs[2] == 'E', {}, "glpk", "row sense after assignment");
            OSIUNITTEST_ASSERT_ERROR(lhsrs[3] == 'R', {}, "glpk", "row sense after assignment");
            OSIUNITTEST_ASSERT_ERROR(lhsrs[4] == 'R', {}, "glpk", "row sense after assignment");
            OSIUNITTEST_ASSERT_ERROR(lhsrs[5] == 'N', {}, "glpk", "row sense after assignment");

            const double * lhsrhs = lhs.getRightHandSide();
            OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[0],2.5), {}, "glpk", "right hand side after assignment");
            OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[1],2.1), {}, "glpk", "right hand side after assignment");
            OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[2],4.0), {}, "glpk", "right hand side after assignment");
            OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[3],5.0), {}, "glpk", "right hand side after assignment");
            OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[4],15.), {}, "glpk", "right hand side after assignment");
            OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[5],0.0), {}, "glpk", "right hand side after assignment");

            const double *lhsrr = lhs.getRowRange();
            OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[0],0.0), {}, "glpk", "row range after assignment");
            OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[1],0.0), {}, "glpk", "row range after assignment");
            OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[2],0.0), {}, "glpk", "row range after assignment");
            OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[3],5.0-1.8), {}, "glpk", "row range after assignment");
            OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[4],15.0-3.0), {}, "glpk", "row range after assignment");
            OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[5],0.0), {}, "glpk", "row range after assignment");

            const CoinPackedMatrix * lhsmbr = lhs.getMatrixByRow();
            OSIUNITTEST_ASSERT_ERROR(lhsmbr != NULL, return, "glpk", "matrix by row after assignment");
            OSIUNITTEST_ASSERT_ERROR(lhsmbr->getMajorDim()    ==  6, return, "glpk", "matrix by row after assignment: major dim");
            OSIUNITTEST_ASSERT_ERROR(lhsmbr->getNumElements() == 14, return, "glpk", "matrix by row after assignment: num elements");

            const double * ev = lhsmbr->getElements();
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4], 3.0), {}, "glpk", "matrix by row after assignment: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3], 1.0), {}, "glpk", "matrix by row after assignment: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2],-2.0), {}, "glpk", "matrix by row after assignment: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1],-1.0), {}, "glpk", "matrix by row after assignment: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0],-1.0), {}, "glpk", "matrix by row after assignment: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6], 2.0), {}, "glpk", "matrix by row after assignment: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 1.1), {}, "glpk", "matrix by row after assignment: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8], 1.0), {}, "glpk", "matrix by row after assignment: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 1.0), {}, "glpk", "matrix by row after assignment: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[10], 2.8), {}, "glpk", "matrix by row after assignment: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9],-1.2), {}, "glpk", "matrix by row after assignment: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 5.6), {}, "glpk", "matrix by row after assignment: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "glpk", "matrix by row after assignment: elements");
            OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 1.9), {}, "glpk", "matrix by row after assignment: elements");

            const CoinBigIndex * mi = lhsmbr->getVectorStarts();
            OSIUNITTEST_ASSERT_ERROR(mi[0] ==  0, {}, "glpk", "matrix by row after assignment: vector starts");
            OSIUNITTEST_ASSERT_ERROR(mi[1] ==  5, {}, "glpk", "matrix by row after assignment: vector starts");
            OSIUNITTEST_ASSERT_ERROR(mi[2] ==  7, {}, "glpk", "matrix by row after assignment: vector starts");
            OSIUNITTEST_ASSERT_ERROR(mi[3] ==  9, {}, "glpk", "matrix by row after assignment: vector starts");
            OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "glpk", "matrix by row after assignment: vector starts");
            OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "glpk", "matrix by row after assignment: vector starts");

            const int * ei = lhsmbr->getIndices();
            OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 0, {}, "glpk", "matrix by row after assignment: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 1, {}, "glpk", "matrix by row after assignment: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "glpk", "matrix by row after assignment: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 4, {}, "glpk", "matrix by row after assignment: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 7, {}, "glpk", "matrix by row after assignment: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 1, {}, "glpk", "matrix by row after assignment: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 2, {}, "glpk", "matrix by row after assignment: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 2, {}, "glpk", "matrix by row after assignment: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 5, {}, "glpk", "matrix by row after assignment: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[10] == 3, {}, "glpk", "matrix by row after assignment: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 6, {}, "glpk", "matrix by row after assignment: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[13] == 0, {}, "glpk", "matrix by row after assignment: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "glpk", "matrix by row after assignment: indices");
            OSIUNITTEST_ASSERT_ERROR(ei[11] == 7, {}, "glpk", "matrix by row after assignment: indices");
        }

    }

    // Test add/delete columns
    {
        OsiGlpkSolverInterface m;
        std::string fn = mpsDir+"p0033";
        m.readMps(fn.c_str(),"mps");
        double inf = m.getInfinity();

        CoinPackedVector c0;
        c0.insert(0, 4);
        c0.insert(1, 1);
        m.addCol(c0, 0, inf, 3);
        m.initialSolve();
        double objValue = m.getObjValue();
        CoinRelFltEq eq(1.0e-2);
        OSIUNITTEST_ASSERT_ERROR(eq(objValue,2520.57), {}, "glpk", "add/delete columns: first optimal value");
        // Try deleting first column that's nonbasic at lower bound (0).
        int * d = new int[1];
        CoinWarmStartBasis *cwsb = dynamic_cast<CoinWarmStartBasis *>(m.getWarmStart()) ;
        OSIUNITTEST_ASSERT_ERROR(cwsb != NULL, {}, "glpk", "add/delete columns: have warm start basis");
        CoinWarmStartBasis::Status stati ;
        int iCol ;
        for (iCol = 0 ;  iCol < cwsb->getNumStructural() ; iCol++)
        {   stati = cwsb->getStructStatus(iCol) ;
            if (stati == CoinWarmStartBasis::atLowerBound) break ;
        }
        d[0]=iCol;
        m.deleteCols(1,d);
        delete [] d;
        delete cwsb;
        d=NULL;
        m.resolve();
        objValue = m.getObjValue();
        OSIUNITTEST_ASSERT_ERROR(eq(objValue,2520.57), {}, "glpk", "add/delete columns: optimal value after deleting nonbasic column");
        // Try deleting column we added. If basic, go to initialSolve as deleting
        // basic variable trashes basis required for warm start.
        iCol = m.getNumCols()-1;
        cwsb = dynamic_cast<CoinWarmStartBasis *>(m.getWarmStart()) ;
        stati =  cwsb->getStructStatus(iCol) ;
        delete cwsb;
        m.deleteCols(1,&iCol);
        if (stati == CoinWarmStartBasis::basic)
        {
            m.initialSolve() ;
        }
        else
        {
            m.resolve();
        }
        objValue = m.getObjValue();
        OSIUNITTEST_ASSERT_ERROR(eq(objValue,2520.57), {}, "glpk", "add/delete columns: optimal value after deleting added column");
    }

#if 0
    // ??? Simplex routines not adapted to OsiGlpk yet

    // Solve an lp by hand
    {
        OsiGlpkSolverInterface m;
        std::string fn = mpsDir+"p0033";
        m.readMps(fn.c_str(),"mps");
        m.setObjSense(-1.0);
        m.getModelPtr()->messageHandler()->setLogLevel(4);
        m.initialSolve();
        m.getModelPtr()->factorization()->maximumPivots(5);
        m.setObjSense(1.0);
        // enable special mode
        m.enableSimplexInterface(true);
        // we happen to know that variables are 0-1 and rows are L
        int numberIterations=0;
        int numberColumns = m.getNumCols();
        int numberRows = m.getNumRows();
        double * fakeCost = new double[numberColumns];
        double * duals = new double [numberRows];
        double * djs = new double [numberColumns];
        const double * solution = m.getColSolution();
        memcpy(fakeCost,m.getObjCoefficients(),numberColumns*sizeof(double));
        while (1) {
            const double * dj;
            const double * dual;
            if ((numberIterations&1)==0) {
                // use given ones
                dj = m.getReducedCost();
                dual = m.getRowPrice();
            } else {
                // create
                dj = djs;
                dual = duals;
                m.getReducedGradient(djs,duals,fakeCost);
            }
            int i;
            int colIn=9999;
            int direction=1;
            double best=1.0e-6;
            // find most negative reduced cost
            // Should check basic - but should be okay on this problem
            for (i=0; i<numberRows; i++) {
                double value=dual[i];
                if (value>best) {
                    direction=-1;
                    best=value;
                    colIn=-i-1;
                }
            }
            for (i=0; i<numberColumns; i++) {
                double value=dj[i];
                if (value<-best&&solution[i]<1.0e-6) {
                    direction=1;
                    best=-value;
                    colIn=i;
                } else if (value>best&&solution[i]>1.0-1.0e-6) {
                    direction=-1;
                    best=value;
                    colIn=i;
                }
            }
            if (colIn==9999)
                break; // should be optimal
            int colOut;
            int outStatus;
            double theta;
            OSIUNITTEST_ASSERT_ERROR(m.primalPivotResult(colIn,direction,colOut,outStatus,theta,NULL) == 0, {}, "glpk", "simplex routines");
            printf("out %d, direction %d theta %g\n", colOut,outStatus,theta);
            numberIterations++;
        }
        delete [] fakeCost;
        delete [] duals;
        delete [] djs;
        // exit special mode
        m.disableSimplexInterface();
        m.getModelPtr()->messageHandler()->setLogLevel(4);
        m.resolve();
        OSIUNITTEST_ASSERT_ERROR(m.getIterationCount() == 0, {}, "glpk", "simplex routines");
        m.setObjSense(-1.0);
        m.initialSolve();
    }
    // Solve an lp when interface is on
    {
        OsiGlpkSolverInterface m;
        std::string fn = mpsDir+"p0033";
        m.readMps(fn.c_str(),"mps");
        // enable special mode
        m.setHintParam(OsiDoScale,false,OsiHintDo);
        m.setHintParam(OsiDoPresolveInInitial,false,OsiHintDo);
        m.setHintParam(OsiDoDualInInitial,false,OsiHintDo);
        m.setHintParam(OsiDoPresolveInResolve,false,OsiHintDo);
        m.setHintParam(OsiDoDualInResolve,false,OsiHintDo);
        m.enableSimplexInterface(true);
        m.initialSolve();
    }
    // Check tableau stuff when simplex interface is on
    {
        OsiGlpkSolverInterface m;
        /*
           Wolsey : Page 130
           max 4x1 -  x2
           7x1 - 2x2    <= 14
           x2    <= 3
           2x1 - 2x2    <= 3
           x1 in Z+, x2 >= 0
        */

        double inf_ = m.getInfinity();
        int n_cols = 2;
        int n_rows = 3;

        double obj[2] = {-4.0, 1.0};
        double collb[2] = {0.0, 0.0};
        double colub[2] = {inf_, inf_};
        double rowlb[3] = {-inf_, -inf_, -inf_};
        double rowub[3] = {14.0, 3.0, 3.0};

        int rowIndices[5] =  {0,     2,    0,    1,    2};
        int colIndices[5] =  {0,     0,    1,    1,    1};
        double elements[5] = {7.0, 2.0, -2.0,  1.0, -2.0};
        CoinPackedMatrix M(true, rowIndices, colIndices, elements, 5);

        m.loadProblem(M, collb, colub, obj, rowlb, rowub);
        m.enableSimplexInterface(true);

        m.initialSolve();

        //check that the tableau matches wolsey (B-1 A)
        // slacks in second part of binvA
        double * binvA = (double*) malloc((n_cols+n_rows) * sizeof(double));

        printf("B-1 A");
        for(int i = 0; i < n_rows; i++) {
            m.getBInvARow(i, binvA,binvA+n_cols);
            printf("\nrow: %d -> ",i);
            for(int j=0; j < n_cols+n_rows; j++) {
                printf("%g, ", binvA[j]);
            }
        }
        printf("\n");
        m.disableSimplexInterface();
        free(binvA);
    }
#endif

    /*
      Read in exmip1 and solve it with verbose output setting.
    */
    {   OsiGlpkSolverInterface osi ;
        std::cout << "Boosting verbosity.\n" ;
        osi.setHintParam(OsiDoReducePrint,false,OsiForceDo) ;

        std::string exmpsfile = mpsDir+"exmip1" ;
        std::string probname ;
        std::cout << "Reading mps file \"" << exmpsfile << "\"\n" ;
        osi.readMps(exmpsfile.c_str(), "mps") ;
        OSIUNITTEST_ASSERT_ERROR(osi.getStrParam(OsiProbName,probname), {}, "glpk", "get problem name");
        std::cout << "Solving " << probname << " ... \n" ;
        osi.initialSolve() ;
        double val = osi.getObjValue() ;
        std::cout << "And the answer is " << val << ".\n" ;
        OSIUNITTEST_ASSERT_ERROR(fabs(val - 3.23) < 0.01, {}, "glpk", "solve exmip1");
    }

    // Do common solverInterface testing
    {
        OsiGlpkSolverInterface m;
        OsiSolverInterfaceCommonUnitTest(&m, mpsDir,netlibDir);
    }

}
Example #3
0
//--------------------------------------------------------------------------
// test EKKsolution methods.
void
CglProbingUnitTest(
  const OsiSolverInterface * baseSiP,
  const std::string mpsDir )
{
# ifdef CGL_DEBUG
  int i ;	// define just once
# endif
  CoinRelFltEq eq(0.000001);

  // Test default constructor
  {
    CglProbing aGenerator;
  }

  // Test copy & assignment
  {
    CglProbing rhs;
    {
      CglProbing bGenerator;
      CglProbing cGenerator(bGenerator);
      rhs=bGenerator;
    }
  }

  {
    OsiCuts osicuts;
    CglProbing test1;
    OsiSolverInterface  * siP = baseSiP->clone();
    int nColCuts;
    int nRowCuts;

    std::string fn = mpsDir+"p0033";
    siP->readMps(fn.c_str(),"mps");
    siP->initialSolve();
    // just unsatisfied variables
    test1.generateCuts(*siP,osicuts);
    nColCuts = osicuts.sizeColCuts();
    nRowCuts = osicuts.sizeRowCuts();
    std::cout<<"There are "<<nRowCuts<<" probing cuts"<<std::endl;
    {
      std::cout<<"there are "<<nColCuts<<" probing column cuts"<<std::endl;

#ifdef CGL_DEBUG
      const double * lo = siP->getColLower();
      const double * up = siP->getColUpper();
      for (i=0; i<nColCuts; i++){
	OsiColCut ccut;
	CoinPackedVector cpv;
	ccut = osicuts.colCut(i);
	cpv = ccut.lbs();
	int n = cpv.getNumElements();
        int j;
	const int * indices = cpv.getIndices();
	double* elements = cpv.getElements();
	for (j=0;j<n;j++) {
	  int icol=indices[j];
	  if (elements[j]>lo[icol])
	    std::cout<<"Can increase lb on "<<icol<<" from "<<lo[icol]<<
	      " to "<<elements[j]<<std::endl;
	}
	cpv = ccut.ubs();
	n = cpv.getNumElements();
	indices = cpv.getIndices();
	elements = cpv.getElements();

	for (j=0;j<n;j++) {
	  int icol=indices[j];
	  if (elements[j]<up[icol])
	    std::cout<<"Can decrease ub on "<<icol<<" from "<<up[icol]<<
	      " to "<<elements[j]<<std::endl;
	}
      }

#endif

    }

#ifdef CGL_DEBUG
    for (i=0; i<nRowCuts; i++){
      OsiRowCut rcut;
      CoinPackedVector rpv;
      const double * colsol = siP->getColSolution();
      rcut = osicuts.rowCut(i);
      rpv = rcut.row();
      const int n = rpv.getNumElements();
      const int * indices = rpv.getIndices();
      double* elements = rpv.getElements();
      double sum2=0.0;
      int k=0;
      double lb=rcut.lb();
      double ub=rcut.ub();
      for (k=0; k<n; k++){
	int column=indices[k];
	sum2 += colsol[column]*elements[k];
      }
      if (sum2 >ub + 1.0e-7 ||sum2 < lb - 1.0e-7) {
	std::cout<<"Cut "<<i<<" lb "<<lb<<" solution "<<sum2<<" ub "<<ub<<std::endl;
	for (k=0; k<n; k++){
	  int column=indices[k];
	  std::cout<<"(col="<<column<<",el="<<elements[k]<<",sol="<<
	    colsol[column]<<") ";
	}
	std::cout <<std::endl;
      }
    }
#endif

    if (nRowCuts==1) {
      CoinPackedVector check;
      int index[] = {6,32};
      double el[] = {1,1};
      check.setVector(2,index,el);
      // sort Elements in increasing order
      CoinPackedVector rpv=osicuts.rowCut(0).row();
      assert (rpv.getNumElements()==2);
      rpv.sortIncrIndex();
      assert (check==rpv);
      assert (osicuts.rowCut(0).lb()==1.0);
    }
    // now all variables
    osicuts=OsiCuts();
    test1.setMode(2);
    test1.setRowCuts(3);
    test1.generateCuts(*siP,osicuts);
    nColCuts = osicuts.sizeColCuts();
    nRowCuts = osicuts.sizeRowCuts();
    std::cout<<"There are "<<nRowCuts<<" probing cuts"<<std::endl;
    {
      std::cout<<"there are "<<nColCuts<<" probing column cuts"<<std::endl;

#ifdef CGL_DEBUG
      const double * lo = siP->getColLower();
      const double * up = siP->getColUpper();
      for (i=0; i<nColCuts; i++){
	OsiColCut ccut;
	CoinPackedVector cpv;
	ccut = osicuts.colCut(i);
	cpv = ccut.lbs();
	int n = cpv.getNumElements();
        int j;
	const int * indices = cpv.getIndices();
	double* elements = cpv.getElements();
	for (j=0;j<n;j++) {
	  int icol=indices[j];
	  if (elements[j]>lo[icol])
	    std::cout<<"Can increase lb on "<<icol<<" from "<<lo[icol]<<
	      " to "<<elements[j]<<std::endl;
	}
	cpv = ccut.ubs();
	n = cpv.getNumElements();
	indices = cpv.getIndices();
	elements = cpv.getElements();
	for (j=0;j<n;j++) {
	  int icol=indices[j];
	  if (elements[j]<up[icol])
	    std::cout<<"Can decrease ub on "<<icol<<" from "<<up[icol]<<
	      " to "<<elements[j]<<std::endl;
	}
      }
#endif

    }

#ifdef CGL_DEBUG
    for (i=0; i<nRowCuts; i++){
      OsiRowCut rcut;
      CoinPackedVector rpv;
      const double * colsol = siP->getColSolution();
      rcut = osicuts.rowCut(i);
      rpv = rcut.row();
      const int n = rpv.getNumElements();
      const int * indices = rpv.getIndices();
      double* elements = rpv.getElements();
      double sum2=0.0;
      int k=0;
      double lb=rcut.lb();
      double ub=rcut.ub();
      for (k=0; k<n; k++){
	int column=indices[k];
	sum2 += colsol[column]*elements[k];
      }
      if (sum2 >ub + 1.0e-7 ||sum2 < lb - 1.0e-7) {
	std::cout<<"Cut "<<i<<" lb "<<lb<<" solution "<<sum2<<" ub "<<ub<<std::endl;
	for (k=0; k<n; k++){
	  int column=indices[k];
	  std::cout<<"(col="<<column<<",el="<<elements[k]<<",sol="<<
	    colsol[column]<<") ";
	}
	std::cout <<std::endl;
      }
    }
#endif

    assert (osicuts.sizeRowCuts()>=4);
    delete siP;
  }

}
Example #4
0
//-----------------------------------------------------------------------------
// Generate LSGFC cuts
//------------------------------------------------------------------- 
void CglFlowCover::generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
				const CglTreeInfo info)
{
  static int count=0;
  if (getMaxNumCuts() <= 0) return;
    
  if (getNumFlowCuts() >= getMaxNumCuts()) return;
  ++count;

#if 0
  bool preInit = false;
  bool preReso = false;
  si.getHintParam(OsiDoPresolveInInitial, preInit);
  si.getHintParam(OsiDoPresolveInResolve, preReso);

  if (preInit == false &&  preReso == false) { // Do once
    if (doneInitPre_ == false) {   
      flowPreprocess(si);
      doneInitPre_ = true;
    }
  }
  else
#endif
    int numberRowCutsBefore = cs.sizeRowCuts();
    
  flowPreprocess(si);

  CoinPackedMatrix matrixByRow(*si.getMatrixByRow());
  const char* sense = si.getRowSense();
  const double* rhs = si.getRightHandSide();

  const double* elementByRow = matrixByRow.getElements();
  const int* colInd = matrixByRow.getIndices();
  const CoinBigIndex* rowStart = matrixByRow.getVectorStarts();
  const int* rowLength = matrixByRow.getVectorLengths();
    
  int* ind        = 0;
  double* coef    = 0;
  int iRow, iCol;

  CglFlowRowType rType;

  for (iRow = 0; iRow < numRows_; ++iRow) {
    rType = getRowType(iRow);
    if( ( rType != CGLFLOW_ROW_MIXUB ) &&
	( rType != CGLFLOW_ROW_MIXEQ ) &&
	( rType != CGLFLOW_ROW_NOBINUB ) &&
	( rType != CGLFLOW_ROW_NOBINEQ ) &&
	( rType != CGLFLOW_ROW_SUMVARUB ) &&
	( rType != CGLFLOW_ROW_SUMVAREQ ) )
      continue;  

    const int sta = rowStart[iRow];     // Start position of iRow
    const int rowLen = rowLength[iRow]; // iRow length / non-zero elements

    if (ind != 0) { delete [] ind; ind = 0; }
    ind = new int [rowLen];
    if (coef != 0) { delete [] coef; coef = 0; }
    coef = new double [rowLen];

    int lastPos = sta + rowLen;
    for (iCol = sta; iCol < lastPos; ++iCol) {
      ind[iCol - sta]  = colInd[iCol];
      coef[iCol - sta] = elementByRow[iCol];
    }

    OsiRowCut flowCut1, flowCut2, flowCut3;
    double violation = 0.0;
    bool hasCut = false;

    if (sense[iRow] == 'E') {
      hasCut = generateOneFlowCut(si, rowLen, ind, coef, 'L', 
				  rhs[iRow], flowCut1, violation);
      if (hasCut)  {                         // If find a cut
	cs.insert(flowCut1);
	incNumFlowCuts();
	if (getNumFlowCuts() >= getMaxNumCuts())
	  break;
      }
      hasCut = false;
      hasCut = generateOneFlowCut(si, rowLen, ind, coef, 'G', 
				  rhs[iRow], flowCut2, violation);
      if (hasCut)  {
	cs.insert(flowCut2);
	incNumFlowCuts();
	if (getNumFlowCuts() >= getMaxNumCuts())
	  break;
      }
    }
    if (sense[iRow] == 'L' || sense[iRow] == 'G') {
      hasCut = generateOneFlowCut(si, rowLen, ind, coef, sense[iRow], 
				  rhs[iRow], flowCut3, violation);
      if (hasCut)  {
	cs.insert(flowCut3);
	incNumFlowCuts();
	if (getNumFlowCuts() >= getMaxNumCuts())
	  break;
      }
    }
  }


#ifdef CGLFLOW_DEBUG2
  if(CGLFLOW_DEBUG) {
    std::cout << "\nnumFlowCuts = "<< getNumFlowCuts()  << std::endl;
    std::cout << "CGLFLOW_COL_BINNEG = "<< CGLFLOW_COL_BINNEG  << std::endl;
  }
#endif
  if (!info.inTree&&((info.options&4)==4||((info.options&8)&&!info.pass))) {
    int numberRowCutsAfter = cs.sizeRowCuts();
    for (int i=numberRowCutsBefore;i<numberRowCutsAfter;i++)
      cs.rowCutPtr(i)->setGloballyValid();
  }

  if (ind != 0)  { delete [] ind; ind = 0; }
  if (coef != 0) { delete [] coef; coef = 0; }
}
Example #5
0
//-------------------------------------------------------------------
// Generate cuts
//-------------------------------------------------------------------
void CglAllDifferent::generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
			      const CglTreeInfo ) const
{
#ifndef NDEBUG
  int nCols=si.getNumCols();
#endif
  int i;
  const double * lower = si.getColLower();
  const double * upper = si.getColUpper();
#ifdef CGL_DEBUG
  const OsiRowCutDebugger * debugger = si.getRowCutDebugger();
  if (debugger&&debugger->onOptimalPath(si)) {
    printf("On optimal path %d\n",nPath);
    nPath++;
    int nCols=si.getNumCols();
    const double * solution = si.getColSolution();
    const double * optimal = debugger->optimalSolution();
    const double * objective = si.getObjCoefficients();
    double objval1=0.0,objval2=0.0;
    for (i=0;i<nCols;i++) {
#if CGL_DEBUG>1
      printf("%d %g %g %g %g\n",i,lower[i],solution[i],upper[i],optimal[i]);
#endif
      objval1 += solution[i]*objective[i];
      objval2 += optimal[i]*objective[i];
      assert(optimal[i]>=lower[i]&&optimal[i]<=upper[i]);
    }
    printf("current obj %g, integer %g\n",objval1,objval2);
  }
#endif
  int * lo = new int[numberDifferent_];
  int * up = new int[numberDifferent_];
  for (i=0;i<numberDifferent_;i++) {
    int iColumn = originalWhich_[i];
    assert (iColumn<nCols);
    lo[i]  = static_cast<int> (lower[iColumn]);
    assert (floor(lower[iColumn]+0.5)==lower[iColumn]);
    up[i]  = static_cast<int> (upper[iColumn]);
    assert (floor(upper[iColumn]+0.5)==upper[iColumn]);
    assert (up[i]>=lo[i]);
  }
  // We are going to assume we can just have one big 2d array!
  // Could save by going to bits
  // also could skip sets where all are fixed
  // could do some of above by separate first pass
  // once a variable fixed - can take out of list
  // so need to redo complete stuff (including temp which_) every big pass
  int offset = COIN_INT_MAX;
  int maxValue = -COIN_INT_MAX;
  int numberLook=0;
  // copies
  //int * which = new int [numberTotal];
  //int * start = new int [numberSets_+1];
  for (i=0;i<numberSets_;i++) {
    for (int j=start_[i];j<start_[i+1];j++) {
      int k=which_[j];
      offset = CoinMin(offset,lo[k]);
      maxValue = CoinMax(maxValue,up[k]);
    }
    numberLook++;
    int gap = maxValue-offset+1;
    double size = static_cast<double> (gap) * numberDifferent_;
    if (size>1.0e7) {
      if (logLevel_)
        printf("Only looking at %d sets\n",numberLook);
      break;
    }
  }
  // Which sets a variable is in
  int * back = new int [start_[numberSets_]];
  int * backStart = new int[numberDifferent_+1];
  memset(backStart,0,(numberDifferent_+1)*sizeof(int));
  int numberTotal = start_[numberLook];
  for (i=0;i<numberTotal;i++) {
    int k=which_[i];
    // note +1
    backStart[k+1]++;
  }
  int n=0;
  for (i=0;i<numberDifferent_;i++) {
    int nThis = backStart[i+1];
    backStart[i+1]=n;
    n+= nThis;
  }
  // at end all backStart correct!
  for (i=0;i<numberLook;i++) {
    for (int j=start_[i];j<start_[i+1];j++) {
      int k=which_[j];
      // note +1
      int iPut = backStart[k+1];
      back[iPut]=i;
      backStart[k+1]=iPut+1;
    }
  }
  // value is possible for variable k if possible[k*gap+value] is nonzero
  int gap = maxValue-offset+1;
  char * possible = new char[gap*numberDifferent_];
  memset(possible,0,gap*numberDifferent_);
  // initialize
  int numberFixed=0;
  int * alreadyFixed = new int[numberDifferent_];
  for (i=0;i<numberDifferent_;i++) {
    alreadyFixed[i]=-1;
    int startV = i*gap + lo[i] - offset;
    int n = up[i]-lo[i]+1;
    memset(possible+startV,1,n);
  }
  for (i=0;i<numberDifferent_;i++) {
    int n = up[i]-lo[i]+1;
    if (n==1) {
      int fixedAt = lo[i]-offset;
      numberFixed++;
      alreadyFixed[i]=fixedAt;
      // take out of all others
      for (int j=backStart[i];j<backStart[i+1];j++) {
        int iSet = back[j];
        for (int jj=start_[iSet];jj<start_[iSet+1];jj++) {
          int k=which_[jj];
          if (k!=i) {
            // impossible
            possible[k*gap+fixedAt]=0;
          }
        }
      }
    }
  }
  bool finished=false;
  //int numberTightened=0;
  bool infeasible=false;
  // space to see which values possible
  int * check = new int[gap];
  unsigned int * bitmap = new unsigned int[numberDifferent_];
  int * stack = new int[numberDifferent_+1];
  int * first = new int[numberDifferent_+1];
  // just for valgrind etc
  memset(stack,0,(numberDifferent_+1)*sizeof(int));
  memset(first,0,(numberDifferent_+1)*sizeof(int));
  // do one set at a time
  while (!finished) {
    finished=true;
    int fixed=numberFixed;
    for (i=0;i<numberLook;i++) {
      memset(check,0,gap*sizeof(int));
      for (int j=start_[i];j<start_[i+1];j++) {
        int k=which_[j];
        if (alreadyFixed[k]>=0) {
          if (check[alreadyFixed[k]]==0) {
            check[alreadyFixed[k]]=1;
            continue;
          } else {
            // infeasible
            infeasible=true;
            i=numberLook;
            break;
          }
        }
        char * allowed = possible + k*gap;
        int n=0;
        for (int jj=0;jj<gap;jj++) {
          if (allowed[jj]) {
            n++;
            check[jj]++;
          }
        }
        if (n<2) {
          if (n==1) {
            // fix
            int fixedAt = -1;
            for (int jj=0;jj<gap;jj++) {
              if (allowed[jj]) {
                fixedAt=jj;
                break;
              }
            }
            numberFixed++;
            alreadyFixed[k]=fixedAt;
            check[fixedAt]=1;
            // take out of all others
            for (int j=backStart[k];j<backStart[k+1];j++) {
              int iSet = back[j];
              for (int jj=start_[iSet];jj<start_[iSet+1];jj++) {
                int kk=which_[jj];
                if (kk!=k) {
                  // impossible
                  possible[kk*gap+fixedAt]=0;
                }
              }
            }
          } else {
            // infeasible
            infeasible=true;
            j=numberTotal;
            i=numberLook;
            break;
          }
        }
      }
      // now check set
      // If number covered < number in set infeasible
      if (gap<30&&!infeasible) {
        int n=start_[i+1]-start_[i];
        memset(bitmap,0,n*sizeof(unsigned int));
        int j;
        int * which = which_+start_[i];
        unsigned int covered=0;
        bool good=true;
        for (j=0;j<n;j++) {
          int k=which[j];
          char * allowed = possible + k*gap;
          int jj;
          for (jj=0;jj<gap;jj++)
            if (allowed[jj])
              break;
          assert (jj<gap);
          first[j]=jj;
          unsigned int iBit = 1<<jj;
          if ((covered&iBit)==0) {
            stack[j]=jj;
            covered |= iBit;
          } else {
            // can't
            jj++;
            for (;jj<gap;jj++) {
              iBit  = iBit << 1;
              if (allowed[jj]&&(covered&iBit)==0)
                break;
            }
            if (jj<gap) {
              stack[j]=jj;
              covered |= iBit;
            } else {
              good = false;
              break;
            }
          }
        }
        int nStack=j;
        // just do first for rest
        for (;j<n;j++) {
          int k=which[j];
          char * allowed = possible + k*gap;
          int jj;
          for (jj=0;jj<gap;jj++)
            if (allowed[jj])
              break;
          assert (jj<gap);
          first[j]=jj;
        }
        int kLook=0;
        while (nStack) {
          nStack--;
          if (good) {
#if 0
            printf("con %d = ",i);
            for (j=0;j<n;j++)
              printf("%d ",stack[j]+1);
            printf("\n");
#endif
            // bug - kLook >= 0
            kLook=0;
            for (j=kLook;j<n;j++) {
              int iBit = 1 << stack[j];
              bitmap[j] |= iBit;
            }
          }
          kLook=nStack;
          int jj=stack[nStack];
          unsigned int iBit = 1<<jj;
          covered &= ~iBit;
          {
            unsigned int kBit=0;
            for (int k=0;k<nStack;k++) {
              int kk=stack[k];
              kBit |= 1<<kk;
            }
            assert (covered==kBit);
          }
          jj++;
          stack[nStack]=jj;
          while (nStack<n) {
            int k=which[nStack];
            char * allowed = possible + k*gap;
            for (;jj<gap;jj++) {
              iBit  = 1 << jj;
              if (allowed[jj]&&(covered&iBit)==0)
                break;
            }
            if (jj<gap) {
              stack[nStack]=jj;
              covered |= iBit;
              nStack++;
              stack[nStack]=first[nStack];
              jj = first[nStack];
              good=true;
            } else {
              good = false;
              break;
            }
          }
        }
        int nnFix=0;
        // Now see if we can fix any
        for (j=0;j<n;j++) {
          int k=which[j];
          unsigned int mapped = bitmap[j];
          char * allowed = possible + k*gap;
          unsigned int iBit=1;
          for (int jj=0;jj<gap;jj++) {
            if ((mapped&iBit)==0) {
              if (allowed[jj]) {
                if (!nnFix)
                  printf("for con %d x ",i);
                nnFix++;
                printf("%d not %d ",j,jj+1);
                allowed[jj]=0;
                finished=false;
              }
            }
            iBit  = iBit << 1;
          }
        }
        if (nnFix)
          printf("\n");
      }
    }
    if (numberFixed>fixed)
      finished=false; // try again
  }
  // Could try two sets
  if (infeasible) {
    // create infeasible cut
    OsiRowCut rc;
    rc.setLb(COIN_DBL_MAX);
    rc.setUb(0.0);
    cs.insert(rc);
  } else {
    // check to see if can tighten bounds
    CoinPackedVector lbs;
    CoinPackedVector ubs;
    int nTightened=0;
    for (i=0;i<numberDifferent_;i++) {
      int iColumn = originalWhich_[i];
      char * allowed = possible+i*gap;
      int firstLo=-1;
      int lastUp=-1;
      for (int jj=0;jj<gap;jj++) {
        if (allowed[jj]) {
          if (firstLo<0)
            firstLo=jj;
          lastUp = jj;
        }
      }
      if (firstLo+offset>lo[i]) {
        lbs.insert(iColumn,static_cast<double> (firstLo+offset));
        nTightened++;
      }
      if (lastUp+offset<up[i]) {
        ubs.insert(iColumn,static_cast<double> (lastUp+offset));
        nTightened++;
      }
    }
    if (nTightened) {
      OsiColCut cc;
      cc.setUbs(ubs);
      cc.setLbs(lbs);
      cc.setEffectiveness(100.0);
      cs.insert(cc);
    }
  }
  //delete [] which;
  //delete [] start;
  delete [] first;
  delete [] stack;
  delete [] bitmap;
  delete [] check;
  delete [] alreadyFixed;
  delete [] back;
  delete [] backStart;
  delete [] possible;
  delete [] lo;
  delete [] up;
}
Example #6
0
// This version fixes stuff and does IP
int
CbcHeuristicLocal::solutionFix(double & objectiveValue,
                               double * newSolution,
                               const int * /*keep*/)
{
/*
  If when is set to off (0), or set to root (1) and we're not at the root,
  return. If this heuristic discovered the current solution, don't continue.
*/

    numCouldRun_++;
    // See if to do
    if (!when() || (when() == 1 && model_->phase() != 1))
        return 0; // switched off
    // Don't do if it was this heuristic which found solution!
    if (this == model_->lastHeuristic())
        return 0;
/*
  Load up a new solver with the solution.

  Why continuousSolver(), as opposed to solver()?
*/
    OsiSolverInterface * newSolver = model_->continuousSolver()->clone();
    const double * colLower = newSolver->getColLower();
    //const double * colUpper = newSolver->getColUpper();

    int numberIntegers = model_->numberIntegers();
    const int * integerVariable = model_->integerVariable();
/*
  The net effect here is that anything that hasn't moved from its lower bound
  will be fixed at lower bound.

  See comments in solution() w.r.t. asymmetric treatment of upper and lower
  bounds.
*/

    int i;
    int nFix = 0;
    for (i = 0; i < numberIntegers; i++) {
        int iColumn = integerVariable[i];
        const OsiObject * object = model_->object(i);
        // get original bounds
        double originalLower;
        double originalUpper;
        getIntegerInformation( object, originalLower, originalUpper);
        newSolver->setColLower(iColumn, CoinMax(colLower[iColumn], originalLower));
        if (!used_[iColumn]) {
            newSolver->setColUpper(iColumn, colLower[iColumn]);
            nFix++;
        }
    }
/*
  Try a `small' branch-and-bound search. The notion here is that we've fixed a
  lot of variables and reduced the amount of `free' problem to a point where a
  small BaB search will suffice to fully explore the remaining problem. This
  routine will execute integer presolve, then call branchAndBound to do the
  actual search.
*/
    int returnCode = 0;
#ifdef CLP_INVESTIGATE2
    printf("Fixing %d out of %d (%d continuous)\n",
           nFix, numberIntegers, newSolver->getNumCols() - numberIntegers);
#endif
    if (nFix*10 <= numberIntegers) {
        // see if we can fix more
        int * which = new int [2*(numberIntegers-nFix)];
        int * sort = which + (numberIntegers - nFix);
        int n = 0;
        for (i = 0; i < numberIntegers; i++) {
            int iColumn = integerVariable[i];
            if (used_[iColumn]) {
                which[n] = iColumn;
                sort[n++] = used_[iColumn];
            }
        }
        CoinSort_2(sort, sort + n, which);
        // only half fixed in total
        n = CoinMin(n, numberIntegers / 2 - nFix);
        int allow = CoinMax(numberSolutions_ - 2, sort[0]);
        int nFix2 = 0;
        for (i = 0; i < n; i++) {
            int iColumn = integerVariable[i];
            if (used_[iColumn] <= allow) {
                newSolver->setColUpper(iColumn, colLower[iColumn]);
                nFix2++;
            } else {
                break;
            }
        }
        delete [] which;
        nFix += nFix2;
#ifdef CLP_INVESTIGATE2
        printf("Number fixed increased from %d to %d\n",
               nFix - nFix2, nFix);
#endif
    }
    if (nFix*10 > numberIntegers) {
        returnCode = smallBranchAndBound(newSolver, numberNodes_, newSolution, objectiveValue,
                                         objectiveValue, "CbcHeuristicLocal");
 /*
  -2 is return due to user event, and -1 is overloaded with what look to be
  two contradictory meanings.
*/
       if (returnCode < 0) {
            returnCode = 0; // returned on size
            int numberColumns = newSolver->getNumCols();
            int numberContinuous = numberColumns - numberIntegers;
            if (numberContinuous > 2*numberIntegers &&
                    nFix*10 < numberColumns) {
#define LOCAL_FIX_CONTINUOUS
#ifdef LOCAL_FIX_CONTINUOUS
                //const double * colUpper = newSolver->getColUpper();
                const double * colLower = newSolver->getColLower();
                int nAtLb = 0;
                //double sumDj=0.0;
                const double * dj = newSolver->getReducedCost();
                double direction = newSolver->getObjSense();
                for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
                    if (!newSolver->isInteger(iColumn)) {
                        if (!used_[iColumn]) {
                            //double djValue = dj[iColumn]*direction;
                            nAtLb++;
                            //sumDj += djValue;
                        }
                    }
                }
                if (nAtLb) {
                    // fix some continuous
                    double * sort = new double[nAtLb];
                    int * which = new int [nAtLb];
                    //double threshold = CoinMax((0.01*sumDj)/static_cast<double>(nAtLb),1.0e-6);
                    int nFix2 = 0;
                    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
                        if (!newSolver->isInteger(iColumn)) {
                            if (!used_[iColumn]) {
                                double djValue = dj[iColumn] * direction;
                                if (djValue > 1.0e-6) {
                                    sort[nFix2] = -djValue;
                                    which[nFix2++] = iColumn;
                                }
                            }
                        }
                    }
                    CoinSort_2(sort, sort + nFix2, which);
                    int divisor = 2;
                    nFix2 = CoinMin(nFix2, (numberColumns - nFix) / divisor);
                    for (int i = 0; i < nFix2; i++) {
                        int iColumn = which[i];
                        newSolver->setColUpper(iColumn, colLower[iColumn]);
                    }
                    delete [] sort;
                    delete [] which;
#ifdef CLP_INVESTIGATE2
                    printf("%d integers have zero value, and %d continuous fixed at lb\n",
                           nFix, nFix2);
#endif
                    returnCode = smallBranchAndBound(newSolver,
                                                     numberNodes_, newSolution,
                                                     objectiveValue,
                                                     objectiveValue, "CbcHeuristicLocal");
                    if (returnCode < 0)
                        returnCode = 0; // returned on size
                }
#endif
            }
        }
    }
/*
  If the result is complete exploration with a solution (3) or proven
  infeasibility (2), we could generate a cut (the AI folks would call it a
  nogood) to prevent us from going down this route in the future.
*/
    if ((returnCode&2) != 0) {
        // could add cut
        returnCode &= ~2;
    }

    delete newSolver;
    return returnCode;
}
Example #7
0
int
CbcHeuristicNaive::solution(double & solutionValue,
                            double * betterSolution)
{
    numCouldRun_++;
    // See if to do
    bool atRoot = model_->getNodeCount() == 0;
    int passNumber = model_->getCurrentPassNumber();
    if (!when() || (when() == 1 && model_->phase() != 1) || !atRoot || passNumber != 1)
        return 0; // switched off
    // Don't do if it was this heuristic which found solution!
    if (this == model_->lastHeuristic())
        return 0;
    numRuns_++;
    double cutoff;
    model_->solver()->getDblParam(OsiDualObjectiveLimit, cutoff);
    double direction = model_->solver()->getObjSense();
    cutoff *= direction;
    cutoff = CoinMin(cutoff, solutionValue);
    OsiSolverInterface * solver = model_->continuousSolver();
    if (!solver)
        solver = model_->solver();
    const double * colLower = solver->getColLower();
    const double * colUpper = solver->getColUpper();
    const double * objective = solver->getObjCoefficients();

    int numberColumns = model_->getNumCols();
    int numberIntegers = model_->numberIntegers();
    const int * integerVariable = model_->integerVariable();

    int i;
    bool solutionFound = false;
    CoinWarmStartBasis saveBasis;
    CoinWarmStartBasis * basis =
        dynamic_cast<CoinWarmStartBasis *>(solver->getWarmStart()) ;
    if (basis) {
        saveBasis = * basis;
        delete basis;
    }
    // First just fix all integers as close to zero as possible
    OsiSolverInterface * newSolver = cloneBut(7); // wassolver->clone();
    for (i = 0; i < numberIntegers; i++) {
        int iColumn = integerVariable[i];
        double lower = colLower[iColumn];
        double upper = colUpper[iColumn];
        double value;
        if (lower > 0.0)
            value = lower;
        else if (upper < 0.0)
            value = upper;
        else
            value = 0.0;
        newSolver->setColLower(iColumn, value);
        newSolver->setColUpper(iColumn, value);
    }
    newSolver->initialSolve();
    if (newSolver->isProvenOptimal()) {
        double solValue = newSolver->getObjValue() * direction ;
        if (solValue < cutoff) {
            // we have a solution
            solutionFound = true;
            solutionValue = solValue;
            memcpy(betterSolution, newSolver->getColSolution(),
                   numberColumns*sizeof(double));
            COIN_DETAIL_PRINT(printf("Naive fixing close to zero gave solution of %g\n", solutionValue));
            cutoff = solValue - model_->getCutoffIncrement();
        }
    }
    // Now fix all integers as close to zero if zero or large cost
    int nFix = 0;
    for (i = 0; i < numberIntegers; i++) {
        int iColumn = integerVariable[i];
        double lower = colLower[iColumn];
        double upper = colUpper[iColumn];
        double value;
        if (fabs(objective[i]) > 0.0 && fabs(objective[i]) < large_) {
            nFix++;
            if (lower > 0.0)
                value = lower;
            else if (upper < 0.0)
                value = upper;
            else
                value = 0.0;
            newSolver->setColLower(iColumn, value);
            newSolver->setColUpper(iColumn, value);
        } else {
            // set back to original
            newSolver->setColLower(iColumn, lower);
            newSolver->setColUpper(iColumn, upper);
        }
    }
    const double * solution = solver->getColSolution();
    if (nFix) {
        newSolver->setWarmStart(&saveBasis);
        newSolver->setColSolution(solution);
        newSolver->initialSolve();
        if (newSolver->isProvenOptimal()) {
            double solValue = newSolver->getObjValue() * direction ;
            if (solValue < cutoff) {
                // try branch and bound
                double * newSolution = new double [numberColumns];
                COIN_DETAIL_PRINT(printf("%d fixed after fixing costs\n", nFix));
                int returnCode = smallBranchAndBound(newSolver,
                                                     numberNodes_, newSolution,
                                                     solutionValue,
                                                     solutionValue, "CbcHeuristicNaive1");
                if (returnCode < 0)
                    returnCode = 0; // returned on size
                if ((returnCode&2) != 0) {
                    // could add cut
                    returnCode &= ~2;
                }
                if (returnCode == 1) {
                    // solution
                    solutionFound = true;
                    memcpy(betterSolution, newSolution,
                           numberColumns*sizeof(double));
                    COIN_DETAIL_PRINT(printf("Naive fixing zeros gave solution of %g\n", solutionValue));
                    cutoff = solutionValue - model_->getCutoffIncrement();
                }
                delete [] newSolution;
            }
        }
    }
#if 1
    newSolver->setObjSense(-direction); // maximize
    newSolver->setWarmStart(&saveBasis);
    newSolver->setColSolution(solution);
    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
        double value = solution[iColumn];
        double lower = colLower[iColumn];
        double upper = colUpper[iColumn];
        double newLower;
        double newUpper;
        if (newSolver->isInteger(iColumn)) {
            newLower = CoinMax(lower, floor(value) - 2.0);
            newUpper = CoinMin(upper, ceil(value) + 2.0);
        } else {
            newLower = CoinMax(lower, value - 1.0e5);
            newUpper = CoinMin(upper, value + 1.0e-5);
        }
        newSolver->setColLower(iColumn, newLower);
        newSolver->setColUpper(iColumn, newUpper);
    }
    newSolver->initialSolve();
    if (newSolver->isProvenOptimal()) {
        double solValue = newSolver->getObjValue() * direction ;
        if (solValue < cutoff) {
            nFix = 0;
            newSolver->setObjSense(direction); // correct direction
            //const double * thisSolution = newSolver->getColSolution();
            for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
                double value = solution[iColumn];
                double lower = colLower[iColumn];
                double upper = colUpper[iColumn];
                double newLower = lower;
                double newUpper = upper;
                if (newSolver->isInteger(iColumn)) {
                    if (value < lower + 1.0e-6) {
                        nFix++;
                        newUpper = lower;
                    } else if (value > upper - 1.0e-6) {
                        nFix++;
                        newLower = upper;
                    } else {
                        newLower = CoinMax(lower, floor(value) - 2.0);
                        newUpper = CoinMin(upper, ceil(value) + 2.0);
                    }
                }
                newSolver->setColLower(iColumn, newLower);
                newSolver->setColUpper(iColumn, newUpper);
            }
            // try branch and bound
            double * newSolution = new double [numberColumns];
            COIN_DETAIL_PRINT(printf("%d fixed after maximizing\n", nFix));
            int returnCode = smallBranchAndBound(newSolver,
                                                 numberNodes_, newSolution,
                                                 solutionValue,
                                                 solutionValue, "CbcHeuristicNaive1");
            if (returnCode < 0)
                returnCode = 0; // returned on size
            if ((returnCode&2) != 0) {
                // could add cut
                returnCode &= ~2;
            }
            if (returnCode == 1) {
                // solution
                solutionFound = true;
                memcpy(betterSolution, newSolution,
                       numberColumns*sizeof(double));
                COIN_DETAIL_PRINT(printf("Naive maximizing gave solution of %g\n", solutionValue));
                cutoff = solutionValue - model_->getCutoffIncrement();
            }
            delete [] newSolution;
        }
    }
#endif
    delete newSolver;
    return solutionFound ? 1 : 0;
}
/*
 * Class:     thebeast_osi_OsiSolverJNI
 * Method:    resolve
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_thebeast_osi_OsiSolverJNI_resolve
  (JNIEnv *, jobject, jint ptr){
  OsiSolverInterface* solver = (OsiSolverInterface*) ptr;
  solver->resolve();
}
/*
 * Class:     thebeast_osi_OsiSolverJNI
 * Method:    branchAndBound
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_thebeast_osi_OsiSolverJNI_branchAndBound
  (JNIEnv *, jobject, jint ptr){
  OsiSolverInterface* solver = (OsiSolverInterface*) ptr;
  solver->branchAndBound();
}
// Returns type
int
CbcFathomDynamicProgramming::checkPossible(int allowableSize)
{
    algorithm_ = -1;
    assert(model_->solver());
    OsiSolverInterface * solver = model_->solver();
    const CoinPackedMatrix * matrix = solver->getMatrixByCol();

    int numberIntegers = model_->numberIntegers();
    int numberColumns = solver->getNumCols();
    size_ = 0;
    if (numberIntegers != numberColumns)
        return -1; // can't do dynamic programming

    const double * lower = solver->getColLower();
    const double * upper = solver->getColUpper();
    const double * rowUpper = solver->getRowUpper();

    int numberRows = model_->getNumRows();
    int i;

    // First check columns to see if possible
    double * rhs = new double [numberRows];
    CoinCopyN(rowUpper, numberRows, rhs);

    // Column copy
    const double * element = matrix->getElements();
    const int * row = matrix->getIndices();
    const CoinBigIndex * columnStart = matrix->getVectorStarts();
    const int * columnLength = matrix->getVectorLengths();
    bool bad = false;
    /* It is just possible that we could say okay as
       variables may get fixed but seems unlikely */
    for (i = 0; i < numberColumns; i++) {
        int j;
        double lowerValue = lower[i];
        assert (lowerValue == floor(lowerValue));
        for (j = columnStart[i];
                j < columnStart[i] + columnLength[i]; j++) {
            int iRow = row[j];
            double value = element[j];
            if (upper[i] > lowerValue && (value <= 0.0 || value != floor(value)))
                bad = true;
            if (lowerValue)
                rhs[iRow] -= lowerValue * value;
        }
    }
    // check possible (at present do not allow covering)
    int numberActive = 0;
    bool infeasible = false;
    bool saveBad = bad;
    for (i = 0; i < numberRows; i++) {
        if (rhs[i] < 0)
            infeasible = true;
        else if (rhs[i] > 1.0e5 || fabs(rhs[i] - floor(rhs[i] + 0.5)) > 1.0e-7)
            bad = true;
        else if (rhs[i] > 0.0)
            numberActive++;
    }
    if (bad || infeasible) {
        delete [] rhs;
        if (!saveBad && infeasible)
            return -2;
        else
            return -1;
    }
    // check size of array needed
    double size = 1.0;
    double check = COIN_INT_MAX;
    for (i = 0; i < numberRows; i++) {
        int n = static_cast<int> (floor(rhs[i] + 0.5));
        if (n) {
            n++; // allow for 0,1... n
            if (numberActive != 1) {
                // power of 2
                int iBit = 0;
                int k = n;
                k &= ~1;
                while (k) {
                    iBit++;
                    k &= ~(1 << iBit);
                }
                // See if exact power
                if (n != (1 << iBit)) {
                    // round up to next power of 2
                    n = 1 << (iBit + 1);
                }
                size *= n;
                if (size >= check)
                    break;
            } else {
                size = n; // just one constraint
            }
        }
    }
    // set size needed
    if (size >= check)
        size_ = COIN_INT_MAX;
    else
        size_ = static_cast<int> (size);

    int n01 = 0;
    int nbadcoeff = 0;
    // See if we can tighten bounds
    for (i = 0; i < numberColumns; i++) {
        int j;
        double lowerValue = lower[i];
        double gap = upper[i] - lowerValue;
        for (j = columnStart[i];
                j < columnStart[i] + columnLength[i]; j++) {
            int iRow = row[j];
            double value = element[j];
            if (value != 1.0)
                nbadcoeff++;
            if (gap*value > rhs[iRow] + 1.0e-8)
                gap = rhs[iRow] / value;
        }
        gap = lowerValue + floor(gap + 1.0e-7);
        if (gap < upper[i])
            solver->setColUpper(i, gap);
        if (gap <= 1.0)
            n01++;
    }
    if (allowableSize && size_ <= allowableSize) {
        if (n01 == numberColumns && !nbadcoeff)
            algorithm_ = 0; // easiest
        else
            algorithm_ = 1;
    }
    if (allowableSize && size_ <= allowableSize) {
        numberActive_ = numberActive;
        indices_ = new int [numberActive_];
        cost_ = new double [size_];
        CoinFillN(cost_, size_, COIN_DBL_MAX);
        // but do nothing is okay
        cost_[0] = 0.0;
        back_ = new int[size_];
        CoinFillN(back_, size_, -1);
        startBit_ = new int[numberActive_];
        numberBits_ = new int[numberActive_];
        lookup_ = new int [numberRows];
        rhs_ = new int [numberActive_];
        numberActive = 0;
        int kBit = 0;
        for (i = 0; i < numberRows; i++) {
            int n = static_cast<int> (floor(rhs[i] + 0.5));
            if (n) {
                lookup_[i] = numberActive;
                rhs_[numberActive] = n;
                startBit_[numberActive] = kBit;
                n++; // allow for 0,1... n
                int iBit = 0;
                // power of 2
                int k = n;
                k &= ~1;
                while (k) {
                    iBit++;
                    k &= ~(1 << iBit);
                }
                // See if exact power
                if (n != (1 << iBit)) {
                    // round up to next power of 2
                    iBit++;
                }
                if (numberActive != 1) {
                    n = 1 << iBit;
                    size *= n;
                    if (size >= check)
                        break;
                } else {
                    size = n; // just one constraint
                }
                numberBits_[numberActive++] = iBit;
                kBit += iBit;
            } else {
                lookup_[i] = -1;
            }
        }
        const double * rowLower = solver->getRowLower();
        if (algorithm_ == 0) {
            // rhs 1 and coefficients 1
            // Get first possible solution for printing
            target_ = -1;
            int needed = 0;
            int numberActive = 0;
            for (i = 0; i < numberRows; i++) {
                int newRow = lookup_[i];
                if (newRow >= 0) {
                    if (rowLower[i] == rowUpper[i]) {
                        needed += 1 << numberActive;
                        numberActive++;
                    }
                }
            }
            for (i = 0; i < size_; i++) {
                if ((i&needed) == needed) {
                    break;
                }
            }
            target_ = i;
        } else {
            coefficients_ = new int[numberActive_];
            // If not too many general rhs then we can be more efficient
            numberNonOne_ = 0;
            for (i = 0; i < numberActive_; i++) {
                if (rhs_[i] != 1)
                    numberNonOne_++;
            }
            if (numberNonOne_*2 < numberActive_) {
                // put rhs >1 every second
                int * permute = new int[numberActive_];
                int * temp = new int[numberActive_];
                // try different ways
                int k = 0;
                for (i = 0; i < numberRows; i++) {
                    int newRow = lookup_[i];
                    if (newRow >= 0 && rhs_[newRow] > 1) {
                        permute[newRow] = k;
                        k += 2;
                    }
                }
                // adjust so k points to last
                k -= 2;
                // and now rest
                int k1 = 1;
                for (i = 0; i < numberRows; i++) {
                    int newRow = lookup_[i];
                    if (newRow >= 0 && rhs_[newRow] == 1) {
                        permute[newRow] = k1;
                        k1++;
                        if (k1 <= k)
                            k1++;
                    }
                }
                for (i = 0; i < numberActive_; i++) {
                    int put = permute[i];
                    temp[put] = rhs_[i];
                }
                memcpy(rhs_, temp, numberActive_*sizeof(int));
                for (i = 0; i < numberActive_; i++) {
                    int put = permute[i];
                    temp[put] = numberBits_[i];
                }
                memcpy(numberBits_, temp, numberActive_*sizeof(int));
                k = 0;
                for (i = 0; i < numberActive_; i++) {
                    startBit_[i] = k;
                    k += numberBits_[i];
                }
                for (i = 0; i < numberRows; i++) {
                    int newRow = lookup_[i];
                    if (newRow >= 0)
                        lookup_[i] = permute[newRow];
                }
                delete [] permute;
                delete [] temp;
                // mark new method
                algorithm_ = 2;
            }
            // Get first possible solution for printing
            target_ = -1;
            int needed = 0;
            int * lower2 = new int[numberActive_];
            for (i = 0; i < numberRows; i++) {
                int newRow = lookup_[i];
                if (newRow >= 0) {
                    int gap = static_cast<int> (rowUpper[i] - CoinMax(0.0, rowLower[i]));
                    lower2[newRow] = rhs_[newRow] - gap;
                    int numberBits = numberBits_[newRow];
                    int startBit = startBit_[newRow];
                    if (numberBits == 1 && !gap) {
                        needed |= 1 << startBit;
                    }
                }
            }
            for (i = 0; i < size_; i++) {
                if ((i&needed) == needed) {
                    // this one may do
                    bool good = true;
                    for (int kk = 0; kk < numberActive_; kk++) {
                        int numberBits = numberBits_[kk];
                        int startBit = startBit_[kk];
                        int size = 1 << numberBits;
                        int start = 1 << startBit;
                        int mask = start * (size - 1);
                        int level = (i & mask) >> startBit;
                        if (level < lower2[kk]) {
                            good = false;
                            break;
                        }
                    }
                    if (good) {
                        break;
                    }
                }
            }
            delete [] lower2;
            target_ = i;
        }
Example #11
0
//--------------------------------------------------------------------------
// test EKKsolution methods.
void
CglOddHoleUnitTest(
  const OsiSolverInterface * baseSiP,
  const std::string mpsDir )
{
  CoinRelFltEq eq(0.000001);

  // Test default constructor
  {
    CglOddHole aGenerator;
  }

  // Test copy & assignment
  {
    CglOddHole rhs;
    {
      CglOddHole bGenerator;
      CglOddHole cGenerator(bGenerator);
      rhs=bGenerator;
    }
  }


  // test on simple case
  {
    const int nRows=3;
    const int nCols=3;
    const int nEls=6;
    const double elem[]={1.0,1.0,1.0,1.0,1.0,1.0};
    const int row[]={0,1,0,2,1,2};
    const CoinBigIndex start[]={0,2,4};
    const int len[]={2,2,2};
    CoinPackedMatrix matrix(true,nRows,nCols,nEls,elem,row,start,len);
    const double sol[]={0.5,0.5,0.5};
    const double dj[]={0,0,0};
    const int which[]={1,1,1};
    const int fixed[]={0,0,0};
    OsiCuts cs;
    CglOddHole test1;
    CglTreeInfo info;
    info.randomNumberGenerator=NULL;
    test1.generateCuts(NULL,matrix,sol,dj,cs,which,fixed,info,true);
    CoinPackedVector check;
    int index[] = {0,1,2};
    double el[] = {1,1,1};
    check.setVector(3,index,el);
    //assert (cs.sizeRowCuts()==2);
    assert (cs.sizeRowCuts()==1);
    // sort Elements in increasing order
    CoinPackedVector rpv=cs.rowCut(0).row();
    rpv.sortIncrIndex();
    assert (check==rpv);
  }

  // Testcase /u/rlh/osl2/mps/scOneInt.mps
  // Model has 3 continous, 2 binary, and 1 general
  // integer variable.
  {
    OsiSolverInterface  * siP = baseSiP->clone();

    std::string fn = mpsDir+"scOneInt";
    siP->readMps(fn.c_str(),"mps");
#if 0
    CglOddHole cg;
    int nCols=siP->getNumCols();

    // Test the siP methods for detecting
    // variable type
    int numCont=0, numBinary=0, numIntNonBinary=0, numInt=0;
    for (int thisCol=0; thisCol<nCols; thisCol++) {
      if ( siP->isContinuous(thisCol) ) numCont++;
      if ( siP->isBinary(thisCol) ) numBinary++;
      if ( siP->isIntegerNonBinary(thisCol) ) numIntNonBinary++;
      if ( siP->isInteger(thisCol) ) numInt++;
    }
    assert(numCont==3);
    assert(numBinary==2);
    assert(numIntNonBinary==1);
    assert(numInt==3);


    // Test initializeCutGenerator
    siP->initialSolve();
    assert(xstar !=NULL);
    for (i=0; i<nCols; i++){
      assert(complement[i]==0);
    }
    int nRows=siP->getNumRows();
    for (i=0; i<nRows; i++){
    int vectorsize = siP->getMatrixByRow()->getVectorSize(i);
    assert(vectorsize==2);
    }

    kccg.cleanUpCutGenerator(complement,xstar);
#endif
    delete siP;
  }

}
Example #12
0
  int
  MilpRounding::solution(double &solutionValue, double *betterSolution)
  {
    if(model_->getCurrentPassNumber() > 1) return 0;
    if (model_->currentDepth() > 2 && (model_->getNodeCount()%howOften_)!=0)
      return 0;
 
    int returnCode = 0; // 0 means it didn't find a feasible solution

    OsiTMINLPInterface * nlp = NULL;
    if(setup_->getAlgorithm() == B_BB)
      nlp = dynamic_cast<OsiTMINLPInterface *>(model_->solver()->clone());
    else
      nlp = dynamic_cast<OsiTMINLPInterface *>(setup_->nonlinearSolver()->clone());

    TMINLP2TNLP* minlp = nlp->problem();
 
    // set tolerances
    double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
    //double primalTolerance = 1.0e-6;

    int n;
    int m;
    int nnz_jac_g;
    int nnz_h_lag;
    Ipopt::TNLP::IndexStyleEnum index_style;
    minlp->get_nlp_info(n, m, nnz_jac_g,
			nnz_h_lag, index_style);

    const Bonmin::TMINLP::VariableType* variableType = minlp->var_types();
    const double* x_sol = minlp->x_sol();
    const double* g_l = minlp->g_l();
    const double* g_u = minlp->g_u();

    const double * colsol = model_->solver()->getColSolution();


    // Get information about the linear and nonlinear part of the instance
    TMINLP* tminlp = nlp->model();
    vector<Ipopt::TNLP::LinearityType> c_lin(m);
    tminlp->get_constraints_linearity(m, c_lin());
    vector<int> c_idx(m);
    int n_lin = 0;
    for (int i=0;i<m;i++) {
      if (c_lin[i]==Ipopt::TNLP::LINEAR)
	c_idx[i] = n_lin++;
      else
	c_idx[i] = -1;
    }


    // Get the structure of the jacobian
    vector<int> indexRow(nnz_jac_g);
    vector<int> indexCol(nnz_jac_g);
    minlp->eval_jac_g(n, x_sol, false,
		      m, nnz_jac_g,
		      indexRow(), indexCol(), 0);

    // get the jacobian values 
    vector<double> jac_g(nnz_jac_g);
    minlp->eval_jac_g(n, x_sol, false,
                      m, nnz_jac_g,
                      NULL, NULL, jac_g());

    // Sort the matrix to column ordered
    vector<int> sortedIndex(nnz_jac_g);
    CoinIotaN(sortedIndex(), nnz_jac_g, 0);
    MatComp c;
    c.iRow = indexRow();
    c.jCol = indexCol();
    std::sort(sortedIndex.begin(), sortedIndex.end(), c);

    vector<int> row (nnz_jac_g);
    vector<double> value (nnz_jac_g);
    vector<int> columnStart(n,0); 
    vector<int> columnLength(n,0);
    int indexCorrection = (index_style == Ipopt::TNLP::C_STYLE) ? 0 : 1;
    int iniCol = -1;
    int nnz = 0;
    for(int i=0; i<nnz_jac_g; i++) {
      int thisIndexCol = indexCol[sortedIndex[i]]-indexCorrection;
      int thisIndexRow = c_idx[indexRow[sortedIndex[i]] - indexCorrection];
      if(thisIndexCol != iniCol) {
	iniCol = thisIndexCol;
	columnStart[thisIndexCol] = nnz;
	columnLength[thisIndexCol] = 0;
      }
      if(thisIndexRow == -1) continue;
      columnLength[thisIndexCol]++;
      row[nnz] = thisIndexRow;
      value[nnz] = jac_g[i];
      nnz++;
    }

    // Build the row lower and upper bounds
    vector<double> newRowLower(n_lin);
    vector<double> newRowUpper(n_lin);
    for(int i = 0 ; i < m ; i++){
      if(c_idx[i] == -1) continue;
      newRowLower[c_idx[i]] = g_l[i];
      newRowUpper[c_idx[i]] = g_u[i];
    }

    // Get solution array for heuristic solution
    vector<double> newSolution(n);
    std::copy(x_sol, x_sol + n, newSolution.begin());

    // Define the constraint matrix for MILP
    CoinPackedMatrix matrix(true,n_lin,n, nnz, value(), row(), columnStart(), columnLength());

      // create objective function and columns lower and upper bounds for MILP
      // and create columns for matrix in MILP
      //double alpha = 0;
      double beta = 1;
      vector<double> objective(n);
      vector<int> idxIntegers;
      idxIntegers.reserve(n);
      for(int i = 0 ; i < n ; i++){
         if(variableType[i] != Bonmin::TMINLP::CONTINUOUS){
            idxIntegers.push_back(i);
            objective[i] = beta*(1 - 2*colsol[i]);
         }
      }

#if 0
      // Get dual multipliers and build gradient of the lagrangean
      const double * duals = nlp->getRowPrice() + 2 *n;
      vector<double> grad(n, 0); 
      vector<int> indices(n, 0);
      tminlp->eval_grad_f(n, x_sol, false, grad());
      for(int i = 0 ; i < m ; i++){
        if(c_lin[i] == Ipopt::TNLP::LINEAR) continue;
        int nnz;
        tminlp->eval_grad_gi(n, x_sol, false, i, nnz, indices(), NULL);  
        tminlp->eval_grad_gi(n, x_sol, false, i, nnz, NULL, grad());
        for(int k = 0 ; k < nnz ; k++){
          objective[indices[k]] += alpha *duals[i] * grad[k];
        } 
      }
      for(int i = 0 ; i < n ; i++){
         if(variableType[i] != Bonmin::TMINLP::CONTINUOUS)
         objective[i] += alpha * grad[i];
         //if(fabs(objective[i]) < 1e-4) objective[i] = 0;
         else objective[i] = 0;
      }
      std::copy(objective.begin(), objective.end(), std::ostream_iterator<double>(std::cout, " "));
      std::cout<<std::endl;
#endif

      // load the problem to OSI
      OsiSolverInterface *si = mip_->solver();
      assert(si != NULL);
      CoinMessageHandler * handler = model_->messageHandler()->clone();
      si->passInMessageHandler(handler);
      si->messageHandler()->setLogLevel(1);

      si->loadProblem(matrix, model_->solver()->getColLower(), model_->solver()->getColUpper(), objective(), 
                      newRowLower(), newRowUpper());
      si->setInteger(idxIntegers(), static_cast<int>(idxIntegers.size()));
      si->applyCuts(noGoods);

      bool hasFractionnal = true;
      while(hasFractionnal){
        mip_->optimize(DBL_MAX, 0, 60);
        hasFractionnal = false;
#if 0
        bool feasible = false;
        if(mip_->getLastSolution()) {
  	const double* solution = mip_->getLastSolution();
          std::copy(solution, solution + n, newSolution.begin());
  	feasible = true;
  
        }

    if(feasible) {
      // fix the integer variables and solve the NLP
      // also add no good cut
      CoinPackedVector v;
      double lb = 1;
      for (int iColumn=0;iColumn<n;iColumn++) {
	if (variableType[iColumn] != Bonmin::TMINLP::CONTINUOUS) {
	  double value=newSolution[iColumn];
	  if (fabs(floor(value+0.5)-value)>integerTolerance) {
#ifdef DEBUG_BON_HEURISTIC_DIVE_MIP
	    cout<<"It should be infeasible because: "<<endl;
	    cout<<"variable "<<iColumn<<" is not integer"<<endl;
#endif
	    feasible = false;
	    break;
	  }
	  else {
	    value=floor(newSolution[iColumn]+0.5);
            if(value > 0.5){
              v.insert(iColumn, -1);
              lb -= value;
            }
	    minlp->SetVariableUpperBound(iColumn, value);
	    minlp->SetVariableLowerBound(iColumn, value);
	  }
	}
      }
      }
#endif
      }
      bool feasible = false;
      if(mip_->getLastSolution()) {
	const double* solution = mip_->getLastSolution();
        std::copy(solution, solution + n, newSolution.begin());
	feasible = true;

        delete handler;
      }
      

    if(feasible) {
      // fix the integer variables and solve the NLP
      // also add no good cut
      CoinPackedVector v;
      double lb = 1;
      for (int iColumn=0;iColumn<n;iColumn++) {
	if (variableType[iColumn] != Bonmin::TMINLP::CONTINUOUS) {
	  double value=newSolution[iColumn];
	  if (fabs(floor(value+0.5)-value)>integerTolerance) {
	    feasible = false;
	    break;
	  }
	  else {
	    value=floor(newSolution[iColumn]+0.5);
            if(value > 0.5){
              v.insert(iColumn, -1);
              lb -= value;
            }
	    minlp->SetVariableUpperBound(iColumn, value);
	    minlp->SetVariableLowerBound(iColumn, value);
	  }
	}
      }
      OsiRowCut c;
      c.setRow(v);
      c.setLb(lb);
      c.setUb(DBL_MAX);
      noGoods.insert(c);
      if(feasible) {
	nlp->initialSolve();
	if(minlp->optimization_status() != Ipopt::SUCCESS) {
	  feasible = false;
	}
	std::copy(x_sol,x_sol+n, newSolution.begin());
      }
    }
    if(feasible) {
      double newSolutionValue;
      minlp->eval_f(n, newSolution(), true, newSolutionValue); 
      if(newSolutionValue < solutionValue) {
        std::copy(newSolution.begin(), newSolution.end(), betterSolution);
	solutionValue = newSolutionValue;
	returnCode = 1;
      }
    }

    delete nlp;

#ifdef DEBUG_BON_HEURISTIC_DIVE_MIP
    std::cout<<"DiveMIP returnCode = "<<returnCode<<std::endl;
#endif

    return returnCode;
  }
Example #13
0
//-------------------------------------------------------------------
//  Given the model data, a row of the model, and a LP solution, 
//  this function tries to generate a violated lifted simple generalized 
//  flow cover.
//-------------------------------------------------------------------  
bool 
CglFlowCover::generateOneFlowCut( const OsiSolverInterface & si, 
				  const int rowLen,
				  int* ind,
				  double* coef,
				  char sense,
				  double rhs,
				  OsiRowCut& flowCut,
				  double& violation )
{
  bool generated       = false;
  const double* xlp    = si.getColSolution();
  const int numCols    = si.getNumCols();
    
  double* up           = new double [rowLen];
  double* x            = new double [rowLen];
  double* y            = new double [rowLen];
  CglFlowColType* sign = new CglFlowColType [rowLen];
    
  int i, j;  
  double value, LB, UB;
    
  CglFlowVLB VLB;
  CglFlowVUB VUB;
  static int count=0;
  ++count;
  CGLFLOW_DEBUG=false;
  doLift=true;
  // Get integer types
  const char * columnType = si.getColType ();
  for (i = 0; i < rowLen; ++i) {
    if ( xlp[ind[i]] - floor(xlp[ind[i]]) > EPSILON_ && ceil(xlp[ind[i]]) - xlp[ind[i]] > EPSILON_ )
      break;
  }
  if (i != rowLen) {
    for (int j = 0; j < rowLen; ++j) {
      if ( fabs(coef[j])<=EPSILON_) {
	doLift = false;
	break;
      }
    }
  } else {
    doLift = false;
  }

  if (!doLift)  {
    delete [] sign;
    delete [] up; 
    delete [] x;   
    delete [] y; 
    return generated;
  }

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

  if (sense == 'G') flipRow(rowLen, coef, rhs); // flips everything,
  // but the sense
					  

  if(CGLFLOW_DEBUG) {
    std::cout << "***************************" << std::endl;
    std::cout << "Generate Flow cover -- initial constraint, converted to L sense..." << std::endl;
    std::cout << "Rhs = " << rhs << std::endl;
    std::cout << "coef [var_index]" << " -- " <<  "xlp[var_index]" << '\t' << "vub_coef[vub_index] vub_lp_value OR var_index_col_ub" << std::endl;
   
    for(int iD = 0; iD < rowLen; ++iD) {
      VUB = getVubs(ind[iD]);

      std::cout << std::setw(5) << coef[iD] << "["  << std::setw(5)  << ind[iD] << "] -- " 
		<< std::setw(20) << xlp[ind[iD]] << '\t';
      if (VUB.getVar() != UNDEFINED_) {  
	std::cout << std::setw(20) << VUB.getVal() << "[" << std::setw(5) << VUB.getVar() << "]" 
		  << std::setw(20) << xlp[VUB.getVar()] << std::endl; 
      }
      else
	std::cout << std::setw(20) << si.getColUpper()[ind[iD]] << "       " << std::setw(20) << 1.0 << std::endl;
	
    }
  }

  //-------------------------------------------------------------------------
  // Generate conservation inequality and capacity equalities from 
  // the given row.
  
  for (i = 0; i < rowLen; ++i) {
	
    VLB = getVlbs(ind[i]);
    LB = ( VLB.getVar() != UNDEFINED_ ) ? 
      VLB.getVal() : si.getColLower()[ind[i]];

    VUB = getVubs(ind[i]);
    UB = ( VUB.getVar() != UNDEFINED_ ) ? 
      VUB.getVal() : si.getColUpper()[ind[i]];

    if (LB < -EPSILON_) {   // Only consider rows whose variables are all
      delete [] sign;       // non-negative (LB>= 0). 
      delete [] up; 
      delete [] x;   
      delete [] y;  
      return generated;     
    }

    if ( columnType[ind[i]]==1 ) {   // Binary variable
      value = coef[i];
      if (value > 0.0)
	sign[i] = CGLFLOW_COL_BINPOS;
      else {
	sign[i] = CGLFLOW_COL_BINNEG;
	value = -value;
      }    
      up[i] = value;
      x[i] =  xlp[ind[i]];
      y[i] = value * x[i];
    }
    else {   
      value = coef[i];
      if (value > 0.0)
	sign[i] = CGLFLOW_COL_CONTPOS;
      else {
	sign[i] = CGLFLOW_COL_CONTNEG;
	value = -value;
      }
      up[i] = value* UB;
      x[i] = (VUB.getVar() != UNDEFINED_) ? xlp[VUB.getVar()] : 1.0;
      y[i] = value * xlp[ind[i]];
    }
  }

  //-------------------------------------------------------------------------
  // Find a initial cover (C+, C-) in (N+, N-)
  double  knapRHS   = rhs;
  double  tempSum   = 0.0;
  double  tempMin   = INFTY_;
  CglFlowColCut *    candidate = new CglFlowColCut [rowLen];
  CglFlowColCut *    label     = new CglFlowColCut [rowLen];
  double* ratio     = new double [rowLen];
  int t = -1;
  for (i = 0; i < rowLen; ++i) {
    candidate[i] = label[i] = CGLFLOW_COL_OUTCUT;
    ratio[i] = INFTY_;
	
    switch(sign[i]) {
    case CGLFLOW_COL_CONTPOS:
    case CGLFLOW_COL_BINPOS:
      if( y[i] > EPSILON_ ) {
	ratio[i] = (1.0 - x[i]) / up[i];
	if( y[i] > up[i] * x[i] - EPSILON_ ) {       // Violated
	  candidate[i] = CGLFLOW_COL_PRIME;
	  tempSum += up[i];
	}
	else {
	  candidate[i] = CGLFLOW_COL_SECONDARY;
	}
      }
      break;
    case CGLFLOW_COL_CONTNEG:
    case CGLFLOW_COL_BINNEG:
      if( up[i] > ( (1.0 - EPSILON_) * INFTY_ ) ) {  // UB is infty
	label[i] = CGLFLOW_COL_INCUT;
      }
      else {
	knapRHS += up[i];
	if( y[i] < up[i] ) {
	  candidate[i] = CGLFLOW_COL_PRIME;
	  ratio[i] = x[i] / up[i];
	  tempSum += up[i];
	}
      }
      break;
    }    
  }
    
  double diff, tempD, lambda;
  int xID = -1;
  if (knapRHS >1.0e10) {
    if(CGLFLOW_DEBUG) {
      std::cout << "knapsack RHS too large. RETURN." << std::endl; 
    }
    delete [] sign;                              
    delete [] up; 
    delete [] x;   
    delete [] y;  
    delete [] candidate;
    delete [] label;
    delete [] ratio;
    return generated;
  }

  while (tempSum < knapRHS + EPSILON_) { // Not a cover yet
    diff = INFTY_;
    for (i = 0; i < rowLen; ++i) {
      if (candidate[i] == CGLFLOW_COL_SECONDARY) {
	tempD = up[i] * x[i] - y[i];
	if (tempD < diff - EPSILON_) {
	  diff = tempD;
	  xID = i;
	}
      }
    }
    
    if( diff > (1.0 - EPSILON_) * INFTY_  ) {   // NO cover exits.
      delete [] sign;                              
      delete [] up; 
      delete [] x;   
      delete [] y;  
      delete [] candidate;
      delete [] label;
      delete [] ratio;
      return generated;
    }
    else {
      tempSum += up[xID];
      candidate[xID] = CGLFLOW_COL_PRIME;
    }
  }

  // Solve the knapsack problem to get an initial cover
  tempSum = 0.0;
  for (i = 0; i < rowLen; ++i) {
    if (candidate[i] == CGLFLOW_COL_PRIME && ratio[i] < EPSILON_) {
      //Zero ratio
      label[i] = CGLFLOW_COL_INCUT;
      tempSum += up[i];
    }
  }
  
  while (tempSum < knapRHS + EPSILON_) {
    tempMin = INFTY_;
    xID=-1;
    for (i = 0; i < rowLen; i++) {   // Search the col with  minimum ratio
      if (candidate[i] == CGLFLOW_COL_PRIME && label[i] == 0 && 
	  ratio[i] < tempMin) {
	tempMin = ratio[i];  
	xID = i; 
      }
    }
    if (xID>=0) {
      label[xID] = CGLFLOW_COL_INCUT;
      tempSum += up[xID];
    } else {
      if(CGLFLOW_DEBUG) {
	std::cout << "knapsack RHS too large B. RETURN." << std::endl; 
      }
      delete [] sign;                              
      delete [] up; 
      delete [] x;   
      delete [] y;  
      delete [] candidate;
      delete [] label;
      delete [] ratio;
      return generated;
    }
  }
  
  // Reduce to a minimal cover
  for (i = 0; i < rowLen; ++i) {
    if (label[i] == CGLFLOW_COL_INCUT && ratio[i] > EPSILON_) {
      if (tempSum - up[i] > knapRHS + EPSILON_) {
	label[i] = CGLFLOW_COL_OUTCUT;
	tempSum -= up[i];
      }
    }
  }
  for (i = 0; i < rowLen; ++i) {
    if (label[i] == CGLFLOW_COL_INCUT && ratio[i] < EPSILON_) {
      if (tempSum - up[i] > knapRHS + EPSILON_) {
	label[i] = CGLFLOW_COL_OUTCUT;
	tempSum -= up[i];
      }
    }
  }
    
  // Due to the way to handle N-
  for(i = 0; i < rowLen; ++i) {
    if( sign[i] < 0 ) 
      label[i] = label[i]==CGLFLOW_COL_OUTCUT?CGLFLOW_COL_INCUT:CGLFLOW_COL_OUTCUT;
  }

  // No cover, no cut. 
  bool emptyCover = true; 
  for (i = 0; i < rowLen; ++i) {
    if (label[i] == CGLFLOW_COL_INCUT) {
      emptyCover = false; 
      break;
    }
  }
  if (emptyCover) {	
    if(CGLFLOW_DEBUG) {
      std::cout << "No cover. RETURN." << std::endl; 
    }
    delete [] sign;                              
    delete [] up; 
    delete [] x;   
    delete [] y;  
    delete [] candidate;
    delete [] label;
    delete [] ratio;
    return generated;  
  }

  lambda = tempSum - knapRHS;

  if(CGLFLOW_DEBUG) {
    double sum_mj_Cplus = 0.0;
    double sum_mj_Cminus= 0.0;
    // double checkLambda; // variable not used anywhere (LL)
    // print out the knapsack variables
    std::cout << "Knapsack Cover: C+" << std::endl;
    for (i = 0; i < rowLen; ++i) { 
      if ( label[i] == CGLFLOW_COL_INCUT && sign[i] > 0 ) {
	std::cout << ind[i] << '\t' << up[i] << std::endl;
	sum_mj_Cplus += up[i];
      }
    } 
    std::cout << "Knapsack Cover: C-" << std::endl;
    for (i = 0; i < rowLen; ++i) { 
      if ( label[i] == CGLFLOW_COL_INCUT && sign[i] < 0 ) {
	std::cout << ind[i] << '\t' << up[i] << std::endl;
	sum_mj_Cminus += up[i];
      }
    }

    // rlh: verified "lambda" is lambda in the paper.
    // lambda = (sum coefficients in C+) - (sum of VUB
    // coefficients in C-) - rhs-orig-constraint
    std::cout << "lambda = " << lambda << std::endl;
  }

  //-------------------------------------------------------------------------
  // Generate a violated SGFC

  int numCMinus = 0;
  int numPlusPlus = 0;
  double* rho     = new double [rowLen];
  double* xCoef   = new double [rowLen]; 
  double* yCoef   = new double [rowLen];
  double cutRHS   = rhs;
  double temp     = 0.0;
  double sum      = 0.0;
  double minPlsM  = INFTY_;
  double minNegM  = INFTY_;

  for(i = 0; i < rowLen; ++i) {
    rho[i]   = 0.0;
    xCoef[i] = 0.0;
    yCoef[i] = 0.0;
  }
    
  // Project out variables in C-
  // d^' = d + sum_{i in C^-} m_i. Now cutRHS = d^'
  for (i = 0; i < rowLen; ++i) { 
    if ( label[i] == CGLFLOW_COL_INCUT && sign[i] < 0 ) {
      cutRHS += up[i];
      ++numCMinus;
    }
  }

  // (1) Compute the coefficients of the simple generalized flow cover
  // (2) Compute minPlsM, minNegM and sum
  //
  // sum = sum_{i in C+\C++} m_i + sum_{i in L--} m_i = m. Page 15.
  // minPlsM = min_{i in C++} m_i
  // minNegM = min_{i in L-} m_i

  temp = cutRHS;
    
  for (i = 0; i < rowLen; ++i) {
    if (label[i] == CGLFLOW_COL_INCUT  && sign[i] > 0) { // C+
      yCoef[i] = 1.0;
      if ( up[i] > lambda + EPSILON_ ) { // C++
	++numPlusPlus;
	xCoef[i] = lambda - up[i];
	cutRHS += xCoef[i];
	if( up[i] < minPlsM ) {
	  minPlsM = up[i];
	}
      }
      else {  // C+\C++
	xCoef[i] = 0.0;  // rlh: is this necesarry? (xCoef initialized to zero)
	sum += up[i];
      } 
    }
	
    if (label[i] != CGLFLOW_COL_INCUT && sign[i] < 0) { // N-\C-
      temp += up[i];
      if ( up[i] > lambda) {      // L-
	if(CGLFLOW_DEBUG) {
	  std::cout << "Variable " << ind[i] << " is in L-" << std::endl;
	}
	yCoef[i] = 0.0;
	xCoef[i] = -lambda;
	label[i] = CGLFLOW_COL_INLMIN;
	if ( up[i] < minNegM ) { 
	  minNegM = up[i];
	}
      }
      else  {        // L--
	if(CGLFLOW_DEBUG) {
	  std::cout << "Variable " << ind[i] << " is in L-- " << std::endl;
	}
	yCoef[i] = -1.0;
	xCoef[i] = 0.0; // rlh: is this necesarry? (xCoef initialized to zero)
	label[i] = CGLFLOW_COL_INLMINMIN;
	sum += up[i];
      }
    }
  }
   
  // Sort the upper bounds (m_i) of variables in C++ and L-.

  int     ix;
  int     index  = 0;
  double* mt     = new double [rowLen];
  double* M      = new double [rowLen + 1];
  // order to look at variables
  int * order = new int [rowLen];
  int nLook=0;
  for (int i = 0; i < rowLen; ++i) {
    if ( (label[i] == CGLFLOW_COL_INCUT && sign[i] > 0) || 
	 label[i] == CGLFLOW_COL_INLMIN ) {     //  C+ || L- 
      // possible
      M[nLook]=-up[i];
      order[nLook++]=i;
    }
  }
  CoinSort_2(M,M+nLook,order);
  int kLook=0;
  
  while (kLook<nLook) {
    ix = UNDEFINED_;
    i = order[kLook];
    kLook++;
    if ( (label[i] == CGLFLOW_COL_INCUT && sign[i] > 0) || 
	 label[i] == CGLFLOW_COL_INLMIN ) {     //  C+ || L- 
      if ( up[i] > lambda ) {       // C++ || L-(up[i] > lambda)
	ix = i;
      }
    }
      
    if( ix == UNDEFINED_ )  break;
      
    mt[index++] = up[ix];  // Record m_i in C++ and L-(not all) in descending order.
	
    if( label[ix] == CGLFLOW_COL_INLMIN )  
      label[ix] = CGLFLOW_COL_INLMINDONE;
    else
      label[ix] = CGLFLOW_COL_INCUTDONE;
  }
  //printf("mins %g %g\n",minNegM,minPlsM);
  if( index == 0 || numPlusPlus == 0) {
    // No column in C++ and L-(not all). RETURN.
    if(CGLFLOW_DEBUG) {
      std::cout << "index = 0. RETURN." << std::endl; 
    }
    delete [] sign;
    delete [] up; 
    delete [] x;   
    delete [] y;  
    delete [] candidate;
    delete [] label;
    delete [] ratio;
    delete [] rho;
    delete [] xCoef;
    delete [] yCoef;
    delete [] mt; 
    delete [] M; 
    delete [] order;
    return generated;
  }

  for ( i = 0; i < rowLen; i++ ) {
    switch( label[i] ) {
    case  CGLFLOW_COL_INCUTDONE:
      label[i] = CGLFLOW_COL_INCUT;
      break;
    case  CGLFLOW_COL_INLMIN:
    case  CGLFLOW_COL_INLMINDONE:
    case  CGLFLOW_COL_INLMINMIN:
      label[i] = CGLFLOW_COL_OUTCUT;
      break;
    case CGLFLOW_COL_INCUT:
    case CGLFLOW_COL_OUTCUT:
    case CGLFLOW_COL_PRIME:
    case CGLFLOW_COL_SECONDARY:
      break;
    }
  }
    
  /* Get t */
  t = 0;
  for ( i = 0; i < index; ++i ) {
    if ( mt[i] < minPlsM ) {
      t = i;
      break;
    } 
  }

  if (i == index) {
    t = index;
  }
    
  /* Compute M_i */
  M[0] = 0.0;
  for ( i = 1; i <= index; ++i ) {
    M[i] = M[(i-1)] + mt[(i-1)];
    if(CGLFLOW_DEBUG) {
      std::cout << "t = " << t << std::endl; 
      std::cout << "mt[" << std::setw(5) << (i-1) << "]=" << std::setw(2) << ", M[" << std::setw(5) << i << "]=" << std::setw(20) << M[i] << std::endl;
    }
  }
  // Exit if very big M
  if (M[index]>1.0e30) { // rlh: should test for huge col UB earler 
    // no sense doing all this work in that case.
    if(CGLFLOW_DEBUG) {
      std::cout << "M[index]>1.0e30. RETURN." << std::endl; 
      delete [] sign;
      delete [] up; 
      delete [] x;   
      delete [] y;  
      delete [] candidate;
      delete [] label;
      delete [] ratio;
      delete [] rho;
      delete [] xCoef;
      delete [] yCoef;
      delete [] mt; 
      delete [] M; 
      delete [] order;
      return generated;
    }
  }

  /* Get ml */
  double ml = CoinMin(sum, lambda);
  if(CGLFLOW_DEBUG) {
    // sum = sum_{i in C+\C++} m_i + sum_{i in L--} m_i = m. Page 15.
    std::cout << "ml = CoinMin(m, lambda) = CoinMin(" << sum << ", " << lambda << ") =" << ml << std::endl; 
  }
  /* rho_i = max[0, m_i - (minPlsM - lamda) - ml */
  if (t < index ) { /* rho exits only for t <= index-1 */
    value = (minPlsM - lambda) + ml;
    for (i = t; i < index; ++i) {
      rho[i] =  CoinMax(0.0, mt[i] - value);
      if(CGLFLOW_DEBUG) {
	std::cout << "rho[" << std::setw(5) << i << "]=" << std::setw(20) << rho[i] << std::endl;
      }
    }
  }
  // Calculate the violation
  violation = -cutRHS;
  for ( i = 0; i < rowLen; ++i ) {
#ifdef CGLFLOW_DEBUG2
    if(CGLFLOW_DEBUG) {
      std::cout << "i = " << i << " ind = " << ind[i] << " sign = " 
		<< sign[i] 
		<< " coef = " << coef[i] << " x = " << x[i] << " xCoef = " 
		<< xCoef[i] << " y = " << y[i] << " yCoef = " << yCoef[i] 
		<< " up = " << up[i] << " label = " << label[i] << std::endl;
    }
#endif
    violation += y[i] * yCoef[i] + x[i] * xCoef[i];
  }

  if(CGLFLOW_DEBUG) {
    std::cout << "violation = " << violation << std::endl;
  }
  //  double violationBeforeLift=violation; // variable not used anywhere (LL)
  if(doLift && fabs(violation) > TOLERANCE_ ) {  // LIFTING
    double estY, estX;
    double movement = 0.0;
    double dPrimePrime = temp + cutRHS; 
    bool lifted = false;
    for( i = 0; i < rowLen; ++i ) {
      if ( (label[i] != CGLFLOW_COL_INCUT) && (sign[i] > 0) ) {/* N+\C+*/
	lifted = liftPlus(estY, estX,
			  index, up[i],
			  lambda,
			  y[i], x[i], 
			  dPrimePrime, M);
	    
	xCoef[i] = -estX;
	yCoef[i] = estY;
	if(CGLFLOW_DEBUG) {
	  if (lifted) {
	    printf("Success: Lifted col %i (up_i=%f,yCoef[i]=%f,xCoef[i]=%f) in N+\\C+\n", 
		   ind[i], up[i], yCoef[i], xCoef[i]);
	  }
	  else {
	    printf("Failed to Lift col %i (m_i=%f) in N+\\C+\n", 
		   ind[i], up[i]);
	  }       
	}
      }
      if (label[i] == CGLFLOW_COL_INCUT && sign[i] < 0) { 
	/* C- */
	liftMinus(movement, t,
		  index, up[i], 
		  dPrimePrime, 
		  lambda, ml,
		  M, rho);
                
	if(movement > EPSILON_) {
	  if(CGLFLOW_DEBUG) {
	    printf("Success: Lifted col %i in C-, movement=%f\n", 
		   ind[i], movement);
	  }
	  lifted = true;
	  xCoef[i] = -movement;
	  cutRHS -= movement;
	}
	else {
	  if(CGLFLOW_DEBUG) {
	    printf("Failed to Lift col %i in C-, g=%f\n",
		   ind[i], movement);
	  }
	}
      }
    }
  }
  //-------------------------------------------------------------------

    
  // Calculate the violation
  violation = -cutRHS;
  for ( i = 0; i < rowLen; ++i ) {
#ifdef CGLFLOW_DEBUG2
    if(CGLFLOW_DEBUG) {
      std::cout << "i = " << i << " ind = " << ind[i] << " sign = " 
		<< sign[i] 
		<< " coef = " << coef[i] << " x = " << x[i] << " xCoef = " 
		<< xCoef[i] << " y = " << y[i] << " yCoef = " << yCoef[i] 
		<< " up = " << up[i] << " label = " << label[i] << std::endl;
    }
#endif
    violation += y[i] * yCoef[i] + x[i] * xCoef[i];
  }

  if(CGLFLOW_DEBUG) {
    std::cout << "violation = " << violation << std::endl;
  }
    
  int     cutLen     = 0;
  int*    cutInd     = 0;
  double* cutCoef    = 0;

  // If violated, transform the inequality back to original system
  if ( violation > TOLERANCE_ ) {
    cutLen = 0;
    cutInd  = new int [3*numCols];
    cutCoef = new double [3*numCols];
      
	  assert (cutLen<numCols);
    for ( i = 0; i < rowLen; ++i )  {
      VUB = getVubs(ind[i]);
      
      if ( ( sign[i] == CGLFLOW_COL_CONTPOS ) || 
	   ( sign[i] == CGLFLOW_COL_CONTNEG ) ) {

	if ( fabs( yCoef[i] ) > EPSILON_ ) {
		    
	  if ( sign[i] == CGLFLOW_COL_CONTPOS ) 
	    cutCoef[cutLen] = coef[i] * yCoef[i];
	  else 
	    cutCoef[cutLen] = -coef[i] * yCoef[i];
	  cutInd[cutLen++] = ind[i];
	}

	if ( fabs( xCoef[i] ) > EPSILON_ ) {
	  if ( VUB.getVar() != UNDEFINED_ ) {
	    cutCoef[cutLen] = xCoef[i];
	    cutInd[cutLen++] = VUB.getVar();
	  }
	  else
	    cutRHS -= xCoef[i];
	}
      }
            
      if ( ( sign[i] == CGLFLOW_COL_BINPOS ) || 
	   ( sign[i] == CGLFLOW_COL_BINNEG ) ) {
	if (fabs(yCoef[i]) > EPSILON_ || fabs(xCoef[i]) > EPSILON_) {
	  if (sign[i] == CGLFLOW_COL_BINPOS) 
	    cutCoef[cutLen] = coef[i] * yCoef[i] + xCoef[i];
	  else 
	    cutCoef[cutLen] = -coef[i] * yCoef[i] + xCoef[i];
	  cutInd[cutLen++] = ind[i];
	}
      }
    }
#if 1
    assert (cutLen);
    CoinShortSort_2(cutInd,cutInd+cutLen,cutCoef);
    j=0;
    int lastInd=cutInd[0];
    double lastCoef=cutCoef[0];
    for ( i = 1; i < cutLen+1; ++i ) {
      if (i==cutLen||cutInd[i]>lastInd) {
	if ( fabs(lastCoef) >= EPSILON_ ) {
	  cutCoef[j]=lastCoef;
	  cutInd[j++]=lastInd;
	  lastCoef = cutCoef[i];
	  if (i<cutLen)
	    lastInd=cutInd[i];
	}
      } else {
	lastCoef += cutCoef[i];
      }
    }
#else
    for ( i = 0; i < cutLen; ++i ) {
      for ( j = 0; j < i; j++ ) {
	if ( cutInd[j] == cutInd[i] ) { /* Duplicate*/
	  cutCoef[j] += cutCoef[i];
	  cutInd[i] = -1;
	}
      }
    }

    for ( j = 0, i = 0; i < cutLen; ++i ) {
      if ( ( cutInd[i] == -1 ) || ( fabs( cutCoef[i]) < EPSILON_ ) ){
	/* Small coeff*/
      }
      else {
	cutCoef[j] = cutCoef[i];
	cutInd[j] = cutInd[i];
	j++;
      }
    }
#endif
    cutLen = j;
    // Skip if no elements ? - bug somewhere
    if (cutLen == 0)
        return false;
        
    // Recheck the violation.
    violation = 0.0;
    for (i = 0; i < cutLen; ++i) 
      violation += cutCoef[i] * xlp[cutInd[i]];
    
    violation -= cutRHS;

    if ( violation > TOLERANCE_ ) {
      flowCut.setRow(cutLen, cutInd, cutCoef);
      flowCut.setLb(-1.0 * si.getInfinity());
      flowCut.setUb(cutRHS);
      flowCut.setEffectiveness(violation);
      generated = true;

      if(CGLFLOW_DEBUG) {
	std::cout << "generateOneFlowCover(): Found a cut" << std::endl;
      }
    }
    else {
      if(CGLFLOW_DEBUG) {
	std::cout << "generateOneFlowCover(): Lost a cut" << std::endl;
      }
    }
  }

  //-------------------------------------------------------------------------
  delete [] sign;
  delete [] up; 
  delete [] x;   
  delete [] y;  
  delete [] candidate;
  delete [] label;
  delete [] ratio;
  delete [] rho;
  delete [] xCoef;
  delete [] yCoef;
  delete [] mt; 
  delete [] M; 
  delete [] order;
  delete [] cutInd;
  delete [] cutCoef;
    
  return generated;
}
Example #14
0
//-------------------------------------------------------------------
// Determine row types. Find the VUBS and VLBS. 
//-------------------------------------------------------------------  
void 
CglFlowCover::flowPreprocess(const OsiSolverInterface& si)
{
  CoinPackedMatrix matrixByRow(*si.getMatrixByRow());

  int numRows = si.getNumRows();
  int numCols = si.getNumCols();
  
  const char* sense        = si.getRowSense();
  const double* RHS        = si.getRightHandSide();

  const double* coefByRow  = matrixByRow.getElements();
  const int* colInds       = matrixByRow.getIndices();
  const int* rowStarts     = matrixByRow.getVectorStarts();
  const int* rowLengths    = matrixByRow.getVectorLengths();
  int iRow      = -1; 
  int iCol      = -1;

  numCols_ = numCols;     // Record col and row numbers for copy constructor
  numRows_ = numRows;

  if (rowTypes_ != 0) {
    delete [] rowTypes_; rowTypes_ = 0;
  }
  rowTypes_ = new CglFlowRowType [numRows];// Destructor will free memory
  // Get integer types
  const char * columnType = si.getColType (true);
    
  // Summarize the row type infomation.
  int numUNDEFINED   = 0;
  int numVARUB       = 0;
  int numVARLB       = 0;
  int numVAREQ       = 0;
  int numMIXUB       = 0;
  int numMIXEQ       = 0;
  int numNOBINUB     = 0;
  int numNOBINEQ     = 0;
  int numSUMVARUB    = 0;
  int numSUMVAREQ    = 0;
  int numUNINTERSTED = 0;

  int* ind     = new int [numCols];
  double* coef = new double [numCols];
  for (iRow = 0; iRow < numRows; ++iRow) {
    int rowLen   = rowLengths[iRow];
    char sen     = sense[iRow];
    double rhs   = RHS[iRow];

    CoinDisjointCopyN(colInds + rowStarts[iRow], rowLen, ind);
    CoinDisjointCopyN(coefByRow + rowStarts[iRow], rowLen, coef);
 
    CglFlowRowType rowType = determineOneRowType(si, rowLen, ind, coef, 
						 sen, rhs);

    rowTypes_[iRow] = rowType;

    switch(rowType) {
    case  CGLFLOW_ROW_UNDEFINED:
      ++numUNDEFINED; 
      break;
    case  CGLFLOW_ROW_VARUB:
      ++numVARUB; 
      break;
    case  CGLFLOW_ROW_VARLB:
      ++numVARLB; 
      break;
    case  CGLFLOW_ROW_VAREQ:
      ++numVAREQ; 
      break;
    case  CGLFLOW_ROW_MIXUB:
      ++numMIXUB; 
      break;
    case  CGLFLOW_ROW_MIXEQ:
      ++numMIXEQ; 
      break;
    case  CGLFLOW_ROW_NOBINUB:
      ++numNOBINUB; 
      break;
    case  CGLFLOW_ROW_NOBINEQ:
      ++numNOBINEQ; 
      break;
    case  CGLFLOW_ROW_SUMVARUB:
      ++numSUMVARUB; 
      break;
    case  CGLFLOW_ROW_SUMVAREQ:
      ++numSUMVAREQ; 
      break;
    case  CGLFLOW_ROW_UNINTERSTED:
      ++numUNINTERSTED;
      break;
    default:
      throw CoinError("Unknown row type", "flowPreprocess",
		      "CglFlowCover");
    }
    
  }
  delete [] ind;  ind  = NULL;
  delete [] coef; coef = NULL;

  if(CGLFLOW_DEBUG) {
    std::cout << "The num of rows = "  << numRows        << std::endl;
    std::cout << "Summary of Row Type" << std::endl;
    std::cout << "numUNDEFINED     = " << numUNDEFINED   << std::endl;
    std::cout << "numVARUB         = " << numVARUB       << std::endl;
    std::cout << "numVARLB         = " << numVARLB       << std::endl;
    std::cout << "numVAREQ         = " << numVAREQ       << std::endl;
    std::cout << "numMIXUB         = " << numMIXUB       << std::endl;
    std::cout << "numMIXEQ         = " << numMIXEQ       << std::endl;
    std::cout << "numNOBINUB       = " << numNOBINUB     << std::endl;
    std::cout << "numNOBINEQ       = " << numNOBINEQ     << std::endl;
    std::cout << "numSUMVARUB      = " << numSUMVARUB    << std::endl;
    std::cout << "numSUMVAREQ      = " << numSUMVAREQ    << std::endl;
    std::cout << "numUNINTERSTED   = " << numUNINTERSTED << std::endl;
  }

  //---------------------------------------------------------------------------
  // Setup  vubs_ and vlbs_
  if (vubs_ != 0) { delete [] vubs_; vubs_ = 0; }
  vubs_ = new CglFlowVUB [numCols];      // Destructor will free memory
  if (vlbs_ != 0) { delete [] vlbs_; vlbs_ = 0; }
  vlbs_ = new CglFlowVLB [numCols];      // Destructor will free memory

  for (iCol = 0; iCol < numCols; ++iCol) {   // Initilized in constructor
    vubs_[iCol].setVar(UNDEFINED_);     // but, need redo since may call
    vlbs_[iCol].setVar(UNDEFINED_);     // preprocess(...) more than once
  }
  
  for (iRow = 0; iRow < numRows; ++iRow) {
	
    CglFlowRowType rowType2 = rowTypes_[iRow];
    
    if ( (rowType2 == CGLFLOW_ROW_VARUB) || 
	 (rowType2 == CGLFLOW_ROW_VARLB) || 
	 (rowType2 == CGLFLOW_ROW_VAREQ) )  { 
      
      int startPos = rowStarts[iRow];
      int index0   = colInds[startPos];
      int index1   = colInds[startPos + 1];
      double coef0 = coefByRow[startPos];
      double coef1 = coefByRow[startPos + 1];
	    
      int    xInd,  yInd;   // x is binary
      double xCoef, yCoef;

      if ( columnType[index0]==1 ) {
	xInd  = index0;   yInd  = index1;
	xCoef = coef0;    yCoef = coef1;
      }
      else {
	xInd  = index1;   yInd  = index0;
	xCoef = coef1;    yCoef = coef0;
      }

      switch (rowType2) {
      case CGLFLOW_ROW_VARUB:       // Inequality: y <= ? * x
	vubs_[yInd].setVar(xInd);
	vubs_[yInd].setVal(-xCoef / yCoef);
	break;
      case CGLFLOW_ROW_VARLB:       // Inequality: y >= ? * x
	vlbs_[yInd].setVar(xInd);
	vlbs_[yInd].setVal(-xCoef / yCoef);
	break;
      case CGLFLOW_ROW_VAREQ:       // Inequality: y >= AND <= ? * x
	vubs_[yInd].setVar(xInd);
	vubs_[yInd].setVal(-xCoef / yCoef);
	vlbs_[yInd].setVar(xInd);
	vlbs_[yInd].setVal(-xCoef / yCoef);
	break;
      default:
	throw CoinError("Unknown row type: impossible", 
			"flowPreprocess", "CglFlowCover");
      }
    }
  }

  if(CGLFLOW_DEBUG) {
    printVubs(std::cout);
  }
}
Example #15
0
int main (int argc, const char *argv[])
{

  // Define your favorite OsiSolver
  
  OsiClpSolverInterface solver1;

  // Read in model using argv[1]
  // and assert that it is a clean model
  std::string mpsFileName;
#if defined(SAMPLEDIR)
  mpsFileName = SAMPLEDIR "/p0033.mps";
#else
  if (argc < 2) {
    fprintf(stderr, "Do not know where to find sample MPS files.\n");
    exit(1);
  }
#endif
  if (argc>=2) mpsFileName = argv[1];
  int numMpsReadErrors = solver1.readMps(mpsFileName.c_str(),"");
  if( numMpsReadErrors != 0 )
  {
     printf("%d errors reading MPS file\n", numMpsReadErrors);
     return numMpsReadErrors;
  }
  double time1 = CoinCpuTime();

  /* Options are:
     preprocess to do preprocessing
     time in minutes
     if 2 parameters and numeric taken as time
  */
  bool preProcess=false;
  double minutes=-1.0;
  int nGoodParam=0;
  for (int iParam=2; iParam<argc;iParam++) {
    if (!strcmp(argv[iParam],"preprocess")) {
      preProcess=true;
      nGoodParam++;
    } else if (!strcmp(argv[iParam],"time")) {
      if (iParam+1<argc&&isdigit(argv[iParam+1][0])) {
        minutes=atof(argv[iParam+1]);
        if (minutes>=0.0) {
          nGoodParam+=2;
          iParam++; // skip time
        }
      }
    }
  }
  if (nGoodParam==0&&argc==3&&isdigit(argv[2][0])) {
    // If time is given then stop after that number of minutes
    minutes = atof(argv[2]);
    if (minutes>=0.0) 
      nGoodParam=1;
  }
  if (nGoodParam!=argc-2&&argc>=2) {
    printf("Usage <file> [preprocess] [time <minutes>] or <file> <minutes>\n");
    exit(1);
  }
  //solver1.getModelPtr()->setLogLevel(0);
  solver1.messageHandler()->setLogLevel(0);
  solver1.initialSolve();
  // Reduce printout
  solver1.setHintParam(OsiDoReducePrint,true,OsiHintTry);
  CbcModel model(solver1);
  model.solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry);
  // Set up some cut generators and defaults
  // Probing first as gets tight bounds on continuous

  CglProbing generator1;
  generator1.setUsingObjective(true);
  generator1.setMaxPass(1);
  generator1.setMaxPassRoot(5);
  // Number of unsatisfied variables to look at
  generator1.setMaxProbe(10);
  generator1.setMaxProbeRoot(1000);
  // How far to follow the consequences
  generator1.setMaxLook(50);
  generator1.setMaxLookRoot(500);
  // Only look at rows with fewer than this number of elements
  generator1.setMaxElements(200);
  generator1.setRowCuts(3);

  CglGomory generator2;
  // try larger limit
  generator2.setLimit(300);

  CglKnapsackCover generator3;

  CglRedSplit generator4;
  // try larger limit
  generator4.setLimit(200);

  CglClique generator5;
  generator5.setStarCliqueReport(false);
  generator5.setRowCliqueReport(false);

  CglMixedIntegerRounding2 mixedGen;
  CglFlowCover flowGen;
  
  // Add in generators
  // Experiment with -1 and -99 etc
  model.addCutGenerator(&generator1,-1,"Probing");
  model.addCutGenerator(&generator2,-1,"Gomory");
  model.addCutGenerator(&generator3,-1,"Knapsack");
  // model.addCutGenerator(&generator4,-1,"RedSplit");
  model.addCutGenerator(&generator5,-1,"Clique");
  model.addCutGenerator(&flowGen,-1,"FlowCover");
  model.addCutGenerator(&mixedGen,-1,"MixedIntegerRounding");
  OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (model.solver());
  // go faster stripes
  if (osiclp) {
    // Turn this off if you get problems
    // Used to be automatically set
    osiclp->setSpecialOptions(128);
    if(osiclp->getNumRows()<300&&osiclp->getNumCols()<500) {
      //osiclp->setupForRepeatedUse(2,1);
      osiclp->setupForRepeatedUse(0,1);
    }
  } 
  // Uncommenting this should switch off most CBC messages
  //model.messagesPointer()->setDetailMessages(10,5,5000);
  // Allow rounding heuristic

  CbcRounding heuristic1(model);
  model.addHeuristic(&heuristic1);

  // Redundant definition of default branching (as Default == User)
  CbcBranchUserDecision branch;
  model.setBranchingMethod(&branch);

  // Definition of node choice
  CbcCompareUser compare;
  model.setNodeComparison(compare);

  // Do initial solve to continuous
  model.initialSolve();

  // Could tune more
  double objValue = model.solver()->getObjSense()*model.solver()->getObjValue();
  double minimumDropA=CoinMin(1.0,fabs(objValue)*1.0e-3+1.0e-4);
  double minimumDrop= fabs(objValue)*1.0e-4+1.0e-4;
  printf("min drop %g (A %g)\n",minimumDrop,minimumDropA);
  model.setMinimumDrop(minimumDrop);

  if (model.getNumCols()<500)
    model.setMaximumCutPassesAtRoot(-100); // always do 100 if possible
  else if (model.getNumCols()<5000)
    model.setMaximumCutPassesAtRoot(100); // use minimum drop
  else
    model.setMaximumCutPassesAtRoot(20);
  model.setMaximumCutPasses(10);
  //model.setMaximumCutPasses(2);

  // Switch off strong branching if wanted
  // model.setNumberStrong(0);
  // Do more strong branching if small
  if (model.getNumCols()<5000)
    model.setNumberStrong(10);
  model.setNumberStrong(20);
  //model.setNumberStrong(5);
  model.setNumberBeforeTrust(5);
  //model.setSizeMiniTree(2);

  model.solver()->setIntParam(OsiMaxNumIterationHotStart,100);

  // Switch off most output
  if (model.getNumCols()<3000) {
    model.messageHandler()->setLogLevel(1);
    //model.solver()->messageHandler()->setLogLevel(0);
  } else {
    model.messageHandler()->setLogLevel(2);
    model.solver()->messageHandler()->setLogLevel(1);
  }
  model.messageHandler()->setLogLevel(6);
  model.solver()->messageHandler()->setLogLevel(1);
  // If time is given then stop after that number of minutes
  if (minutes>=0.0) {
    std::cout<<"Stopping after "<<minutes<<" minutes"<<std::endl;
    model.setDblParam(CbcModel::CbcMaximumSeconds,60.0*minutes);
  }
  // Default strategy will leave cut generators as they exist already
  // so cutsOnlyAtRoot (1) ignored
  // numberStrong (2) is 5 (default)
  // numberBeforeTrust (3) is 5 (default is 0)
  // printLevel (4) defaults (0)
  CbcStrategyDefault strategy(true,5,5);
  // Set up pre-processing to find sos if wanted
  if (preProcess)
    strategy.setupPreProcessing(2);
  model.setStrategy(strategy);
  int numberColumns = model.solver()->getNumCols();
  double * bestSolution=NULL;
  int * priority = new int[numberColumns];
  // Do two passes
  for (int iPass=0;iPass<2;iPass++) {
    time1 = CoinCpuTime();
    // Do hot start on second pass
    if (bestSolution) {
      model.setHotstartSolution(bestSolution,priority);
      delete [] bestSolution;
      bestSolution=NULL;
      delete [] priority;
      model.setMaximumNodes(40000);
    } else {
      model.setMaximumNodes(40000);
    }
    // Do complete search
    model.branchAndBound();
    
    std::cout<<mpsFileName<<" took "<<CoinCpuTime()-time1<<" seconds, "
             <<model.getNodeCount()<<" nodes with objective "
             <<model.getObjValue()
             <<(!model.status() ? " Finished" : " Not finished")
             <<std::endl;
    // Print solution if finished - we can't get names from Osi! - so get from OsiClp
    
    assert (model.getMinimizationObjValue()<1.0e50);
    OsiSolverInterface * solver = model.solver();
    int numberColumns = solver->getNumCols();
    
    const double * solution = solver->getColSolution();
    // save solution
    if (!iPass) {
      bestSolution = CoinCopyOfArray(solution,numberColumns);
      for (int i=0;i<numberColumns;i++) {
        if (solution[i]>0.5)
          priority[i]=-1;
        else
          priority[i]=2;
      }
    }
    //const double * lower = solver->getColLower();
    //const double * upper = solver->getColUpper();

    // Get names from solver1 (as OsiSolverInterface may lose)
    std::vector<std::string> columnNames = *solver1.getModelPtr()->columnNames();
    
    int iColumn;
    std::cout<<std::setiosflags(std::ios::fixed|std::ios::showpoint)<<std::setw(14);
    
    std::cout<<"--------------------------------------"<<std::endl;
    for (iColumn=0;iColumn<numberColumns;iColumn++) {
      double value=solution[iColumn];
      if (fabs(value)>1.0e-7&&solver->isInteger(iColumn)) 
	std::cout<<std::setw(6)<<iColumn<<" "
                 <<columnNames[iColumn]<<" "
                 <<value
          //<<" "<<lower[iColumn]<<" "<<upper[iColumn]
                 <<std::endl;
    }
    std::cout<<"--------------------------------------"<<std::endl;
  
    std::cout<<std::resetiosflags(std::ios::fixed|std::ios::showpoint|std::ios::scientific);
    model.resetToReferenceSolver();
  }
  return 0;
}    
Example #16
0
/*
  First tries setting a variable to better value.  If feasible then
  tries setting others.  If not feasible then tries swaps
  Returns 1 if solution, 0 if not */
int
CbcHeuristicVND::solution(double & solutionValue,
                          double * betterSolution)
{
    numCouldRun_++;
    int returnCode = 0;
    const double * bestSolution = model_->bestSolution();
    if (!bestSolution)
        return 0; // No solution found yet
    if (numberSolutions_ < model_->getSolutionCount()) {
        // new solution - add info
        numberSolutions_ = model_->getSolutionCount();

        int numberIntegers = model_->numberIntegers();
        const int * integerVariable = model_->integerVariable();

        int i;
        for (i = 0; i < numberIntegers; i++) {
            int iColumn = integerVariable[i];
            const OsiObject * object = model_->object(i);
            // get original bounds
            double originalLower;
            double originalUpper;
            getIntegerInformation( object, originalLower, originalUpper);
            double value = bestSolution[iColumn];
            if (value < originalLower) {
                value = originalLower;
            } else if (value > originalUpper) {
                value = originalUpper;
            }
        }
    }
    int numberNodes = model_->getNodeCount();
    if (howOften_ == 100) {
        if (numberNodes < lastNode_ + 12)
            return 0;
        // Do at 50 and 100
        if ((numberNodes > 40 && numberNodes <= 50) || (numberNodes > 90 && numberNodes < 100))
            numberNodes = howOften_;
    }
    if ((numberNodes % howOften_) == 0 && (model_->getCurrentPassNumber() == 1 ||
                                           model_->getCurrentPassNumber() == 999999)) {
        lastNode_ = model_->getNodeCount();
        OsiSolverInterface * solver = model_->solver();

        int numberIntegers = model_->numberIntegers();
        const int * integerVariable = model_->integerVariable();

        const double * currentSolution = solver->getColSolution();
        OsiSolverInterface * newSolver = cloneBut(3); // was model_->continuousSolver()->clone();
        //const double * colLower = newSolver->getColLower();
        //const double * colUpper = newSolver->getColUpper();

        double primalTolerance;
        solver->getDblParam(OsiPrimalTolerance, primalTolerance);

        // Sort on distance
        double * distance = new double [numberIntegers];
        int * which = new int [numberIntegers];

        int i;
        int nFix = 0;
        double tolerance = 10.0 * primalTolerance;
        for (i = 0; i < numberIntegers; i++) {
            int iColumn = integerVariable[i];
            const OsiObject * object = model_->object(i);
            // get original bounds
            double originalLower;
            double originalUpper;
            getIntegerInformation( object, originalLower, originalUpper);
            double valueInt = bestSolution[iColumn];
            if (valueInt < originalLower) {
                valueInt = originalLower;
            } else if (valueInt > originalUpper) {
                valueInt = originalUpper;
            }
            baseSolution_[iColumn] = currentSolution[iColumn];
            distance[i] = fabs(currentSolution[iColumn] - valueInt);
            which[i] = i;
            if (fabs(currentSolution[iColumn] - valueInt) < tolerance)
                nFix++;
        }
        CoinSort_2(distance, distance + numberIntegers, which);
        nDifferent_ = numberIntegers - nFix;
        stepSize_ = nDifferent_ / 10;
        k_ = stepSize_;
        //nFix = numberIntegers-stepSize_;
        for (i = 0; i < nFix; i++) {
            int j = which[i];
            int iColumn = integerVariable[j];
            const OsiObject * object = model_->object(i);
            // get original bounds
            double originalLower;
            double originalUpper;
            getIntegerInformation( object, originalLower, originalUpper);
            double valueInt = bestSolution[iColumn];
            if (valueInt < originalLower) {
                valueInt = originalLower;
            } else if (valueInt > originalUpper) {
                valueInt = originalUpper;
            }
            double nearest = floor(valueInt + 0.5);
            newSolver->setColLower(iColumn, nearest);
            newSolver->setColUpper(iColumn, nearest);
        }
        delete [] distance;
        delete [] which;
        if (nFix > numberIntegers / 5) {
            //printf("%d integers have samish value\n",nFix);
            returnCode = smallBranchAndBound(newSolver, numberNodes_, betterSolution, solutionValue,
                                             model_->getCutoff(), "CbcHeuristicVND");
            if (returnCode < 0)
                returnCode = 0; // returned on size
            else
                numRuns_++;
            if ((returnCode&1) != 0)
                numberSuccesses_++;
            //printf("return code %d",returnCode);
            if ((returnCode&2) != 0) {
                // could add cut
                returnCode &= ~2;
                //printf("could add cut with %d elements (if all 0-1)\n",nFix);
            } else {
                //printf("\n");
            }
            numberTries_++;
            if ((numberTries_ % 10) == 0 && numberSuccesses_*3 < numberTries_)
                howOften_ += static_cast<int> (howOften_ * decayFactor_);
        }

        delete newSolver;
    }
    return returnCode;
}
Example #17
0
int
CbcHeuristicCrossover::solution(double & solutionValue,
                                double * betterSolution)
{
    if (when_ == 0)
        return 0;
    numCouldRun_++;
    bool useBest = (numberSolutions_ != model_->getSolutionCount());
    if (!useBest && (when_ % 10) == 1)
        return 0;
    numberSolutions_ = model_->getSolutionCount();
    OsiSolverInterface * continuousSolver = model_->continuousSolver();
    int useNumber = CoinMin(model_->numberSavedSolutions(), useNumber_);
    if (useNumber < 2 || !continuousSolver)
        return 0;
    // Fix later
    if (!useBest)
        abort();
    numRuns_++;
    double cutoff;
    model_->solver()->getDblParam(OsiDualObjectiveLimit, cutoff);
    double direction = model_->solver()->getObjSense();
    cutoff *= direction;
    cutoff = CoinMin(cutoff, solutionValue);
    OsiSolverInterface * solver = cloneBut(2);
    // But reset bounds
    solver->setColLower(continuousSolver->getColLower());
    solver->setColUpper(continuousSolver->getColUpper());
    int numberColumns = solver->getNumCols();
    // Fixed
    double * fixed = new double [numberColumns];
    for (int i = 0; i < numberColumns; i++)
        fixed[i] = -COIN_DBL_MAX;
    int whichSolution[10];
    for (int i = 0; i < useNumber; i++)
        whichSolution[i] = i;
    for (int i = 0; i < useNumber; i++) {
        int k = whichSolution[i];
        const double * solution = model_->savedSolution(k);
        for (int j = 0; j < numberColumns; j++) {
            if (solver->isInteger(j)) {
                if (fixed[j] == -COIN_DBL_MAX)
                    fixed[j] = floor(solution[j] + 0.5);
                else if (fabs(fixed[j] - solution[j]) > 1.0e-7)
                    fixed[j] = COIN_DBL_MAX;
            }
        }
    }
    const double * colLower = solver->getColLower();
    for (int i = 0; i < numberColumns; i++) {
        if (solver->isInteger(i)) {
            double value = fixed[i];
            if (value != COIN_DBL_MAX) {
                if (when_ < 10) {
                    solver->setColLower(i, value);
                    solver->setColUpper(i, value);
                } else if (value == colLower[i]) {
                    solver->setColUpper(i, value);
                }
            }
        }
    }
    int returnCode = smallBranchAndBound(solver, numberNodes_, betterSolution,
                                         solutionValue,
                                         solutionValue, "CbcHeuristicCrossover");
    if (returnCode < 0)
        returnCode = 0; // returned on size
    if ((returnCode&2) != 0) {
        // could add cut
        returnCode &= ~2;
    }

    delete solver;
    return returnCode;
}
Example #18
0
int doBaCParam (CoinParam *param)

{
    assert (param != 0) ;
    CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ;
    assert (genParam != 0) ;
    CbcGenCtlBlk *ctlBlk = genParam->obj() ;
    assert (ctlBlk != 0) ;
    CbcModel *model = ctlBlk->model_ ;
    assert (model != 0) ;
    /*
      Setup to return nonfatal/fatal error (1/-1) by default.
    */
    int retval ;
    if (CoinParamUtils::isInteractive()) {
        retval = 1 ;
    } else {
        retval = -1 ;
    }
    ctlBlk->setBaBStatus(CbcGenCtlBlk::BACAbandon, CbcGenCtlBlk::BACmInvalid,
                         CbcGenCtlBlk::BACwNotStarted, false, 0) ;
    /*
      We ain't gonna do squat without a good model.
    */
    if (!ctlBlk->goodModel_) {
        std::cout << "** Current model not valid!" << std::endl ;
        return (retval) ;
    }
    /*
      Start the clock ticking.
    */
    double time1 = CoinCpuTime() ;
    double time2 ;
    /*
      Create a clone of the model which we can modify with impunity. Extract
      the underlying solver for convenient access.
    */
    CbcModel babModel(*model) ;
    OsiSolverInterface *babSolver = babModel.solver() ;
    assert (babSolver != 0) ;
# if CBC_TRACK_SOLVERS > 0
    std::cout
        << "doBaCParam: initial babSolver is "
        << std::hex << babSolver << std::dec
        << ", log level " << babSolver->messageHandler()->logLevel()
        << "." << std::endl ;
# endif
    /*
      Solve the root relaxation. Bail unless it solves to optimality.
    */
    if (!solveRelaxation(&babModel)) {
        ctlBlk->setBaBStatus(&babModel, CbcGenCtlBlk::BACwBareRoot) ;
        return (0) ;
    }
# if COIN_CBC_VERBOSITY > 0
    std::cout
        << "doBaCParam: initial relaxation z = "
        << babSolver->getObjValue() << "." << std::endl ;
# endif
    /*
      Are we up for fixing variables based on reduced cost alone?
    */
    if (ctlBlk->djFix_.action_ == true) {
        reducedCostHack(babSolver, ctlBlk->djFix_.threshold_) ;
    }
    /*
      Time to consider preprocessing. We'll do a bit of setup before getting to
      the meat of the issue.

      preIppSolver will hold a clone of the unpreprocessed constraint system.
      We'll need it when we postprocess. ippSolver holds the preprocessed
      constraint system.  Again, we clone it and give the clone to babModel for
      B&C. Presumably we need an unmodified copy of the preprocessed system to
      do postprocessing, but the copy itself is hidden inside the preprocess
      object.
    */
    OsiSolverInterface *preIppSolver = 0 ;
    CglPreProcess ippObj ;
    bool didIPP = false ;

    int numberChanged = 0 ;
    int numberOriginalColumns = babSolver->getNumCols() ;
    CbcGenCtlBlk::IPPControl ippAction = ctlBlk->getIPPAction() ;

    if (!(ippAction == CbcGenCtlBlk::IPPOff ||
            ippAction == CbcGenCtlBlk::IPPStrategy)) {
        double timeLeft = babModel.getMaximumSeconds() ;
        preIppSolver = babSolver->clone() ;
        OsiSolverInterface *ippSolver ;
#   if CBC_TRACK_SOLVERS > 0
        std::cout
            << "doBaCParam: clone made prior to IPP is "
            << std::hex << preIppSolver << std::dec
            << ", log level " << preIppSolver->messageHandler()->logLevel()
            << "." << std::endl ;
#   endif

        preIppSolver->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo) ;
        ippObj.messageHandler()->setLogLevel(babModel.logLevel()) ;

        CglProbing probingGen ;
        probingGen.setUsingObjective(true) ;
        probingGen.setMaxPass(3) ;
        probingGen.setMaxProbeRoot(preIppSolver->getNumCols()) ;
        probingGen.setMaxElements(100) ;
        probingGen.setMaxLookRoot(50) ;
        probingGen.setRowCuts(3) ;
        ippObj.addCutGenerator(&probingGen) ;
        /*
          For preProcessNonDefault, the 2nd parameter controls the conversion of
          clique and SOS constraints. 0 does nothing, -1 converts <= to ==, and
          2 and 3 form SOS sets under strict and not-so-strict conditions,
          respectively.
        */
        int convert = 0 ;
        if (ippAction == CbcGenCtlBlk::IPPEqual) {
            convert = -1 ;
        } else if (ippAction == CbcGenCtlBlk::IPPEqualAll) {
            convert = -2 ;
        } else if (ippAction == CbcGenCtlBlk::IPPSOS) {
            convert = 2 ;
        } else if (ippAction == CbcGenCtlBlk::IPPTrySOS) {
            convert = 3 ;
        }

        ippSolver = ippObj.preProcessNonDefault(*preIppSolver, convert, 10) ;
#   if CBC_TRACK_SOLVERS > 0
        std::cout
            << "doBaCParam: solver returned from IPP is "
            << std::hex << ippSolver << std::dec ;
        if (ippSolver) {
            std::cout
                << ", log level " << ippSolver->messageHandler()->logLevel() ;
        }
        std::cout << "." << std::endl ;
#   endif
        /*
          ippSolver == 0 is success of a sort --- integer preprocess has found the
          problem to be infeasible or unbounded. Need to think about how to indicate
          status.
        */
        if (!ippSolver) {
            std::cout
                << "Integer preprocess says infeasible or unbounded" << std::endl ;
            delete preIppSolver ;
            ctlBlk->setBaBStatus(&babModel, CbcGenCtlBlk::BACwIPP) ;
            return (0) ;
        }
#   if COIN_CBC_VERBOSITY > 0
        else {
            std::cout
                << "After integer preprocessing, model has "
                << ippSolver->getNumRows()
                << " rows, " << ippSolver->getNumCols() << " columns, and "
                << ippSolver->getNumElements() << " elements." << std::endl ;
        }
#   endif

        preIppSolver->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo) ;
        ippSolver->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo) ;

        if (ippAction == CbcGenCtlBlk::IPPSave) {
            ippSolver->writeMps("presolved", "mps", 1.0) ;
            std::cout
                << "Integer preprocessed model written to `presolved.mps' "
                << "as minimisation problem." << std::endl ;
        }

        OsiSolverInterface *osiTmp = ippSolver->clone() ;
        babModel.assignSolver(osiTmp) ;
        babSolver = babModel.solver() ;
#   if CBC_TRACK_SOLVERS > 0
        std::cout
            << "doBaCParam: clone of IPP solver passed to babModel is "
            << std::hex << babSolver << std::dec
            << ", log level " << babSolver->messageHandler()->logLevel()
            << "." << std::endl ;
#   endif
        if (!solveRelaxation(&babModel)) {
            delete preIppSolver ;
            ctlBlk->setBaBStatus(&babModel, CbcGenCtlBlk::BACwIPPRelax) ;
            return (0) ;
        }
#   if COIN_CBC_VERBOSITY > 0
        std::cout
            << "doBaCParam: presolved relaxation z = "
            << babSolver->getObjValue() << "." << std::endl ;
#   endif
        babModel.setMaximumSeconds(timeLeft - (CoinCpuTime() - time1)) ;
        didIPP = true ;
    }
    /*
      At this point, babModel and babSolver hold the constraint system we'll use
      for B&C (either the original system or the preprocessed system) and we have
      a solution to the lp relaxation.

      If we're using the COSTSTRATEGY option, set up priorities here and pass
      them to the babModel.
    */
    if (ctlBlk->priorityAction_ != CbcGenCtlBlk::BPOff) {
        setupPriorities(&babModel, ctlBlk->priorityAction_) ;
    }
    /*
      Install heuristics and cutting planes.
    */
    installHeuristics(ctlBlk, &babModel) ;
    installCutGenerators(ctlBlk, &babModel) ;
    /*
      Set up status print frequency for babModel.
    */
    if (babModel.getNumCols() > 2000 || babModel.getNumRows() > 1500 ||
            babModel.messageHandler()->logLevel() > 1)
        babModel.setPrintFrequency(100) ;
    /*
      If we've read in a known good solution for debugging, activate the row cut
      debugger.
    */
    if (ctlBlk->debugSol_.values_) {
        if (ctlBlk->debugSol_.numCols_ == babModel.getNumCols()) {
            babSolver->activateRowCutDebugger(ctlBlk->debugSol_.values_) ;
        } else {
            std::cout
                << "doBaCParam: debug file has incorrect number of columns."
                << std::endl ;
        }
    }
    /*
      Set ratio-based integrality gap, if specified by user.
    */
    if (ctlBlk->setByUser_[CbcCbcParam::GAPRATIO] == true) {
        double obj = babSolver->getObjValue() ;
        double gapRatio = babModel.getDblParam(CbcModel::CbcAllowableFractionGap) ;
        double gap = gapRatio * (1.0e-5 + fabs(obj)) ;
        babModel.setAllowableGap(gap) ;
        std::cout
            << "doBaCParam: Continuous objective = " << obj
            << ", so allowable gap set to " << gap << std::endl ;
    }
    /*
      A bit of mystery code. As best I can figure, setSpecialOptions(2) suppresses
      the removal of warm start information when checkSolution runs an lp to check
      a solution. John's comment, ``probably faster to use a basis to get integer
      solutions'' makes some sense in this context. Didn't try to track down
      moreMipOptions just yet.
    */
    babModel.setSpecialOptions(babModel.specialOptions() | 2) ;
    /*
      { int ndx = whichParam(MOREMIPOPTIONS,numberParameters,parameters) ;
        int moreMipOptions = parameters[ndx].intValue() ;
        if (moreMipOptions >= 0)
        { printf("more mip options %d\n",moreMipOptions);
          babModel.setSearchStrategy(moreMipOptions); } }
    */
    /*
      Begin the final run-up to branch-and-cut.

      Make sure that objects are set up in the solver. It's possible that whoever
      loaded the model into the solver also set up objects. But it's also
      entirely likely that none exist to this point (and interesting to note that
      IPP doesn't need to know anything about objects).
    */
    setupObjects(babSolver, didIPP, &ippObj) ;
    /*
      Set the branching method. We can't do this until we establish objects,
      because the constructor will set up arrays based on the number of objects,
      and there's no provision to set this information after creation. Arguably not
      good --- it'd be nice to set this in the prototype model that's cloned for
      this routine. In CoinSolve, shadowPriceMode is handled with the TESTOSI
      option.
    */
    OsiChooseStrong strong(babSolver) ;
    strong.setNumberBeforeTrusted(babModel.numberBeforeTrust()) ;
    strong.setNumberStrong(babModel.numberStrong()) ;
    strong.setShadowPriceMode(ctlBlk->chooseStrong_.shadowPriceMode_) ;
    CbcBranchDefaultDecision decision ;
    decision.setChooseMethod(strong) ;
    babModel.setBranchingMethod(decision) ;
    /*
      Here I've deleted a huge block of code that deals with external priorities,
      branch direction, pseudocosts, and solution. (PRIORITYIN) Also a block of
      code that generates C++ code.
    */
    /*
      Set up strategy for branch-and-cut. Note that the integer code supplied to
      setupPreProcessing is *not* compatible with the IPPAction enum. But at least
      it's documented. See desiredPreProcess_ in CbcStrategyDefault. `1' is
      accidentally equivalent to IPPOn.
    */

    if (ippAction == CbcGenCtlBlk::IPPStrategy) {
        CbcStrategyDefault strategy(true, 5, 5) ;
        strategy.setupPreProcessing(1) ;
        babModel.setStrategy(strategy) ;
    }
    /*
      Yes! At long last, we're ready for the big call. Do branch and cut. In
      general, the solver used to return the solution will not be the solver we
      passed in, so reset babSolver here.
    */
    int statistics = (ctlBlk->printOpt_ > 0) ? ctlBlk->printOpt_ : 0 ;
# if CBC_TRACK_SOLVERS > 0
    std::cout
        << "doBaCParam: solver at call to branchAndBound is "
        << std::hex << babModel.solver() << std::dec
        << ", log level " << babModel.solver()->messageHandler()->logLevel()
        << "." << std::endl ;
# endif
    babModel.branchAndBound(statistics) ;
    babSolver = babModel.solver() ;
# if CBC_TRACK_SOLVERS > 0
    std::cout
        << "doBaCParam: solver at return from branchAndBound is "
        << std::hex << babModel.solver() << std::dec
        << ", log level " << babModel.solver()->messageHandler()->logLevel()
        << "." << std::endl ;
# endif
    /*
      Write out solution to preprocessed model.
    */
    if (ctlBlk->debugCreate_ == "createAfterPre" &&
            babModel.bestSolution()) {
        CbcGenParamUtils::saveSolution(babSolver, "debug.file") ;
    }
    /*
      Print some information about branch-and-cut.
    */
# if COIN_CBC_VERBOSITY > 0
    std::cout
        << "Cuts at root node changed objective from "
        << babModel.getContinuousObjective()
        << " to " << babModel.rootObjectiveAfterCuts() << std::endl ;

    for (int iGen = 0 ; iGen < babModel.numberCutGenerators() ; iGen++) {
        CbcCutGenerator *generator = babModel.cutGenerator(iGen) ;
        std::cout
            << generator->cutGeneratorName() << " was tried "
            << generator->numberTimesEntered() << " times and created "
            << generator->numberCutsInTotal() << " cuts of which "
            << generator->numberCutsActive()
            << " were active after adding rounds of cuts" ;
        if (generator->timing()) {
            std::cout << " ( " << generator->timeInCutGenerator() << " seconds)" ;
        }
        std::cout << std::endl ;
    }
# endif

    time2 = CoinCpuTime();
    ctlBlk->totalTime_ += time2 - time1;
    /*
      If we performed integer preprocessing, time to back it out.
    */
    if (ippAction != CbcGenCtlBlk::IPPOff) {
#   if CBC_TRACK_SOLVERS > 0
        std::cout
            << "doBaCParam: solver passed to IPP postprocess is "
            << std::hex << babSolver << std::dec << "." << std::endl ;
#   endif
        ippObj.postProcess(*babSolver);
        babModel.assignSolver(preIppSolver) ;
        babSolver = babModel.solver() ;
#   if CBC_TRACK_SOLVERS > 0
        std::cout
            << "doBaCParam: solver in babModel after IPP postprocess is "
            << std::hex << babSolver << std::dec << "." << std::endl ;
#   endif
    }
    /*
      Write out postprocessed solution to debug file, if requested.
    */
    if (ctlBlk->debugCreate_ == "create" && babModel.bestSolution()) {
        CbcGenParamUtils::saveSolution(babSolver, "debug.file") ;
    }
    /*
      If we have a good solution, detach the solver with the answer. Fill in the
      rest of the status information for the benefit of the wider world.
    */
    bool keepAnswerSolver = false ;
    OsiSolverInterface *answerSolver = 0 ;
    if (babModel.bestSolution()) {
        babModel.setModelOwnsSolver(false) ;
        keepAnswerSolver = true ;
        answerSolver = babSolver ;
    }
    ctlBlk->setBaBStatus(&babModel, CbcGenCtlBlk::BACwBAC,
                         keepAnswerSolver, answerSolver) ;
    /*
      And one last bit of information & statistics.
    */
    ctlBlk->printBaBStatus() ;
    std::cout << "    " ;
    if (keepAnswerSolver) {
        std::cout
            << "objective " << babModel.getObjValue() << "; " ;
    }
    std::cout
        << babModel.getNodeCount() << " nodes and "
        << babModel.getIterationCount() << " iterations - took "
        << time2 - time1 << " seconds" << std::endl ;

    return (0) ;
}
Example #19
0
/*
  First tries setting a variable to better value.  If feasible then
  tries setting others.  If not feasible then tries swaps
  Returns 1 if solution, 0 if not 
  The main body of this routine implements an O((q^2)/2) brute force search
  around the current solution, for q = number of integer variables. Call this
  the inc/dec heuristic.  For each integer variable x<i>, first decrement the
  value. Then, for integer variables x<i+1>, ..., x<q-1>, try increment and
  decrement. If one of these permutations produces a better solution,
  remember it.  Then repeat, with x<i> incremented. If we find a better
  solution, update our notion of current solution and continue.

  The net effect is a greedy walk: As each improving pair is found, the
  current solution is updated and the search continues from this updated
  solution.

  Way down at the end, we call solutionFix, which will create a drastically
  restricted problem based on variables marked as used, then do mini-BaC on
  the restricted problem. This can occur even if we don't try the inc/dec
  heuristic. This would be more obvious if the inc/dec heuristic were broken
  out as a separate routine and solutionFix had a name that reflected where
  it was headed.

  The return code of 0 is grossly overloaded, because it maps to a return
  code of 0 from solutionFix, which is itself grossly overloaded. See
  comments in solutionFix and in CbcHeuristic::smallBranchAndBound.
  */
int
CbcHeuristicLocal::solution(double & solutionValue,
                            double * betterSolution)
{
/*
  Execute only if a new solution has been discovered since the last time we
  were called.
*/

    numCouldRun_++;
    // See if frequency kills off idea
    int swap = swap_%100;
    int skip = swap_/100;
    int nodeCount = model_->getNodeCount();
    if (nodeCount<lastRunDeep_+skip && nodeCount != lastRunDeep_+1) 
      return 0;
    if (numberSolutions_ == model_->getSolutionCount() &&
	(numberSolutions_ == howOftenShallow_ ||
	 nodeCount < lastRunDeep_+2*skip))
        return 0;
    howOftenShallow_ = numberSolutions_;
    numberSolutions_ = model_->getSolutionCount();
    if (nodeCount<lastRunDeep_+skip ) 
      return 0;
    lastRunDeep_ = nodeCount;
    howOftenShallow_ = numberSolutions_;

    if ((swap%10) == 2) {
        // try merge
        return solutionFix( solutionValue, betterSolution, NULL);
    }
/*
  Exclude long (column), thin (row) systems.

  Given the n^2 nature of the search, more than 100,000 columns could get
  expensive. But I don't yet see the rationale for the second part of the
  condition (cols > 10*rows). And cost is proportional to number of integer
  variables --- shouldn't we use that?

  Why wait until we have more than one solution?
*/
    if ((model_->getNumCols() > 100000 && model_->getNumCols() >
            10*model_->getNumRows()) || numberSolutions_ <= 1)
        return 0; // probably not worth it
    // worth trying

    OsiSolverInterface * solver = model_->solver();
    const double * rowLower = solver->getRowLower();
    const double * rowUpper = solver->getRowUpper();
    const double * solution = model_->bestSolution();
/*
  Shouldn't this test be redundant if we've already checked that
  numberSolutions_ > 1? Stronger: shouldn't this be an assertion?
*/
    if (!solution)
        return 0; // No solution found yet
    const double * objective = solver->getObjCoefficients();
    double primalTolerance;
    solver->getDblParam(OsiPrimalTolerance, primalTolerance);

    int numberRows = matrix_.getNumRows();

    int numberIntegers = model_->numberIntegers();
    const int * integerVariable = model_->integerVariable();

    int i;
    double direction = solver->getObjSense();
    double newSolutionValue = model_->getObjValue() * direction;
    int returnCode = 0;
    numRuns_++;
    // Column copy
    const double * element = matrix_.getElements();
    const int * row = matrix_.getIndices();
    const CoinBigIndex * columnStart = matrix_.getVectorStarts();
    const int * columnLength = matrix_.getVectorLengths();

    // Get solution array for heuristic solution
    int numberColumns = solver->getNumCols();
    double * newSolution = new double [numberColumns];
    memcpy(newSolution, solution, numberColumns*sizeof(double));
#ifdef LOCAL_FIX_CONTINUOUS
    // mark continuous used
    const double * columnLower = solver->getColLower();
    for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
        if (!solver->isInteger(iColumn)) {
            if (solution[iColumn] > columnLower[iColumn] + 1.0e-8)
                used_[iColumn] = numberSolutions_;
        }
    }
#endif

    // way is 1 if down possible, 2 if up possible, 3 if both possible
    char * way = new char[numberIntegers];
    // corrected costs
    double * cost = new double[numberIntegers];
    // for array to mark infeasible rows after iColumn branch
    char * mark = new char[numberRows];
    memset(mark, 0, numberRows);
    // space to save values so we don't introduce rounding errors
    double * save = new double[numberRows];
/*
  Force variables within their original bounds, then to the nearest integer.
  Overall, we seem to be prepared to cope with noninteger bounds. Is this
  necessary? Seems like we'd be better off to force the bounds to integrality
  as part of preprocessing.  More generally, why do we need to do this? This
  solution should have been cleaned and checked when it was accepted as a
  solution!

  Once the value is set, decide whether we can move up or down.

  The only place that used_ is used is in solutionFix; if a variable is not
  flagged as used, it will be fixed (at lower bound). Why the asymmetric
  treatment? This makes some sense for binary variables (for which there are
  only two options). But for general integer variables, why not make a similar
  test against the original upper bound?
*/

    // clean solution
    for (i = 0; i < numberIntegers; i++) {
        int iColumn = integerVariable[i];
        const OsiObject * object = model_->object(i);
        // get original bounds
        double originalLower;
        double originalUpper;
        getIntegerInformation( object, originalLower, originalUpper);
        double value = newSolution[iColumn];
        if (value < originalLower) {
            value = originalLower;
            newSolution[iColumn] = value;
        } else if (value > originalUpper) {
            value = originalUpper;
            newSolution[iColumn] = value;
        }
        double nearest = floor(value + 0.5);
        //assert(fabs(value-nearest)<10.0*primalTolerance);
        value = nearest;
        newSolution[iColumn] = nearest;
        // if away from lower bound mark that fact
        if (nearest > originalLower) {
            used_[iColumn] = numberSolutions_;
        }
        cost[i] = direction * objective[iColumn];
/*
  Given previous computation we're checking that value is at least 1 away
  from the original bounds.
*/
        int iway = 0;

        if (value > originalLower + 0.5)
            iway = 1;
        if (value < originalUpper - 0.5)
            iway |= 2;
        way[i] = static_cast<char>(iway);
    }
/*
  Calculate lhs of each constraint for groomed solution.
*/
    // get row activities
    double * rowActivity = new double[numberRows];
    memset(rowActivity, 0, numberRows*sizeof(double));

    for (i = 0; i < numberColumns; i++) {
        int j;
        double value = newSolution[i];
        if (value) {
            for (j = columnStart[i];
                    j < columnStart[i] + columnLength[i]; j++) {
                int iRow = row[j];
                rowActivity[iRow] += value * element[j];
            }
        }
    }
/*
  Check that constraints are satisfied. For small infeasibility, force the
  activity within bound. Again, why is this necessary if the current solution
  was accepted as a valid solution?

  Why are we scanning past the first unacceptable constraint?
*/
    // check was feasible - if not adjust (cleaning may move)
    // if very infeasible then give up
    bool tryHeuristic = true;
    for (i = 0; i < numberRows; i++) {
        if (rowActivity[i] < rowLower[i]) {
            if (rowActivity[i] < rowLower[i] - 10.0*primalTolerance)
                tryHeuristic = false;
            rowActivity[i] = rowLower[i];
        } else if (rowActivity[i] > rowUpper[i]) {
            if (rowActivity[i] < rowUpper[i] + 10.0*primalTolerance)
                tryHeuristic = false;
            rowActivity[i] = rowUpper[i];
        }
    }
/*
  This bit of code is not quite totally redundant: it'll bail at 10,000
  instead of 100,000. Potentially we can do a lot of work to get here, only
  to abandon it.
*/
    // Switch off if may take too long
    if (model_->getNumCols() > 10000 && model_->getNumCols() >
            10*model_->getNumRows())
        tryHeuristic = false;
/*
  Try the inc/dec heuristic?
*/
    if (tryHeuristic) {

        // total change in objective
        double totalChange = 0.0;
        // local best change in objective
        double bestChange = 0.0;
	// maybe just do 1000
	int maxIntegers = numberIntegers;
	if (((swap/10) &1) != 0) {
	  maxIntegers = CoinMin(1000,numberIntegers);
	}
/*
  Outer loop to walk integer variables. Call the current variable x<i>. At the
  end of this loop, bestChange will contain the best (negative) change in the
  objective for any single pair.

  The trouble is, we're limited to monotonically increasing improvement.
  Suppose we discover an improvement of 10 for some pair. If, later in the
  search, we discover an improvement of 9 for some other pair, we will not use
  it. That seems wasteful.
*/

        for (i = 0; i < numberIntegers; i++) {
            int iColumn = integerVariable[i];
	    bestChange = 0.0;
	    int endInner = CoinMin(numberIntegers,i+maxIntegers);

            double objectiveCoefficient = cost[i];
            int k;
            int j;
            int goodK = -1;
            int wayK = -1, wayI = -1;
/*
  Try decrementing x<i>.
*/
            if ((way[i]&1) != 0) {
                int numberInfeasible = 0;
/*
  Adjust row activities where x<i> has a nonzero coefficient. Save the old
  values for restoration. Mark any rows that become infeasible as a result
  of the decrement.
*/
                // save row activities and adjust
                for (j = columnStart[iColumn];
                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
                    int iRow = row[j];
                    save[iRow] = rowActivity[iRow];
                    rowActivity[iRow] -= element[j];
                    if (rowActivity[iRow] < rowLower[iRow] - primalTolerance ||
                            rowActivity[iRow] > rowUpper[iRow] + primalTolerance) {
                        // mark row
                        mark[iRow] = 1;
                        numberInfeasible++;
                    }
                }
  /*
  Run through the remaining integer variables. Try increment and decrement on
  each one. If the potential objective change is better than anything we've
  seen so far, do a full evaluation of x<k> in that direction.  If we can
  repair all infeasibilities introduced by pushing x<i> down, we have a
  winner. Remember the best variable, and the direction for x<i> and x<k>.
*/
              // try down
                for (k = i + 1; k < endInner; k++) {
                    if ((way[k]&1) != 0) {
                        // try down
                        if (-objectiveCoefficient - cost[k] < bestChange) {
                            // see if feasible down
                            bool good = true;
                            int numberMarked = 0;
                            int kColumn = integerVariable[k];
                            for (j = columnStart[kColumn];
                                    j < columnStart[kColumn] + columnLength[kColumn]; j++) {
                                int iRow = row[j];
                                double newValue = rowActivity[iRow] - element[j];
                                if (newValue < rowLower[iRow] - primalTolerance ||
                                        newValue > rowUpper[iRow] + primalTolerance) {
                                    good = false;
                                    break;
                                } else if (mark[iRow]) {
                                    // made feasible
                                    numberMarked++;
                                }
                            }
                            if (good && numberMarked == numberInfeasible) {
                                // better solution
                                goodK = k;
                                wayK = -1;
                                wayI = -1;
                                bestChange = -objectiveCoefficient - cost[k];
                            }
                        }
                    }
                    if ((way[k]&2) != 0) {
                        // try up
                        if (-objectiveCoefficient + cost[k] < bestChange) {
                            // see if feasible up
                            bool good = true;
                            int numberMarked = 0;
                            int kColumn = integerVariable[k];
                            for (j = columnStart[kColumn];
                                    j < columnStart[kColumn] + columnLength[kColumn]; j++) {
                                int iRow = row[j];
                                double newValue = rowActivity[iRow] + element[j];
                                if (newValue < rowLower[iRow] - primalTolerance ||
                                        newValue > rowUpper[iRow] + primalTolerance) {
                                    good = false;
                                    break;
                                } else if (mark[iRow]) {
                                    // made feasible
                                    numberMarked++;
                                }
                            }
                            if (good && numberMarked == numberInfeasible) {
                                // better solution
                                goodK = k;
                                wayK = 1;
                                wayI = -1;
                                bestChange = -objectiveCoefficient + cost[k];
                            }
                        }
                    }
                }
/*
  Remove effect of decrementing x<i> by restoring original lhs values.
*/
                // restore row activities
                for (j = columnStart[iColumn];
                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
                    int iRow = row[j];
                    rowActivity[iRow] = save[iRow];
                    mark[iRow] = 0;
                }
            }
/*
  Try to increment x<i>. Actions as for decrement.
*/
            if ((way[i]&2) != 0) {
                int numberInfeasible = 0;
                // save row activities and adjust
                for (j = columnStart[iColumn];
                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
                    int iRow = row[j];
                    save[iRow] = rowActivity[iRow];
                    rowActivity[iRow] += element[j];
                    if (rowActivity[iRow] < rowLower[iRow] - primalTolerance ||
                            rowActivity[iRow] > rowUpper[iRow] + primalTolerance) {
                        // mark row
                        mark[iRow] = 1;
                        numberInfeasible++;
                    }
                }
                // try up
                for (k = i + 1; k < endInner; k++) {
                    if ((way[k]&1) != 0) {
                        // try down
                        if (objectiveCoefficient - cost[k] < bestChange) {
                            // see if feasible down
                            bool good = true;
                            int numberMarked = 0;
                            int kColumn = integerVariable[k];
                            for (j = columnStart[kColumn];
                                    j < columnStart[kColumn] + columnLength[kColumn]; j++) {
                                int iRow = row[j];
                                double newValue = rowActivity[iRow] - element[j];
                                if (newValue < rowLower[iRow] - primalTolerance ||
                                        newValue > rowUpper[iRow] + primalTolerance) {
                                    good = false;
                                    break;
                                } else if (mark[iRow]) {
                                    // made feasible
                                    numberMarked++;
                                }
                            }
                            if (good && numberMarked == numberInfeasible) {
                                // better solution
                                goodK = k;
                                wayK = -1;
                                wayI = 1;
                                bestChange = objectiveCoefficient - cost[k];
                            }
                        }
                    }
                    if ((way[k]&2) != 0) {
                        // try up
                        if (objectiveCoefficient + cost[k] < bestChange) {
                            // see if feasible up
                            bool good = true;
                            int numberMarked = 0;
                            int kColumn = integerVariable[k];
                            for (j = columnStart[kColumn];
                                    j < columnStart[kColumn] + columnLength[kColumn]; j++) {
                                int iRow = row[j];
                                double newValue = rowActivity[iRow] + element[j];
                                if (newValue < rowLower[iRow] - primalTolerance ||
                                        newValue > rowUpper[iRow] + primalTolerance) {
                                    good = false;
                                    break;
                                } else if (mark[iRow]) {
                                    // made feasible
                                    numberMarked++;
                                }
                            }
                            if (good && numberMarked == numberInfeasible) {
                                // better solution
                                goodK = k;
                                wayK = 1;
                                wayI = 1;
                                bestChange = objectiveCoefficient + cost[k];
                            }
                        }
                    }
                }
                // restore row activities
                for (j = columnStart[iColumn];
                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
                    int iRow = row[j];
                    rowActivity[iRow] = save[iRow];
                    mark[iRow] = 0;
                }
            }
/*
  We've found a pair x<i> and x<k> which produce a better solution. Update our
  notion of current solution to match.

  Why does this not update newSolutionValue?
*/
            if (goodK >= 0) {
                // we found something - update solution
                for (j = columnStart[iColumn];
                        j < columnStart[iColumn] + columnLength[iColumn]; j++) {
                    int iRow = row[j];
                    rowActivity[iRow]  += wayI * element[j];
                }
                newSolution[iColumn] += wayI;
                int kColumn = integerVariable[goodK];
                for (j = columnStart[kColumn];
                        j < columnStart[kColumn] + columnLength[kColumn]; j++) {
                    int iRow = row[j];
                    rowActivity[iRow]  += wayK * element[j];
                }
                newSolution[kColumn] += wayK;
/*
  Adjust motion range for x<k>. We may have banged up against a bound with that
  last move.
*/
               // See if k can go further ?
                const OsiObject * object = model_->object(goodK);
                // get original bounds
                double originalLower;
                double originalUpper;
                getIntegerInformation( object, originalLower, originalUpper);

                double value = newSolution[kColumn];
                int iway = 0;

                if (value > originalLower + 0.5)
                    iway = 1;
                if (value < originalUpper - 0.5)
                    iway |= 2;
                way[goodK] = static_cast<char>(iway);
		totalChange += bestChange;
            }
        }
/*
  End of loop to try increment/decrement of integer variables.

  newSolutionValue does not necessarily match the current newSolution, and
  bestChange simply reflects the best single change. Still, that's sufficient
  to indicate that there's been at least one change. Check that we really do
  have a valid solution.
*/
        if (totalChange + newSolutionValue < solutionValue) {
            // paranoid check
            memset(rowActivity, 0, numberRows*sizeof(double));

            for (i = 0; i < numberColumns; i++) {
                int j;
                double value = newSolution[i];
                if (value) {
                    for (j = columnStart[i];
                            j < columnStart[i] + columnLength[i]; j++) {
                        int iRow = row[j];
                        rowActivity[iRow] += value * element[j];
                    }
                }
            }
            int numberBad = 0;
            double sumBad = 0.0;
            // check was approximately feasible
            for (i = 0; i < numberRows; i++) {
                if (rowActivity[i] < rowLower[i]) {
                    sumBad += rowLower[i] - rowActivity[i];
                    if (rowActivity[i] < rowLower[i] - 10.0*primalTolerance)
                        numberBad++;
                } else if (rowActivity[i] > rowUpper[i]) {
                    sumBad += rowUpper[i] - rowActivity[i];
                    if (rowActivity[i] > rowUpper[i] + 10.0*primalTolerance)
                        numberBad++;
                }
            }
            if (!numberBad) {
                for (i = 0; i < numberIntegers; i++) {
                    int iColumn = integerVariable[i];
                    const OsiObject * object = model_->object(i);
                    // get original bounds
                    double originalLower;
                    double originalUpper;
                    getIntegerInformation( object, originalLower, originalUpper);

                    double value = newSolution[iColumn];
                    // if away from lower bound mark that fact
                    if (value > originalLower) {
                        used_[iColumn] = numberSolutions_;
                    }
                }
/*
  Copy the solution to the array returned to the client. Grab a basis from
  the solver (which, if it exists, is almost certainly infeasible, but it
  should be ok for a dual start). The value returned as solutionValue is
  conservative because of handling of newSolutionValue and bestChange, as
  described above.
*/
                // new solution
                memcpy(betterSolution, newSolution, numberColumns*sizeof(double));
                CoinWarmStartBasis * basis =
                    dynamic_cast<CoinWarmStartBasis *>(solver->getWarmStart()) ;
                if (basis) {
                    model_->setBestSolutionBasis(* basis);
                    delete basis;
                }
                returnCode = 1;
                solutionValue = newSolutionValue + bestChange;
            } else {
                // bad solution - should not happen so debug if see message
                COIN_DETAIL_PRINT(printf("Local search got bad solution with %d infeasibilities summing to %g\n",
					 numberBad, sumBad));
            }
        }
    }
/*
  We're done. Clean up.
*/
    delete [] newSolution;
    delete [] rowActivity;
    delete [] way;
    delete [] cost;
    delete [] save;
    delete [] mark;
/*
  Do we want to try swapping values between solutions?
  swap_ is set elsewhere; it's not adjusted during heuristic execution.

  Again, redundant test. We shouldn't be here if numberSolutions_ = 1.
*/
    if (numberSolutions_ > 1 && (swap%10) == 1) {
        // try merge
        int returnCode2 = solutionFix( solutionValue, betterSolution, NULL);
        if (returnCode2)
            returnCode = 1;
    }
    return returnCode;
}
Example #20
0
OsiSolverInterface* cpropagation_preprocess(CPropagation *cp, int nindexes[])
{
    if(cp->varsToFix == 0)
    {
        /* printf("There are no variables to remove from the problem!\n"); */
        return NULL; /* returns a pointer to original solver */
    }

    const double *colLb = problem_vars_lower_bound(cp->problem), *colUb = problem_vars_upper_bound(cp->problem);
    const double *objCoef = problem_vars_obj_coefs(cp->problem);
    const char *ctype = problem_vars_type(cp->problem);

    double sumFixedObj = 0.0; /* stores the sum of objective coefficients of all variables fixed to 1 */

    OsiSolverInterface *preProcSolver = new OsiClpSolverInterface();
    preProcSolver->setIntParam(OsiNameDiscipline, 2);
    preProcSolver->messageHandler()->setLogLevel(0);
    preProcSolver->setHintParam(OsiDoReducePrint,true,OsiHintTry);
    //preProcSolver->setObjName(cp->solver->getObjName());

    for(int i = 0, j = 0; i < problem_num_cols(cp->problem); i++)
    {
        nindexes[i] = -1;
        if(cp->isToFix[i] == UNFIXED)
        {
            preProcSolver->addCol(0, NULL, NULL, colLb[i], colUb[i], objCoef[i]);
            preProcSolver->setColName(j, problem_var_name(cp->problem, i));
            if(problem_var_type(cp->problem, i) == CONTINUOUS)
                preProcSolver->setContinuous(j);
            else 
                preProcSolver->setInteger(j);
            nindexes[i] = j++;
        }
        else if(cp->isToFix[i] == ACTIVATE)
            sumFixedObj += objCoef[i];
    }

    if(fabs(sumFixedObj) > EPS)
    {
        /* adding a variable with cost equals to the sum of all coefficients of variables fixed to 1 */
        preProcSolver->addCol(0, NULL, NULL, 1.0, 1.0, sumFixedObj);
        preProcSolver->setColName(preProcSolver->getNumCols()-1, "sumFixedObj");
        preProcSolver->setInteger(preProcSolver->getNumCols()-1);
    }

    for(int idxRow = 0; idxRow < problem_num_rows(cp->problem); idxRow++)
    {
        const int nElements = problem_row_size(cp->problem, idxRow);
        const int *idxs = problem_row_idxs(cp->problem, idxRow);
        const double *coefs = problem_row_coefs(cp->problem, idxRow);
        vector< int > vidx; vidx.reserve(problem_num_cols(cp->problem));
        vector< double > vcoef; vcoef.reserve(problem_num_cols(cp->problem));
        double activeCoefs = 0.0;

        for(int i = 0; i < nElements; i++)
        {
            if(cp->isToFix[idxs[i]] == UNFIXED)
            {
                assert(nindexes[idxs[i]] >= 0 && nindexes[idxs[i]] < problem_num_cols(cp->problem));
                vidx.push_back(nindexes[idxs[i]]);
                vcoef.push_back(coefs[i]);
            }
            else if(cp->isToFix[idxs[i]] == ACTIVATE)
            	activeCoefs += coefs[i];
        }

        if(!vidx.empty())
        {
        	double rlb, rub;
        	const char sense = problem_row_sense(cp->problem, idxRow);
        	
        	if(sense == 'E')
            {
                rlb = problem_row_rhs(cp->problem, idxRow) - activeCoefs;
                rub = problem_row_rhs(cp->problem, idxRow) - activeCoefs;
            }
        	else if(sense == 'L')
            {
                rlb = preProcSolver->getInfinity();
                rub = problem_row_rhs(cp->problem, idxRow) - activeCoefs;
            }
        	else if(sense == 'G')
            {
                rlb = problem_row_rhs(cp->problem, idxRow) - activeCoefs;
                rub = preProcSolver->getInfinity();
            }
        	else
        	{
        		fprintf(stderr, "Error: invalid type of constraint!\n");
        		exit(EXIT_FAILURE);
        	}

        	preProcSolver->addRow((int)vcoef.size(), &vidx[0], &vcoef[0], rlb, rub);
            preProcSolver->setRowName(idxRow, problem_row_name(cp->problem, idxRow));
        }
	}

    return preProcSolver;
}
Example #21
0
// Create result
void 
OsiSolverResult::createResult(const OsiSolverInterface & solver, const double * lowerBefore,
                              const double * upperBefore)
{
  delete [] primalSolution_;
  delete [] dualSolution_;
  if (solver.isProvenOptimal()&&!solver.isDualObjectiveLimitReached()) {
    objectiveValue_ = solver.getObjValue()*solver.getObjSense();
    CoinWarmStartBasis * basis = dynamic_cast<CoinWarmStartBasis *> (solver.getWarmStart());
    assert (basis);
    basis_ = * basis;
    int numberRows = basis_.getNumArtificial();
    int numberColumns = basis_.getNumStructural();
    assert (numberColumns==solver.getNumCols());
    assert (numberRows==solver.getNumRows());
    primalSolution_ = CoinCopyOfArray(solver.getColSolution(),numberColumns);
    dualSolution_ = CoinCopyOfArray(solver.getRowPrice(),numberRows);
    fixed_.addBranch(-1,numberColumns,lowerBefore,solver.getColLower(),
                     upperBefore,solver.getColUpper());
  } else {
    // infeasible
    objectiveValue_ = COIN_DBL_MAX;
    basis_ = CoinWarmStartBasis();;
    primalSolution_=NULL;
    dualSolution_=NULL;
  }
}
Example #22
0
//-------------------------------------------------------------------
// Determine the type of a given row 
//-------------------------------------------------------------------
CglFlowRowType
CglFlowCover::determineOneRowType(const OsiSolverInterface& si,
				  int rowLen, int* ind, 
				  double* coef, char sense, 
				  double rhs) const
{
  if (rowLen == 0) 
    return CGLFLOW_ROW_UNDEFINED;
  if (sense == 'R')
    return CGLFLOW_ROW_UNINTERSTED; // Could be fixed
    
  CglFlowRowType rowType = CGLFLOW_ROW_UNDEFINED;
  // Get integer types
  const char * columnType = si.getColType ();
    
  int  numPosBin = 0;      // num of positive binary variables
  int  numNegBin = 0;      // num of negative binary variables
  int  numBin    = 0;      // num of binary variables
  int  numPosCol = 0;      // num of positive variables
  int  numNegCol = 0;      // num of negative variables
  int  i;
  bool flipped = false;

  // Range row will only consider as 'L'
  if (sense == 'G') {        // Transform to " <= "
    flipRow(rowLen, coef, sense, rhs);                
    flipped = true;
  }
    
  // Summarize the variable types of the given row.
  for ( i = 0; i < rowLen; ++i ) {
    if ( coef[i] < -EPSILON_ ) {
      ++numNegCol;
      if( columnType[ind[i]]==1 )
	++numNegBin;
    }
    else {
      ++numPosCol;
      if( columnType[ind[i]]==1 )
	++numPosBin;    
    }
  }
  numBin = numNegBin + numPosBin;

  if(CGLFLOW_DEBUG) {
    std::cout << "numNegBin = " << numNegBin << std::endl;
    std::cout << "numPosBin = " << numPosBin << std::endl;
    std::cout << "numBin = " << numBin << std::endl;
    std::cout << "rowLen = " << rowLen << std::endl;
  }
    
    
  //------------------------------------------------------------------------
  // Classify row type based on the types of variables.
    
  // All variables are binary. NOT interested in this type of row right now
  if (numBin == rowLen) 
    rowType = CGLFLOW_ROW_UNINTERSTED;

  // All variables are NOT binary
  if (rowType == CGLFLOW_ROW_UNDEFINED && numBin == 0) {
    if (sense == 'L')
      rowType = CGLFLOW_ROW_NOBINUB;
    else 
      rowType = CGLFLOW_ROW_NOBINEQ;
  }

  // There are binary and other types of variables   
  if (rowType == CGLFLOW_ROW_UNDEFINED) {  
    if ((rhs < -EPSILON_) || (rhs > EPSILON_) || (numBin != 1)) {
      if (sense == 'L')
	rowType = CGLFLOW_ROW_MIXUB;
      else 
	rowType = CGLFLOW_ROW_MIXEQ;
    }
    else {                               // EXACTLY one binary
      if (rowLen == 2) {               // One binary and one other type
	if (sense == 'L') {
	  if (numNegCol == 1 && numNegBin == 1)
	    rowType = CGLFLOW_ROW_VARUB;
	  if (numPosCol == 1 && numPosBin == 1)
	    rowType = CGLFLOW_ROW_VARLB;
	}
	else
	  rowType = CGLFLOW_ROW_VAREQ;
      }
      else {               // One binary and 2 or more other types
	if (numNegCol==1 && numNegBin==1) {// Binary has neg coef and 
	  if (sense == 'L')  // other are positive
	    rowType = CGLFLOW_ROW_SUMVARUB;
	  else
	    rowType = CGLFLOW_ROW_SUMVAREQ;
	}
      }
    }
  }
  
  // Still undefined
  if (rowType == CGLFLOW_ROW_UNDEFINED) {
    if (sense == 'L') 
      rowType = CGLFLOW_ROW_MIXUB;
    else
      rowType = CGLFLOW_ROW_MIXEQ;
  }
  if (flipped == true) {
    flipRow(rowLen, coef, sense, rhs);                
  }

  return rowType;
}