int pushCbcOsiDbl (CoinParam *param) { assert (param != 0) ; CbcOsiParam *osiParam = dynamic_cast<CbcOsiParam *>(param) ; assert (osiParam != 0) ; OsiSolverInterface *osi = osiParam->obj() ; assert (osi != 0) ; double val = osiParam->dblVal() ; CbcOsiParam::CbcOsiParamCode code = osiParam->paramCode() ; assert (osi != 0) ; /* Setup to return nonfatal/fatal error (1/-1) by default, so that all we need to do is correct to 0 (no error) if we're successful. */ int retval ; if (CoinParamUtils::isInteractive()) { retval = 1 ; } else { retval = -1 ; } /* Translate the parameter code from CbcOsiParamCode into the correct key for CbcDblParam. */ OsiDblParam key ; switch (code) { case CbcOsiParam::PRIMALTOLERANCE: { key = OsiPrimalTolerance ; break ; } case CbcOsiParam::DUALTOLERANCE: { key = OsiDualTolerance ; ; break ; } case CbcOsiParam::DUALBOUND: { key = OsiDualObjectiveLimit ; break ; } default: { std::cerr << "pushCbcOsiDblParam: no equivalent OsiDblParam for " << "parameter code `" << code << "'." << std::endl ; retval = -1 ; break ; } } bool setOK = osi->setDblParam(key, val) ; if (setOK == false) { retval = -1 ; } return (retval) ; }
void HeuristicInnerApproximation::extractInnerApproximation(Bonmin::OsiTMINLPInterface & nlp, OsiSolverInterface &si, const double * x, bool getObj) { printf("************ Start extracting inner approx"); int n; int m; int nnz_jac_g; int nnz_h_lag; Ipopt::TNLP::IndexStyleEnum index_style; Bonmin::TMINLP2TNLP * problem = nlp.problem(); //Get problem information problem->get_nlp_info(n, m, nnz_jac_g, nnz_h_lag, index_style); Bonmin::vector<int> jRow(nnz_jac_g); Bonmin::vector<int> jCol(nnz_jac_g); Bonmin::vector<double> jValues(nnz_jac_g); problem->eval_jac_g(n, NULL, 0, m, nnz_jac_g, jRow(), jCol(), NULL); if(index_style == Ipopt::TNLP::FORTRAN_STYLE)//put C-style { for(int i = 0 ; i < nnz_jac_g ; i++){ jRow[i]--; jCol[i]--; } } //get Jacobian problem->eval_jac_g(n, x, 1, m, nnz_jac_g, NULL, NULL, jValues()); Bonmin::vector<double> g(m); problem->eval_g(n, x, 1, m, g()); Bonmin::vector<int> nonLinear(m); //store non linear constraints (which are to be removed from IA) int numNonLinear = 0; const double * rowLower = nlp.getRowLower(); const double * rowUpper = nlp.getRowUpper(); const double * colLower = nlp.getColLower(); const double * colUpper = nlp.getColUpper(); assert(m == nlp.getNumRows()); double infty = si.getInfinity(); double nlp_infty = nlp.getInfinity(); Bonmin::vector<Ipopt::TNLP::LinearityType> constTypes(m); Bonmin::vector<Ipopt::TNLP::LinearityType> varTypes(n); problem->get_constraints_linearity(m, constTypes()); problem->get_variables_linearity(n, varTypes()); for (int i = 0; i < m; i++) { if (constTypes[i] == Ipopt::TNLP::NON_LINEAR) { nonLinear[numNonLinear++] = i; } } Bonmin::vector<double> rowLow(m - numNonLinear); Bonmin::vector<double> rowUp(m - numNonLinear); int ind = 0; for (int i = 0; i < m; i++) { if (constTypes[i] != Ipopt::TNLP::NON_LINEAR) { if (rowLower[i] > -nlp_infty) { // printf("Lower %g ", rowLower[i]); rowLow[ind] = (rowLower[i]); } else rowLow[ind] = -infty; if (rowUpper[i] < nlp_infty) { // printf("Upper %g ", rowUpper[i]); rowUp[ind] = (rowUpper[i]); } else rowUp[ind] = infty; ind++; } } CoinPackedMatrix mat(true, jRow(), jCol(), jValues(), nnz_jac_g); mat.setDimensions(m, n); // In case matrix was empty, this should be enough //remove non-linear constraints mat.deleteRows(numNonLinear, nonLinear()); int numcols = nlp.getNumCols(); Bonmin::vector<double> obj(numcols); for (int i = 0; i < numcols; i++) obj[i] = 0.; si.loadProblem(mat, nlp.getColLower(), nlp.getColUpper(), obj(), rowLow(), rowUp()); const Bonmin::TMINLP::VariableType* variableType = problem->var_types(); for (int i = 0; i < n; i++) { if ((variableType[i] == Bonmin::TMINLP::BINARY) || (variableType[i] == Bonmin::TMINLP::INTEGER)) si.setInteger(i); } if (getObj) { bool addObjVar = false; if (problem->hasLinearObjective()) { double zero; Bonmin::vector<double> x0(n, 0.); problem->eval_f(n, x0(), 1, zero); si.setDblParam(OsiObjOffset, -zero); //Copy the linear objective and don't create a dummy variable. problem->eval_grad_f(n, x, 1, obj()); si.setObjective(obj()); } else { addObjVar = true; } if (addObjVar) { nlp.addObjectiveFunction(si, x); } } // Hassan IA initial description int InnerDesc = 1; if (InnerDesc == 1) { OsiCuts cs; double * p = CoinCopyOfArray(colLower, n); double * pp = CoinCopyOfArray(colLower, n); double * up = CoinCopyOfArray(colUpper, n); for (int i = 0; i < n; i++) { if (p[i] < -1e3){ p[i] = pp[i] = -1e3; } if (up[i] > 1e2){ up[i] = 1e2; } } const int& nbAp = nbAp_; printf("Generating approximation with %i points.\n", nbAp); std::vector<double> step(n); int n_lin = 0; for (int i = 0; i < n; i++) { //if ((variableType[i] == Bonmin::TMINLP::BINARY) || (variableType[i] == Bonmin::TMINLP::INTEGER)) { if (varTypes[i] == Ipopt::TNLP::LINEAR) { n_lin ++; step[i] = 0; p[i] = pp[i] = up[i] = 0; } else { step[i] = (up[i] - p[i]) / (nbAp); } } printf("Number of linears %i\n", n_lin); for (int j = 1; j < nbAp; j++) { for (int i = 0; i < n; i++) { pp[i] += step[i]; } for (int i = 0; (i < m ); i++) { if (constTypes[i] == Ipopt::TNLP::LINEAR) continue; bool status = getMyInnerApproximation(nlp, cs, i, p, pp);// Generate a chord connecting the two points if(status == false){ printf("Error in generating inner approximation\n"); exit(1); } } std::copy(pp, pp+n, p); } for(int i = 0; (i< m); i++) { if (constTypes[i] == Ipopt::TNLP::LINEAR) continue; getMyInnerApproximation(nlp, cs, i, p, up);// Generate a chord connecting the two points } delete [] p; delete [] pp; delete [] up; si.applyCuts(cs); } printf("************ Done extracting inner approx ********"); }
void CglLandP::generateCuts(const OsiSolverInterface & si, OsiCuts & cs, const CglTreeInfo info ) { if ((info.pass == 0) && !info.inTree) { numrows_ = si.getNumRows(); } // scanExtraCuts(cs, si.getColSolution()); Parameters params = params_; params.rhsWeight = numrows_ + 2; handler_->message(CUT_GAP, messages_)<<info.pass<<si.getObjValue() <<CoinMessageEol; if (info.inTree) //put lower pivot limit { params.pivotLimit = std::min(params.pivotLimit, params.pivotLimitInTree); params.countMistakenRc = true; } if (params.timeLimit < 0) { params.pivotLimit = 0; } assert(si.basisIsAvailable()); #ifdef APPEND_ROW OsiSolverInterface * t_si = si.clone(); if (params.modularize) { int new_idx = si.getNumCols(); int v_idx[1] = {new_idx}; double v_val[1] = {-1}; CoinPackedVector v(1, v_idx, v_val, false); t_si->addCol(CoinPackedVector(), 0, 1, 0); t_si->setInteger(new_idx); t_si->addRow(v,0, 0); t_si->resolve(); } #else const OsiSolverInterface * t_si = &si; #endif cached_.getData(*t_si); CglLandPSimplex landpSi(*t_si, cached_, params, validator_); if (params.generateExtraCuts == CglLandP::AllViolatedMigs) { landpSi.genThisBasisMigs(cached_, params); } landpSi.setLogLevel(handler_->logLevel()); int nCut = 0; std::vector<int> indices; getSortedFractionalIndices(indices,cached_, params); #ifndef NDEBUG int numrows = si.getNumRows(); #endif #ifdef DO_STAT //Get informations on current optimum { OsiSolverInterface * gapTester = si.clone(); gapTester->resolve(); roundsStats_.analyseOptimalBasis(gapTester,info.pass, numrows_); delete gapTester; } #endif params_.timeLimit += CoinCpuTime(); CoinRelFltEq eq(1e-04); for (unsigned int i = 0; i < indices.size() && nCut < params.maxCutPerRound && nCut < cached_.nBasics_ ; i++) { //Check for time limit int iRow = indices[i]; assert(iRow < numrows); OsiRowCut cut; int code=1; OsiSolverInterface * ncSi = NULL; if (params.pivotLimit != 0) { ncSi = t_si->clone(); landpSi.setSi(ncSi); ncSi->setDblParam(OsiDualObjectiveLimit, COIN_DBL_MAX); ncSi->messageHandler()->setLogLevel(0); } int generated = 0; if (params.pivotLimit == 0) { generated = landpSi.generateMig(iRow, cut, params); } else { generated = landpSi.optimize(iRow, cut, cached_, params); if (params.generateExtraCuts == CglLandP::AllViolatedMigs) { landpSi.genThisBasisMigs(cached_, params); } landpSi.resetSolver(cached_.basis_); } code = 0; if (generated) code = validator_(cut, cached_.colsol_, si, params, originalColLower_, originalColUpper_); if (!generated || code) { if (params.pivotLimit !=0) { handler_->message(LAP_CUT_FAILED_DO_MIG, messages_)<<validator_.failureString(code)<<CoinMessageEol; landpSi.freeSi(); OsiSolverInterface * ncSi = t_si->clone(); landpSi.setSi(ncSi); params.pivotLimit = 0; if (landpSi.optimize(iRow, cut, cached_, params)) { code = validator_(cut, cached_.colsol_, si, params, originalColLower_, originalColUpper_); } params.pivotLimit = params_.pivotLimit; } } if (params.pivotLimit != 0) { landpSi.freeSi(); } if (code) { handler_->message(CUT_REJECTED, messages_)<< validator_.failureString(code)<<CoinMessageEol; } else { if (canLift_) { cut.setGloballyValid(true); } cs.insertIfNotDuplicate(cut, eq); //cs.insert(cut); { //std::cout<<"Violation "<<cut.violated(cached_.colsol_)<<std::endl; nCut++; } } } Cuts& extra = landpSi.extraCuts(); for (int i = 0 ; i < cached_.nNonBasics_; i++) { OsiRowCut * cut = extra.rowCut(i); if (cut == NULL) continue; int code = validator_(*cut, cached_.colsol_, si, params, originalColLower_, originalColUpper_); if (code) { handler_->message(LAP_CUT_FAILED_DO_MIG, messages_) <<validator_.failureString(code)<<CoinMessageEol; } else { cs.insertIfNotDuplicate(*cut, eq); { nCut++; } } delete cut; } landpSi.outPivInfo(nCut); params_.timeLimit -= CoinCpuTime(); cached_.clean(); #ifdef APPEND_ROW assert(t_si != &si); delete t_si; #endif }
/// OaDecomposition method double OaFeasibilityChecker::performOa(OsiCuts & cs, solverManip &lpManip, BabInfo * babInfo, double &cutoff,const CglTreeInfo & info) const { bool isInteger = true; bool feasible = 1; OsiSolverInterface * lp = lpManip.si(); OsiBranchingInformation branch_info(lp,false); //int numcols = lp->getNumCols(); double milpBound = -COIN_DBL_MAX; int numberPasses = 0; double * nlpSol = NULL; int numberCutsBefore = cs.sizeRowCuts(); while (isInteger && feasible ) { numberPasses++; //setup the nlp //Fix the variable which have to be fixed, after having saved the bounds double * colsol = const_cast<double *>(lp->getColSolution()); branch_info.solution_ = colsol; fixIntegers(*nlp_,branch_info, parameters_.cbcIntegerTolerance_,objects_, nObjects_); //Now solve the NLP get the cuts, and intall them in the local LP nlp_->resolve(txt_id); if (post_nlp_solve(babInfo, cutoff)) { //nlp solved and feasible // Update the cutoff double ub = nlp_->getObjValue(); cutoff = ub > 0 ? ub *(1 - parameters_.cbcCutoffIncrement_) : ub*(1 + parameters_.cbcCutoffIncrement_); // Update the lp solver cutoff lp->setDblParam(OsiDualObjectiveLimit, cutoff); } // Get the cuts outer approximation at the current point nlpSol = const_cast<double *>(nlp_->getColSolution()); const double * toCut = (parameter().addOnlyViolated_)? colsol:NULL; if(cut_count_ <= maximum_oa_cuts_ && type_ == OA) nlp_->getOuterApproximation(cs, nlpSol, 1, toCut, true); else {//if (type_ == Benders) nlp_->getBendersCut(cs, parameter().global_); } if(pol_ == DetectCycles) nlp_->getBendersCut(savedCuts_, parameter().global_); int numberCuts = cs.sizeRowCuts() - numberCutsBefore; cut_count_ += numberCuts; if (numberCuts > 0) installCuts(*lp, cs, numberCuts); lp->resolve(); double objvalue = lp->getObjValue(); //milpBound = max(milpBound, lp->getObjValue()); feasible = (lp->isProvenOptimal() && !lp->isDualObjectiveLimitReached() && (objvalue<cutoff)) ; //if value of integers are unchanged then we have to get out bool changed = true;//if lp is infeasible we don't have to check anything isInteger = 0; // if(!fixed)//fathom on bounds // milpBound = 1e200; if (feasible) { changed = isDifferentOnIntegers(*nlp_, objects_, nObjects_, 0.1, nlp_->getColSolution(), lp->getColSolution()); } if (changed) { branch_info.solution_ = lp->getColSolution(); isInteger = integerFeasible(*lp,branch_info, parameters_.cbcIntegerTolerance_, objects_, nObjects_); } else { isInteger = 0; // if(!fixed)//fathom on bounds milpBound = 1e200; } #ifdef OA_DEBUG printf("Obj value after cuts %g, %d rows\n",lp->getObjValue(), numberCuts) ; #endif } int num_cuts_now = cs.sizeRowCuts(); if(pol_ == KeepAll){ for(int i = numberCutsBefore ; i < num_cuts_now ; i++){ cs.rowCut(i).setEffectiveness(99.9e99); } } #ifdef OA_DEBUG debug_.printEndOfProcedureDebugMessage(cs, true, cutoff, milpBound, isInteger, feasible, std::cout); std::cout<<"milpBound found: "<<milpBound<<std::endl; #endif return milpBound; }
void HeuristicInnerApproximation::extractInnerApproximation(OsiTMINLPInterface & nlp, OsiSolverInterface &si, const double * x, bool getObj) { int n; int m; int nnz_jac_g; int nnz_h_lag; Ipopt::TNLP::IndexStyleEnum index_style; TMINLP2TNLP * problem = nlp.problem(); //Get problem information problem->get_nlp_info(n, m, nnz_jac_g, nnz_h_lag, index_style); vector<int> jRow(nnz_jac_g); vector<int> jCol(nnz_jac_g); vector<double> jValues(nnz_jac_g); problem->eval_jac_g(n, NULL, 0, m, nnz_jac_g, jRow(), jCol(), NULL); if(index_style == Ipopt::TNLP::FORTRAN_STYLE)//put C-style { for(int i = 0 ; i < nnz_jac_g ; i++){ jRow[i]--; jCol[i]--; } } //get Jacobian problem->eval_jac_g(n, x, 1, m, nnz_jac_g, NULL, NULL, jValues()); vector<double> g(m); problem->eval_g(n, x, 1, m, g()); vector<int> nonLinear(m); //store non linear constraints (which are to be removed from IA) int numNonLinear = 0; const double * rowLower = nlp.getRowLower(); const double * rowUpper = nlp.getRowUpper(); const double * colLower = nlp.getColLower(); const double * colUpper = nlp.getColUpper(); assert(m == nlp.getNumRows()); double infty = si.getInfinity(); double nlp_infty = nlp.getInfinity(); vector<Ipopt::TNLP::LinearityType> constTypes(m); problem->get_constraints_linearity(m, constTypes()); for (int i = 0; i < m; i++) { if (constTypes[i] == Ipopt::TNLP::NON_LINEAR) { nonLinear[numNonLinear++] = i; } } vector<double> rowLow(m - numNonLinear); vector<double> rowUp(m - numNonLinear); int ind = 0; for (int i = 0; i < m; i++) { if (constTypes[i] != Ipopt::TNLP::NON_LINEAR) { if (rowLower[i] > -nlp_infty) { // printf("Lower %g ", rowLower[i]); rowLow[ind] = (rowLower[i]); } else rowLow[ind] = -infty; if (rowUpper[i] < nlp_infty) { // printf("Upper %g ", rowUpper[i]); rowUp[ind] = (rowUpper[i]); } else rowUp[ind] = infty; ind++; } } CoinPackedMatrix mat(true, jRow(), jCol(), jValues(), nnz_jac_g); mat.setDimensions(m, n); // In case matrix was empty, this should be enough //remove non-linear constraints mat.deleteRows(numNonLinear, nonLinear()); int numcols = nlp.getNumCols(); vector<double> obj(numcols); for (int i = 0; i < numcols; i++) obj[i] = 0.; si.loadProblem(mat, nlp.getColLower(), nlp.getColUpper(), obj(), rowLow(), rowUp()); const Bonmin::TMINLP::VariableType* variableType = problem->var_types(); for (int i = 0; i < n; i++) { if ((variableType[i] == TMINLP::BINARY) || (variableType[i] == TMINLP::INTEGER)) si.setInteger(i); } if (getObj) { bool addObjVar = false; if (problem->hasLinearObjective()) { double zero; vector<double> x0(n, 0.); problem->eval_f(n, x0(), 1, zero); si.setDblParam(OsiObjOffset, -zero); //Copy the linear objective and don't create a dummy variable. problem->eval_grad_f(n, x, 1, obj()); si.setObjective(obj()); } else { addObjVar = true; } if (addObjVar) { nlp.addObjectiveFunction(si, x); } } // Hassan IA initial description int InnerDesc = 1; if (InnerDesc == 1) { OsiCuts cs; double * p = CoinCopyOfArray(colLower, n); double * pp = CoinCopyOfArray(colLower, n); double * up = CoinCopyOfArray(colUpper, n); const int& nbAp = nbAp_; std::vector<int> nbG(m, 0);// Number of generated points for each nonlinear constraint std::vector<double> step(n); for (int i = 0; i < n; i++) { if (colUpper[i] > 1e08) { up[i] = 0; } if (colUpper[i] > 1e08 || colLower[i] < -1e08 || (variableType[i] == TMINLP::BINARY) || (variableType[i] == TMINLP::INTEGER)) { step[i] = 0; } else step[i] = (up[i] - colLower[i]) / (nbAp); if (colLower[i] < -1e08) { p[i] = 0; pp[i] = 0; } } vector<double> g_p(m); vector<double> g_pp(m); for (int j = 1; j <= nbAp; j++) { for (int i = 0; i < n; i++) { pp[i] += step[i]; } problem->eval_g(n, p, 1, m, g_p()); problem->eval_g(n, pp, 1, m, g_pp()); double diff = 0; int varInd = 0; for (int i = 0; (i < m && constTypes[i] == Ipopt::TNLP::NON_LINEAR); i++) { if (varInd == n - 1) varInd = 0; diff = std::abs(g_p[i] - g_pp[i]); if (nbG[i] < nbAp - 1) { getMyInnerApproximation(nlp, cs, i, p, pp);// Generate a chord connecting the two points p[varInd] = pp[varInd]; nbG[i]++; } varInd++; } } for(int i = 0; (i< m && constTypes[i] == Ipopt::TNLP::NON_LINEAR); i++) { // getConstraintOuterApproximation(cs, i, colUpper, NULL, true);// Generate Tangents at current point getMyInnerApproximation(nlp, cs, i, p, up);// Generate a chord connecting the two points } delete [] p; delete [] pp; delete [] up; si.applyCuts(cs); } }
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; } }