//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;
}
Beispiel #3
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, &param_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;
}
Beispiel #4
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;
}