/* ************************************************************ PROCEDURE spsub - Let z = x - y INPUT xir, xpr, xnnz - sparse vector yir, ypr, ynnz - sparse vector iwsize - ynnz+2 + floor(log_2(ynnz+1)) OUTPUT zir, zpr - length znnz arrays containing sparse output z = x - y. WORK iwork - length iwsize working array RETURNS znnz ************************************************************ */ int spsub(int *zir, double *zpr, const int *xir, const double *xpr, const int xnnz, const int *yir, const double *ypr, const int ynnz, int iwsize, char *cfound, int *iwork) { int inz,jnz,knz, i; int *yinx; /* ------------------------------------------------------------ Partition working array [yinx(ynnz+2), iwork(log_2(ynnz+1))]. ------------------------------------------------------------ */ yinx = iwork; iwork += ynnz + 2; iwsize -= ynnz + 2; intmbsearch(yinx, cfound, xir, xnnz, yir, ynnz, iwork, iwsize); jnz = yinx[1]; memcpy(zir, xir, jnz * sizeof(int)); memcpy(zpr, xpr, jnz * sizeof(double)); for(i = 0; i < ynnz; i++){ inz = yinx[i+1]; if(cfound[i]) zpr[jnz] = xpr[inz++] - ypr[i]; else zpr[jnz] = -ypr[i]; zir[jnz++] = yir[i]; knz = yinx[i+2]-inz; memcpy(zir + jnz, xir + inz, knz * sizeof(int)); memcpy(zpr + jnz, xpr + inz, knz * sizeof(double)); jnz += knz; } return jnz; }
/* ************************************************************ PROCEDURE spadd - Let z = x + y INPUT xir, xpr, xnnz - sparse vector yir, ypr, ynnz - sparse vector iwsize - ynnz+2 + floor(log_2(ynnz+1)) OUTPUT zir, zpr - length znnz arrays containing sparse output z = x + y. WORK iwork - length iwsize working array RETURNS znnz ************************************************************ */ mwIndex spadd2(mwIndex *zir, double *zpr, const mwIndex *xir, const double *xpr, const mwIndex xnnz, const mwIndex *yir, const double *ypr, const mwIndex ynnz, mwIndex iwsize, bool *cfound, mwIndex *iwork) { mwIndex inz,jnz,knz, i; mwIndex * yinx; /* ------------------------------------------------------------ Partition working array [yinx(ynnz+2), iwork(log_2(ynnz+1))]. ------------------------------------------------------------ */ yinx = iwork; iwork += ynnz + 2; iwsize -= ynnz + 2; intmbsearch(yinx, cfound, xir, xnnz, yir, ynnz, iwork, iwsize); jnz = yinx[1]; memcpy(zir, xir, jnz * sizeof(mwIndex)); memcpy(zpr, xpr, jnz * sizeof(double)); for(i = 0; i < ynnz; i++){ inz = yinx[i+1]; if(cfound[i]) zpr[jnz] = xpr[inz++] + ypr[i]; else zpr[jnz] = ypr[i]; zir[jnz++] = yir[i]; knz = yinx[i+2]-inz; memcpy(zir + jnz, xir + inz, knz * sizeof(mwIndex)); memcpy(zpr + jnz, xpr + inz, knz * sizeof(double)); jnz += knz; } return jnz; }
/* ************************************************************ PROCEDURE smakereal INPUT xir,xpr,xpi - sparse vector with xnnz nonzeros, in PSD ONLY!. xnnz - length of xir,xpr,xpi (PSD only). idelta - subscript adjustment of 1st PSD entry cpxsi - length twons increasing integer array. The old subscripts of the kth Hermitian block in x are cpxsi[2*k]:cpxsi[2*k+1]-1. twons - twons/2 is number of Hermitian PSD blocks. lenfull - length of full(x)-vector, 1 beyond last possible subscript. iwsize Length of iwork, should be 2*(1+ns) + floor(log_2(1+2*ns)). 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+2*ns + floor(log_2(1+2*ns)). RETURNS ynnz (<=2*xnnz), number of nonzeros in y. ************************************************************ */ mwIndex smakereal(mwIndex *yir, double *ypr, const mwIndex *xir, const double *xpr, const double *xpi, const mwIndex xnnz, const mwIndex idelta, const mwIndex *cpxsi, const mwIndex twons, const mwIndex lenfull, bool *cfound, mwIndex *iwork, mwIndex iwsize) { mwIndex i,j,k,inz,jnz; mwIndex *ipos; /* ------------------------------------------------------------ Partition WORKING ARRAY: ------------------------------------------------------------ */ ipos = iwork; /* length 2*(1+ns) array */ iwork += 2 + twons; iwsize -= 2 + twons; /* ------------------------------------------------------------ Locate cpxsi in x(jcs:end); these mark the start+ends of Hermitian blocks, and hence the complement are real blocks. ------------------------------------------------------------ */ if(intmbsearch(ipos, cfound, xir, xnnz, cpxsi, twons, iwork, iwsize) != 0) mexErrMsgTxt("Out of working space"); /* ------------------------------------------------------------ Write real PSD blocks into y, i.e. skip Hermitian blocks ------------------------------------------------------------ */ memcpy(ypr, xpr, ipos[1] * sizeof(double)); if(idelta != 0) intscalaradd(yir, idelta, xir, ipos[1]); else memcpy(yir, xir, ipos[1] * sizeof(mwIndex)); jnz = ipos[1]; j = idelta; /* subscript adjustment */ for(i = 0; i < twons; ){ j -= cpxsi[i+1] - cpxsi[i]; /* skip complex block */ i += 2; inz = ipos[i]; k = ipos[i + 1] - inz; memcpy(ypr + jnz, xpr + inz, k * sizeof(double)); intscalaradd(yir+jnz, j, xir+inz, k); jnz += k; } /* ------------------------------------------------------------ Write Hermitian PSD blocks into y ------------------------------------------------------------ */ j += lenfull; /* j points to 1st available index for Hermitian blocks */ for(i = 0; i < twons; i += 2){ k = cpxsi[i]; /* Old 1st index of Herm PSD block */ /* ---------- write real part ---------- */ writenz(yir, ypr, &jnz, xir, xpr, ipos[i+1],ipos[i+2],j-k); j += cpxsi[i+1] - k; /* point to 1st available index */ /* ---------- write imag part ---------- */ if(xpi != (double *) NULL) writenz(yir, ypr, &jnz, xir, xpi, ipos[i+1],ipos[i+2],j-k); j += cpxsi[i+1] - k; /* point to 1st available index */ } /* ------------------------------------------------------------ RETURN number of nonzeros written into y ------------------------------------------------------------ */ return jnz; }
/* ************************************************************ PROCEDURE findblks INPUT Ajc1, Ajc2, Air, m - sparse N x m matrix, we only consider nonzeros in Air[Ajc1[k]:Ajc2[k]-1], k=0:m-1. blkstart, nblk - length nblk integer array of subscripts. blkstartm1 - length nblk array, blkstartm1[k]=blkstart[k]-1 iwsize - length of iwork, iwsize = nblk+2+floor(log(1+nblk)/log(2)). OUTPUT Ablkjc, Ablkir - sparse nblk x m matrix, less than sum(Ajc2-Ajc1) nonzeros. WORK cfound - length nblk char work array iwork - length iwsize = nblk+2+floor(log(1+nblk)/log(2)) work array. ************************************************************ */ void findblks(mwIndex *Ablkir, mwIndex *Ablkjc, const mwIndex *Ajc1,const mwIndex *Ajc2, const mwIndex *Air, const mwIndex *blkstart, const mwIndex *blkstartm1, const mwIndex m,const mwIndex nblk, mwIndex iwsize, bool *cfound, mwIndex *iwork) { mwIndex i,j,inz,ajnnz; mwIndex *ipos; /* ------------------------------------------------------------ Partition working array into ipos(nblk+2), iwork. ------------------------------------------------------------ */ ipos = iwork; iwork += nblk+2; iwsize -= nblk+2; inz = 0; for(j = 0; j < m; j++){ Ablkjc[j] = inz; /* ------------------------------------------------------------ If A(:,j) has more nonzeros than blkstart, we search blkstart ------------------------------------------------------------ */ if((ajnnz = Ajc2[j]-Ajc1[j]) > nblk){ intmbsearch(ipos, cfound, Air+Ajc1[j], ajnnz, blkstart, nblk, iwork, iwsize); for(i = 0; i < nblk; i++) if(ipos[i+2] > ipos[i+1]) Ablkir[inz++] = i; } else{ /* ------------------------------------------------------------ If A(:,j) has less nonzeros than blkstart, we search those nonzeros within blkstartm1. The position of the nonzero is then the block number+1. ------------------------------------------------------------ */ intmbsearch(ipos, cfound, blkstartm1,nblk, Air+Ajc1[j],ajnnz, iwork, iwsize); for(i = 0; i < ajnnz; i++) if(ipos[i+1] > ipos[i]) /* New block number ? */ Ablkir[inz++] = ipos[i+1] - 1; /* ipos is block number + 1 */ } } /* ------------------------------------------------------------ Close last column of Ablk ------------------------------------------------------------ */ Ablkjc[m] = inz; }
/* ************************************************************ PROCEDURE partitA INPUT Ajc, Air, m - sparse N x m matrix blkstart, nblk - length nblk integer array of subscripts. iwsize - length of iwork, iwsize = floor(log(1+nblk)/log(2)). OUTPUT Ablkjc - length (nblk+2)*m array. Rows 1+(1:nblk) list 1st nonzero with subscript at or beyond blkstart. WORK cfound - length nblk char work array iwork - length iwsize = floor(log(1+nblk)/log(2)) work array. ************************************************************ */ void partitA(int *Ablkjc, const int *Ajc,const int *Air, const int *blkstart, const int m,const int nblk, const int iwsize, char *cfound, int *iwork) { int j, L; L = nblk+2; for(j = 0; j < m; j++) intmbsearch(Ablkjc + j*L, cfound, Air+Ajc[j], Ajc[j+1]-Ajc[j], blkstart, nblk, iwork, iwsize); for(j = 0; j < m; j++) intadd(Ablkjc + j*L, Ajc[j],L); }
/* ************************************************************ PROCEDURE partitA INPUT Ajc, Air, m - sparse N x m matrix blkstart, nblk - length nblk integer array of subscripts. iwsize - length of iwork, iwsize = floor(log(1+nblk)/log(2)). OUTPUT Ablkjc - length (nblk+1)*m array. Rows 1+(1:nblk) list 1st nonzero with subscript at or beyond blkstart. WORK cfound - length nblk char work array iwork - length iwsize = floor(log(1+nblk)/log(2)) work array. ************************************************************ */ void partitA(mwIndex *Ablkjc, const mwIndex *Ajc,const mwIndex *Air, const mwIndex *blkstart, const mwIndex m,const mwIndex nblk, const mwIndex iwsize, bool *cfound, mwIndex *iwork) { mwIndex j, L; L = nblk+2; for(j = 0; j < m; j++) intmbsearch(Ablkjc + j*L, cfound, Air+Ajc[j], Ajc[j+1]-Ajc[j], blkstart, nblk, iwork, iwsize); for(j = 0; j < m; j++) intadd(Ablkjc + j*L, Ajc[j],L); }
/* ************************************************************ PROCEDURE fmakereal INPUT xir,xpi - sparse imaginary vector with xnnz "nonzeros" in LP/Lorentz. If xpi == NULL, then all imaginary data is zero. xnnz - length of xir,xpi, before PSD part. cpxf - length nf integer array, listing free imaginary vars. nf - length of cpxf iwsize Length of iwork, should be 2+nf + floor(log_2(1+nf)). 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+nf + floor(log_2(1+nf)). RETURNS ynnz (<=2*xnnz), number of free imag nonzeros in y. ************************************************************ */ mwIndex fmakereal(mwIndex *yir, double *ypr, const mwIndex *xir, const double *xpi, const mwIndex xnnz, const mwIndex *cpxf, const mwIndex nf, bool *cfound, mwIndex *iwork, mwIndex iwsize) { mwIndex i,jnz; mwIndex *ipos; double yj; if(xpi == (double *) NULL) return 0; /* No imaginary nonzeros */ /* ------------------------------------------------------------ Partition WORKING ARRAY: ------------------------------------------------------------ */ ipos = iwork; iwork += 2 + nf; iwsize -= 2 + nf; /* ------------------------------------------------------------ Locate cpx.f in xir(1:xnnz) ------------------------------------------------------------ */ if(intmbsearch(ipos, cfound, xir, xnnz, cpxf, nf, iwork, iwsize) != 0) mexErrMsgTxt("Out of working space"); /* ------------------------------------------------------------ Write y = sparse(imag(x(cpx.f))), the free imaginary components ------------------------------------------------------------ */ jnz = 0; for(i = 0; i < nf; i++) if(cfound[i] != 0){ if( (yj = xpi[ipos[i+1]]) != 0.0){ ypr[jnz] = yj; yir[jnz] = i; jnz++; } } /* ------------------------------------------------------------ RETURN number of (free imag) nonzeros in y ------------------------------------------------------------ */ return jnz; }
/* ************************************************************ PROCEDURE xmakereal INPUT xir,xpr,xpi - sparse vector with xnnz nonzeros in LP/Lor. xnnz - length of xir,xpr,xpi; counting only LP/Lor nonzeros. idelta - Subscript adjustment for x(1), i.e. nf. cpxx - length nx integer array, listing Lorentz constrained imaginary vars. nx - length of cpxx. iwsize Length of iwork, should be 2+nx + floor(log_2(1+nx)). OUTPUT yir, ypr - sparse real output vector, ynnz nonzeros. WORK ARRAYS cfound - length nx character working array. iwork - lengt iwsize working array. Needs iwsize >= 2+nx + floor(log_2(1+nx)). RETURNS ynnz (<=2*xnnz), number of nonzeros in y. ************************************************************ */ mwIndex xmakereal(mwIndex *yir, double *ypr, const mwIndex *xir, const double *xpr, const double *xpi, const mwIndex xnnz, const mwIndex idelta, const mwIndex *cpxx, const mwIndex nx, bool *cfound, mwIndex *iwork, mwIndex iwsize) { mwIndex i,j,k,inz,jnz; mwIndex *ipos; double yj; /* ------------------------------------------------------------ Partition WORKING ARRAY: ------------------------------------------------------------ */ ipos = iwork; iwork += 2 + nx; iwsize -= 2 + nx; /* ------------------------------------------------------------ Locate cpx.x in xir(1:xnnz) ------------------------------------------------------------ */ if(intmbsearch(ipos, cfound, xir, xnnz, cpxx, nx, iwork, iwsize) != 0) mexErrMsgTxt("Out of working space"); /* ------------------------------------------------------------ Write y(nf:nf+dimflqr+nx) = merge( real(x), imag(x(cpx.xcomplex)) ) ------------------------------------------------------------ */ memcpy(ypr, xpr, ipos[1] * sizeof(double)); if(idelta != 0) intscalaradd(yir, idelta, xir, ipos[1]); else memcpy(yir, xir, ipos[1] * sizeof(mwIndex)); jnz = ipos[1]; for(i = 0; i < nx; ){ if(cfound[i++]){ inz = ipos[i]; j = xir[inz] + idelta + i; /* new index of imag part */ if((yj = xpr[inz]) != 0.0){ ypr[jnz] = yj; yir[jnz] = j-1; /* index of real part */ jnz++; } if(xpi != (double *) NULL) if((yj = xpi[inz]) != 0.0){ ypr[jnz] = yj; yir[jnz] = j; /* imag part */ jnz++; } inz++; /* point to first nonzero in x beyond cpx.x(i) */ } else inz = ipos[i]; /* point to first nonzero in x beyond cpx.x(i) */ /* ------------------------------------------------------------ Let y(nf+i+(cpx.x(i)+1:cpx.x(i+1)-1)) = real(x(cpx.x(i)+1:cpx.x(i+1)-1)) If i==nx, then this is simply the remainder. ------------------------------------------------------------ */ k = ipos[i+1] - inz; /* number of nonzeros to copy */ memcpy(ypr + jnz, xpr + inz, k * sizeof(double)); intscalaradd(yir+jnz, idelta + i, xir+inz, k); /* adjust subscript */ jnz += k; } /* ------------------------------------------------------------ RETURN number of nonzeros written into y ------------------------------------------------------------ */ return jnz; }