📄 sparchol2.c
字号:
double xjk; ++xjjc; /* now it points beyond bottom of columns */ for(j = 0; j < nj; j++){ jcol = mj - relind[j]; /* affected column */ bottomj = xjjc[jcol]; xjk = xk[j] / xkk; for(i = j; i < mk; i++) xnz[bottomj - relind[i]] -= xjk * xk[i]; xk[j] = xjk; /* FINAL entry ljk */ }}/* ************************************************************ spadd -- Let xj += xk, where the supernode "xj", has a sparsity structure. The relevant nonzeros of xj are accessed by a indirection, via "relind[:]". INPUT mj, nj - supernode "xj" has mj rows in its 1st column. In total, we will update nj columns, corresponding to the 1st nj nonzero rows in xk. xjjc - xjjc[0] is start of 1st column of xj (as index into xnz), etc. mk - length of xk. WE ASSUME mk <= mj. relind - (mj - relind[0:mk-1]) yields the locations in xj on which the xk nonzeros will act. xk - mk * nk - nk*(nk-1)/2 matrix, with column lengths mk, mk-1, mk-2,.. mk-(nj-1). They'll be substracted from the entries in xj that are listed by relind. UPDATED xnz - On return, xj(relind,:) += xk ************************************************************ */void spadd(const int *xjjc, double *xnz, const int mj, const int nj, const double *xk, const int mk, const int *relind){ int i, j, jcol, bottomj,mkcol; ++xjjc; /* now it points beyond bottom of columns */ mkcol = mk; /* mkcol = mk - j */ for(j = 0; j < nj; j++){ jcol = mj - relind[j]; /* affected column */ bottomj = xjjc[jcol]; for(i = j; i < mk; i++) xnz[bottomj - relind[i]] += xk[i]; xk += (--mkcol); /* xk(i:mk-1) is next column */ }}/* ************************************************************ PROCEDURE precorrect - Apply corrections from affecting supernode (skipping subnodes with non-positive diagonal) on supernodal diagonal block in L-factor. INPUT ljc - start of columns in lpr. d - Length neqns vector. The diagonal in L*diag(d)*L'. Only d[firstk:nextk-1] will be used. irInv - For row-indices Jir of affected supernode, Jir[m-irInv[i]] == i. nextj - Last subnode of affected supernode is nextj-1. firstk, nextk - subnodes of affecting supernode are firstk:nextk-1. Kir - unfinished row indices of affecting supernode mk - number of unfinished nonzeros in affecting supernode fwsiz - Allocated length of fwork. UPDATED lpr - For each column k=firstk:nextk-1, and the affected columns j in node, DO L(:,j) -= (ljk / lkk) * L(:,k), and store the definitive j-th row of L, viz. ljk /= lkk. WORKING ARRAYS relind - length mk integer array fwork - length fwsiz vector, for storing -Xk * inv(LABK) * Xk'. RETURNS ncolup, number of columns updated by snode k. if -1, then fwsiz is too small. ************************************************************ */int precorrect(double *lpr, const int *ljc,const double *d, const int *irInv, const int nextj, const int *Kir, const int mk, const int firstk, const int nextk, int *relind, const int fwsiz, double *fwork){ int i,j,k,ncolup,mj; double *xj;/* ------------------------------------------------------------ j = first subscript in k (== 1st affected column) i = last subscript in k ncolup = number of nz-rows in k corresponding to columns in node. mj = number of nonzeros in l(:,j), the 1st affected column ------------------------------------------------------------ */ j = Kir[0]; i = Kir[mk-1]; if(i < nextj) ncolup = mk; else for(ncolup = 1; Kir[ncolup] < nextj; ncolup++); mj = ljc[j+1] - ljc[j];/* ------------------------------------------------------------ If nz-structure of k is a single block in structure of node, (i.e. irInv[Kir[0]] - irInv[Kir[mk-1]] == mk-1). The subnodes of "node" must then be consecutive and at the start. Thus, we use dense computations : ------------------------------------------------------------ */ if(irInv[j] - irInv[i] < mk){ xj = lpr + ljc[j]; for(k = firstk; k < nextk; k++) if(d[k] > 0.0) /* Skip pivot when d[k] <= 0 */ suboutprod(xj, mj, ncolup, lpr + ljc[k+1] - mk, d[k], mk); } else{/* ------------------------------------------------------------ Otherwise, the nz-indices of k are scattered within the structure of node. Let relind be the position of these nz's in node, COUNTED FROM THE BOTTOM. ------------------------------------------------------------*/ for(i = 0; i < mk; i++) relind[i] = irInv[Kir[i]];/* ------------------------------------------------------------ If k is a single column, then perform update directly in lpr: ------------------------------------------------------------ */ if(nextk - firstk == 1){ if(d[firstk] > 0.0) /* Skip pivot when d[k] <= 0 */ spsuboutprod(ljc+j,lpr,mj, ncolup, lpr + ljc[nextk]-mk, d[firstk],mk, relind); } else{/* ------------------------------------------------------------ Multiple columns in affecting snode: 1. compute the complete modification, and store it in fwork: fwork = -Xk * inv(LABK) * Xk' ------------------------------------------------------------ */ if(fwsiz < mk * ncolup - ncolup*(ncolup-1)/2) return -1; for(k = firstk; k < nextk; k++) /* find 1st positive diag */ if(d[k] > 0.0) break; if(k < nextk){ /* if any positive diag: */ isminoutprod(fwork, ncolup, lpr + ljc[k+1] - mk, d[k], mk); for(++k; k < nextk; k++) /* remaining cols */ if(d[k] > 0.0) /* Skip pivot when d[k] <= 0 */ suboutprod(fwork, mk, ncolup, lpr + ljc[k+1] - mk, d[k], mk);/* ------------------------------------------------------------ 2. subtract fwork from the sparse columns of node, using relind. ------------------------------------------------------------ */ spadd(ljc+j,lpr,mj, ncolup, fwork,mk, relind); } /* end exists positive diag */ } /* end multiple affecting cols */ } /* end of scattered case *//* ------------------------------------------------------------ RETURN number of columns updated, i.e. #subnodes in k that we finished. ------------------------------------------------------------ */ return ncolup;}/* ************************************************************ BLKLDL -- Block-sparse L*D*L' Cholesky factorization. INPUT: neqns - Order "m": L is neqns * neqns nsuper - Number of supernodes (blocks). xsuper - Length nsuper+1: first simple-node of each supernode snode - Length neqns: snode(node) is the supernode containing "node". xlindx - Length nsuper+1: Start of sparsity structure in lindx, for each supernode (all simple nodes in a supernode have the same nonzero-structure). lindx - row indices, for each supernode. ljc - Length neqns+1: start of the columns of L. perm - Length neqns: reordering of pne->At columns in Cholesky. ub - max(diag(x)) / maxu^2. No stability check for pivots > ub. maxu - Force max(max(abs(L))) <= maxu (by adding low-rank diag). iwsiz, fwsiz - size of integer and floating-point working storage. See "WORKING ARRAYS" for required amount. UPDATED: Lpr - On input, contains tril(X), on output, L is such that X = L*D*L'. For columns k where d[k]=0, L(:,k) contains the column updated upto pivot k-1. lb - Length neqns. INPUT: cancelation threshold per pivot. Skip pivot if it drops below. OUTPUT: lb(skipIr) are values of low rank diag. matrix that is added before factorization. OUTPUT d - length neqns vector, diagonal in L*diag(d)*L'. skipIr - length nskip (<= neqns) array. skipIr(1:nskip) lists the columns that have been skipped in the Cholesky. d[skipIr] = 0. WORKING ARRAYS: iwork - Length iwsiz working array, used for link(nsuper), length(nsuper), irInv(neqns), relind(neqns), iwsiz = 2*m + 2 * nsuper fwork - Length fwsiz. Used for fwork(L.tmpsiz) in precorrect. fwsiz = L.tmpsiz. ACKNOWLEDGMENT: Parts are inspired by F77-block Cholesky of Ng and Peyton (ORNL). RETURNS nskip (<=neqns), number of skipped nodes. Length of skipIr. if -1 then not enough workspace (iwsiz, fwsiz) allocated. ************************************************************ */int blkLDL(const int neqns, const int nsuper, const int *xsuper, const int *snode, const int *xlindx, const int *lindx, double *lb, const int *ljc, double *lpr, double *d, const int *perm, const double ub, const double maxu, int *skipIr, int iwsiz, int *iwork, int fwsiz, double *fwork){ const int *Jir; int *link, *length, *irInv, *relind, *ncolupLst; int node,nextj,i,j,nnzj,n,inz, k,colk,mk,linkk, ncolup,snodei, nskip;/* ------------------------------------------------------------ Partition integer working array of size 2*(nsuper+neqns): iwork = [link(nsuper); length(nsuper); irInv(neqns); relind(neqns)]. ------------------------------------------------------------ */ if(iwsiz < 2 * (neqns + nsuper)) return -1; link = iwork; /* 2 times length nsuper: */ length = link + nsuper; irInv = length + nsuper; /* 2 * length neqns: */ relind = irInv + neqns;/* ------------------------------------------------------------ ncolupLst(neqns) shares the same working array as irInv(neqns). Namely, at stage j=xsuper[node], irInv uses only entries >= j, whereas ncolupLst only applies to the "old" columns < j. ------------------------------------------------------------ */ ncolupLst = irInv;/* ------------------------------------------------------------ Initialize: link = nsuper * ones(nsuper,1) (means END-OF-LIST) ------------------------------------------------------------ */ for(node = 0; node < nsuper; node++) link[node] = nsuper;/* ------------------------------------------------------------ Initialize nskip = 0. ------------------------------------------------------------ */ nskip = 0;/* ------------------------------------------------------------ For each supernode "node", start at subnode j = xsuper[node], having sparsity pattern Jir. ------------------------------------------------------------ */ nextj = xsuper[0]; for(node = 0; node < nsuper; node++){ j = nextj; /* 1st col in node */ nextj = xsuper[node+1]; n = nextj - j; /* length of node */ Jir = lindx + xlindx[node]; /* row-indices for column j */ nnzj = ljc[j+1] - ljc[j]; /* nnz( column j ) *//* ------------------------------------------------------------ Compute inverse of Jir, yielding position from the bottom: Jir[nnzj-irInv[i]] == i This will be handy when adding a column with a sub-sparsity structure to column j. ------------------------------------------------------------ */ getbwIrInv(irInv, Jir, nnzj);/* ------------------------------------------------------------ Apply corrections from relevant previous super-nodes; these snodes are node -> link[node] -> link[link[node]] -> ... ------------------------------------------------------------ */ for(k = link[node]; k < nsuper; k = link[k]){ if((ncolupLst[k] = precorrect(lpr,ljc,d,irInv, nextj, lindx + xlindx[k+1]-length[k], length[k],xsuper[k],xsuper[k+1], relind,fwsiz,fwork)) < 0) return -1; /* fwsiz too small */ } /* ------------------------------------------------------------ DO DENSE CHOLESKY on the current supernode ------------------------------------------------------------ */ cholonBlk(lpr + ljc[j],d+j, nnzj, n, j, ub, maxu, lb+j, skipIr,&nskip);/* ------------------------------------------------------------ insert each current affecting snode k into linked list of next supernode it will affect. ------------------------------------------------------------ */ for(k = link[node]; k < nsuper; k = linkk){ linkk = link[k]; mk = (length[k] -= ncolupLst[k]); /* unfinished nonzeros in k */ if(mk){ /* if not yet terminated: */ i = lindx[xlindx[k+1]-mk]; snodei = snode[i]; link[k] = link[snodei]; /* prev. also affecting i */ link[snodei] = k; /* next snode it'll affect */ } }/* ------------------------------------------------------------ The same for current snode "node" itself: ------------------------------------------------------------ */ if((length[node] = nnzj - n) > 0){ i = Jir[n]; /* 1st row outside snode */ snodei = snode[i]; link[node] = link[snodei]; /* prev. also affecting i */ link[snodei] = node; } else length[node] = 0; /* Supernode terminated */ } /* node = 0:nsuper-1 *//* ------------------------------------------------------------ FINISHING: return the number of skipped pivots ------------------------------------------------------------ */ return nskip;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -