Пример #1
0
int mosekNNSolverWrapper(const Matrix &Q, const Matrix &Eq, const Matrix &b,
                         const Matrix &InEq, const Matrix &ib,
                         const Matrix &lowerBounds, const Matrix &upperBounds,
                         Matrix &sol, double *objVal, MosekObjectiveType objType)
{
  DBGP("Mosek QP Wrapper started");
  MSKrescodee  r;
  MSKtask_t task = NULL;

  // Get the only instance of the mosek environment.
  MSKenv_t     env  = getMosekEnv();
  // Create the optimization task.
  r = MSK_maketask(env, 0, 0, &task);
  if (r != MSK_RES_OK) {
    DBGA("Failed to create optimization task");
    return -1;
  }
  MSK_linkfunctotaskstream(task, MSK_STREAM_LOG, NULL, printstr);

  //---------------------------------------
  //start inputing the problem
  //prespecify number of variables to make inputting faster
  r = MSK_putmaxnumvar(task, sol.rows());
  //number of constraints (both equality and inequality)
  if (r == MSK_RES_OK) {
    r = MSK_putmaxnumcon(task, Eq.rows() + InEq.rows());
  }
  //make sure default value is 0 for sparse matrices
  assert(Q.getDefault() == 0.0);
  assert(Eq.getDefault() == 0.0);
  assert(InEq.getDefault() == 0.0);
  //number of non-zero entries in A
  if (r == MSK_RES_OK) {
    r = MSK_putmaxnumanz(task, Eq.numElements() + InEq.numElements());
  }
  if (r != MSK_RES_OK) {
    DBGA("Failed to input variables");
    MSK_deletetask(&task);
    return -1;
  }

  //solver is sensitive to numerical problems. Scale the problem down
  //we will use this value to scale down the right hand side of equality
  //and inequality constraints and lower and upper bounds
  //after solving, we must scale back up the solution and the value of the
  //objective
  double scale = b.absMax();
  if (scale < 1.0e2) {
    scale = 1.0;
  } else {
    DBGP("Mosek solver: scaling problem down by " << scale);
  }

  //---------------------------------------
  //insert the actual variables and constraints

  //append the variables
  MSK_append(task, MSK_ACC_VAR, sol.rows());
  //append the constraints.
  MSK_append(task, MSK_ACC_CON, Eq.rows() + InEq.rows());

  int i, j;
  double value;
  if (objType == MOSEK_OBJ_QP) {
    //quadratic optimization objective
    //the quadratic term
    Q.sequentialReset();
    while (Q.nextSequentialElement(i, j, value)) {
      MSK_putqobjij(task, i, j, 2.0 * value);
    }
  } else if (objType == MOSEK_OBJ_LP) {
    //linear objective
    for (j = 0; j < Q.cols(); j++) {
      if (fabs(Q.elem(0, j)) > 1.0e-5) {
        MSK_putcj(task, j, Q.elem(0, j));
      }
    }
  } else {
    assert(0);
  }

  //variable bounds
  assert(sol.rows() == lowerBounds.rows());
  assert(sol.rows() == upperBounds.rows());
  for (i = 0; i < sol.rows(); i++) {
    if (lowerBounds.elem(i, 0) >= upperBounds.elem(i, 0)) {
      if (lowerBounds.elem(i, 0) > upperBounds.elem(i, 0)) {
        assert(0);
      }
      if (lowerBounds.elem(i, 0) == -std::numeric_limits<double>::max()) {
        assert(0);
      }
      if (upperBounds.elem(i, 0) == std::numeric_limits<double>::max()) {
        assert(0);
      }
      //fixed variable
      DBGP(i << ": fixed " << lowerBounds.elem(i, 0) / scale);
      MSK_putbound(task, MSK_ACC_VAR, i, MSK_BK_FX,
                   lowerBounds.elem(i, 0) / scale, upperBounds.elem(i, 0) / scale);
    } else if (lowerBounds.elem(i, 0) != -std::numeric_limits<double>::max()) {
      //finite lower bound
      if (upperBounds.elem(i, 0) != std::numeric_limits<double>::max()) {
        //two finite bounds
        DBGP(i << ": finite bounds " << lowerBounds.elem(i, 0) / scale
             << " " << upperBounds.elem(i, 0) / scale);
        MSK_putbound(task, MSK_ACC_VAR, i, MSK_BK_RA,
                     lowerBounds.elem(i, 0) / scale, upperBounds.elem(i, 0) / scale);
      } else {
        //lower bound
        DBGP(i << ": lower bound " << lowerBounds.elem(i, 0) / scale);
        MSK_putbound(task, MSK_ACC_VAR, i, MSK_BK_LO,
                     lowerBounds.elem(i, 0) / scale, +MSK_INFINITY);

      }
    } else {
      //infinite lower bound
      if (upperBounds.elem(i, 0) != std::numeric_limits<double>::max()) {
        //upper bound
        DBGP(i << ": upper bound " << upperBounds.elem(i, 0) / scale);
        MSK_putbound(task, MSK_ACC_VAR, i, MSK_BK_UP,
                     -MSK_INFINITY, upperBounds.elem(i, 0) / scale);
      } else {
        //unbounded
        DBGP(i << ": unbounded");
        MSK_putbound(task, MSK_ACC_VAR, i, MSK_BK_FR,
                     -MSK_INFINITY, +MSK_INFINITY);

      }
    }
  }

  //constraints and constraint bounds
  //equality constraints
  Eq.sequentialReset();
  while (Eq.nextSequentialElement(i, j, value)) {
    MSK_putaij(task, i, j, value);
  }
  for (i = 0; i < Eq.rows(); i++) {
    MSK_putbound(task, MSK_ACC_CON, i, MSK_BK_FX, b.elem(i, 0) / scale, b.elem(i, 0) / scale);
  }
  //inequality constraints, <=
  InEq.sequentialReset();
  while (InEq.nextSequentialElement(i, j, value)) {
    int eqi = i + Eq.rows();
    MSK_putaij(task, eqi, j, value);
  }
  for (i = 0; i < InEq.rows(); i++) {
    int eqi = i + Eq.rows();
    MSK_putbound(task, MSK_ACC_CON, eqi, MSK_BK_UP, -MSK_INFINITY, ib.elem(i, 0) / scale);
  }
  //specify objective: minimize
  MSK_putobjsense(task, MSK_OBJECTIVE_SENSE_MINIMIZE);

  //give it 800 iterations, twice the default.
  MSK_putintparam(task, MSK_IPAR_INTPNT_MAX_ITERATIONS, 800);

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

  //solve the thing
  DBGP("Optimization started");
  r = MSK_optimize(task);
  DBGP("Optimization returns");

  //write problem to file
  /*
  static int fileNum = 0;
  if (r != MSK_RES_OK) {
    char filename[50];
    sprintf(filename,"mosek_error_%d_%d.opf",fileNum++, r);
    MSK_writedata(task, filename);
    FILE *fp = fopen(filename,"a");
    fprintf(fp,"\n\nEquality matrix:\n");
    Eq.print(fp);
    fclose(fp);
  }
  */

  if (r != MSK_RES_OK) {
    DBGA("Mosek optimization call failed, error code " << r);
    MSK_deletetask(&task);
    return -1;
  }
  DBGP("Optimization complete");
  //debug code, find out number of iterations used
  //int iter;
  //MSK_getintinf(task, MSK_IINF_INTPNT_ITER, &iter);
  //DBGA("Iterations used: " << iter);

  //find out what kind of solution we have
  MSKprostae pst;
  MSKsolstae sst;
  MSK_getsolutionstatus(task, MSK_SOL_ITR, &pst, &sst);
  int result;
  if (sst == MSK_SOL_STA_OPTIMAL || sst == MSK_SOL_STA_NEAR_OPTIMAL) {
    //success, we have an optimal problem
    if (sst == MSK_SOL_STA_OPTIMAL) {DBGP("QP solution is optimal");}
    else {DBGA("QP solution is *nearly* optimal");}
    result = 0;
  } else if (sst == MSK_SOL_STA_PRIM_INFEAS_CER) {
    //unfeasible problem
    DBGP("Mosek optimization: primal infeasible");
    result = 1;
  } else if (sst == MSK_SOL_STA_DUAL_INFEAS_CER) {
    //unfeasible problem
    DBGA("Mosek optimization: dual infeasible (primal unbounded?)");
    result = 1;
  } else if (sst == MSK_SOL_STA_PRIM_AND_DUAL_FEAS) {
    //i think this means feasible problem, but unbounded solution
    //this shouldn't happen as our Q is positive semidefinite
    DBGA("QP solution is prim and dual feasible, but not optimal");
    DBGA("Is Q positive semidefinite?");
    result = -1;
  } else {
    //unknown return status
    DBGA("QP fails with solution status " << sst << " and problem status " << pst);
    result = -1;
  }

  //MSK_SOL_STA_DUAL_FEAS;

  //retrieve the solutions
  if (!result) {
    //get the value of the objective function
    MSKrealt obj, foo;
    MSK_getsolutioninf(task, MSK_SOL_ITR, &pst, &sst, &obj,
                       &foo, &foo, &foo, &foo, &foo, &foo, &foo, &foo);
    if (objType == MOSEK_OBJ_QP) {
      *objVal = obj * scale * scale;
    } else if (objType == MOSEK_OBJ_LP) {
      *objVal = obj * scale;
    } else {
      assert(0);
    }
    double *xx = new double[sol.rows()];
    MSK_getsolutionslice(task, MSK_SOL_ITR, MSK_SOL_ITEM_XX,
                         0, sol.rows(), xx);
    for (i = 0; i < sol.rows(); i++) {
      sol.elem(i, 0) = scale * xx[i];
      DBGP("x" << i << ": " << xx[i]);
    }
    delete [] xx;
  }
  MSK_deletetask(&task);
  return result;
}
Пример #2
0
int main (int argc, char * argv[])
{
  MSKtask_t   task = NULL;
  MSKenv_t    env  = NULL;
  MSKrescodee r  = MSK_RES_OK;

  if (argc <= 1)
  {
    printf ("Missing argument. The syntax is:\n");
    printf (" simple inputfile [ solutionfile ]\n");
  }
  else
  {    
    /* Create the mosek environment. 
       The `NULL' arguments here, are used to specify customized 
       memory allocators and a memory debug file. These can
       safely be ignored for now. */
    
    r = MSK_makeenv(&env, NULL, NULL, NULL, NULL);
      
    /* Initialize the environment */
    if ( r==MSK_RES_OK )
      MSK_initenv (env);

    /* Create a task object linked to the environment env.
       Initially we create it with 0 variables and 0 columns, 
       since we do not know the size of the problem. */ 
    if ( r==MSK_RES_OK )
      r = MSK_maketask (env, 0,0, &task);

    if (r == MSK_RES_OK)
      MSK_linkfunctotaskstream(task,MSK_STREAM_LOG,NULL,printstr);
      
    /* We assume that a problem file was given as the first command
       line argument (received in `argv'). */
    if ( r==MSK_RES_OK )   
      r = MSK_readdata (task, argv[1]);


    /* Solve the problem */
    if ( r==MSK_RES_OK )
    {
      MSKrescodee trmcode;
      
      MSK_optimizetrm(task,&trmcode);
    }

    /* Print a summary of the solution. */
    MSK_solutionsummary(task, MSK_STREAM_MSG);

    if (r == MSK_RES_OK)
    {
      MSKprostae prosta;
      MSKsolstae  solsta;
      MSKrealt primalobj,maxpbi,maxpcni,maxpeqi,maxinti,
        dualobj, maxdbi, maxdcni, maxdeqi;
      MSKintt isdef;
      MSKsoltypee whichsol = MSK_SOL_BAS;
      int accepted = 1;
      
        
      MSK_getsolutioninf (
                          task,
                          whichsol,
                          &prosta,
                          &solsta,
                          &primalobj,
                          &maxpbi,
                          &maxpcni,
                          &maxpeqi,
                          &maxinti,
                          &dualobj,
                          &maxdbi,
                          &maxdcni,
                          &maxdeqi);

        switch(solsta)
        {
          case MSK_SOL_STA_OPTIMAL:
          case MSK_SOL_STA_NEAR_OPTIMAL:
            {
              double max_primal_infeas = 0.0; /* maximal primal infeasibility */
              double max_dual_infeas   = 0.0; /* maximal dual infeasibility */
              double obj_gap = fabs(dualobj-primalobj);
           
            
              max_primal_infeas = double_max(max_primal_infeas,maxpbi);
              max_primal_infeas = double_max(max_primal_infeas,maxpcni);
              max_primal_infeas = double_max(max_primal_infeas,maxpeqi);
            
              max_dual_infeas = double_max(max_dual_infeas,maxdbi);
              max_dual_infeas = double_max(max_dual_infeas,maxdcni);
              max_dual_infeas = double_max(max_dual_infeas,maxdeqi);

              /* Assume the application needs the solution to be within
                 1e-6 ofoptimality in an absolute sense. Another approach
                 would be looking at the relative objective gap */
              printf("Objective gap: %e\n",obj_gap);
              if (obj_gap > 1e-6)
              {
                printf("Warning: The objective gap is too large.");
                accepted = 0;
              }            

              printf("Max primal infeasibility: %e\n", max_primal_infeas);
              printf("Max dual infeasibility: %e\n"  , max_dual_infeas);

              /* We will accept a primal infeasibility of 1e-8 and
                 dual infeasibility of 1e-6 */
            
              if (max_primal_infeas > 1e-8)
              {
                printf("Warning: Primal infeasibility is too large");
                accepted = 0;
              }

              if (max_dual_infeas > 1e-6)
              {
                printf("Warning: Dual infeasibility is too large");
                accepted = 0;
              }         
            }
            
            if (accepted && r == MSK_RES_OK)
            {
              MSKintt numvar,j;
              MSKrealt *xx = NULL;

              MSK_getnumvar(task,&numvar);
              
              xx = (double *) malloc(numvar*sizeof(MSKrealt));
              
              MSK_getsolutionslice(task,
                                   MSK_SOL_BAS,    /* Request the basic solution. */
                                   MSK_SOL_ITEM_XX,/* Which part of solution.     */
                                   0,              /* Index of first variable.    */
                                   numvar,         /* Index of last variable+1.   */
                                   xx);

      
              printf("Optimal primal solution\n");
              for(j=0; j<numvar; ++j)
                printf("x[%d]: %e\n",j,xx[j]);

              free(xx);
            }
            else
            {
              /* Print detailed information about the solution */
              if (r == MSK_RES_OK)
                r = MSK_analyzesolution(task,MSK_STREAM_LOG,whichsol);
            }
            break;
          case MSK_SOL_STA_DUAL_INFEAS_CER:
          case MSK_SOL_STA_PRIM_INFEAS_CER:
          case MSK_SOL_STA_NEAR_DUAL_INFEAS_CER:
          case MSK_SOL_STA_NEAR_PRIM_INFEAS_CER:  
            printf("Primal or dual infeasibility certificate found.\n");
            break;
          case MSK_SOL_STA_UNKNOWN:
            printf("The status of the solution could not be determined.\n");
            break;
          default:
            printf("Other solution status");
            break;
        }
    }
    else
    {
      printf("Error while optimizing.\n");
    }

    MSK_deletetask(&task);
    MSK_deleteenv(&env);
  }
  return r;
}