Example #1
0
MaxResults adjust_max_map(Model B, PoSition **Pos,  double *adj_map)

   /*=======================================================================*/
   /* FUNCTION NAME : adjust_max_map                                        */
   /*                                                                       */
   /* DESCRIPTION : Improves the maximal alignment by including motif       */
   /*               motif elements whose inclusion (whether it is forward   */
   /*               or reverse complement) improves upon the maximum        */
   /*               calculated map value                                    */
   /*=======================================================================*/
 
{
  double     map_fwd, map_rev, map_same;
  int        n, t, newpos; 
  MaxResults M; /** Have to set these -- will then be returned **/
  int        last_inc;
  double     dMax, dLocMax;
  double     **dProbArray;
  int        maxnum;
  ProbStruct P;		/* BT 2/21/97 */
  int        start, end;
  int        nSeq;
  int        typ;
  int        p;
  int        len;

  init_maxdata(&M);
  map_fwd = map_rev = map_same = (*adj_map);
  for( nSeq = 0; nSeq < B->IP->nNumSequences; nSeq += SeqInc( B, nSeq ) )
    {
      len = SequenceLength( B, nSeq ); 
      start = SequenceStartPos( B, nSeq );
      end = SequenceEndPos( B, nSeq );
      for(n = start; n <= end; n++) 
	{      
	  for(t = 0; t < B->IP->nNumMotifTypes; t++) 
	    {
	      if(((B->IP->is_defined[cl_E] && 
		   B->RP->nSites[nSeq] < B->RP->nMaxBlocks) || 
		  (! B->IP->is_defined[cl_E])) &&
		 PossibleStartPos( Pos, n, t, len, nSeq, B) &&
		 !OverlapsPrevMotif(n,B->IP->nNumMotifTypes,Pos) &&  
		 !Pos[t][n].nMotifStartPos) 
		{
		  newpos = -1;	/* BT 3/12/97 */
		  if( AnyOverlap(B, n, t, Pos, &newpos, &typ) )
		    {
		      for( p = 0; p < SeqInc( B, nSeq ); p++ )
			{
			  adjust_counts(B,DELETE,newpos + p * len, typ, Pos[typ][newpos + p * len].RevComp);
			  B->IP->nNumMotifs[typ][Pos[typ][newpos + p * len].RevComp]--;
			  B->RP->nSites[nSeq + p]--;
			  not_in_motif(Pos, newpos + p * len,B,typ);
			}
		    } 
		  
		  /* Calculate the map values for the current position */
		  /* being excluded (map_same), included as a forward  */
		  /* motif (map_fwd), or being included as a reverse   */
		  /* complement motif (map_rev).                       */
		  
		  map_same = CalcMapProb(B, B->IP->is_defined[cl_R]); 
		  
		  if( PossibleStartPos( Pos, n, t, len, nSeq, B) )
		    {		  
		      for( p = 0; p < SeqInc( B, nSeq ); p++ )
			{
			  adjust_counts(B, ADD, n + p * len,t,FALSE);
			  B->RP->nSites[nSeq+p]++;	      
			  B->IP->nNumMotifs[t][FORWARD]++;		/* BT 3/12/97 */
			}
		      map_fwd = CalcMapProb(B, B->IP->is_defined[cl_R]);	      
		      for( p = 0; p < SeqInc( B, nSeq ); p++ )
			{
			  adjust_counts(B, DELETE, n + p * len,t,FALSE);
			  B->RP->nSites[nSeq+p]--;
			  B->IP->nNumMotifs[t][FORWARD]--;		/* BT 3/12/97 */
			}
		      
		      if(B->IP->RevComplement) 
			{
			  for( p = 0; p < SeqInc( B, nSeq ); p++ )
			    {
			      adjust_counts(B, ADD, n + p * len, t,TRUE);
			      B->RP->nSites[nSeq+p]++;
			      B->IP->nNumMotifs[t][REVERSE]++;		/* BT 3/12/97 */
			    }
			  map_rev = CalcMapProb(B, B->IP->is_defined[cl_R]);
			  for( p = 0; p < SeqInc( B, nSeq ); p++ )
			    {
			      adjust_counts(B, DELETE, n + p * len, t, TRUE);
			      B->RP->nSites[nSeq+p]--;
			      B->IP->nNumMotifs[t][REVERSE]--;		/* BT 3/12/97 */
			    }
			}
		      
		      /* See if the forward map improves the maximal */
		      /* map calculated so far                       */
		      
		      if((map_fwd >= map_same)  && (map_fwd >= map_rev) &&
			 (map_fwd >= (*adj_map)))
			{
			  for( p = 0; p < SeqInc( B, nSeq ); p++ )
			    {
			      adjust_counts(B, ADD, n + p * len,t, FALSE);
			      B->RP->nSites[nSeq+p]++;
			      B->IP->nNumMotifs[t][FORWARD]++;
			      set_in_motif(Pos,n + p * len,B,t,FALSE);
			    }
			  (*adj_map) = map_fwd;
			  
			  /* as this segment in alignment, we need to check */
			  /* segments do not overlap with this segment */
			  n += (MotifWidth( B, t ) - 1);
			}		
		      
		      /* See if the reverse complement map improves */
		      /* the maximal map calculated so far          */
		      
		      else if(B->IP->RevComplement && 
			      (map_rev >= map_same) && (map_rev >= map_fwd) && 
			      (map_rev >= (*adj_map))) 
			{
			  for( p = 0; p < SeqInc( B, nSeq ); p++ )
			    {
			      adjust_counts(B, ADD, n + p * len,t, TRUE);
			      B->RP->nSites[nSeq+p]++;
			      B->IP->nNumMotifs[t][REVERSE]++;
			      set_in_motif(Pos,n + p * len,B,t,TRUE);
			    }
			  (*adj_map) = map_rev;
			  /* as this segment in alignment, we need to check */
			  /* segments do not overlap with this segment */
			  n += (MotifWidth( B, t ) - 1);
			}     		  
		      /* if we removed a motif and things did not improve when we */
		      /* added n, put the old motif back */
		      /* BT 3/12/97 */ 
		      else if( newpos >= 0 )
			{
			  for( p = 0; p < SeqInc( B, nSeq ); p++ )
			    {
			      adjust_counts(B, ADD,newpos + p * len,typ,Pos[typ][newpos + p * len].RevComp);
			      B->IP->nNumMotifs[typ][Pos[typ][newpos+p*len].RevComp]++;
			      set_in_motif(Pos,newpos + p*len,B,typ, Pos[typ][newpos+p*len].RevComp);
			      B->RP->nSites[nSeq+p]++;
			    }
			}           		
		      else if(Pos[t][n].nMotifStartPos) 
			/* as this segment in alignment, we need to check */
			/* segments do not overlap with this segment */
			n += (MotifWidth( B, t ) - 1);
		    }
		}
	    }
	}
    }
   
   maxnum = findMaxNumMotif(B->IP);
      
   init_prob( &P, B->IP );			/* BT 2/21/97 */
   update_prob( &P, B, TRUE  );
   update_posterior_prob(B);		/* BT 3/17/97 */

   dProbArray = setElementProb( B, Pos, P );

   M = setMaxData(B->F, B->IP, (*adj_map), 1, Pos, &last_inc, &dMax,
                  &dLocMax, M, dProbArray, B);
   FREEP(dProbArray, maxnum); 
   M.frequency = NULL; 

   free_prob( &P, B->IP );
    
   return M;
}
//Main Function
void mexFunction(int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[])
{
    //Input Args
    double *f, *blin = NULL, *lb = NULL, *ub = NULL, *y0 = NULL;
    
    //Return Args
    double *x, *pval, *dval, *exitflag, *iter, *pinf, *dinf, *realgap, *xzgap;
    
    //Options (most get defaults written in)
    int maxiter = 1500;  
    
    //Internal Vars
    size_t ndec = 0, nlincon = 0, lincon_nz = 0, total_dim = 0, ncones = 0; 
    size_t i, j;
    const char *onames[2] = {"pval","dval"};
    const char *fnames[5] = {"iter","pinf","dinf","realgap","xzgap"};    
    double evaltime;
    int status = -1, nb = 0, linoffset = 0, indlb = 1, indub = 1, nLB = 0, nUB = 0;
    mwIndex *jc;
    
    //CSDP Problem Data
    struct blockmatrix C;
    double *b, *y, *xx, objconstant = 0.0;
    struct constraintmatrix *constraints;
    struct blockmatrix X, Z;
    struct sparseblock *blockptr;
    struct paramstruc params;

    //Version Return
    if(nrhs < 1) {
        if(nlhs < 1)
            printSolverInfo();
        else
            plhs[0] = mxCreateString(CSDP_VERSION);
        return;
    }        
    
    //Check Inputs
    checkInputs(prhs,nrhs); 
    
    //Get pointers to Input variables
	f = mxGetPr(pF); ndec = mxGetNumberOfElements(pF);
    if(!mxIsEmpty(pA)) {
        blin = mxGetPr(pB);
        nlincon = mxGetM(pA);
        jc = mxGetJc(pA);
        lincon_nz = jc[ndec];        
    }
    if(nrhs > eLB && !mxIsEmpty(pLB)) {
        lb = mxGetPr(pLB); 
        //Ensure we have at least one finite bound
        for(i=0,j=0;i<ndec;i++)
            if(mxIsInf(lb[i]))
                j++;
        if(j==ndec)
            lb = NULL;
    }
    if(nrhs > eUB && !mxIsEmpty(pUB)) {
        ub = mxGetPr(pUB);
        //Ensure we have at least one finite bound
        for(i=0,j=0;i<ndec;i++)
            if(mxIsInf(ub[i]))
                j++;
        if(j==ndec)
            ub = NULL;
    }
    if(nrhs > eSDP && !mxIsEmpty(pSDP)) {
        if(mxIsCell(pSDP))
            ncones = mxGetNumberOfElements(pSDP);
        else
            ncones = 1;
    }
    if(nrhs > eY0 && !mxIsEmpty(pY0))
        y0 = mxGetPr(pY0);
    
    //Create Outputs
    plhs[0] = mxCreateDoubleMatrix(ndec,1, mxREAL);
    plhs[1] = mxCreateStructMatrix(1,1,2,onames);
    mxSetField(plhs[1],0,onames[0],mxCreateDoubleMatrix(1,1, mxREAL));
    mxSetField(plhs[1],0,onames[1],mxCreateDoubleMatrix(1,1, mxREAL));
    plhs[2] = mxCreateDoubleMatrix(1,1, mxREAL);   
    x = mxGetPr(plhs[0]); 
    pval = mxGetPr(mxGetField(plhs[1],0,onames[0]));
    dval = mxGetPr(mxGetField(plhs[1],0,onames[1]));
    exitflag = mxGetPr(plhs[2]);    
    //Info Output    
    plhs[3] = mxCreateStructMatrix(1,1,5,fnames);
    mxSetField(plhs[3],0,fnames[0],mxCreateDoubleMatrix(1,1, mxREAL));
    mxSetField(plhs[3],0,fnames[1],mxCreateDoubleMatrix(1,1, mxREAL));
    mxSetField(plhs[3],0,fnames[2],mxCreateDoubleMatrix(1,1, mxREAL));
    mxSetField(plhs[3],0,fnames[3],mxCreateDoubleMatrix(1,1, mxREAL));
    mxSetField(plhs[3],0,fnames[4],mxCreateDoubleMatrix(1,1, mxREAL));
    iter = mxGetPr(mxGetField(plhs[3],0,fnames[0]));
    pinf = mxGetPr(mxGetField(plhs[3],0,fnames[1]));
    dinf = mxGetPr(mxGetField(plhs[3],0,fnames[2]));
    realgap = mxGetPr(mxGetField(plhs[3],0,fnames[3]));
    xzgap = mxGetPr(mxGetField(plhs[3],0,fnames[4]));
    
    //Set Defaults
    citer = 0;
    maxtime = 1000;
    printLevel = 0;
    
    //Allocate Initial Storage for the Problem
    b = (double*)malloc((ndec+1)*sizeof(double));       //objective vector
    //C matrices [LB UB LIN SD]
    nb = (int)ncones+(int)(nlincon>0)+(int)(lb!=NULL)+(int)(ub!=NULL);
    #ifdef DEBUG
        mexPrintf("Number of blocks (including bounds, linear and sdcones): %d\n",nb);
    #endif            
    C.nblocks   = nb;
    C.blocks    = (struct blockrec*)malloc((nb+1)*sizeof(struct blockrec)); //+1 due to fortran index
    if(C.blocks == NULL)
        mexErrMsgTxt("Error allocating memory for C matrices");
    //Constraints (i.e. 1 per decision variable)
    constraints = (struct constraintmatrix*)malloc((ndec+1)*sizeof(struct constraintmatrix)); //+1 due to fortran index
    if(constraints == NULL) {
        free(C.blocks);
        mexErrMsgTxt("Error allocating memory for A matrices");
    }
    for(i=1;i<=ndec;i++)
        constraints[i].blocks=NULL; //initially set as NULL
    
    //Copy in and negate objective vector
    for(i=0;i<ndec;i++)
        b[i+1] = -f[i];
    
    //Create Bounds if Present
    if(lb || ub)
        linoffset += addBounds(C,lb,ub,ndec,&nLB,&nUB);
    
    //Create Linear Cone (diagonal) if present
    if(nlincon) {
        //Initialize C
        C.blocks[linoffset+1].blockcategory = DIAG;
        C.blocks[linoffset+1].blocksize = (int)nlincon;
        C.blocks[linoffset+1].data.vec = (double*)malloc((nlincon+1)*sizeof(double));
        if(C.blocks[linoffset+1].data.vec == NULL)
            mexErrMsgTxt("Error allocating memory for LP C diagonal");
        #ifdef DEBUG
            mexPrintf("LP C[%d] Vector size: %d\n",linoffset+1,nlincon);
        #endif        
        //Copy Elements
        for(i=0;i<nlincon;i++) {
            C.blocks[linoffset+1].data.vec[i+1] = -blin[i];
            #ifdef DEBUG
                mexPrintf("  C vec[%d] = %f\n",i+1,-blin[i]);
            #endif
        }
        linoffset++;
    }
    
    #ifdef DEBUG
        mexPrintf("\nBlock offset after bounds + linear con: %d\n\n",linoffset);
    #endif
    
    //Setup Semidefinite C matrices (note all full matrices, dense, in order from 1)
    for(i=1;i<=ncones;i++) {
        //Single Cone
        if(ncones == 1 && !mxIsCell(pSDP))
            total_dim += addCMatrix(C,pSDP,(int)i+linoffset);
        //Multiple Cones
        else 
            total_dim += addCMatrix(C,mxGetCell(pSDP,i-1),(int)i+linoffset);     
    }    
    //Add Linear Dims
    total_dim += nLB+nUB+nlincon;
    
    #ifdef DEBUG
        mexPrintf("\nTotal dimension of all cones: %d\n\n",total_dim);
    #endif
    
    //Setup Each Constraint (for each decision var) (in order from 1)
    indlb = 1; indub = 1;
    for(i=1;i<=ndec;i++) { 
        //For each Semidefinte A matrix (sparse triu, in reverse order, i.e. [SD, LP, UB, LB])
        for(j=ncones;j>0;j--) {
            //Create an A matrix            
            blockptr=(struct sparseblock*)malloc(sizeof(struct sparseblock));
            if(blockptr==NULL) {
                sprintf(msgbuf,"Error allocating memory for Semidefinite A[%d,%d]",i,j+linoffset);
                mexErrMsgTxt(msgbuf);
            }            
            //Single Cone
            if(ncones == 1 && !mxIsCell(pSDP)) 
                addAMatrix(blockptr,pSDP,(int)i,(int)j+linoffset); 
            //Multiple Cones
            else 
                addAMatrix(blockptr,mxGetCell(pSDP,j-1),(int)i,(int)j+linoffset);
            
            //Insert A matrix into constraint list
            blockptr->next=constraints[i].blocks;
            constraints[i].blocks=blockptr;
        }  
        
        //Linear Inequality Constraints
        if(nlincon) {
            //Create an A matrix
             blockptr=(struct sparseblock*)malloc(sizeof(struct sparseblock));
            if(blockptr==NULL) {
                sprintf(msgbuf,"Error allocating memory for LP A[%d]",i);
                mexErrMsgTxt(msgbuf);
            }
            //Insert LP A entries
            j = 1 + (int)(nUB > 0) + (int)(nLB > 0);
            insertLPVector(blockptr, pA, (int)i, (int)j);             
            //Insert A matrix into constraint list
            blockptr->next=constraints[i].blocks;
            constraints[i].blocks=blockptr;
        }
        
        //Upper Bounds
        if(nUB) {
            //Create an A matrix
            blockptr=(struct sparseblock*)malloc(sizeof(struct sparseblock));
            if(blockptr==NULL) {
                sprintf(msgbuf,"Error allocating memory for UB A[%d]",i);
                mexErrMsgTxt(msgbuf);
            }            
            //Insert Bound A matrix entries
            if(nLB > 0)
                indub += insertBound(blockptr,ub,nUB,(int)i,2,indub,1.0); //block 2 ([LB,UB,..] 1.0 for ub)
            else
                indub += insertBound(blockptr,ub,nUB,(int)i,1,indub,1.0); //block 1 (first block, 1.0 for ub)
            //Insert A matrix into constraint list
            blockptr->next=constraints[i].blocks;
            constraints[i].blocks=blockptr;
        }
        
        //Lower Bounds
        if(nLB) {
            //Create an A matrix
            blockptr=(struct sparseblock*)malloc(sizeof(struct sparseblock));
            if(blockptr==NULL) {
                sprintf(msgbuf,"Error allocating memory for LB A[%d]",i);
                mexErrMsgTxt(msgbuf);
            }            
            //Insert Bound A matrix entries
            indlb += insertBound(blockptr,lb,nLB,(int)i,1,indlb,-1.0); //block 1 (always first block, -1.0 for lb)
            //Insert A matrix into constraint list
            blockptr->next=constraints[i].blocks;
            constraints[i].blocks=blockptr;
        }
    }

//     //Set y0
//     if (y0)
//         for (i=0;i<ndec;i++) {
//             DSDP_ERR( DSDPSetY0(dsdp,(int)i+1,y0[i]), "Error setting Y0");            
//         }
//     
    
    //Get CSDP Default Options
    initparams(&params,&printLevel); 
    //Set OPTI default printLevel (none)
    printLevel = 0;
    
    //Get User Options (overwrites defaults above)
    if(nrhs > eOPTS && !mxIsEmpty(pOPTS)) {
        //OPTI Options
        GetIntegerOption(pOPTS,"maxiter",&params.maxiter);
        GetDoubleOption(pOPTS,"maxtime",&maxtime);
        GetIntegerOption(pOPTS,"display",&printLevel);
        GetDoubleOption(pOPTS,"objconstant",&objconstant);
        //CSDP Options
        GetDoubleOption(pOPTS,"axtol",&params.axtol);
        GetDoubleOption(pOPTS,"atytol",&params.atytol);
        GetDoubleOption(pOPTS,"objtol",&params.objtol);
        GetDoubleOption(pOPTS,"pinftol",&params.pinftol);
        GetDoubleOption(pOPTS,"dinftol",&params.dinftol);
        GetDoubleOption(pOPTS,"minstepfrac",&params.minstepfrac);
        GetDoubleOption(pOPTS,"maxstepfrac",&params.maxstepfrac);
        GetDoubleOption(pOPTS,"minstepp",&params.minstepp);
        GetDoubleOption(pOPTS,"minstepd",&params.minstepd);
        GetIntegerOption(pOPTS,"usexzgap",&params.usexzgap);
        GetIntegerOption(pOPTS,"tweakgap",&params.tweakgap); 
        GetIntegerOption(pOPTS,"affine",&params.affine);
        GetDoubleOption(pOPTS,"perturbobj",&params.perturbobj);
        //Optionally write problem to a SDPA sparse file
        if(mxGetField(pOPTS,0,"writeprob") && !mxIsEmpty(mxGetField(pOPTS,0,"writeprob")) && mxIsChar(mxGetField(pOPTS,0,"writeprob"))) {
            mxGetString(mxGetField(pOPTS,0,"writeprob"),msgbuf,1024);
            write_prob(msgbuf,(int)total_dim,(int)ndec,C,b,constraints);
        }
    }

    //Print Header
    if(printLevel) {
        mexPrintf("\n------------------------------------------------------------------\n");
        mexPrintf(" This is CSDP v%s\n",CSDP_VERSION); 
        mexPrintf(" Author: Brian Borchers\n MEX Interface J. Currie 2013\n\n");
        mexPrintf(" Problem Properties:\n");
        mexPrintf(" # Decision Variables:        %4d\n",ndec);   
        mexPrintf(" # Linear Inequalities:       %4d ",nlincon);
        if(nlincon)
            mexPrintf("[%d nz]\n",lincon_nz);
        else
            mexPrintf("\n");   
        mexPrintf(" # Semidefinite Cones:        %4d\n",ncones);

        mexPrintf("------------------------------------------------------------------\n");
    }
    
    //Start timer
    start = clock();
    //Find Initial Solution
    initsoln((int)total_dim,(int)ndec,C,b,constraints,&X,&y,&Z);
    //Solve the problem
    status=easy_sdp((int)total_dim,(int)ndec,C,b,constraints,objconstant,params,&X,&y,&Z,pval,dval,pinf,dinf,realgap,xzgap);
    //Stop Timer
    end = clock();
    evaltime = ((double)(end-start))/CLOCKS_PER_SEC;
    
    //Copy and negate solution
    for(i=0;i<ndec;i++)
        x[i] = -y[i+1];
    //Assign other MATLAB outputs
    *iter = (double)citer-1;    
    *exitflag = (double)status;
     
    //Print Header
    if(printLevel){            
        //Detail termination reason
        switch(status)
        {
            //Success
            case 0:	
                mexPrintf("\n *** CSDP CONVERGED ***\n");  break;
            //Infeasible
            case 1:
                mexPrintf("\n *** TERMINATION: Primal Infeasible ***\n");  break;
            case 2:
                mexPrintf("\n *** TERMINATION: Dual Infeasible ***\n");  break;
            //Partial Success
            case 3:
                mexPrintf("\n *** TERMINATION: PARTIAL SUCESS ***\n *** A Solution is found but full accuracy was not achieved ***\n"); break;
            //Error
            case 4:
                mexPrintf("\n *** TERMINATION: EARLY EXIT ***\n *** CAUSE: Maximum Iterations Reached ***\n"); break;
            case CSDP_MAX_TIME:
                mexPrintf("\n *** TERMINATION: EARLY EXIT ***\n *** CAUSE: Maximum Time Reached ***\n"); break;
            case 5:
                mexPrintf("\n *** TERMINATION: EARLY EXIT ***\n *** CAUSE: Stuck at edge of primal feasibility ***\n"); break;
            case 6:
                mexPrintf("\n *** TERMINATION: EARLY EXIT ***\n *** CAUSE: Stuck at edge of dual infeasibility ***\n"); break;
            case 7:
                mexPrintf("\n *** TERMINATION: EARLY EXIT ***\n *** CAUSE: Lack of progress ***\n"); break;
            case 8:
                mexPrintf("\n *** TERMINATION: EARLY EXIT ***\n *** CAUSE: X, Z, or O was singular ***\n"); break;
            case 9:
                mexPrintf("\n *** TERMINATION: EARLY EXIT ***\n *** CAUSE: Detected NaN or Inf values ***\n"); break;
            case 10:
                mexPrintf("\n *** TERMINATION: EARLY EXIT ***\n *** CAUSE: Easy-SDP General Failure ***\n"); break;
            case 11:
                mexPrintf("\n *** TERMINATION: EARLY EXIT ***\n *** CAUSE: Failed C Check - Check Symmetry! ***\n"); break;
            case 12:
                mexPrintf("\n *** TERMINATION: EARLY EXIT ***\n *** CAUSE: Failed Constraints Check ***\n"); break;
            case CSDP_USER_TERMINATION:
                mexPrintf("\n *** TERMINATION: EARLY EXIT ***\n *** CAUSE: User Exited ***\n"); break;            
            //Here is ok too?
            default:
                mexPrintf("\n *** CSDP FINISHED ***\n"); break;
        }

        if(status==0 || status==3)
        	mexPrintf("\n Final Primal Objective:  %2.5g\n Final Dual Objective:    %2.5g\n In %5d iterations\n    %5.2f seconds\n",*pval,*dval,citer-1,evaltime);

        mexPrintf("------------------------------------------------------------------\n\n");
    }  
    
    //Optionally write solution to a SDPA sparse file
    if(nrhs > eOPTS && !mxIsEmpty(pOPTS) && mxGetField(pOPTS,0,"writesol") && !mxIsEmpty(mxGetField(pOPTS,0,"writesol")) && mxIsChar(mxGetField(pOPTS,0,"writesol"))) {
        mxGetString(mxGetField(pOPTS,0,"writesol"),msgbuf,1024);
        write_sol(msgbuf,(int)total_dim,(int)ndec,X,y,Z);
    }
    
    //Optionally retrieve X
    if(nlhs > 4) {
        plhs[4] = mxCreateCellMatrix(X.nblocks,1);
        for(i=0;i<X.nblocks;i++) {            
            //Set Block Values
            if(X.blocks[i+1].blockcategory == DIAG) {
                mxSetCell(plhs[4],i,mxCreateDoubleMatrix(X.blocks[i+1].blocksize,1,mxREAL)); //create vector
                xx = mxGetPr(mxGetCell(plhs[4],i));
                for(j=0;j<X.blocks[i+1].blocksize;j++)
                    xx[j] = X.blocks[i+1].data.vec[j+1]; 
            }
            else {
                mxSetCell(plhs[4],i,mxCreateDoubleMatrix(X.blocks[i+1].blocksize,X.blocks[i+1].blocksize,mxREAL)); //create matrix
                xx = mxGetPr(mxGetCell(plhs[4],i));
                for(j=0;j<(X.blocks[i+1].blocksize*X.blocks[i+1].blocksize);j++)
                    xx[j] = X.blocks[i+1].data.mat[j];           
            }
        }        
    }

    //Free CSDP Problem (including all allocated memory)
    free_prob((int)total_dim,(int)ndec,C,b,constraints,X,y,Z);
}