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; }
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; }