/* ************************************************************ PROCEDURE getfirstpiv - Find first affecting pivot on column j = 1:n. These column numbers are in NON-PIVOTED ORDER, i.e. the order in which they appear in Xjc. INPUT invperm - length n array, yields position in list of nonzeros "dzir". xsuper - length n (though it may have n+1) array, partitioning of permuted subscripts, is "dzjc". Xjc - length n+1 array Xir - length Xjc[n] array n - number of columns in X. OUTPUT firstpiv - length n array ************************************************************ */ void getfirstpiv(mwIndex *firstpiv, const mwIndex *invperm, const mwIndex *xsuper, const mwIndex *Xjc, const mwIndex *Xir, const mwIndex n) { mwIndex i,j,inz,firstj; inz = Xjc[0]; /* typically inz = 0*/ for(j = 0; j < n; j++){ /* ------------------------------------------------------------ Let firstj = min(invperm(find(X(:,j)))) ------------------------------------------------------------ */ if(inz < Xjc[j+1]){ firstj = invperm[Xir[inz]]; for(++inz; inz < Xjc[j+1]; inz++) if((i = invperm[Xir[inz]]) < firstj) firstj = i; /* ------------------------------------------------------------ First node covering firstj, i.e. xsuper[y] < firstj+1 <= xsuper[y+1], with y denoting firstpiv[j]. ------------------------------------------------------------ */ firstpiv[j] = 0; /* search from start */ intbsearch(firstpiv+j,xsuper+1,n-1,firstj+1); } else firstpiv[j] = n; /* if all-0 then no affecting pivot */ } }
/* ************************************************************ PROCEDURE makereal INPUT xir,xpr,xpi - sparse vector with xnnz nonzeros. xnnz - length of xir,xpr,xpi. cpxf - length nf integer array, listing free imaginary vars. nf - length of cpxf cpxx - length nx integer array, listing Lorentz constrained imaginary vars. nx - length of cpxx. cpxsi - length 2*ns increasing integer array. The old subscripts of the kth Hermitian block in x are cpxsi[2*k]:cpxsi[2*k+1]-1. ns - number of Hermitian PSD blocks. lenfull - length of full(x)-vector, 1 beyond last possible subscript. iwsize Length of iwork, should be 2 + MAXN + floor(log_2(1+MAXN)). lenfull - dimension of x. dimflqr - dimension of f/l/q/r part in x, i.e. 1st valid PSD subscript. OUTPUT yir, ypr - sparse real output vector, ynnz nonzeros. WORK ARRAYS cfound - length MAXN := MAX(nf,nx,2*ns) character working array. iwork - lengt iwsize working array. Needs iwsize >= 2 + MAXN + floor(log_2(1+MAXN)). RETURNS ynnz (<=2*xnnz), number of nonzeros in y. ************************************************************ */ mwIndex makereal(mwIndex *yir, double *ypr, const mwIndex *xir, const double *xpr, const double *xpi, const mwIndex xnnz, const mwIndex *cpxf, const mwIndex nf, const mwIndex *cpxx, const mwIndex nx, const mwIndex *cpxsi, const mwIndex ns, const mwIndex lenfull, const mwIndex dimflqr, bool *cfound, mwIndex *iwork, mwIndex iwsize) { mwIndex jcs, jnz; /* ------------------------------------------------------------ Find position of 1st PSD nonzero ------------------------------------------------------------ */ jcs = 0; intbsearch(&jcs, xir, xnnz, dimflqr); /* ------------------------------------------------------------ Write free imaginary nonzeros into y ------------------------------------------------------------ */ jnz = fmakereal(yir,ypr, xir,xpi,jcs, cpxf,nf, cfound,iwork,iwsize); /* ------------------------------------------------------------ Write LP/Lorentz nonzeros into y, make Lorentz bounded imag nonzeros explicit reals. ------------------------------------------------------------ */ jnz += xmakereal(yir+jnz,ypr+jnz, xir,xpr,xpi,jcs, nf, cpxx,nx, cfound,iwork,iwsize); /* ------------------------------------------------------------ Write PSD nonzeros into y. First the real blocks, then Hermitian. ------------------------------------------------------------ */ if(xpi != (double *) NULL) xpi += jcs; /* point to 1st imag PSD nonzero */ jnz += smakereal(yir+jnz, ypr+jnz, xir+jcs,xpr+jcs,xpi,xnnz-jcs, nf+nx, cpxsi,2*ns, lenfull, cfound,iwork,iwsize); /* ------------------------------------------------------------ Return number of nonzeros in y ------------------------------------------------------------ */ return jnz; }
/* ************************************************************ PROCEDURE vectril - Applies sptotril(xk) for each PSD block k. On output, each PSD block is lower triangular, i.e. Zk = tril(Xk+Xk')/2. INPUT xir,xpr,xnnz psdNL - K.s blkstart - length psdN+1 array. PSD block k has subscripts blkstart[k]:blkstart[k+1]-1. isblk - length psdDim array, with k = xblk(i-blkstart[0]) iff blkstart[k] <= i < blkstart[k+1], k=0:psdN-1. rpsdN - number of real PSD blocks psdN - number of PSD blocks iwsize - maxn*(2*maxn+1)+log_2(1+maxn*(maxn-1)/2), where maxn := max(K.s). OUTPUT zir - length znnz <= xnnz int array: subscripts of z = vectril(x). zpr - length znnz <= xnnz vector: nonzeros of z = vectril(x). WORKING ARRAYS cwork - length maxn*(maxn-1)/2 char array, where maxn := max(K.s). iwork - length iwsize integer working array fwork - length max(K.s.^2) vector. (Note: not double for Hermitian blocks, since we treat real and imag parts seperately.) RETURNS znnz ************************************************************ */ int vectril(int *zir, double *zpr, const int *xir, const double *xpr, const int xnnz, const int *psdNL, const int *blkstart, const int *isblk, const int rpsdN, const int psdN, const int iwsize, char *cwork, int *iwork, double *fwork) { int inz, jnz, k, nk; /* ------------------------------------------------------------ Copy f,l,q,r parts without change. Let inz point to first PSD-nonzero in x, jnz in z. ------------------------------------------------------------ */ inz = 0; /* pointer into x */ intbsearch(&inz, xir, xnnz, blkstart[0]); /* inz points to start PSD */ isblk -= blkstart[0]; memcpy(zir, xir, inz * sizeof(int)); memcpy(zpr, xpr, inz * sizeof(double)); jnz = inz; /* jnz points to start PSD in z */ /* ------------------------------------------------------------ Process all PSD blocks ------------------------------------------------------------ */ while(inz < xnnz){ k = isblk[xir[inz]]; nk = psdNL[k]; jnz += sptotril(zir + jnz, zpr + jnz, xir, xpr, &inz, xnnz, blkstart[k], nk,0, iwsize, cwork, iwork, fwork); /* ------------------------------------------------------------ For the imaginary part, we do a skew transpose: tril(IM Xk)-triu(IM Xk)'. This will make the diagonal of the imaginary block zero. ------------------------------------------------------------ */ if(k >= rpsdN){ jnz += sptotril(zir + jnz, zpr + jnz, xir, xpr, &inz, xnnz, blkstart[k]+SQR(nk), nk,1, iwsize, cwork, iwork, fwork); } } return jnz; }