📄 sparchol2.c
字号:
/* This file is part of SeDuMi 1.03BETA Copyright (C) 1999 Jos F. Sturm 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., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include <math.h>#include <string.h>#include "blksdp.h"#include "mex.h"/* ------------------------------------------------------------ PROTOTYPES: ------------------------------------------------------------ */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);/* ************************************************************ TIME-CRITICAL PROCEDURE -- isscalarmul(x,alpha,n) Computes x *= alpha using LEVEL 8 loop-unrolling. ************************************************************ */void isscalarmul(double *x, const double alpha, const int n){ int i; for(i=0; i< n-7; i++){ /* LEVEL 8 */ x[i++] *= alpha; x[i++] *= alpha; x[i++] *= alpha; x[i++] *= alpha; x[i++] *= alpha; x[i++] *= alpha; x[i++] *= alpha; x[i] *= alpha; }/* ------------------------------------------------------------ Now, i in {n-7, n-6, ..., n}. Do the last n-i elements. ------------------------------------------------------------ */ if(i < n-3){ /* LEVEL 4 */ x[i++] *= alpha; x[i++] *= alpha; x[i++] *= alpha; x[i++] *= alpha; } if(i < n-1){ /* LEVEL 2 */ x[i++] *= alpha; x[i++] *= alpha; } if(i < n) /* LEVEL 1 */ x[i] *= alpha;}/* ************************************************************ PROCEDURE maxabs - computes inf-norm INPUT x - vector of length n n - length of x. RETURNS y = norm(x,inf). ************************************************************ */double maxabs(const double *x,const int n){ int i; double y,xi; y = 0.0; for(i = 0; i < n; i++) if((xi = fabs(x[i])) > y) y = xi; return y;}/* ************************************************************ PROCEDURE cholonBlk - CHOLESKY on a dense diagonal block. Also updates nonzeros below this diagonal block - they need merely be divided by the scalar diagonals "lkk" afterwards. INPUT m - number of rows (length of the first column). ncols - number of columns in the supernode.(n <= m) lb - Length ncols. Skip k-th pivot if drops below lb[k]. ub - max(diag(x)) / maxu^2. No stability check for pivots > ub. maxu - Max. acceptable |lik|/lkk when lkk suffers cancelation. first - global column number of column 0. This is used only to insert the global column numbers into skipIr. UPDATED x - On input, contains the columns of the supernode to be factored. On output, contains the factored columns of the supernode. skipIr - Lists skipped pivots with their global column number in 0:neqns-1. Active range is first:first+ncols-1. Skipped if d(k) suffers cancelation and max(abs(L(:,k)) > maxu. *pnskip - nnz in skip; *pnskip <= order N of sparse matrix. OUTPUT d - Length ncols. Diagonal in L*diag(d)*L' with diag(L)=all-1. ************************************************************ */void cholonBlk(double *x, double *d, int m, const int ncols, const int first, const double ub, const double maxu, double *lb, int *skipIr, int *pnskip){ int inz,i,k,n,coltail, nskip; double xkk, xik, ubk; double *xi;/* ------------------------------------------------------------ Initialize: ------------------------------------------------------------ */ n = ncols; nskip = *pnskip; inz = 0; coltail = m - ncols; for(k = 0; k < ncols; k++, --m, --n){/* ------------------------------------------------------- Let xkk = L(k,k), ubk = max(|xik|) / maxu. ------------------------------------------------------- */ xkk = x[inz]; if(xkk > lb[k]){ /* now xkk > 0 */ if(xkk < ub){ ubk = maxabs(x+inz+1,m-1) / maxu; if(xkk < ubk){/* ------------------------------------------------------------ If we need to add on diagonal, store this in (skipIr, lb(k)). ------------------------------------------------------------ */ skipIr[nskip++] = first + k; lb[k] = ubk - xkk; /* amount added on diagonal */ xkk = ubk; } }/* -------------------------------------------------------------- Set dk = xkk, lkk = 1 (for LDL'). -------------------------------------------------------------- */ d[k] = xkk; /* now d[k] > 0 MEANS NO-SKIPPING */ x[inz] = 1.0; xi = x + inz + m; /* point to next column */ ++inz;/* -------------------------------------------------------------- REGULAR JOB: correct remaining n-k cols with col k. x(k+1:m,k+1:n) -= x(k+1:m,k) * x(k+1:n,k)' / xkk x(k+1:n,k) /= xkk, -------------------------------------------------------------- */ for(i = 1; i < n; i++){ xik = x[inz] / xkk; subscalarmul(xi, xik, x+inz, m-i); x[inz++] = xik; xi += m-i; } inz += coltail; /* Let inz point to next column */ }/* ------------------------------------------------------------ If skipping is enabled and this pivot is too small: 1) don't touch L(k:end,k): allows pivot delaying if desired. 2) List first+k in skipIr. Set dk = 0 (MEANS SKIPPING). -------------------------------------------------------------- */ else{ skipIr[nskip++] = first + k; d[k] = 0.0; /* tag "0": means column skipped in LDL'.*/ inz += m; /* Don't touch nor use L(k:end,k) */ } } /* k=0:ncols-1 *//* ------------------------------------------------------------ Return updated number of added or skipped pivots. ------------------------------------------------------------ */ *pnskip = nskip;}/* ************************************************************ getbwIrInv -- Inverse of the subscript function: given a subscript, irInv yields the position, counted FROM THE BOTTOM of the sparse column. INPUT PARAMETERS - nnz - LENGTH OF THE FIRST COLUMN OF THE SUPERNODE, INCLUDING THE DIAGONAL ENTRY. Lir - Lir[0:nnz-1] ARE THE ROW INDICES OF THE NONZEROS OF THE FIRST COLUMN OF THE SUPERNODE. OUTPUT PARAMETERS - irInv - On return, irInv[Lir[0:nnz-1]] = nnz:-1:1, so that Lir[nnz-irInv[i]] == i The position of subscript "xij" is thus xjc[j+1] - irInv[i]. ************************************************************ */void getbwIrInv(int *irInv, const int *Lir, const int nnz){ int inz,bwinz; bwinz = nnz; for(inz = 0; inz < nnz; inz++, bwinz--) irInv[Lir[inz]] = bwinz; /* bwinz = nnz:-1:1 */}/* ************************************************************ suboutprod -- Computes update from a single previous column "xk" on a supernode "xj", using dense computations. INPUT mj, nj - supernode "xj" is mj x nj. More precisely, the column lengths are {mj, mj-1, ..., mj-(nj-1)}. xkk - scalar, the 1st nj entries in xk are divided by this number. mk - length of xk. WE ASSUME mk <= mj. Only 1st mk rows in xj are updated. UPDATED xj - On return, xj -= xk*xk(0:nj-1)'/xkk xk - On return, xk(0:nj-1) /= xkk ************************************************************ */void suboutprod(double *xj, int mj, const int nj, double *xk, const double xkk, int mk){ int j; double xjk; for(j = 0; j < nj; j++){ xjk = xk[0] / xkk; subscalarmul(xj, xjk, xk, mk); /* xj -= xjk * xk */ xk[0] = xjk; /* FINAL entry ljk */ xj += mj; /* point to next column which is 1 shorter */ --mj; --mk; ++xk; }}/* ************************************************************ isminoutprod -- Computes update from a column "xk" and stores it in "xj", using dense computations. If "xkk<=0", then let xj = 0. INPUT mk, nj - output "xj" is mk x nj - nj*(nj-1)/2. Its column lengths are {mk, mk-1, ..., mk-(nj-1)}. xkk - scalar, the 1st nj entries in xk are divided by this number. OUTPUT xj - On return, xj = -xk*xk(0:nj-1)'/xkk (NOTE THE MINUS !) BUT: if xkk <= 0, then xj = zeros(nj*(2m-nj+1)/2,1). UPDATED xk - On return, xk(0:nj-1) /= xkk if xkk > 0, otherwise unchanged. ************************************************************ */void isminoutprod(double *xj, const int nj, double *xk, const double xkk, int mk){ int j; double xjk; if(xkk > 0.0) /* if not phase 2 node */ for(j = 0; j < nj; j++){ xjk = xk[0] / xkk; memcpy(xj,xk,mk * sizeof(double)); isscalarmul(xj, -xjk, mk); /* xj = -xjk * xk */ xk[0] = xjk; /* FINAL entry ljk */ xj += mk; /* point to next column which is 1 shorter */ --mk; ++xk; } else /* initialize to all-0 if phase-2 node */ fzeros(xj,(nj * (mk + mk-nj + 1))/2);}/* ************************************************************ spsuboutprod -- Computes update from a single previous column "xk" on a supernode "xj", with a different sparsity structure. The relevant nonzeros of xj are accessed by a single 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 nonzeros in xk. xjjc - xjjc[0] is start of 1st column of xj (as index into xnz), etc. xkk - scalar, the 1st nj entries in xk are divided by this number. 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. UPDATED xnz - On return, xj(relind,:) -= xk*xk(0:nj-1)'/xkk xk - On return, xk(0:nj-1) /= xkk ************************************************************ */void spsuboutprod(const int *xjjc, double *xnz, const int mj, const int nj, double *xk,const double xkk,const int mk, const int *relind){ int i, j, jcol, bottomj;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -