int solve(pwork *w, vars *sol) { idxint i = 0; int exitflag = ECOS_solve(w); for(i = 0; i < 2; ++i) { sol->a[i] = w->x[i + 2]; } sol->b = w->x[66]; return exitflag; }
/* Default ECOS options */ opts_ecos.feastol = FEASTOL; opts_ecos.reltol = RELTOL; opts_ecos.abstol = ABSTOL; opts_ecos.feastol_inacc = FTOL_INACC; opts_ecos.abstol_inacc = ATOL_INACC; opts_ecos.reltol_inacc = RTOL_INACC; opts_ecos.maxit = MAXIT; opts_ecos.verbose = VERBOSE; /* This calls ECOS setup function */ mywork = ECOS_setup(n, m, p, l, ncones, q, e, Gpr, Gjc, Gir, Apr, Ajc, Air, cpr, hpr, bpr); /* Set settings for ECOS */ mywork->stgs->verbose = opts_ecos.verbose mywork->stgs->abstol = opts_ecos.abstol; mywork->stgs->feastol = opts_ecos.feastol; mywork->stgs->reltol = opts_ecos.reltol; mywork->stgs->abstol_inacc = opts_ecos.abstol_inacc; mywork->stgs->feastol_inacc = opts_ecos.feastol_inacc; mywork->stgs->reltol_inacc = opts_ecos.reltol_inacc; mywork->stgs->maxit = opts_ecos.maxit; /* Solve! */ exitcode = ECOS_solve(mywork); ECOS_cleanup(mywork, 4); }
int main(void) { /*char ver[7];*/ idxint exitflag = ECOS_FATAL; pwork* mywork; #if PROFILING > 0 double ttotal, tsolve, tsetup; #endif #if PROFILING > 1 double torder, tkktcreate, ttranspose, tfactor, tkktsolve; #endif /* set up data */ mywork = ECOS_setup(n, m, p, l, ncones, q, Gpr, Gjc, Gir, Apr, Ajc, Air, c, h, b); if( mywork != NULL ){ /* solve */ exitflag = ECOS_solve(mywork); /* test second solve exitflag = ECOS_solve(mywork); */ /* some statistics in milliseconds */ #if PROFILING > 0 tsolve = mywork->info->tsolve * 1000; tsetup = mywork->info->tsetup * 1000; ttotal = tsetup + tsolve; #endif #if PROFILING > 1 torder = mywork->info->torder * 1000; tkktcreate = mywork->info->tkktcreate * 1000; ttranspose = mywork->info->ttranspose * 1000; tfactor = mywork->info->tfactor * 1000; tkktsolve = mywork->info->tkktsolve * 1000; #endif #if PRINTLEVEL > 2 #if PROFILING > 1 printf("ECOS timings (all times in milliseconds):\n\n"); printf("1. Setup: %7.3f (%4.1f%%)\n", tsetup, tsetup / ttotal*100); printf("2. Solve: %7.3f (%4.1f%%)\n", tsolve, tsolve / ttotal*100); printf("----------------------------------\n"); printf(" Total solve time: %7.3f ms\n\n", ttotal); printf("Detailed timings in SETUP:\n"); printf("Create transposes: %7.3f (%4.1f%%)\n", ttranspose, ttranspose / tsetup*100); printf("Create KKT Matrix: %7.3f (%4.1f%%)\n", tkktcreate, tkktcreate / tsetup*100); printf(" Compute ordering: %7.3f (%4.1f%%)\n", torder, torder / tsetup*100); printf(" Other: %7.3f (%4.1f%%)\n", tsetup-torder-tkktcreate-ttranspose, (tsetup-torder-tkktcreate-ttranspose) / tsetup*100); printf("\n"); printf("Detailed timings in SOLVE:\n"); printf(" Factorizations: %7.3f (%4.1f%% of tsolve / %4.1f%% of ttotal)\n", tfactor, tfactor / tsolve*100, tfactor / ttotal*100); printf(" KKT solves: %7.3f (%4.1f%% of tsolve / %4.1f%% of ttotal)\n", tkktsolve, tkktsolve / tsolve*100, tfactor / ttotal*100); printf(" Other: %7.3f (%4.1f%% of tsolve / %4.1f%% of ttotal)\n", tsolve-tkktsolve-tfactor, (tsolve-tkktsolve-tfactor) / tsolve*100, (tsolve-tkktsolve-tfactor) / ttotal*100); printf("\n"); #endif #endif /* clean up memory */ ECOS_cleanup(mywork, 0); } /* test version number ECOS_ver(ver); printf("This test has been run on ECOS version %s\n", ver); */ /* explicitly truncate exit code */ return (int)exitflag; }
static PyObject *csolve(PyObject* self, PyObject *args, PyObject *kwargs) { /* Expects a function call * sol = csolve((m,n,p),c,Gx,Gi,Gp,h,dims,Ax,Ai,Ap,b,verbose) * where * * the triple (m,n,p) corresponds to: * `m`: the rows of G * `n`: the cols of G and A, must agree with the length of c * `p`: the rows of A * `c` is a Numpy array of doubles * "G" is a sparse matrix in column compressed storage. "Gx" are the values, * "Gi" are the rows, and "Gp" are the column pointers. * `Gx` is a Numpy array of doubles * `Gi` is a Numpy array of ints * `Gp` is a Numpy array of ints * `h` is a Numpy array * `dims` is a dictionary with * `dims['l']` an integer specifying the dimension of positive orthant cone * `dims['q']` an *list* specifying dimensions of second-order cones * * "A" is an optional sparse matrix in column compressed storage. "Ax" are * the values, "Ai" are the rows, and "Ap" are the column pointers. * `Ax` is a Numpy array of doubles * `Ai` is a Numpy array of ints * `Ap` is a Numpy array of ints * `b` is an optional argument, which is a Numpy array of doubles * `verbose` is an optional bool signaling whether to print info * * This call will solve the problem * * minimize c'*x * subject to A*x = b * h - G*x \in K * * The code returns a Python dictionary with five keys, 'x', 'y', 'info', 's', * and 'z'. These correspond to the following: * * `x`: primal variables * `y`: dual variables for equality constraints * `s`: slacks for Gx + s <= h, s \in K * `z`: dual variables for inequality constraints s \in K * `info`: another dictionary with the following fields: * exitflag: 0=OPTIMAL, 1=PRIMAL INFEASIBLE, 2=DUAL INFEASIBLE, -1=MAXIT REACHED * infostring: gives information about the status of solution * pcost: value of primal objective * dcost: value of dual objective * pres: primal residual on inequalities and equalities * dres: dual residual * pinf: primal infeasibility measure * dinf: dual infeasibility measure * pinfres: NaN * dinfres: 3.9666e+15 * gap: duality gap * relgap: relative duality gap * r0: ??? * numerr: numerical error? * iter: number of iterations * timing: dictionary with timing information */ /* data structures for arguments */ //matrix *c, *h, *b = NULL; //spmatrix *G, *A = NULL; PyArrayObject *Gx, *Gi, *Gp, *c, *h; PyArrayObject *Ax = NULL; PyArrayObject *Ai = NULL; PyArrayObject *Ap = NULL; PyArrayObject *b = NULL; PyObject *dims, *verbose = NULL; idxint n; // number or variables idxint m; // number of conic variables idxint p = 0; // number of equality constraints idxint ncones = 0; // number of cones idxint numConicVariables = 0; /* ECOS data structures */ idxint l = 0; idxint *q = NULL; pfloat *Gpr = NULL; idxint *Gjc = NULL; idxint *Gir = NULL; pfloat *Apr = NULL; idxint *Ajc = NULL; idxint *Air = NULL; pfloat *cpr = NULL; pfloat *hpr = NULL; pfloat *bpr = NULL; pwork* mywork; idxint i; static char *kwlist[] = {"shape", "c", "Gx", "Gi", "Gp", "h", "dims", "Ax", "Ai", "Ap", "b", "verbose", NULL}; // parse the arguments and ensure they are the correct type #ifdef DLONG static char *argparse_string = "(lll)O!O!O!O!O!O!|O!O!O!O!O!"; #else static char *argparse_string = "(iii)O!O!O!O!O!O!|O!O!O!O!O!"; #endif if( !PyArg_ParseTupleAndKeywords(args, kwargs, argparse_string, kwlist, &m, &n, &p, &PyArray_Type, &c, &PyArray_Type, &Gx, &PyArray_Type, &Gi, &PyArray_Type, &Gp, &PyArray_Type, &h, &PyDict_Type, &dims, &PyArray_Type, &Ax, &PyArray_Type, &Ai, &PyArray_Type, &Ap, &PyArray_Type, &b, &PyBool_Type, &verbose) ) { return NULL; } if (m < 0) { PyErr_SetString(PyExc_ValueError, "m must be a positive integer"); return NULL; } if (n < 0) { PyErr_SetString(PyExc_ValueError, "n must be a positive integer"); return NULL; } if (p < 0) { PyErr_SetString(PyExc_ValueError, "p must be a positive integer"); return NULL; } /* get the typenum for the primitive int and double types */ int intType = getIntType(); int doubleType = getDoubleType(); /* set G */ if( !PyArray_ISFLOAT(Gx) || PyArray_NDIM(Gx) != 1) { PyErr_SetString(PyExc_TypeError, "Gx must be a numpy array of floats"); return NULL; } if( !PyArray_ISINTEGER(Gi) || PyArray_NDIM(Gi) != 1) { PyErr_SetString(PyExc_TypeError, "Gi must be a numpy array of ints"); return NULL; } if( !PyArray_ISINTEGER(Gp) || PyArray_NDIM(Gp) != 1) { PyErr_SetString(PyExc_TypeError, "Gp must be a numpy array of ints"); return NULL; } PyArrayObject *Gx_arr = getContiguous(Gx, doubleType); PyArrayObject *Gi_arr = getContiguous(Gi, intType); PyArrayObject *Gp_arr = getContiguous(Gp, intType); Gpr = (pfloat *) PyArray_DATA(Gx_arr); Gir = (idxint *) PyArray_DATA(Gi_arr); Gjc = (idxint *) PyArray_DATA(Gp_arr); /* set c */ if (!PyArray_ISFLOAT(c) || PyArray_NDIM(c) != 1) { PyErr_SetString(PyExc_TypeError, "c must be a dense numpy array with one dimension"); Py_DECREF(Gx_arr); Py_DECREF(Gi_arr); Py_DECREF(Gp_arr); return NULL; } if (PyArray_DIM(c,0) != n){ PyErr_SetString(PyExc_ValueError, "c has incompatible dimension with G"); Py_DECREF(Gx_arr); Py_DECREF(Gi_arr); Py_DECREF(Gp_arr); return NULL; } PyArrayObject *c_arr = getContiguous(c, doubleType); cpr = (pfloat *) PyArray_DATA(c_arr); /* set h */ if (!PyArray_ISFLOAT(h) || PyArray_NDIM(h) != 1) { PyErr_SetString(PyExc_TypeError, "h must be a dense numpy array with one dimension"); Py_DECREF(Gx_arr); Py_DECREF(Gi_arr); Py_DECREF(Gp_arr); Py_DECREF(c_arr); return NULL; } if (PyArray_DIM(h,0) != m){ PyErr_SetString(PyExc_ValueError, "h has incompatible dimension with G"); Py_DECREF(Gx_arr); Py_DECREF(Gi_arr); Py_DECREF(Gp_arr); Py_DECREF(c_arr); return NULL; } PyArrayObject *h_arr = getContiguous(h, doubleType); hpr = (pfloat *) PyArray_DATA(h_arr); /* get dims['l'] */ PyObject *linearObj = PyDict_GetItemString(dims, "l"); if(linearObj) { if(PyInt_Check(linearObj) && ((l = (idxint) PyInt_AsLong(linearObj)) >= 0)) { numConicVariables += l; } else { PyErr_SetString(PyExc_TypeError, "dims['l'] ought to be a nonnegative integer"); Py_DECREF(Gx_arr); Py_DECREF(Gi_arr); Py_DECREF(Gp_arr); Py_DECREF(c_arr); Py_DECREF(h_arr); return NULL; } } /* get dims['q'] */ PyObject *socObj = PyDict_GetItemString(dims, "q"); if(socObj) { if (PyList_Check(socObj)) { ncones = PyList_Size(socObj); q = calloc(ncones, sizeof(idxint)); for (i = 0; i < ncones; ++i) { PyObject *qi = PyList_GetItem(socObj, i); if(PyInt_Check(qi) && ((q[i] = (idxint) PyInt_AsLong(qi)) > 0)) { numConicVariables += q[i]; } else { PyErr_SetString(PyExc_TypeError, "dims['q'] ought to be a list of positive integers"); Py_DECREF(Gx_arr); Py_DECREF(Gi_arr); Py_DECREF(Gp_arr); Py_DECREF(c_arr); Py_DECREF(h_arr); return NULL; } } } else { PyErr_SetString(PyExc_TypeError, "dims['q'] ought to be a list"); Py_DECREF(Gx_arr); Py_DECREF(Gi_arr); Py_DECREF(Gp_arr); Py_DECREF(c_arr); Py_DECREF(h_arr); return NULL; } } PyArrayObject *Ax_arr = NULL; PyArrayObject *Ai_arr = NULL; PyArrayObject *Ap_arr = NULL; PyArrayObject *b_arr = NULL; if(Ax && Ai && Ap && b) { /* set A */ if( !PyArray_ISFLOAT(Ax) || PyArray_NDIM(Ax) != 1 ) { PyErr_SetString(PyExc_TypeError, "Ax must be a numpy array of floats"); if(q) free(q); Py_DECREF(Gx_arr); Py_DECREF(Gi_arr); Py_DECREF(Gp_arr); Py_DECREF(c_arr); Py_DECREF(h_arr); return NULL; } if( !PyArray_ISINTEGER(Ai) || PyArray_NDIM(Ai) != 1) { PyErr_SetString(PyExc_TypeError, "Ai must be a numpy array of ints"); if(q) free(q); Py_DECREF(Gx_arr); Py_DECREF(Gi_arr); Py_DECREF(Gp_arr); Py_DECREF(c_arr); Py_DECREF(h_arr); return NULL; } if( !PyArray_ISINTEGER(Ap) || PyArray_NDIM(Ap) != 1) { PyErr_SetString(PyExc_TypeError, "Ap must be a numpy array of ints"); if(q) free(q); Py_DECREF(Gx_arr); Py_DECREF(Gi_arr); Py_DECREF(Gp_arr); Py_DECREF(c_arr); Py_DECREF(h_arr); return NULL; } // if ((SpMatrix_Check(A) && SP_ID(A) != DOUBLE)){ // PyErr_SetString(PyExc_TypeError, "A must be a sparse 'd' matrix"); // if(q) free(q); // Py_DECREF(Gx_arr); Py_DECREF(Gi_arr); Py_DECREF(Gp_arr); // Py_DECREF(c_arr); Py_DECREF(h_arr); // return NULL; // } // if ((p = SP_NROWS(A)) < 0) { // PyErr_SetString(PyExc_ValueError, "p must be a nonnegative integer"); // if(q) free(q); // Py_DECREF(Gx_arr); Py_DECREF(Gi_arr); Py_DECREF(Gp_arr); // Py_DECREF(c_arr); Py_DECREF(h_arr); // return NULL; // } // if (SP_NCOLS(A) != n) { // PyErr_SetString(PyExc_ValueError, "A has incompatible dimension with c"); // if(q) free(q); // Py_DECREF(Gx_arr); Py_DECREF(Gi_arr); Py_DECREF(Gp_arr); // Py_DECREF(c_arr); Py_DECREF(h_arr); // return NULL; // } // if (p != 0) { // Apr = SP_VALD(A); // Air = SP_ROW(A); // Ajc = SP_COL(A); // } Ax_arr = getContiguous(Ax, doubleType); Ai_arr = getContiguous(Ai, intType); Ap_arr = getContiguous(Ap, intType); Apr = (pfloat *) PyArray_DATA(Ax_arr); Air = (idxint *) PyArray_DATA(Ai_arr); Ajc = (idxint *) PyArray_DATA(Ap_arr); /* set b */ // if (!Matrix_Check(b) || MAT_NCOLS(b) != 1 || MAT_ID(b) != DOUBLE) { // PyErr_SetString(PyExc_TypeError, "b must be a dense 'd' matrix with one column"); // if(q) free(q); // return NULL; // } // if (MAT_NROWS(b) != p){ // PyErr_SetString(PyExc_ValueError, "b has incompatible dimension with A"); // if(q) free(q); // return NULL; // } // if (p != 0) { // bpr = MAT_BUFD(b); // } if (!PyArray_ISFLOAT(b) || PyArray_NDIM(b) != 1) { PyErr_SetString(PyExc_TypeError, "b must be a dense numpy array with one dimension"); if(q) free(q); Py_DECREF(Gx_arr); Py_DECREF(Gi_arr); Py_DECREF(Gp_arr); Py_DECREF(c_arr); Py_DECREF(h_arr); Py_DECREF(Ax_arr); Py_DECREF(Ai_arr); Py_DECREF(Ap_arr); return NULL; } if (PyArray_DIM(b,0) != p){ PyErr_SetString(PyExc_ValueError, "b has incompatible dimension with A"); if(q) free(q); Py_DECREF(Gx_arr); Py_DECREF(Gi_arr); Py_DECREF(Gp_arr); Py_DECREF(c_arr); Py_DECREF(h_arr); Py_DECREF(Ax_arr); Py_DECREF(Ai_arr); Py_DECREF(Ap_arr); return NULL; } b_arr = getContiguous(b, doubleType); bpr = (pfloat *) PyArray_DATA(b_arr); } else if (Ax || Ai || Ap || b) { // check that A and b are both supplied PyErr_SetString(PyExc_ValueError, "A and b arguments must be supplied together"); if(q) free(q); Py_DECREF(Gx_arr); Py_DECREF(Gi_arr); Py_DECREF(Gp_arr); Py_DECREF(c_arr); Py_DECREF(h_arr); return NULL; } /* check that sum(q) + l = m */ if( numConicVariables != m ){ PyErr_SetString(PyExc_ValueError, "Number of rows of G does not match dims.l+sum(dims.q)"); if (q) free(q); Py_DECREF(Gx_arr); Py_DECREF(Gi_arr); Py_DECREF(Gp_arr); Py_DECREF(c_arr); Py_DECREF(h_arr); if (b_arr) Py_DECREF(b_arr); if (Ax_arr) Py_DECREF(Ax_arr); if (Ai_arr) Py_DECREF(Ai_arr); if (Ap_arr) Py_DECREF(Ap_arr); return NULL; } /* This calls ECOS setup function. */ mywork = ECOS_setup(n, m, p, l, ncones, q, Gpr, Gjc, Gir, Apr, Ajc, Air, cpr, hpr, bpr); if( mywork == NULL ){ PyErr_SetString(PyExc_RuntimeError, "Internal problem occurred in ECOS while setting up the problem.\nPlease send a bug report with data to Alexander Domahidi.\nEmail: [email protected]"); if(q) free(q); Py_DECREF(Gx_arr); Py_DECREF(Gi_arr); Py_DECREF(Gp_arr); Py_DECREF(c_arr); Py_DECREF(h_arr); if (b_arr) Py_DECREF(b_arr); if (Ax_arr) Py_DECREF(Ax_arr); if (Ai_arr) Py_DECREF(Ai_arr); if (Ap_arr) Py_DECREF(Ap_arr); return NULL; } /* Set settings for ECOS. */ if(verbose) { mywork->stgs->verbose = (idxint) PyObject_IsTrue(verbose); } /* Solve! */ idxint exitcode = ECOS_solve(mywork); /* create output (all data is *deep copied*) */ // TODO: request CVXOPT API for constructing from existing pointer /* x */ // matrix *x; // if(!(x = Matrix_New(n,1,DOUBLE))) // return PyErr_NoMemory(); // memcpy(MAT_BUFD(x), mywork->x, n*sizeof(double)); npy_intp veclen[1]; veclen[0] = n; PyObject *x = PyArray_SimpleNewFromData(1, veclen, NPY_DOUBLE, mywork->x); /* y */ // matrix *y; // if(!(y = Matrix_New(p,1,DOUBLE))) // return PyErr_NoMemory(); // memcpy(MAT_BUFD(y), mywork->y, p*sizeof(double)); veclen[0] = p; PyObject *y = PyArray_SimpleNewFromData(1, veclen, NPY_DOUBLE, mywork->y); /* info dict */ // infostring const char* infostring; switch( exitcode ){ case ECOS_OPTIMAL: infostring = "Optimal solution found"; break; case ECOS_MAXIT: infostring = "Maximum number of iterations reached"; break; case ECOS_PINF: infostring = "Primal infeasible"; break; case ECOS_DINF: infostring = "Dual infeasible"; break; case ECOS_NUMERICS: infostring = "Run into numerical problems"; break; case ECOS_OUTCONE: infostring = "PROBLEM: Multipliers leaving the cone"; break; default: infostring = "UNKNOWN PROBLEM IN SOLVER"; } // numerical errors idxint numerr = 0; if( (exitcode == ECOS_NUMERICS) || (exitcode == ECOS_OUTCONE) || (exitcode == ECOS_FATAL) ){ numerr = 1; } // timings #if PROFILING > 0 PyObject *tinfos = Py_BuildValue( #if PROFILING > 1 "{s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d}", #else "{s:d,s:d,s:d}", #endif #if PROFILING > 1 "tkktcreate",(double)mywork->info->tkktcreate, "tkktsolve",(double)mywork->info->tkktsolve, "tkktfactor",(double)mywork->info->tfactor, "torder",(double)mywork->info->torder, "ttranspose",(double)mywork->info->ttranspose, #endif "runtime",(double)mywork->info->tsolve + (double)mywork->info->tsetup, "tsetup",(double)mywork->info->tsetup, "tsolve",(double)mywork->info->tsolve); #endif PyObject *infoDict = Py_BuildValue( #if PROFILING > 0 "{s:l,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:l,s:s,s:O,s:l}", #else "{s:l,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:l,s:s,s:l}", #endif "exitFlag", exitcode, "pcost", (double)mywork->info->pcost, "dcost", (double)mywork->info->dcost, "pres", (double)mywork->info->pres, "dres", (double)mywork->info->dres, "pinf", (double)mywork->info->pinf, "dinf", (double)mywork->info->dinf, "pinfres",(double)mywork->info->pinfres, "dinfres",(double)mywork->info->dinfres, "gap",(double)mywork->info->gap, "relgap",(double)mywork->info->relgap, "r0",(double)mywork->stgs->feastol, "iter",mywork->info->iter, "infostring",infostring, #if PROFILING > 0 "timing", tinfos, #endif "numerr",numerr); #if PROFILING > 0 // give reference to infoDict Py_DECREF(tinfos); #endif /* s */ // matrix *s; // if(!(s = Matrix_New(m,1,DOUBLE))) // return PyErr_NoMemory(); // memcpy(MAT_BUFD(s), mywork->s, m*sizeof(double)); veclen[0] = m; PyObject *s = PyArray_SimpleNewFromData(1, veclen, NPY_DOUBLE, mywork->s); /* z */ // matrix *z; // if(!(z = Matrix_New(m,1,DOUBLE))) // return PyErr_NoMemory(); // memcpy(MAT_BUFD(z), mywork->z, m*sizeof(double)); veclen[0] = m; PyObject *z = PyArray_SimpleNewFromData(1, veclen, NPY_DOUBLE, mywork->z); /* cleanup */ ECOS_cleanup(mywork, 4); PyObject *returnDict = Py_BuildValue( "{s:O,s:O,s:O,s:O,s:O}", "x",x, "y",y, "z",z, "s",s, "info",infoDict); // give up ownership to the return dictionary Py_DECREF(x); Py_DECREF(y); Py_DECREF(z); Py_DECREF(s); Py_DECREF(infoDict); // no longer need pointers to arrays that held primitives if(q) free(q); Py_DECREF(Gx_arr); Py_DECREF(Gi_arr); Py_DECREF(Gp_arr); Py_DECREF(c_arr); Py_DECREF(h_arr); if (b_arr) Py_DECREF(b_arr); if (Ax_arr) Py_DECREF(Ax_arr); if (Ai_arr) Py_DECREF(Ai_arr); if (Ap_arr) Py_DECREF(Ap_arr); return returnDict; }
void get_bounds(idxint node_idx, ecos_bb_pwork* prob){ idxint i, ret_code, branchable, viable_rounded_sol; viable_rounded_sol = 0; set_prob( prob, get_bool_node_id(node_idx,prob), get_int_node_id(node_idx, prob) ); ret_code = ECOS_solve(prob->ecos_prob); #if MI_PRINTLEVEL > 1 if (prob->stgs->verbose){ print_ecos_solution(prob); } if (ret_code != ECOS_OPTIMAL && ret_code != ECOS_PINF && ret_code != ECOS_DINF){ PRINTTEXT("1Exit code: %u\n", ret_code); } #endif if (ret_code >= 0 || ret_code == ECOS_MAXIT || ret_code == ECOS_NUMERICS ) { prob->nodes[node_idx].L = eddot(prob->ecos_prob->n, prob->ecos_prob->x, prob->ecos_prob->c); /* Figure out if x is already an integer solution if the solution had no numerical errors*/ branchable = 1; for (i=0; i<prob->num_bool_vars; ++i){ prob->tmp_bool_node_id[i] = (char) pfloat_round( prob->ecos_prob->x[prob->bool_vars_idx[i]] ); branchable &= float_eqls( prob->ecos_prob->x[i] , (pfloat) prob->tmp_bool_node_id[i], prob->stgs->integer_tol ); } for (i=0; i<prob->num_int_vars; ++i){ prob->tmp_int_node_id[2 * i + 1] = pfloat_round(prob->ecos_prob->x[prob->int_vars_idx[i]] ); prob->tmp_int_node_id[2*i] = -(prob->tmp_int_node_id[2*i + 1]); branchable &= float_eqls( prob->ecos_prob->x[i] , prob->tmp_int_node_id[2*i + 1], prob->stgs->integer_tol ); } branchable = !branchable; #if MI_PRINTLEVEL > 1 if (prob->stgs->verbose){ PRINTTEXT("Is branchable: %u\n",branchable); } #endif if (branchable){ /* pfloat_round and check feasibility*/ get_branch_var(prob, &(prob->nodes[node_idx].split_idx), &(prob->nodes[node_idx].split_val) ); prob->nodes[node_idx].status = MI_SOLVED_BRANCHABLE; #if MI_PRINTLEVEL > 1 if (prob->stgs->verbose){ print_node(prob,-1); PRINTTEXT("Rounded Solution:\n"); } #endif set_prob(prob, prob->tmp_bool_node_id, prob->tmp_int_node_id); ret_code = ECOS_solve(prob->ecos_prob); #if MI_PRINTLEVEL > 1 if (prob->stgs->verbose){ print_ecos_solution(prob); } if (ret_code != ECOS_OPTIMAL && ret_code != ECOS_PINF && ret_code != ECOS_DINF){ PRINTTEXT("2Exit code: %u\n", ret_code); } #endif if (ret_code == ECOS_OPTIMAL){ /* Use the node's U as tmp storage */ prob->nodes[node_idx].U = eddot(prob->ecos_prob->n, prob->ecos_prob->x, prob->ecos_prob->c); viable_rounded_sol = 1; } }else{ /* This is already an integer solution*/ prob->nodes[node_idx].status = MI_SOLVED_NON_BRANCHABLE; prob->nodes[node_idx].U = eddot(prob->ecos_prob->n, prob->ecos_prob->x, prob->ecos_prob->c); } if (prob->nodes[node_idx].U < prob->global_U){ #if MI_PRINTLEVEL > 1 if (prob->stgs->verbose){ PRINTTEXT("New optimal solution, U: %.2f\n", prob->nodes[node_idx].U); print_ecos_xequil(prob); print_ecos_c(prob); print_ecos_solution(prob); } #endif store_solution(prob); prob->global_U = prob->nodes[node_idx].U; } if (viable_rounded_sol){ /* Reset the node's U back to INF because it was not originally feasible */ prob->nodes[node_idx].U = INFINITY; } }else { /*Assume node infeasible*/ prob->nodes[node_idx].L = INFINITY; prob->nodes[node_idx].U = INFINITY; prob->nodes[node_idx].status = MI_SOLVED_NON_BRANCHABLE; } }
/* THE mex-function */ void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) { idxint i, n, m, p; idxint exitcode; idxint numerr = 0; const mxArray* c; const mxArray* G; const mxArray* h; const mxArray* A = NULL; const mxArray* b = NULL; const mxArray* dims; const mxArray* dims_l; const mxArray* dims_q; const mxArray* opts = NULL; const mxArray* opts_verbose = NULL; const mxArray* opts_feastol = NULL; const mxArray* opts_reltol = NULL; const mxArray* opts_abstol = NULL; const mxArray* opts_feastol_inacc = NULL; const mxArray* opts_reltol_inacc = NULL; const mxArray* opts_abstol_inacc = NULL; const mxArray* opts_maxit = NULL; const mwSize *size_c; const mwSize *size_G; const mwSize *size_h; const mwSize *size_A; const mwSize *size_b; const mwSize *size_q; const mwSize ZERO[2] = {0, 0}; mxArray* outvar; mxArray* tinfos; /* change number of infofields according to profiling setting */ #if PROFILING > 0 #define NINFOFIELDS 16 #else #define NINFOFIELDS 15 #endif const char *infofields[NINFOFIELDS] = { "exitflag", "infostring", "pcost", "dcost", "pres", "dres", "pinf", "dinf", "pinfres", "dinfres", "gap", "relgap", "r0", "numerr", "iter" #if PROFILING > 0 ,"timing" #endif }; #if PROFILING == 1 #define NTFIELDS 3 const char *tinfo[NTFIELDS] = {"runtime", "tsolve", "tsetup"}; #endif #if PROFILING == 2 #define NTFIELDS 10 const char *tinfo[NTFIELDS] = {"runtime", "tsolve", "tsetup", "tkktcreate", "tkktfactor", "tkktsolve", "torder", "ttranspose","tfactor_t1","tfactor_t2"}; #endif idxint l; double *q; idxint *qint; idxint ncones; idxint numConicVariables = 0; /* options */ idxint verbose; pfloat abstol; pfloat reltol; pfloat feastol; idxint maxit; pfloat *Gpr = NULL; idxint *Gjc = NULL; idxint *Gir = NULL; pfloat *Apr = NULL; idxint *Ajc = NULL; idxint *Air = NULL; pfloat *cpr = NULL; pfloat *hpr = NULL; pfloat *bpr = NULL; pwork* mywork; #ifdef MEXARGMUENTCHECKS if( !(nrhs >= 4 && nrhs <= 7) ) { mexPrintf("ECOS %s - (c) A. Domahidi, Automatic Control Laboratory, ETH Zurich, 2012-14.\n", ECOS_VERSION); mexErrMsgTxt("ECOS takes 4 to 7 arguments: ECOS(c,G,h,dims), ECOS(c,G,h,dims,opts), ECOS(c,G,h,dims,A,b), or ECOS(c,G,h,dims,A,b,opts)"); } #endif /* get pointers to data */ c = prhs[0]; size_c = c ? mxGetDimensions(c) : (const mwSize *) &ZERO; G = prhs[1]; size_G = G ? mxGetDimensions(G) : (const mwSize *) &ZERO; h = prhs[2]; size_h = h ? mxGetDimensions(h) : (const mwSize *) &ZERO; dims = prhs[3]; dims_l = dims ? mxGetField(dims, 0, "l") : NULL; dims_q = dims ? mxGetField(dims, 0, "q") : NULL; size_q = dims_q ? mxGetDimensions(dims_q) : (const mwSize *) &ZERO; if( nrhs >= 6 ) { A = prhs[4]; size_A = A ? mxGetDimensions(A) : (const mwSize *) &ZERO; b = prhs[5]; size_b = b ? mxGetDimensions(b) : (const mwSize *) &ZERO; } if( nrhs == 5 || nrhs == 7 ) { opts = nrhs==5 ? prhs[4] : prhs[6]; opts_verbose = opts ? mxGetField(opts, 0, "verbose") : 0; opts_abstol = opts ? mxGetField(opts, 0, "abstol") : 0; opts_feastol = opts ? mxGetField(opts, 0, "feastol") : 0; opts_reltol = opts ? mxGetField(opts, 0, "reltol") : 0; opts_abstol_inacc = opts ? mxGetField(opts, 0, "abstol_inacc") : 0; opts_feastol_inacc = opts ? mxGetField(opts, 0, "feastol_inacc") : 0; opts_reltol_inacc = opts ? mxGetField(opts, 0, "reltol_inacc") : 0; opts_maxit = opts ? mxGetField(opts, 0, "maxit") : 0; } /* determine sizes */ n = (idxint)size_c[0]; m = (idxint)size_G[0]; p = (nrhs >= 6) ? (idxint)size_A[0] : 0; /* argument checking */ #ifdef MEXARGMUENTCHECKS if( !mxIsDouble(c) || size_c[1] > 1 ) { mexErrMsgTxt("First argument needs to be a column vector"); } if( !mxIsDouble(G) ) { mexErrMsgTxt("Second argument needs to be a matrix"); } if( !mxIsSparse(G) ) { mexErrMsgTxt("Second argument needs to be a sparse matrix"); } if( size_G[1] != n ) { mexErrMsgTxt("c and G do not match in dimension"); } if( m > 0 ){ if( size_h[0] != m ) { mexErrMsgTxt("G and h do not match in dimension"); } if( size_h[1] != 1 ) { mexErrMsgTxt("h is expected to be a column vector"); } } if( !mxIsStruct(dims) ) { mexErrMsgTxt("Struct dims expected as 4th argument"); } if( dims_l == NULL && dims_q == NULL ) { mexErrMsgTxt("Neither dims.l nor dims.q exist - unconstrained problem?"); } if( mxIsSparse(c) ) { mexErrMsgTxt("c must be a dense vector"); } if( mxIsSparse(h) ) { mexErrMsgTxt("h must be a dense vector"); } if( nrhs >= 6 ) { if( size_A[1] != n ) { mexErrMsgTxt("c and A dimension mismatch"); } if( !mxIsDouble(A) ) { mexErrMsgTxt("Fifth argument needs to be a matrix"); } if( !mxIsSparse(A) ) { mexErrMsgTxt("Fifth argument (A) needs to be a sparse matrix"); } if( size_b[0] != p ) { mexErrMsgTxt("b and A dimension mismatch"); } if( size_b[1] != 1 ) { mexErrMsgTxt("b is expected to be a column vector"); } if( mxIsSparse(b) ) { mexErrMsgTxt("b must be a dense vector"); } } if( nrhs == 7 || nrhs == 5 ) { if( !mxIsStruct(opts) ) { mexErrMsgTxt("Struct opts expected as last argument"); } } if( nlhs > 5 ){ mexErrMsgTxt("ECOS has up to 5 output arguments only"); } #endif /* find out dimensions of cones */ l = (idxint)(*mxGetPr(dims_l)); numConicVariables += l; if( dims_q != NULL) { q = mxGetPr(dims_q); } else { q = NULL; } if( q == NULL || size_q[0] == 0 || size_q[1]==0 ){ ncones = 0; } else { ncones = size_q[1] > size_q[0] ? size_q[1] : size_q[0]; } /* get problem data in right format matrices */ if( m > 0){ Gpr = (pfloat *)mxGetPr(G); Gjc = (idxint *)mxGetJc(G); Gir = (idxint *)mxGetIr(G); } else { mexErrMsgTxt( "ECOS does not support equality constrained problems without inequalities yet." ); } if( p > 0 ){ Apr = (pfloat *)mxGetPr(A); Ajc = (idxint *)mxGetJc(A); Air = (idxint *)mxGetIr(A); } cpr = (pfloat *)mxGetPr(c); hpr = (pfloat *)mxGetPr(h); if ( p > 0 ) { bpr = (pfloat *)mxGetPr(b); } /* we have to copy the number of cones since Matlab gives us double * values but the C version of ECOS expects idxint values */ qint = (idxint *)mxMalloc(ncones*sizeof(idxint)); for( i=0; i < ncones; i++ ){ qint[i] = (idxint)q[i]; numConicVariables += qint[i]; } /* check that number of rows matches info defined in dims */ if ( numConicVariables != m ) { mexErrMsgTxt("Number of rows does not match information given in dims"); } /* This calls ECOS setup function. */ mywork = ECOS_setup(n, m, p, l, ncones, qint, Gpr, Gjc, Gir, Apr, Ajc, Air, cpr, hpr, bpr); if( mywork == NULL ){ mexErrMsgTxt("Internal problem occurred in ECOS while setting up the problem.\nPlease send a bug report with data to Alexander Domahidi.\nEmail: [email protected]"); } /* Set options */ if( opts != NULL ) { if(opts_verbose != NULL ) { mywork->stgs->verbose = mxIsLogical(opts_verbose) ? (idxint) (*mxGetLogicals(opts_verbose)) : (idxint)(*mxGetPr(opts_verbose)); } if(opts_feastol != NULL ) { mywork->stgs->feastol = (pfloat)(*mxGetPr(opts_feastol)); } if(opts_abstol != NULL ) { mywork->stgs->abstol = (pfloat)(*mxGetPr(opts_abstol)); } if(opts_reltol != NULL ) { mywork->stgs->reltol = (pfloat)(*mxGetPr(opts_reltol)); } if(opts_feastol_inacc != NULL ) { mywork->stgs->feastol_inacc = (pfloat)(*mxGetPr(opts_feastol_inacc)); } if(opts_abstol_inacc != NULL ) { mywork->stgs->abstol_inacc = (pfloat)(*mxGetPr(opts_abstol_inacc)); } if(opts_reltol_inacc != NULL ) { mywork->stgs->reltol_inacc = (pfloat)(*mxGetPr(opts_reltol_inacc)); } if(opts_maxit != NULL ) { mywork->stgs->maxit = (idxint)(*mxGetPr(opts_maxit)); } } /* Solve! */ exitcode = ECOS_solve(mywork); /* create output */ /* x */ if( nlhs > 0 ){ plhs[0] = mxCreateDoubleMatrix(0, 0, mxREAL); mxSetPr(plhs[0], mywork->x); mxSetM(plhs[0], n); mxSetN(plhs[0], 1); } /* y */ if( nlhs > 1 ){ plhs[1] = mxCreateDoubleMatrix(0, 0, mxREAL); mxSetPr(plhs[1], mywork->y); mxSetM(plhs[1], mywork->p); mxSetN(plhs[1], 1); } if( nlhs > 2 ){ plhs[2] = mxCreateStructMatrix(1, 1, NINFOFIELDS, infofields); /* 0. exitflag */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)exitcode; mxSetField(plhs[2], 0, "exitflag", outvar); /* 1. primal objective */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->info->pcost; mxSetField(plhs[2], 0, "pcost", outvar); /* 2. dual objective */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->info->dcost; mxSetField(plhs[2], 0, "dcost", outvar); /* 3. primal residual */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->info->pres; mxSetField(plhs[2], 0, "pres", outvar); /* 4. dual residual */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->info->dres; mxSetField(plhs[2], 0, "dres", outvar); /* 5. primal infeasible? */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->info->pinf; mxSetField(plhs[2], 0, "pinf", outvar); /* 6. dual infeasible? */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->info->dinf; mxSetField(plhs[2], 0, "dinf", outvar); /* 7. primal infeasibility measure */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->info->pinfres; mxSetField(plhs[2], 0, "pinfres", outvar); /* 8. dual infeasibility measure */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->info->dinfres; mxSetField(plhs[2], 0, "dinfres", outvar); /* 9. duality gap */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->info->gap; mxSetField(plhs[2], 0, "gap", outvar); /* 10. relative duality gap */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->info->relgap; mxSetField(plhs[2], 0, "relgap", outvar); /* 11. feasibility tolerance??? */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->stgs->feastol; mxSetField(plhs[2], 0, "r0", outvar); /* 12. iterations */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->info->iter; mxSetField(plhs[2], 0, "iter", outvar); /* 13. infostring */ switch( exitcode ){ case ECOS_OPTIMAL: outvar = mxCreateString("Optimal solution found"); break; case (ECOS_OPTIMAL + ECOS_INACC_OFFSET): outvar = mxCreateString("Optimal solution found within reduced tolerances"); break; case ECOS_MAXIT: outvar = mxCreateString("Maximum number of iterations reached"); break; case ECOS_PINF: outvar = mxCreateString("Certificate of primal infeasibility found"); break; case (ECOS_PINF + ECOS_INACC_OFFSET): outvar = mxCreateString("Certificate of primal infeasibility found within reduced tolerances"); break; case ECOS_DINF: outvar = mxCreateString("Certificate of dual infeasibility found"); break; case (ECOS_DINF + ECOS_INACC_OFFSET): outvar = mxCreateString("Certificate of dual infeasibility found within reduced tolerances"); break; case ECOS_NUMERICS: outvar = mxCreateString("Numerical problems"); break; case ECOS_OUTCONE: outvar = mxCreateString("PROBLEM: Mulitpliers leaving the cone"); break; default: outvar = mxCreateString("UNKNOWN PROBLEM IN SOLVER"); } mxSetField(plhs[2], 0, "infostring", outvar); #if PROFILING > 0 /* 14. timing information */ tinfos = mxCreateStructMatrix(1, 1, NTFIELDS, tinfo); /* 14.1 --> runtime */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->info->tsolve + (double)mywork->info->tsetup; mxSetField(tinfos, 0, "runtime", outvar); /* 14.2 --> setup time */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->info->tsetup; mxSetField(tinfos, 0, "tsetup", outvar); /* 14.3 --> solve time */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->info->tsolve; mxSetField(tinfos, 0, "tsolve", outvar); #if PROFILING > 1 /* 14.4 time to create KKT matrix */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->info->tkktcreate; mxSetField(tinfos, 0, "tkktcreate", outvar); /* 14.5 time for kkt solve */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->info->tkktsolve; mxSetField(tinfos, 0, "tkktsolve", outvar); /* 14.6 time for kkt factor */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->info->tfactor; mxSetField(tinfos, 0, "tkktfactor", outvar); /* 14.7 time for ordering */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->info->torder; mxSetField(tinfos, 0, "torder", outvar); /* 14.8 time for transposes */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->info->ttranspose; mxSetField(tinfos, 0, "ttranspose", outvar); /* 14.9 time for factoring, part 1 */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->info->tfactor_t1; mxSetField(tinfos, 0, "tfactor_t1", outvar); /* 14.10 time for transposes */ outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)mywork->info->tfactor_t2; mxSetField(tinfos, 0, "tfactor_t2", outvar); #endif mxSetField(plhs[2], 0, "timing", tinfos); #endif /* 15. numerical error? */ if( (exitcode == ECOS_NUMERICS) || (exitcode == ECOS_OUTCONE) || (exitcode == ECOS_FATAL) ){ numerr = 1; } outvar = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(outvar) = (double)numerr; mxSetField(plhs[2], 0, "numerr", outvar); } /* s */ if( nlhs > 3 ){ plhs[3] = mxCreateDoubleMatrix(0, 0, mxREAL); mxSetPr(plhs[3], mywork->s); mxSetM(plhs[3], m); mxSetN(plhs[3], 1); } /* z */ if( nlhs > 4 ){ plhs[4] = mxCreateDoubleMatrix(0, 0, mxREAL); mxSetPr(plhs[4], mywork->z); mxSetM(plhs[4], m); mxSetN(plhs[4], 1); } /* cleanup */ ECOS_cleanup(mywork, nlhs > 2? nlhs-1 : nlhs); mxFree(qint); }