예제 #1
0
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;
}
예제 #2
0
파일: ecosmodule.Cpp 프로젝트: anqif/ecos-r
    /* 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);
}

예제 #3
0
파일: runecos.c 프로젝트: echu/ecos
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;
}
예제 #5
0
파일: ecos_bb.c 프로젝트: aeternocap/ecos
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;
    }
}
예제 #6
0
파일: ecos_mex.c 프로젝트: echu/ecos
/* 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);
}