Page MenuHomec4science

getada3.c
No OneTemporary

File Metadata

Created
Sun, Jul 13, 18:33

getada3.c

/* ************************************************************
% [ADA,absd] = getada3(ADA, A,Ajc1,Aord, udsqr,K)
% GETADA3 Compute ADA(i,j) = (D(d^2)*A.t(:,i))' *A.t(:,j),
% and exploit sparsity as much as possible.
% absd - length m output vector, containing
% absd(i) = abs((D(d^2)*A.t(:,i))' *abs(A.t(:,i)).
% Hence, diag(ADA)./absd gives a measure of cancelation (in [0,1]).
%
% SEE ALSO sedumi, getada1, getada2
% ******************** INTERNAL FUNCTION OF SEDUMI ********************
function [ADA,absd] = getada3(ADA, A,Ajc1,Aord, udsqr,K)
% This file is part of SeDuMi 1.1 by Imre Polik and Oleksandr Romanko
% Copyright (C) 2005 McMaster University, Hamilton, CANADA (since 1.1)
%
% Copyright (C) 2001 Jos F. Sturm (up to 1.05R5)
% Dept. Econometrics & O.R., Tilburg University, the Netherlands.
% Supported by the Netherlands Organization for Scientific Research (NWO).
%
% Affiliation SeDuMi 1.03 and 1.04Beta (2000):
% Dept. Quantitative Economics, Maastricht University, the Netherlands.
%
% Affiliations up to SeDuMi 1.02 (AUG1998):
% CRL, McMaster University, Canada.
% Supported by the Netherlands Organization for Scientific Research (NWO).
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
% 02110-1301, USA
************************************************************ */
#include <string.h>
#include <math.h>
#include "mex.h"
#include "blksdp.h"
#define ADA_OUT myplhs[0]
#define ABSD_OUT myplhs[1]
#define NPAROUT 2
#define ADA_IN prhs[0] /* sparsity struct ADA */
#define AT_IN prhs[1] /* N x m sparse At */
#define AJC1_IN prhs[2] /* start of PSD blocks in At */
#define AORD_IN prhs[3]
#define UDSQR_IN prhs[4] /* Scale data */
#define K_IN prhs[5]
#define NPARIN 6
/* ========================= G E N E R A L ========================= */
void spzeros(double *x,const mwIndex *xir,const mwIndex n)
{
mwIndex i;
for(i = 0; i < n; i++)
x[xir[i]] = 0.0;
}
/* ************************************************************
PROCEDURE exmerge - mergeing 2 exclusive, increasing integer arrays.
INPUT
x - length nx array, increasing entries.
y - length ny array, its entries are increasing, and do not occur in x.
nx,ny - order of x and y.
OUTPUT
z - length nx+ny vector
WORK
cwork - length ny
iwork - length ny+2+floor(log_2(1+ny)).
************************************************************ */
void exmerge(mwIndex *x, const mwIndex *y, const mwIndex nx, const mwIndex ny,
const mwIndex iwsize, bool *cwork, mwIndex *ipos)
{
mwIndex i,j,inz;
/* ------------------------------------------------------------
Search all "insertion" positions of y-entries in list x
------------------------------------------------------------ */
intmbsearch(ipos,cwork, x,nx,y,ny, ipos+ny+2,iwsize-(ny+2));
/* ------------------------------------------------------------
Shift x-entries down to make room for y-entries
------------------------------------------------------------ */
for(i = ny; i > 0; i--){ /* shift i entries down */
inz = ipos[i];
if((j = ipos[i+1]-inz) > 0)
memmove(x+inz+i,x+inz,j*sizeof(mwIndex));
}
/* ------------------------------------------------------------
Insert y-entries
------------------------------------------------------------ */
++ipos;
for(i = 0; i < ny; i++)
x[ipos[i]+i] = y[i]; /* add i, number prev. inserted y's */
#ifndef NDEBUG
for(i = 1; i < nx+ny; i++)
mxAssert(x[i] > x[i-1],"");
#endif
}
/* ************************************************************
PROCEDURE cpspdiag -- Let d := diag(X), where X is sparse m x m.
INPUT
m - number of columns in ada
x - contains COMPLETE SYMMETRIC sparsity structure,
OUTPUT
d - length m vector, diag(X).
************************************************************ */
void cpspdiag(double *d, const jcir x, const mwIndex m)
{
mwIndex j, inz;
const mwIndex *diagFound;
/* ------------------------------------------------------------
For each column j: let dj = x(j,j)
------------------------------------------------------------ */
for(j = 0; j < m; j++){
if((diagFound = ibsearch(&j,x.ir+x.jc[j],x.jc[j+1]-x.jc[j])) != NULL){
inz = diagFound - x.ir; /* convert pointer to index */
d[j] = x.pr[inz]; /* diag entry found */
}
else
d[j] = 0.0; /* no diag entry -> d[j] = 0.0 */
}
}
/* ************************************************************
PROCEDURE spmakesym -- Let X := X+X'-diag(diag(X)), with X a
real sparse square matrix.
INPUT
m - number of columns in ada
UPDATED
x - on input, contains COMPLETE SYMMETRIC sparsity structure,
and the values (possibly 0's on some locations). On return,
X = X+X'-diag(diag(X)), i.e. X is symmetrized, and the off-
diagonal entries are "DUPLICATED" (allowing part in xij and xji).
WORK
iwork - length m array of integers. Points to "below row j"
part of columns (trilstart). (initial contents irrelevant)
************************************************************ */
void spmakesym(jcir x, const mwIndex m, mwIndex *iwork)
{
mwIndex i, j, inz, jend;
double xij;
/* ------------------------------------------------------------
Initialize: let iwork(0:m-1) = ada.jc(0:m-1)
------------------------------------------------------------ */
memcpy(iwork, x.jc, m * sizeof(mwIndex)); /* don't copy x.jc[m] */
/* ------------------------------------------------------------
For each column j: for each index i > j:
let xij = x(i,j) + x(j,i).
Let iwork point to next nonzero in col i
Guard: x.ir[iwork(i)] >= j for all i >= j.
------------------------------------------------------------ */
for(j = 0; j < m; j++){
jend = x.jc[j+1]; /* Let [inz,jend) be tril(:,j) */
inz = iwork[j];
if(inz < jend){
if(x.ir[inz] == j) /* skip diagonal entry */
inz++;
while(inz < jend){ /* off-diagonal entries */
i = x.ir[inz];
xij = x.pr[iwork[i]] + x.pr[inz]; /* xji + xij */
x.pr[iwork[i]++] = xij;
x.pr[inz++] = xij;
}
}
}
}
/* ************************************************************
PROCEDURE dzblkpartit
INPUT
dzir - length dznnz array, NOT sorted
xblk - length max(dzir) array, xblk(dzir) maps into 0:nblk-1.
dznnz - order of dzir
nblk - 1+max(xblk), number of blocks
OUTPUT
dzjc - length nblk+1 array. Has blockstarts so that all subscripts
in dzir fit in the resulting partition.
************************************************************ */
void dzblkpartit(mwIndex *dzjc, const mwIndex *dzir, const mwIndex *xblk,
const mwIndex dznnz, const mwIndex nblk)
{
mwIndex i,j;
/* ------------------------------------------------------------
Init dzjc = all-0
------------------------------------------------------------ */
for(i = 0; i <= nblk; i++)
dzjc[i] = 0;
/* ------------------------------------------------------------
Pre-partition dzir(dznnz) space into blocks
------------------------------------------------------------ */
++dzjc;
for(i = 0; i < dznnz; i++)
dzjc[xblk[dzir[i]]]++; /* accumulate nnz */
j = 0;
for(i = 0; i < nblk; i++){ /* cumsum */
j += dzjc[i];
dzjc[i] = j;
}
mxAssert(dzjc[nblk-1] == dznnz,"");
}
/* ************************************************************
PROCEDURE: getada3
INPUT
ada.{jc,ir} - sparsity structure of ada.
At - sparse N x m matrix.
udsqr - lenud vector containing D, D(ud.perm,ud.perm) = Ud'*Ud.
Ajc1 - m mwIndex array, Ajc1(:,1) points to start of PSD nz's in At.
dzjc - psdN+1, partition of dz rowsubscipts into PSD blocks.
dzstructjc, dzstructir - sparse N x m matrix, giving NEW PSD-nonzero
positions of At(:,perm(j)).
blkstart - length(K.s): starting indices of PSD blocks
xblk - length psdDim array, with k = xblk(i-blkstart[0]) iff
blkstart[k] <= i < blkstart[k+1], k=0:nblk-1.
psdDim:=blkstart[end]-blkstart[0].
psdNL - K.s in integer
perm, invperm - length(m) array, ordering in which ADA should be computed,
and its inverse. We compute in order triu(ADA(perm,perm)), but store
at original places. OPTIMAL order: start with sparsest dzstruct.
m - order of ADA, number of constraints.
lenud - blkstart[end] - blkstart[0], PSD dimension.
pcK - pointer to cone K structure.
rpsdN - sum(K.s(i) | i is real sym PSD block).
UPDATED
ada.pr - ada(i,j) += ai'*D(d^2; PSD)*aj. PSD-part. Only entries
in triu(ADA(perm,perm) are affected.
OUTPUT
absd - length(m) vector, contains abs(aj)'*abs(D(d^2)*aj).
WORKING ARRAYS
fwork - work vector, size
fwsiz = lenud + 2 * max(rMaxn^2, 2*hMaxn^2).
iwork - integer work array, size
iwsiz = 2*psdN + dznnz + max(srchsize, max(nk(PSD))).
where dznnz = dzstructjc[m] and
srchsize = 2+maxadd+floor(log(1+maxadd))
cwork - maxadd, where maxadd = max(dzstructjc(i+1)-dzstructjc(i))
************************************************************ */
void getada3(jcir ada, double *absd, jcir At, const double *udsqr,
const mwIndex *Ajc1, const mwIndex *dzjc,
const mwIndex *dzstructjc, const mwIndex *dzstructir,
const mwIndex *blkstart, const mwIndex *xblk, const mwIndex *psdNL,
const mwIndex *perm, const mwIndex *invperm,
const mwIndex m, const mwIndex lenud, const coneK *pcK,
double *fwork, mwIndex fwsiz, mwIndex *iwork, mwIndex iwsiz,
bool *cwork)
{
mwIndex i,j,k, knz,inz, dznnz, permj, rsdpN, nblk, nnzbj;
double *daj;
double adaij, termj, absadajj;
mwIndex *dzknnz, *dzir, *blksj;
rsdpN = pcK->rsdpN;
/* ------------------------------------------------------------
Partition working arrays
mwIndex: dzknnz(psdN=length(K.s)), blksj(psdN), dzir(dznnz = dzstructjc[m]),
iwork[iwsiz],
with iwsiz = max(dznnz, max(nk(PSD))).
double: daj(lenud), fwork[fwsiz],
with fwsiz = 2 * max(rMaxn^2, 2*hMaxn^2).
------------------------------------------------------------ */
nblk = pcK->sdpN;
dznnz = dzstructjc[m];
if(dznnz <= 0)
return; /* nothing to do if no PSD*/
dzknnz = iwork; /* dzknnz(nblk) */
blksj = dzknnz + nblk; /* blksj(nblk) */
dzir = blksj + nblk; /* dzir(dznnz) */
iwork = dzir + dznnz; /* iwork(iwsiz) */
iwsiz -= 2*nblk + dznnz;
mxAssert(iwsiz >= MAX(pcK->rMaxn,pcK->hMaxn), "iwork too small in getada3()");
daj = fwork; /* lenfull */
fwork = daj + lenud; /* fwsiz */
fwsiz -= lenud;
mxAssert(fwsiz >= 2 * MAX(SQR(pcK->rMaxn),2 * SQR(pcK->hMaxn)), "fwork too small in getada3()");
/* ------------------------------------------------------------
Make "lenfull" vector index valid into daj.
------------------------------------------------------------ */
daj -= blkstart[0]; /* We'll use daj[blkstart[0]:end] */
/* ------------------------------------------------------------
Initialize dzknnz = 0, meaning dz=[]. Later we will merge
columns from dzstruct, with dz, and partition into selected blocks.
------------------------------------------------------------ */
mxAssert(dznnz > 0, ""); /* we know that there exist nonempty PSD: */
for(i = 0; i < nblk; i++)
dzknnz[i] = 0;
for(j = 1; dzstructjc[j] == 0; j++); /* 1st nonzero PSD constraint */
/* ============================================================
MAIN getada LOOP: loop over nodes perm(0:m-1)
============================================================ */
for(--j; j < m; j++){
permj = perm[j];
/* ------------------------------------------------------------
Make dzir: the PSD-nonzero locations, with pointers
to the selected PSD blocks. nz-locs = merge(dzir,dzstruct(:,j)).
------------------------------------------------------------ */
i = dzstructjc[j];
while( i < dzstructjc[j+1]){
k = xblk[dzstructir[i]];
knz = i; /* add dzstructir(knz:i-1) */
intbsearch(&i, dzstructir, dzstructjc[j+1], blkstart[k+1]);
mxAssert(i > knz,"");
exmerge(dzir+dzjc[k], dzstructir+knz, dzknnz[k],i-knz,iwsiz,
cwork,iwork);
dzknnz[k] += i-knz; /* number added */
}
/* ------------------------------------------------------------
Compute daj = P(d)*aj = vec(D*Aj*D).
------------------------------------------------------------ */
nnzbj = spsqrscale(daj,blksj,dzjc,dzir,dzknnz, udsqr,
At.ir,At.pr,Ajc1[permj],At.jc[permj+1],
blkstart, xblk, psdNL, rsdpN, fwork, iwork);
/* iwork(max(K.s)), fwork(2 * (rMaxn^2 + 2*hMaxn^2))*/
mxAssert(nnzbj <= nblk, ""); /* number of nz-matrix-blocks */
/* ------------------------------------------------------------
For all i with invpermi < j:
ada_ij = a_i'*daj.
------------------------------------------------------------ */
for(inz = ada.jc[permj]; inz < ada.jc[permj+1]; inz++){
i = ada.ir[inz];
if(invperm[i] <= j){
adaij = ada.pr[inz];
if(invperm[i] < j)
for(knz = Ajc1[i]; knz < At.jc[i+1]; knz++)
adaij += At.pr[knz] * daj[At.ir[knz]];
else{ /* diag entry: absd[j] = sum(abs(aj.*daj)) */
absadajj = adaij;
for(knz = Ajc1[i]; knz < At.jc[i+1]; knz++){
termj = At.pr[knz] * daj[At.ir[knz]];
adaij += termj;
absadajj += fabs(termj);
}
absd[permj] = absadajj;
}
ada.pr[inz] = adaij;
}
}
/* ------------------------------------------------------------
Set daj = all-0
------------------------------------------------------------ */
for(knz = 0; knz < nnzbj; knz++){
i = blksj[knz];
spzeros(daj,dzir+dzjc[i],dzknnz[i]);
}
} /* j = 0:m-1 */
mxAssert(dzjc[nblk-1]+dzknnz[nblk-1] == dznnz,"");
}
/* ============================================================
MEXFUNCTION
============================================================ */
/* ************************************************************
PROCEDURE mexFunction - Entry for Matlab
************************************************************ */
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
mxArray *myplhs[NPAROUT];
coneK cK;
const mxArray *MY_FIELD;
mwIndex lenfull, lenud, m, i, j, k, fwsiz, iwsiz, dznnz, maxadd;
const double *permPr, *Ajc1Pr, *blkstartPr, *udsqr;
const mwIndex *dzstructjc, *dzstructir;
double *fwork, *absd;
mwIndex *blkstart, *iwork, *Ajc1, *psdNL, *xblk, *perm, *invperm, *dzjc;
bool *cwork;
jcir At, ada;
/* ------------------------------------------------------------
Check for proper number of arguments
------------------------------------------------------------ */
mxAssert(nrhs >= NPARIN, "getADA requires more input arguments.");
mxAssert(nlhs <= NPAROUT, "getADA produces less output arguments.");
/* ------------------------------------------------------------
Disassemble cone K structure
------------------------------------------------------------ */
conepars(K_IN, &cK);
/* ------------------------------------------------------------
Compute some statistics based on cone K structure
------------------------------------------------------------ */
lenud = cK.rDim + cK.hDim; /* for PSD */
lenfull = cK.lpN + cK.qDim + lenud;
/* ------------------------------------------------------------
Allocate working array blkstart(|K.s|+1).
------------------------------------------------------------ */
blkstart = (mwIndex *) mxCalloc(cK.sdpN + 1, sizeof(mwIndex));
/* ------------------------------------------------------------
Translate blkstart from Fortran-double to C-mwIndex
------------------------------------------------------------ */
MY_FIELD = mxGetField(K_IN,(mwIndex)0,"blkstart"); /*K.blkstart*/
mxAssert( MY_FIELD != NULL, "Missing K.blkstart.");
mxAssert(mxGetM(MY_FIELD) * mxGetN(MY_FIELD) == 2+cK.lorN+cK.sdpN, "Size mismatch K.blkstart.");
blkstartPr = mxGetPr(MY_FIELD) + cK.lorN + 1; /* point to start of PSD */
for(i = 0; i <= cK.sdpN; i++){ /* to integers */
j = (mwIndex) blkstartPr[i];
mxAssert(j>0,"");
blkstart[i] = --j;
}
/* ------------------------------------------------------------
INPUT sparse constraint matrix At:
------------------------------------------------------------ */
mxAssert(mxGetM(AT_IN) == lenfull, "Size mismatch At"); /* At */
m = mxGetN(AT_IN);
mxAssert(mxIsSparse(AT_IN), "At should be sparse.");
At.pr = mxGetPr(AT_IN);
At.jc = mxGetJc(AT_IN);
At.ir = mxGetIr(AT_IN);
/* ------------------------------------------------------------
Get SCALING VECTOR: udsqr
------------------------------------------------------------ */
mxAssert(mxGetM(UDSQR_IN) * mxGetN(UDSQR_IN) == lenud, "udsqr size mismatch."); /* udsqr */
udsqr = mxGetPr(UDSQR_IN);
/* ------------------------------------------------------------
Get Ajc1
------------------------------------------------------------ */
mxAssert(mxGetM(AJC1_IN)*mxGetN(AJC1_IN) == m, "Ajc1 size mismatch");
Ajc1Pr = mxGetPr(AJC1_IN);
/* ------------------------------------------------------------
DISASSEMBLE Aord structure: Aord.{dz,sperm}
------------------------------------------------------------ */
mxAssert(mxIsStruct(AORD_IN), "Aord should be a structure.");
MY_FIELD = mxGetField(AORD_IN,(mwIndex)0,"dz"); /* Aord.dz */
mxAssert( MY_FIELD != NULL, "Missing field Aord.dz.");
mxAssert(mxGetN(MY_FIELD) >= m, "Size mismatch Aord.dz.");
mxAssert(mxGetM(MY_FIELD) == lenfull, "Aord.dz size mismatch");
mxAssert(mxIsSparse(MY_FIELD), "Aord.dz should be sparse.");
dzstructjc = mxGetJc(MY_FIELD);
dzstructir = mxGetIr(MY_FIELD);
MY_FIELD = mxGetField(AORD_IN,(mwIndex)0,"sperm"); /* Aord.sperm */
mxAssert( MY_FIELD != NULL, "Missing field Aord.sperm.");
mxAssert(mxGetM(MY_FIELD) * mxGetN(MY_FIELD) == m, "Aord.sperm size mismatch");
permPr = mxGetPr(MY_FIELD);
/* ------------------------------------------------------------
Allocate output matrix ADA as a duplicate of ADA_IN:
------------------------------------------------------------ */
mxAssert(mxGetM(ADA_IN) == m && mxGetN(ADA_IN) == m, "Size mismatch ADA.");
mxAssert(mxIsSparse(ADA_IN), "ADA should be sparse.");
ADA_OUT = mxDuplicateArray(ADA_IN); /* ADA = ADA_IN */
ada.jc = mxGetJc(ADA_OUT);
ada.ir = mxGetIr(ADA_OUT);
ada.pr = mxGetPr(ADA_OUT);
/* ------------------------------------------------------------
Create output vector absd(m)
------------------------------------------------------------ */
ABSD_OUT = mxCreateDoubleMatrix(m,(mwSize)1,mxREAL);
absd = mxGetPr(ABSD_OUT);
/* ------------------------------------------------------------
The following ONLY if there are PSD blocks:
------------------------------------------------------------ */
if(cK.sdpN > 0){
maxadd = dzstructjc[1];
for(i = 1; i < m; i++)
if(dzstructjc[i+1] > dzstructjc[i] + maxadd)
maxadd = dzstructjc[i+1] - dzstructjc[i];
/* ------------------------------------------------------------
ALLOCATE integer work array iwork(iwsiz), with
iwsiz = MAX(m, 2*nblk + dznnz +
max(maxadd+2+log_2(1+maxadd), max(nk(PSD)))),
where dznnz = dzstructjc[m].
------------------------------------------------------------ */
dznnz = dzstructjc[m];
iwsiz = (mwIndex) floor(log(1.0+maxadd)/log(2.0)); /* double to mwIndex */
iwsiz += maxadd + 2;
iwsiz = 2*cK.sdpN + dznnz + MAX(iwsiz,MAX(cK.rMaxn,cK.hMaxn));
iwork = (mwIndex *) mxCalloc(MAX(iwsiz,m), sizeof(mwIndex));
/* ------------------------------------------------------------
ALLOCATE integer working arrays:
Ajc1(m) psdNL[cK.sdpN], dzjc(cK.sdpN+1), perm(m), invperm(m), xblk(lenud).
cwork(maxadd).
------------------------------------------------------------ */
Ajc1 = (mwIndex *) mxCalloc(MAX(m,1), sizeof(mwIndex));
psdNL = (mwIndex *) mxCalloc(1+2*cK.sdpN + lenud, sizeof(mwIndex));
xblk = psdNL + cK.sdpN; /* Not own alloc: we'll subtract blkstart[0] */
dzjc = xblk + lenud; /*dzjc(sdpN+1) */
perm = (mwIndex *) mxCalloc(MAX(2 * m,1), sizeof(mwIndex));
invperm = perm + m; /* invperm(m) */
cwork = (bool *) mxCalloc(MAX(1,maxadd), sizeof(bool));
/* ------------------------------------------------------------
ALLOCATE float working array:
fwork[fwsiz] with fwsiz = lenud + 2 * max(rMaxn^2, 2*hMaxn^2).
------------------------------------------------------------ */
fwsiz = lenud + 2 * MAX(SQR(cK.rMaxn),2*SQR(cK.hMaxn));
fwork = (double *) mxCalloc(MAX(fwsiz,1), sizeof(double));
/* ------------------------------------------------------------
perm to integer C-style
------------------------------------------------------------ */
for(i = 0; i < m; i++){
j = (mwIndex) permPr[i];
mxAssert(j>0,"");
perm[i] = --j;
}
/* ------------------------------------------------------------
Let invperm(perm) = 0:m-1.
------------------------------------------------------------ */
for(i = 0; i < m; i++)
invperm[perm[i]] = i;
/* ------------------------------------------------------------
Let psdNL = K.s in integer, Ajc1 = Ajc1Pr in integer.
------------------------------------------------------------ */
for(i = 0; i < cK.sdpN; i++) /* K.s */
psdNL[i] = (mwIndex) cK.sdpNL[i];
for(i = 0; i < m; i++)
Ajc1[i] = (mwIndex) Ajc1Pr[i];
/* ------------------------------------------------------------
Let k = xblk(j-blkstart[0]) iff
blkstart[k] <= j < blkstart[k+1], k=0:nblk-1.
------------------------------------------------------------ */
j = blkstart[0];
xblk -= j; /* Make blkstart[0]:blkstart[end] valid indices */
for(k = 0; k < cK.sdpN; k++){
i = blkstart[k+1];
while(j < i)
xblk[j++] = k;
}
/* ------------------------------------------------------------
ACTUAL COMPUTATION: handle constraint aj=At(:,perm(j)), j=0:m-1.
------------------------------------------------------------ */
dzblkpartit(dzjc, dzstructir, xblk, dznnz, cK.sdpN);
getada3(ada, absd, At,udsqr,Ajc1, dzjc,dzstructjc,dzstructir, blkstart,
xblk,psdNL, perm,invperm, m,lenud, &cK, fwork,fwsiz,
iwork,iwsiz, cwork);
/* ------------------------------------------------------------
RELEASE WORKING ARRAYS (for PSD blocks only).
------------------------------------------------------------ */
mxFree(fwork);
mxFree(cwork);
mxFree(perm);
mxFree(psdNL);
mxFree(Ajc1);
} /* ~isempty(K.s) */
/* ------------------------------------------------------------
If no PSD-blocks, than we merely compute absd = diag(ADA)
ALLOCATE integer work array iwork(m), with
------------------------------------------------------------ */
else{
iwork = (mwIndex *) mxCalloc(MAX(1,m), sizeof(mwIndex));
cpspdiag(absd, ada,m);
}
/* ------------------------------------------------------------
Let ADA = (ADA+ADA')/2, so that it gets symmetric.
------------------------------------------------------------ */
spmakesym(ada,m,iwork); /* uses iwork(m) */
/* ------------------------------------------------------------
RELEASE WORKING ARRAYS iwork and blkstart.
------------------------------------------------------------ */
mxFree(iwork);
mxFree(blkstart);
/* ------------------------------------------------------------
Copy requested output parameters (at least 1), release others.
------------------------------------------------------------ */
i = MAX(nlhs, 1);
memcpy(plhs,myplhs, i * sizeof(mxArray *));
for(; i < NPAROUT; i++)
mxDestroyArray(myplhs[i]);
}

Event Timeline