//Main Function void mexFunction(int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[]) { int printLevel = 0; DerivedHandler *mexprinter = NULL; try { //Header if(nrhs < 1) { if(nlhs < 1) printSolverInfo(); else plhs[0] = mxCreateString(BONMIN_VERSION); return; } // Check to see if we have the correct number of input and output arguments. if (nrhs != 3) throw MatlabException("Incorrect number of input arguments"); if (nlhs != 2) throw MatlabException("Incorrect number of output arguments"); // See if we are printing messages if(mxGetField(prhs[2],0,"display")) printLevel = (int)*mxGetPr(mxGetField(prhs[2],0,"display")); else printLevel = 0; // Get the first input which specifies the initial iterate. Iterate x0(mxDuplicateArray(prhs[0])); // Get the second input which specifies the callback functions. CallbackFunctions funcs(prhs[1]); //Append linear constraints if present if(mxGetField(prhs[2],0,"A") && !mxIsEmpty(mxGetField(prhs[2],0,"A"))) funcs.appLinearConstraints(mxGetField(prhs[2],0,"A")); //Setup our Message Handler if(printLevel) { mexprinter = new DerivedHandler(); mexprinter->setLogLevel(printLevel); } // Create a new Bonmin setup object and process the options. BonminSetup app(mexprinter); app.initializeOptionsAndJournalist(); Options options(x0,app,prhs[2]); // Set up the BONMIN console if(printLevel) { //Create Journal to receive BONMIN messages SmartPtr<Journal> console = new MatlabJournal((EJournalLevel)printLevel); app.journalist()->AddJournal(console); } // The first output argument is the value of the optimization variables obtained at the solution. plhs[0] = mxDuplicateArray(x0); Iterate x(plhs[0]); // The second output argument stores other information, such as // the exit status, the value of the Lagrange multipliers upon // termination, the final state of the auxiliary data, and so on. MatlabInfo info(plhs[1]); // Check to see whether the user provided a callback function for // computing the Hessian. This is not needed in the special case // when a quasi-Newton approximation to the Hessian is being used. if (!options.bonminOptions().useQuasiNewton() && !funcs.hessianFuncIsAvailable()) throw MatlabException("You must supply a callback function for computing the Hessian unless you decide to use a quasi-Newton approximation to the Hessian"); // If the user tried to use her own scaling, report an error. if (options.bonminOptions().userScaling()) throw MatlabException("The user-defined scaling option does not work in the MATLAB interface for BONMIN"); //If the user supplied linear constraints, see if we can enable constant jac if(funcs.linearAIsAvailable()) { int nl = options.numNLconstraints(); //If no nonlinear constraints, set all linear if(!nl) { //Set in relaxed solver (BONMIN is done automatically in options) app.options()->SetStringValue("jac_c_constant","yes"); app.options()->SetStringValue("jac_d_constant","yes"); } //Else check if any inequality or equality constraints are nonlinear else { bool nlEq=false, nlIneq=false; const double *cl = options.constraintlb(), *cu = options.constraintub(); for(int i = 0; i < nl; i++) if(cl[i] == cu[i]) nlEq = true; else nlIneq = true; //Enable relaxed solver options based on what we found above (BONMIN is done automatically in options) if(!nlEq) app.options()->SetStringValue("jac_c_constant","yes"); if(!nlIneq) app.options()->SetStringValue("jac_d_constant","yes"); } } /*** EDIT FOR LIBMWMA57 ***/ //If using MA57 assume MathWorks version, disable MeTiS use (crashes on uncon problem) #ifdef haveMA57 if (!options.bonminOptions().usingMA57()) { int value; app.options()->GetIntegerValue("ma57_pivot_order",value,""); if(value > 3) { //mexWarnMsgTxt("overriding ma57 pivot order to option 2 (no MeTiS)."); app.options()->SetIntegerValue("ma57_pivot_order",2); } } #endif // Create a new instance of the constrained, mixed integer nonlinear program. MatlabProgram* matlabProgram = new MatlabProgram(x0,funcs,options,x,options.getAuxData(),info); SmartPtr<TMINLP> program = matlabProgram; // Intialize the Bonmin Setup object and process the options. try { app.initialize(GetRawPtr(program)); } catch(...) { mexErrMsgTxt("Error initializing BONMIN problem!"); } // Ask Bonmin to solve the problem. Bab bb; try { bb(app); } catch (std::exception& error) { mexErrMsgTxt(error.what()); } catch(...) { mexErrMsgTxt("Error running BONMIN solver, ensure your problem is not infeasible at the root node."); } // Collect statistics about Bonmin run info.setIterationCount(bb.iterationCount()); info.setNumNodes(bb.numNodes()); info.setExitStatus(bb.mipStatus()); //If feasible solution found, get best (relaxed) info.setBestObj(bb.continuousRelaxation()); // Free the dynamically allocated memory. mxDestroyArray(x0); } catch (std::exception& error) { mexErrMsgTxt(error.what()); } catch(...) { mexErrMsgTxt("Error in BONMIN MEX Interface"); } }
// status = write_mps_file(c,a,lhs,rhs,ub,lb,btype,vartype,filename); // btype is not yet used. But I keep this parameter for the future extern "C" int write_mps_file(char * fname) { int m_c, n_c; int m_a, n_a; int m_lhs, n_lhs; int m_rhs, n_rhs; int m_ub, n_ub; int m_lb, n_lb; int m_col_name, n_col_name; int m_row_name, n_row_name; vector<string> RowNames, ColNames; stringstream tmpstring; CoinMpsIO mpsWriter; DerivedHandler * printer = NULL; CoinPackedMatrix A_matrix; SciSparse S_A; char ** pColNames = NULL; char ** pRowNames = NULL; int i, j, status; int nrows, ncols, count, type; int * c_addr = NULL, * lhs_addr = NULL, * rhs_addr = NULL, * ub_addr = NULL, * lb_addr = NULL; int * btype_addr = NULL, * vartype_addr = NULL, * pb_name_addr = NULL, * a_addr = NULL; int * col_name_addr = NULL, * row_name_addr = NULL, * filename_addr = NULL, * verbose_addr = NULL; double * c = NULL, * lhs = NULL, * rhs = NULL, * ub = NULL, * lb = NULL, * a = NULL; double verbose = 0; char * btype = NULL, * vartype = NULL, * pb_name = NULL, * filename = NULL; SciErr _SciErr; _SciErr = getVarAddressFromPosition(pvApiCtx, C_IN, &c_addr); SCICOINOR_ERROR; _SciErr = getMatrixOfDouble(pvApiCtx, c_addr, &n_c, &m_c, &c); SCICOINOR_ERROR; _SciErr = getVarAddressFromPosition(pvApiCtx, LHS_IN, &lhs_addr); SCICOINOR_ERROR; _SciErr = getMatrixOfDouble(pvApiCtx, lhs_addr, &n_lhs, &m_lhs, &lhs); SCICOINOR_ERROR; _SciErr = getVarAddressFromPosition(pvApiCtx, RHS_IN, &rhs_addr); SCICOINOR_ERROR; _SciErr = getMatrixOfDouble(pvApiCtx, rhs_addr, &n_rhs, &m_rhs, &rhs); SCICOINOR_ERROR; _SciErr = getVarAddressFromPosition(pvApiCtx, UB_IN, &ub_addr); SCICOINOR_ERROR; _SciErr = getMatrixOfDouble(pvApiCtx, ub_addr, &n_ub, &m_ub, &ub); SCICOINOR_ERROR; _SciErr = getVarAddressFromPosition(pvApiCtx, LB_IN, &lb_addr); SCICOINOR_ERROR; _SciErr = getMatrixOfDouble(pvApiCtx, lb_addr, &n_lb, &m_lb, &lb); SCICOINOR_ERROR; _SciErr = getVarAddressFromPosition(pvApiCtx, BTYPE_IN, &btype_addr); SCICOINOR_ERROR; getAllocatedSingleString(pvApiCtx, btype_addr, &btype); _SciErr = getVarAddressFromPosition(pvApiCtx, VARTYPE_IN, &vartype_addr); SCICOINOR_ERROR; getAllocatedSingleString(pvApiCtx, vartype_addr, &vartype); _SciErr = getVarAddressFromPosition(pvApiCtx, PB_NAME_IN, &pb_name_addr); SCICOINOR_ERROR; getAllocatedSingleString(pvApiCtx, pb_name_addr, &pb_name); _SciErr = getVarAddressFromPosition(pvApiCtx, COL_NAME_IN, &col_name_addr); SCICOINOR_ERROR; getAllocatedMatrixOfString(pvApiCtx, col_name_addr, &n_col_name, &m_col_name, &pColNames); _SciErr = getVarAddressFromPosition(pvApiCtx, ROW_NAME_IN, &row_name_addr); SCICOINOR_ERROR; getAllocatedMatrixOfString(pvApiCtx, row_name_addr, &n_row_name, &m_row_name, &pRowNames); _SciErr = getVarAddressFromPosition(pvApiCtx, FILENAME_IN, &filename_addr); SCICOINOR_ERROR; getAllocatedSingleString(pvApiCtx, filename_addr, &filename); _SciErr = getVarAddressFromPosition(pvApiCtx, VERBOSE_IN, &verbose_addr); SCICOINOR_ERROR; getScalarDouble(pvApiCtx, verbose_addr, &verbose); nrows = n_lhs * m_lhs; if (nrows==0) nrows = n_rhs*m_rhs; ncols = n_c * m_c; #ifdef DEBUG DBGPRINTF("rowname n = %d m = %d\n", n_row_name, m_row_name); #endif if (n_row_name * m_row_name==0) { RowNames.resize(nrows); for(i=0;i<nrows;i++) { tmpstring.str(""); tmpstring << "R" << i; RowNames[i] = tmpstring.str(); } } else { RowNames.resize(nrows); for(i=0;i<nrows;i++) { RowNames[i] = string(pRowNames[i]); } } #ifdef DEBUG DBGPRINTF("colname n = %d m = %d\n", n_col_name, m_col_name); #endif if (n_col_name * m_col_name==0) { ColNames.resize(ncols); for(i=0;i<ncols;i++) { tmpstring.str(""); tmpstring << "R" << i; ColNames[i] = tmpstring.str(); } } else { ColNames.resize(ncols); for(i=0;i<ncols;i++) { ColNames[i] = string(pColNames[i]); } } ////////////////// // The A matrix // ////////////////// _SciErr = getVarAddressFromPosition(pvApiCtx, A_IN, &a_addr); SCICOINOR_ERROR; _SciErr = getVarType(pvApiCtx, a_addr, &type); SCICOINOR_ERROR; if(type!=sci_sparse) { _SciErr = getMatrixOfDouble(pvApiCtx, a_addr, &n_a, &m_a, &a); SCICOINOR_ERROR; A_matrix.setDimensions(nrows,ncols); if (a==NULL) { Scierror(999,"%s: invalid value of matrix a\n",fname); freeAllocatedSingleString(btype); freeAllocatedSingleString(vartype); freeAllocatedSingleString(pb_name); freeAllocatedSingleString(filename); if (pRowNames) freeAllocatedMatrixOfString(m_row_name, n_row_name, pRowNames); if (pColNames) freeAllocatedMatrixOfString(m_col_name, n_col_name, pColNames); return 0; } for(i=0; i<m_a; i++) { for(j=0; j<n_a; j++) { if (*(a+i+j*m_a) != 0) A_matrix.modifyCoefficient(i,j,*(a+i+j*m_a)); } } } else { getAllocatedSparseMatrix(pvApiCtx, a_addr, &S_A.m, &S_A.n, &S_A.nel, &S_A.mnel, &S_A.icol, &S_A.R); A_matrix.setDimensions(nrows,ncols); count = 0; for(i=0;i<S_A.m;i++) { if (S_A.mnel[i]!=0) { for(j=0;j<S_A.mnel[i];j++) { count++; A_matrix.modifyCoefficient(i,S_A.icol[count-1]-1,S_A.R[count-1]); } } } freeAllocatedSparseMatrix(S_A.mnel, S_A.icol, S_A.R); } if (verbose) { printer = new DerivedHandler(); printer->setLogLevel((int)verbose); mpsWriter.passInMessageHandler(printer); } // void setMpsData (const CoinPackedMatrix &m, const double infinity, // const double *collb, const double *colub, // const double *obj, const char *integrality, // const double *rowlb, const double *rowub, // const std::vector< std::string > &colnames, const std::vector< std::string > &rownames) mpsWriter.setMpsData(A_matrix, mpsWriter.getInfinity(), lb, ub, c, vartype, lhs, rhs, ColNames, RowNames); mpsWriter.setProblemName(pb_name); status = mpsWriter.writeMps(filename); createScalarDouble(pvApiCtx, STATUS_OUT, (double)status); LhsVar(1) = STATUS_OUT; freeAllocatedSingleString(btype); freeAllocatedSingleString(vartype); freeAllocatedSingleString(pb_name); freeAllocatedSingleString(filename); if (pRowNames) freeAllocatedMatrixOfString(m_row_name, n_row_name, pRowNames); if (pColNames) freeAllocatedMatrixOfString(m_col_name, n_col_name, pColNames); return 0; }
// To define the function sciclp as a C function and allow this function to be loaded easily in scilab extern "C" int sciclp(char * fname) { ClpSimplex * modelSimplex = NULL; ClpInterior * modelInterior = NULL; ClpModel * modelBase = NULL; ClpCholeskyBase * cholesky = NULL; DerivedHandler * printer = NULL; ClpSolve modelSolve; // YC: we can set some parameters via CbcSolve CoinPackedMatrix A_matrix, Q_matrix; #ifdef HANDLE_CTRLC MyClpEventHandler SciClpEventHandler; SciClpEventHandler.setInCbc(false); #endif int Log = 0; int ncols = 0, nrows = 0, i, j, nz = 0, writemps = 0; int count = 0, status = 0, type; char * writemps_filename = NULL; SciSparse S_A, S_Q; if (Rhs<LASTPARAM) { Scierror(999,"%s: 12 inputs required in call to %s. Bug in clp.sci ?...\n", fname, fname); return 0; } /* Get pointers to input */ int n_a, m_a, * a_addr = NULL; int n_c, m_c, * c_addr = NULL; int n_lhs, m_lhs, * lhs_addr = NULL; int n_rhs, m_rhs, * rhs_addr = NULL; int n_upper, m_upper, * upper_addr = NULL; int n_lower, m_lower, * lower_addr = NULL; int * vtype_addr = NULL; int * ctype_addr = NULL; int n_q, m_q, * q_addr = NULL; double * c = NULL, * lhs = NULL, * rhs = NULL, * lower = NULL, * upper = NULL, * a = NULL; double * q = NULL; char * ctype = NULL, * vtype = NULL; SciErr _SciErr; _SciErr = getVarAddressFromPosition(pvApiCtx, C_IN, &c_addr); SCICOINOR_ERROR; _SciErr = getMatrixOfDouble(pvApiCtx, c_addr, &n_c, &m_c, &c); SCICOINOR_ERROR; _SciErr = getVarAddressFromPosition(pvApiCtx, LHS_IN, &lhs_addr); SCICOINOR_ERROR; _SciErr = getMatrixOfDouble(pvApiCtx, lhs_addr, &n_lhs, &m_lhs, &lhs); SCICOINOR_ERROR; _SciErr = getVarAddressFromPosition(pvApiCtx, RHS_IN, &rhs_addr); SCICOINOR_ERROR; _SciErr = getMatrixOfDouble(pvApiCtx, rhs_addr, &n_rhs, &m_rhs, &rhs); SCICOINOR_ERROR; _SciErr = getVarAddressFromPosition(pvApiCtx, LOWER_IN, &lower_addr); SCICOINOR_ERROR; _SciErr = getMatrixOfDouble(pvApiCtx, lower_addr, &n_lower, &m_lower, &lower); SCICOINOR_ERROR; _SciErr = getVarAddressFromPosition(pvApiCtx, UPPER_IN, &upper_addr); SCICOINOR_ERROR; _SciErr = getMatrixOfDouble(pvApiCtx, upper_addr, &n_upper, &m_upper, &upper); SCICOINOR_ERROR; _SciErr = getVarAddressFromPosition(pvApiCtx, CTYPE_IN, &ctype_addr); SCICOINOR_ERROR; getAllocatedSingleString(pvApiCtx, ctype_addr, &ctype); _SciErr = getVarAddressFromPosition(pvApiCtx, VTYPE_IN, &vtype_addr); SCICOINOR_ERROR; getAllocatedSingleString(pvApiCtx, vtype_addr, &vtype); ncols = n_c * m_c; /* Length of c == number of columns */ nrows = n_rhs * m_rhs; /* length of b == number of rows */ if (nrows==0) nrows = n_lhs * m_lhs; #ifdef DEBUG sciprint("DEBUG: c size: m = %d n = %d\n", m_c, n_c); sciprint("DEBUG: lhs size: m = %d n = %d\n", m_lhs, n_lhs); sciprint("DEBUG: rhs size: m = %d n = %d\n", m_rhs, n_rhs); sciprint("DEBUG: lower size: m = %d n = %d\n", m_lower, n_lower); sciprint("DEBUG: upper size: m = %d n = %d\n", m_upper, n_upper); sciprint("DEBUG: ctype size: m = %d n = %d\n", m_ctype, n_ctype); sciprint("DEBUG: vtype size: m = %d n = %d\n", m_vtype, n_vtype); sciprint("DEBUG: nrows = %d\n", nrows); sciprint("DEBUG: ncols = %d\n", ncols); sciprint("c :"); for(i=0;i<ncols; i++) sciprint("%f ",*(c+i)); sciprint("\n"); sciprint("lhs :"); for(i=0;i<nrows; i++) sciprint("%f ",*(lhs+i)); sciprint("\n"); sciprint("rhs :"); for(i=0;i<nrows; i++) sciprint("%f ",*(rhs+i)); sciprint("\n"); sciprint("lb :"); for(i=0;i<ncols; i++) sciprint("%f ",*(lower+i)); sciprint("\n"); sciprint("ub :"); for(i=0;i<ncols; i++) sciprint("%f ",*(upper+i)); sciprint("\n"); sciprint("ctype = %s\n", ctype); sciprint("vtype = %s\n", vtype); #endif ////////////////// // The A matrix // ////////////////// _SciErr = getVarAddressFromPosition(pvApiCtx, A_IN, &a_addr); SCICOINOR_ERROR; _SciErr = getVarType(pvApiCtx, a_addr, &type); SCICOINOR_ERROR; if(type!=sci_sparse) { #ifdef DEBUG sciprint("DEBUG: A_IN is not sparse\n"); #endif _SciErr = getMatrixOfDouble(pvApiCtx, a_addr, &m_a, &n_a, &a); SCICOINOR_ERROR; A_matrix.setDimensions(nrows,ncols); if (a==NULL) { Scierror(999,"%s: invalid value of matrix a\n",fname); freeAllocatedSingleString(ctype); freeAllocatedSingleString(vtype); return 0; } for(i=0; i<m_a; i++) { for(j=0; j<n_a; j++) { if (*(a+i+j*m_a) != 0) A_matrix.modifyCoefficient(i,j,*(a+i+j*m_a)); #ifdef DEBUG sciprint("%f ",*(a+i+j*m_a)); #endif } #ifdef DEBUG sciprint("\n"); #endif } } else { #ifdef DEBUG sciprint("DEBUG: A_IN is sparse\n"); #endif getAllocatedSparseMatrix(pvApiCtx, a_addr, &S_A.m, &S_A.n, &S_A.nel, &S_A.mnel, &S_A.icol, &S_A.R); A_matrix.setDimensions(nrows,ncols); #ifdef DEBUG sciprint("A = [%d,%d]\n", m_a, n_a); #endif nz = S_A.nel; count = 0; for(i=0;i<S_A.m;i++) { if (S_A.mnel[i]!=0) { #ifdef DEBUG sciprint("mnel[%d] = %d - ",i, S_A.mnel[i]); #endif for(j=0;j<S_A.mnel[i];j++) { count++; A_matrix.modifyCoefficient(i,S_A.icol[count-1]-1,S_A.R[count-1]); #ifdef DEBUG sciprint("[%d] = %f ", S_A.icol[count-1]-1, S_A.R[count-1]); #endif } #ifdef DEBUG sciprint("\n"); #endif } } freeAllocatedSparseMatrix(S_A.mnel, S_A.icol, S_A.R); } ///////////////// // Get options // ///////////////// #ifdef DEBUG sciprint("DEBUG: get options\n"); #endif // Default settings int * param_in_addr = NULL; int solverchoice = 1, loglevel = 0, fact_freq = 200, perturb = 0; int presolve = 0, red_grad = 1, maximumbarrieriterations = 200; int tmp_int, tmp_res; double tmp_double; char * tmp_char; initPList(pvApiCtx, PARAM_IN, ¶m_in_addr); if (!checkPList(pvApiCtx, param_in_addr)) { Scierror(999, "%s: argument n° %d is not a plist\n", fname, PARAM_IN); return 0; } // solver option getIntInPList(pvApiCtx, param_in_addr, "solver", &tmp_int, &tmp_res, 1, Log, CHECK_NONE); if (tmp_res!=-1) solverchoice = tmp_int; // Load the matrix in the solver switch(solverchoice) { case 6: modelInterior = new ClpInterior; modelBase = (ClpModel *)modelInterior; break; default: modelSimplex = new ClpSimplex; modelBase = (ClpModel *)modelSimplex; break; } // maxnumiterations option getIntInPList(pvApiCtx, param_in_addr, "maxnumiterations", &tmp_int, &tmp_res, 1000, Log, CHECK_NONE); if (tmp_res!=-1) modelBase->setMaximumIterations(tmp_int); // maxnumseconds option getDoubleInPList(pvApiCtx, param_in_addr, "maxnumseconds", &tmp_double, &tmp_res, 3600, Log, CHECK_NONE); if (tmp_res!=-1) modelBase->setMaximumSeconds(tmp_double); // primaltolerance option getDoubleInPList(pvApiCtx, param_in_addr, "primaltolerance", &tmp_double, &tmp_res, 1e-7, Log, CHECK_NONE); if (tmp_res!=-1) modelBase->setPrimalTolerance(tmp_double); // dualtolerance option getDoubleInPList(pvApiCtx, param_in_addr, "dualtolerance", &tmp_double, &tmp_res, 1e-7, Log, CHECK_NONE); if (tmp_res!=-1) modelBase->setDualTolerance(tmp_double); // verbose option getIntInPList(pvApiCtx, param_in_addr, "verbose", &tmp_int, &tmp_res, 0, Log, CHECK_NONE); if (tmp_res!=-1) { /////////////////////////////// // Enable printing in Scilab // // and set parameters of clp // /////////////////////////////// loglevel = tmp_int; printer = new DerivedHandler(); // assumed open printer->setLogLevel(loglevel); } // optim_dir option getIntInPList(pvApiCtx, param_in_addr, "optim_dir", &tmp_int, &tmp_res, 1, Log, CHECK_NONE); if (tmp_res!=-1) modelBase->setOptimizationDirection(tmp_int); // writemps option getStringInPList(pvApiCtx, param_in_addr, "writemps", &tmp_char, &tmp_res, "test.mps", Log, CHECK_NONE); if (tmp_res!=-1) { writemps_filename = tmp_char; writemps = 1; #ifdef DEBUG sciprint("DEBUG: writemps_filename = %s\n", writemps_filename); #endif } // perturb option getIntInPList(pvApiCtx, param_in_addr, "perturb", &tmp_int, &tmp_res, 0, Log, CHECK_NONE); if (tmp_res!=-1) perturb = tmp_int; // scaling option // Sets or unsets scaling: // - 0 -off // - 1 equilibrium (default) // - 2 geometric // - 3 auto // - 4 auto-but-as-initialSolve-in-bab. getIntInPList(pvApiCtx, param_in_addr, "scaling", &tmp_int, &tmp_res, 1, Log, CHECK_NONE); if (tmp_res!=-1) modelBase->scaling(tmp_int); // factorization frequency option getIntInPList(pvApiCtx, param_in_addr, "fact_freq", &tmp_int, &tmp_res, 200, Log, CHECK_NONE); if (tmp_res!=-1) fact_freq = tmp_int; // presolve option getIntInPList(pvApiCtx, param_in_addr, "presolve", &tmp_int, &tmp_res, 0, Log, CHECK_NONE); if (tmp_res!=-1) presolve = tmp_int; // reduced gradient phase option getIntInPList(pvApiCtx, param_in_addr, "red_grad", &tmp_int, &tmp_res, 1, Log, CHECK_NONE); if (tmp_res!=-1) red_grad = tmp_int; // maxnumiterationshotstart getIntInPList(pvApiCtx, param_in_addr, "maxnumiterationshotstart", &tmp_int, &tmp_res, 1000, Log, CHECK_NONE); if (tmp_res!=-1) modelBase->setIntParam(ClpMaxNumIterationHotStart, tmp_int); // dualobjectivelimit getDoubleInPList(pvApiCtx, param_in_addr, "dualobjectivelimit", &tmp_double, &tmp_res, 1e-7, Log, CHECK_NONE); if (tmp_res!=-1) modelBase->setDblParam(ClpDualObjectiveLimit, tmp_double); // primalobjectivelimit getDoubleInPList(pvApiCtx, param_in_addr, "primalobjectivelimit", &tmp_double, &tmp_res, 1e-7, Log, CHECK_NONE); if (tmp_res!=-1) modelBase->setDblParam(ClpPrimalObjectiveLimit, tmp_double); // obj offset getDoubleInPList(pvApiCtx, param_in_addr, "objoffset", &tmp_double, &tmp_res, 0.0, Log, CHECK_NONE); if (tmp_res!=-1) modelBase->setDblParam(ClpObjOffset, tmp_double); // presolvetolerance getDoubleInPList(pvApiCtx, param_in_addr, "presolvetolerance", &tmp_double, &tmp_res, 1e-7, Log, CHECK_NONE); if (tmp_res!=-1) modelBase->setDblParam(ClpPresolveTolerance, tmp_double); // maximumBarrierIterations getIntInPList(pvApiCtx, param_in_addr, "maxnumbarrieriterations", &tmp_int, &tmp_res, 200, Log, CHECK_NONE); if (tmp_res!=-1) maximumbarrieriterations = tmp_int; ///////////////////////////////////// // Set the bounds on the variables // ///////////////////////////////////// modelBase->loadProblem(A_matrix,lhs,rhs,c,lower,upper); for(i=0;i<ncols; i++) { modelBase->setColUpper(i, *(upper+i)); modelBase->setColLower(i, *(lower+i)); modelBase->setObjectiveCoefficient(i,*(c+i)); if ((*(vtype+i)=='I')||(*(vtype+i)=='i')) { modelBase->setInteger(i); } else { modelBase->setContinuous(i); } } ///////////////////////////////////////// // Set the boundary of the constraints // ///////////////////////////////////////// // 'L' - smaller than - <= // 'E' - equality - = // 'G' - greater than - >= // 'R' - Range - <= + >= // 'N' - Free - no constraints #ifdef DEBUG sciprint("DEBUG: dealing with btype\n"); #endif for(i=0;i<nrows; i++) { switch(*(ctype+i)) { case 'l': case 'L': modelBase->setRowUpper(i, *(rhs+i)); modelBase->setRowLower(i, -COIN_DBL_MAX); break; case 'e': case 'E': modelBase->setRowUpper(i, *(rhs+i)); modelBase->setRowLower(i, *(rhs+i)); break; case 'n': case 'N': modelBase->setRowUpper(i, COIN_DBL_MAX); modelBase->setRowLower(i, -COIN_DBL_MAX); break; case 'r': case 'R': modelBase->setRowUpper(i, *(rhs+i)); modelBase->setRowLower(i, *(lhs+i)); break; case 'g': case 'G': default: modelBase->setRowUpper(i, COIN_DBL_MAX); modelBase->setRowLower(i, *(lhs+i)); break; } #ifdef DEBUG sciprint("row lower[%d] = %f row upper[%d] = %f\n", i, modelBase->getRowLower()[i], i, modelBase->getRowUpper()[i]); #endif } /////////////////////////////////// // Affect names to rows and cols // /////////////////////////////////// modelBase->setIntParam(ClpNameDiscipline,0); //////////////////////// // Any quadratic part // //////////////////////// #ifdef DEBUG sciprint("DEBUG: dealing with Q\n"); #endif _SciErr = getVarAddressFromPosition(pvApiCtx, Q_IN, &q_addr); SCICOINOR_ERROR; _SciErr = getVarType(pvApiCtx, q_addr, &type); SCICOINOR_ERROR; if(type!=sci_sparse) { _SciErr = getMatrixOfDouble(pvApiCtx, q_addr, &m_q, &n_q, &q); SCICOINOR_ERROR; if (n_q * m_q !=0) { #ifdef DEBUG sciprint("DEBUG: Q_IN is not sparse\n"); sciprint("DEBUG: Q size: n = %d m= %d\n", n_q, m_q); #endif Q_matrix.setDimensions(nrows,ncols); nz = n_q * m_q; if (q==NULL) { Scierror(999,"%s: invalid value of matrix q\n",fname); freeAllocatedSingleString(ctype); freeAllocatedSingleString(vtype); if (writemps_filename) FREE(writemps_filename); return 0; } for(i=0; i<m_q; i++) { for(j=0; j<n_q; j++) { if (*(q+i+j*m_q)!=0) Q_matrix.modifyCoefficient(i,j,*(q+i+j*m_q)); } } modelBase->loadQuadraticObjective(Q_matrix); } } else { getAllocatedSparseMatrix(pvApiCtx, q_addr, &S_Q.m, &S_Q.n, &S_Q.nel, &S_Q.mnel, &S_Q.icol, &S_Q.R); if (S_Q.n * S_Q.m!=0) { #ifdef DEBUG sciprint("DEBUG: Q_IN is sparse\n"); sciprint("DEBUG: Q size: n = %d m= %d\n", S_Q.n, S_Q.m); #endif Q_matrix.setDimensions(nrows,ncols); nz = S_Q.nel; count = 0; for(i=0;i<S_Q.m;i++) { if (S_Q.mnel[i]!=0) { for(j=0;j<S_Q.mnel[i];j++) { count++; Q_matrix.modifyCoefficient(i,S_Q.icol[count-1]-1,S_Q.R[count-1]); } } } modelBase->loadQuadraticObjective(Q_matrix); } freeAllocatedSparseMatrix(S_Q.mnel, S_Q.icol, S_Q.R); } // Solver specific part switch(solverchoice) { case 6: modelInterior->setMaximumBarrierIterations(maximumbarrieriterations); break; default: modelSimplex->setFactorizationFrequency(fact_freq); modelSimplex->setPerturbation(perturb); break; } /////////////////////////// // Pre / Post resolution // /////////////////////////// #ifdef HANDLE_CTRLC /////////////////////////////////////////////////////////// // Pass in the event handler, to handle ctrl+c in scilab // /////////////////////////////////////////////////////////// if (modelSimplex) { modelSimplex->passInEventHandler(&SciClpEventHandler); modelSimplex->passInMessageHandler(printer); } #endif #ifdef DEBUG sciprint("DEBUG: presolve\n"); #endif // If the solver is not ClpInterior we can set the presolve option if (presolve && solverchoice!=6) { TRYCATCH(modelSimplex->initialSolve(modelSolve)); switch(presolve) { case 2: TRYCATCH(modelSimplex->initialDualSolve()); break; case 3: TRYCATCH(modelSimplex->initialPrimalSolve()); break; case 4: TRYCATCH(modelSimplex->initialBarrierSolve()); break; case 5: TRYCATCH(modelSimplex->initialBarrierNoCrossSolve()); break; default: TRYCATCH(modelSimplex->initialSolve()); break; } } //////////////////////////////////////////// // If needed, write the problem in a file // //////////////////////////////////////////// #ifdef DEBUG sciprint("DEBUG: dealing with writemps\n"); #endif if (writemps) { modelBase->writeMps(writemps_filename); if (loglevel) sciprint("sciclp: writing %s mps file\n",writemps_filename); } //////////////// // Resolution // //////////////// #ifdef DEBUG sciprint("DEBUG: resolution\n"); sciprint("model number columns = %d\n", modelBase->numberColumns()); sciprint("model number rows = %d\n", modelBase->numberRows()); #endif if ((solverchoice>=1)&&(solverchoice<=5)) { TRYCATCH(modelSimplex->initialSolve()) } #ifdef HANDLE_CTRLC /////////////////////////////////////////////////////////// // Pass in the event handler, to handle ctrl+c in scilab // /////////////////////////////////////////////////////////// if (modelSimplex) { modelSimplex->passInEventHandler(&SciClpEventHandler); modelSimplex->passInMessageHandler(printer); } if (modelInterior) { modelInterior->passInEventHandler(&SciClpEventHandler); modelInterior->passInMessageHandler(printer); } #endif switch (solverchoice) { case 2: TRYCATCH(status = modelSimplex->dual()); break; case 3: TRYCATCH(status = modelSimplex->barrier(false)); break; case 4: TRYCATCH(status = modelSimplex->barrier(true)); break; case 5: TRYCATCH(status = modelSimplex->reducedGradient(red_grad)); break; case 6: cholesky = new ClpCholeskyBase(); cholesky->setKKT(true); modelInterior->setCholesky(cholesky); TRYCATCH(status = modelInterior->primalDual()); break; case 7: TRYCATCH(status = modelInterior->pdco()); break; default: TRYCATCH(status = modelSimplex->primal()); break; } #ifdef DEBUG if (status && loglevel) sciprint("Optimization failed\n"); #endif int clp_status = 0; clp_status = (int)(pow(2.0,0.0)*modelBase->isAbandoned()); clp_status += (int)(pow(2.0,1.0)*modelBase->isProvenOptimal()); clp_status += (int)(pow(2.0,2.0)*modelBase->isProvenPrimalInfeasible()); clp_status += (int)(pow(2.0,3.0)*modelBase->isProvenDualInfeasible()); clp_status += (int)(pow(2.0,4.0)*modelBase->isPrimalObjectiveLimitReached()); clp_status += (int)(pow(2.0,5.0)*modelBase->isDualObjectiveLimitReached()); clp_status += (int)(pow(2.0,6.0)*modelBase->isIterationLimitReached()); ////////////////////////////// // Allocate for return data // ////////////////////////////// #ifdef DEBUG sciprint("DEBUG: allocating data\n"); #endif int m_xmin = ncols, n_xmin = 1; int m_lambda = 1, n_lambda = nrows; int * extra_addr = NULL; char * ListLabels [] = {"lambda","secondary_status","clp_status"}; _SciErr = createMatrixOfDouble(pvApiCtx, XMIN_OUT, m_xmin, n_xmin, (double *)modelBase->primalColumnSolution()); SCICOINOR_ERROR; createScalarDouble(pvApiCtx, FMIN_OUT, modelBase->getObjValue()); createScalarDouble(pvApiCtx, STATUS_OUT, (double)modelBase->status()); _SciErr = createPList(pvApiCtx, EXTRA_OUT, &extra_addr, (char **)ListLabels, 3); SCICOINOR_ERROR; _SciErr = createColVectorOfDoubleInPList(pvApiCtx, EXTRA_OUT, extra_addr, "lambda", m_lambda*n_lambda, (double *)modelBase->dualRowSolution()); SCICOINOR_ERROR; _SciErr = createIntInPList(pvApiCtx, EXTRA_OUT, extra_addr, "secondary_status", modelBase->secondaryStatus()); SCICOINOR_ERROR; _SciErr = createIntInPList(pvApiCtx, EXTRA_OUT, extra_addr, "clp_status", clp_status); SCICOINOR_ERROR; #ifdef DEBUG sciprint("DEBUG: getting solution\n"); #endif // // status of problem: // -1 - unknown e.g. before solve or if postSolve says not optimal // 0 - optimal // 1 - primal infeasible // 2 - dual infeasible // 3 - stopped on iterations or time // 4 - stopped due to errors // 5 - stopped by event handler (virtual int ClpEventHandler::event()) // // Secondary status of problem - may get extended // - 0 - none // - 1 - primal infeasible because dual limit reached OR probably primal infeasible but can't prove it (main status 4) // - 2 - scaled problem optimal - unscaled problem has primal infeasibilities // - 3 - scaled problem optimal - unscaled problem has dual infeasibilities // - 4 - scaled problem optimal - unscaled problem has primal and dual infeasibilities // - 5 - giving up in primal with flagged variables // - 6 - failed due to empty problem check // - 7 - postSolve says not optimal // - 8 - failed due to bad element check // - 9 - status was 3 and stopped on time // - 100 up - translation of enum from ClpEventHandler. ///////////////////////////////// // Copy solutions if available // ///////////////////////////////// #ifdef DEBUG sciprint("DEBUG: returning data\n"); #endif LhsVar(1) = XMIN_OUT; LhsVar(2) = FMIN_OUT; LhsVar(3) = STATUS_OUT; LhsVar(4) = EXTRA_OUT; ////////////////////////////// // Delete allocated objects // ////////////////////////////// if (modelSimplex) delete modelSimplex; if (modelInterior) delete modelInterior; if (printer) delete printer; freeAllocatedSingleString(ctype); freeAllocatedSingleString(vtype); if (writemps_filename) FREE(writemps_filename); return 0; }
// mex function usage: // [x,y,status] = mexosi(n_vars,n_cons,A,x_lb,x_ub,c,Ax_lb,Ax_ub,isMIP,isQP,vartype,Q,options) // 0 1 2 3 4 5 6 7 8 9 10 11 12 void mexFunction(int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[]) { // Enable printing in MATLAB int loglevel = 0; DerivedHandler *mexprinter = new DerivedHandler(); // assumed open mexprinter->setLogLevel(loglevel); // check that we have the right number of inputs if(nrhs < 10) mexErrMsgTxt("At least 10 inputs required in call to mexosi. Bug in osi.m?..."); // check that we have the right number of outputs if(nlhs < 3) mexErrMsgTxt("At least 3 ouptuts required in call to mexosi. Bug in osi.m?..."); // Get pointers to input values const int n_vars = (int)*mxGetPr(prhs[0]); const int n_cons = (int)*mxGetPr(prhs[1]); const mxArray *A = prhs[2]; const double *x_lb = mxGetPr(prhs[3]); const double *x_ub = mxGetPr(prhs[4]); const double *c = mxGetPr(prhs[5]); const double *Ax_lb = mxGetPr(prhs[6]); const double *Ax_ub = mxGetPr(prhs[7]); const bool isMIP = (bool)*(mxLogical*)mxGetData(prhs[8]); const bool isQP = (bool)*(mxLogical*)mxGetData(prhs[9]); mxLogical *isinteger = (mxLogical*)mxGetData(prhs[10]); const mxArray* Q = prhs[11]; // process the options int returnStatus = 0; // extract row/col/value data from A const mwIndex * A_col_starts = mxGetJc(A); const mwIndex * A_row_index = mxGetIr(A); const double * A_data = mxGetPr(A); // figure out the number of non-zeros in A int nnz = (int)(A_col_starts[n_vars] - A_col_starts[0]); // number of non-zeros //mexPrintf("nnz = %d, n_vars = %d, n_cons = %d\n",nnz,n_vars,n_cons); // we need to convert these into other types of indices for Coin to use them std::vector<CoinBigIndex> A_col_starts_coin(A_col_starts,A_col_starts+n_vars+1); std::vector<int> A_row_index_coin(A_row_index,A_row_index+nnz); // declare the solver OsiSolverInterface* pSolver; // initialize the solver if ( isMIP ) { pSolver = new OsiCbcSolverInterface; } else { pSolver = new OsiClpSolverInterface; } // OsiCbcSolverInterface is deprecated and CbcModel should be used instead but don't // know how to get that working with loadProblem. // OsiCbcSolverInterface solver1; // CbcModel model(solver1); // CbcMain0(model); // OsiSolverInterface * pSolver = model.solver(); if (nrhs>12) { // get stuff out of the options structure if provided // Finish me } // mexPrintf("Setting Log Level to 0.\n"); // load the problem mexPrintf("Loading the problem.\n"); pSolver->loadProblem( n_vars, n_cons, // problem size &A_col_starts_coin[0], &A_row_index_coin[0], A_data, // the A matrix x_lb, x_ub, c, // the objective and bounds Ax_lb, Ax_ub ); // the constraint bounds // pSolver->messageHandler()->setLogLevel(0); // This doesn't seem to work pSolver->setHintParam(OsiDoReducePrint,true,OsiHintTry); // deal with integer inputs if ( isMIP ) { for(int i=0;i<n_vars;i++) { if (isinteger[i]) pSolver->setInteger(i); } } if (isQP) { error("QP is not working yet"); // need to call loadQuadraticObjective here ??? } // CbcModel model(pSolver); // model.solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry); // solve the problem //mexPrintf("Trying to solve the problem.\n"); if (isMIP) { pSolver->branchAndBound(); // model.branchAndBound(); } else { // model.initialSolve(); pSolver->initialSolve(); } // Allocate memory for return data plhs[0] = mxCreateDoubleMatrix(n_vars,1, mxREAL); // for the solution plhs[1] = mxCreateDoubleMatrix(n_cons,1, mxREAL); // for the constraint prices plhs[2] = mxCreateDoubleMatrix(1,1, mxREAL); // for the return status double *x = mxGetPr(plhs[0]); double *y = mxGetPr(plhs[1]); double *returncode = mxGetPr(plhs[2]); // Copy solutions if available if ( pSolver->isProvenOptimal() ) { // if ( model.isProvenOptimal() ) { // if ( model.solver()->isProvenOptimal() ) { //mexPrintf("Solution found.\n"); // extract the solutions const double * solution = pSolver->getColSolution(); const double * dualvars = pSolver->getRowPrice(); // copy the solution to the outpus memcpy(x,solution,n_vars*sizeof(double)); memcpy(y,dualvars,n_cons*sizeof(double)); *returncode = 1; } else { if ( pSolver->isProvenPrimalInfeasible() ) { mexPrintf("Primal problem is proven infeasible.\n"); *returncode = 0; } else if ( pSolver->isProvenDualInfeasible() ) { mexPrintf("Dual problem is proven infeasible.\n"); *returncode = -1; } else if ( pSolver->isPrimalObjectiveLimitReached() ) { mexPrintf("The primal objective limit was reached.\n"); *returncode = -2; } else if ( pSolver->isDualObjectiveLimitReached() ) { mexPrintf("The dual objective limit was reached.\n"); *returncode = -3; } else if ( pSolver->isIterationLimitReached() ) { mexPrintf("The iteration limit was reached\n"); *returncode = -4; } } // clean up memory if ( mexprinter!= NULL) delete mexprinter; delete pSolver; }