📄 zsvdc.c
字号:
#include "f2c.h"
#include "netlib.h"
extern double sqrt(double); /* #include <math.h> */
/* Modified by Peter Vanroose, June 2001: manual optimisation and clean-up */
/* and moved zswap() zscal() zdrot() zdotc() zaxpy() to separate files */
/*
* Calling this ensures that the operands are spilled to
* memory and thus avoids excessive precision when compiling
* for x86 with heavy optimization (gcc). It is better to do
* this than to turn on -ffloat-store.
*/
static int fsm_ieee_doubles_equal(const doublereal *x, const doublereal *y);
/* Table of constant values */
static integer c__1 = 1;
static doublecomplex c_1 = {1.,0.};
static doublecomplex c_m1 = {-1.,0.};
/* ====================================================================== */
/* NIST Guide to Available Math Software. */
/* Fullsource for module ZSVDC from package LINPACK. */
/* Retrieved from NETLIB on Fri May 9 10:03:02 1997. */
/* ====================================================================== */
/* Subroutine */ void zsvdc_(x, ldx, n, p, s, e, u, ldu, v, ldv, work, job, info)
doublecomplex *x;
const integer *ldx, *n, *p;
doublecomplex *s, *e, *u;
const integer *ldu;
doublecomplex *v;
const integer *ldv;
doublecomplex *work;
const integer *job;
integer *info;
{
/* System generated locals */
integer i__1, i__2;
doublereal d__1, d__2;
doublecomplex z__1;
/* Local variables */
static integer jobu, iter;
static doublereal test;
static doublereal b, c;
static doublereal f, g;
static integer i, j, k, l, m;
static doublecomplex r, t;
static doublereal scale;
static doublereal shift;
static integer maxit;
static logical wantu, wantv;
static doublereal t1, ztest;
static doublereal el;
static doublereal cs;
static integer mm, ls;
static doublereal sl;
static integer lu;
static doublereal sm, sn;
static integer nct, ncu, nrt;
static doublereal emm1, smm1;
/************************************************************************/
/* */
/* zsvdc is a subroutine to reduce a complex*16 nxp matrix x by */
/* unitary transformations u and v to diagonal form. the */
/* diagonal elements s(i) are the singular values of x. the */
/* columns of u are the corresponding left singular vectors, */
/* and the columns of v the right singular vectors. */
/* */
/* on entry */
/* */
/* x complex*16(ldx,p), where ldx.ge.n. */
/* x contains the matrix whose singular value */
/* decomposition is to be computed. x is */
/* destroyed by zsvdc. */
/* */
/* ldx integer. */
/* ldx is the leading dimension of the array x. */
/* */
/* n integer. */
/* n is the number of rows of the matrix x. */
/* */
/* p integer. */
/* p is the number of columns of the matrix x. */
/* */
/* ldu integer. */
/* ldu is the leading dimension of the array u */
/* (see below). */
/* */
/* ldv integer. */
/* ldv is the leading dimension of the array v */
/* (see below). */
/* */
/* work complex*16(n). */
/* work is a scratch array. */
/* */
/* job integer. */
/* job controls the computation of the singular */
/* vectors. it has the decimal expansion ab */
/* with the following meaning */
/* */
/* a.eq.0 do not compute the left singular */
/* vectors. */
/* a.eq.1 return the n left singular vectors */
/* in u. */
/* a.ge.2 returns the first min(n,p) */
/* left singular vectors in u. */
/* b.eq.0 do not compute the right singular */
/* vectors. */
/* b.eq.1 return the right singular vectors */
/* in v. */
/* */
/* on return */
/* */
/* s complex*16(mm), where mm=min(n+1,p). */
/* the first min(n,p) entries of s contain the */
/* singular values of x arranged in descending */
/* order of magnitude. */
/* */
/* e complex*16(p). */
/* e ordinarily contains zeros. however see the */
/* discussion of info for exceptions. */
/* */
/* u complex*16(ldu,k), where ldu.ge.n. if joba.eq.1 */
/* then k.eq.n, if joba.ge.2 then */
/* k.eq.min(n,p). */
/* u contains the matrix of left singular vectors. */
/* u is not referenced if joba.eq.0. if n.le.p */
/* or if joba.gt.2, then u may be identified with x */
/* in the subroutine call. */
/* */
/* v complex*16(ldv,p), where ldv.ge.p. */
/* v contains the matrix of right singular vectors. */
/* v is not referenced if jobb.eq.0. if p.le.n, */
/* then v may be identified whth x in the */
/* subroutine call. */
/* */
/* info integer. */
/* the singular values (and their corresponding */
/* singular vectors) s(info+1),s(info+2),...,s(m) */
/* are correct (here m=min(n,p)). thus if */
/* info.eq.0, all the singular values and their */
/* vectors are correct. in any event, the matrix */
/* b = ctrans(u)*x*v is the bidiagonal matrix */
/* with the elements of s on its diagonal and the */
/* elements of e on its super-diagonal (ctrans(u) */
/* is the conjugate-transpose of u). thus the */
/* singular values of x and b are the same. */
/* */
/************************************************************************/
/* linpack. this version dated 03/19/79 . */
/* correction to shift calculation made 2/85. */
/* g.w. stewart, university of maryland, argonne national lab. */
/* */
/* zsvdc uses the following functions and subprograms. */
/* */
/* external zdrot */
/* blas zaxpy,zdotc,zscal,zswap,dznrm2,drotg */
/* fortran dmax1,zabs,dcmplx */
/* fortran dconjg,max0,min0,mod,dsqrt */
/* set the maximum number of iterations. */
maxit = 30;
/* determine what is to be computed. */
wantu = FALSE_;
wantv = FALSE_;
jobu = *job % 100 / 10;
ncu = *n;
if (jobu > 1) {
ncu = min(*n,*p);
}
if (jobu != 0) {
wantu = TRUE_;
}
if (*job % 10 != 0) {
wantv = TRUE_;
}
/* reduce x to bidiagonal form, storing the diagonal elements */
/* in s and the super-diagonal elements in e. */
*info = 0;
nct = min(*n - 1, *p);
nrt = max(0, min(*p - 2, *n));
lu = max(nct,nrt);
for (l = 0; l < lu; ++l) {
if (l > nct-1) {
goto L20;
}
/* compute the transformation for the l-th column and */
/* place the l-th diagonal in s(l). */
i__1 = *n - l;
s[l].r = dznrm2_(&i__1, &x[l+l* *ldx], &c__1);
s[l].i = 0.;
if (s[l].r == 0.) {
goto L10;
}
i__2 = l + l * *ldx; /* index [l,l] */
if (x[i__2].r != 0. || x[i__2].i != 0.) {
d__1 = z_abs(&s[l]);
d__2 = z_abs(&x[i__2]);
s[l].r = d__1 * x[i__2].r / d__2,
s[l].i = d__1 * x[i__2].i / d__2;
}
z_div(&z__1, &c_1, &s[l]);
i__1 = *n - l;
zscal_(&i__1, &z__1, &x[i__2], &c__1);
x[i__2].r += 1.;
L10:
s[l].r = -s[l].r, s[l].i = -s[l].i;
L20:
for (j = l+1; j < *p; ++j) {
/* apply the transformation. */
if (l < nct && (s[l].r != 0. || s[l].i != 0.)) {
i__1 = *n - l;
i__2 = l + l * *ldx; /* index [l,l] */
zdotc_(&t, &i__1, &x[i__2], &c__1, &x[l+j* *ldx], &c__1);
t.r = -t.r, t.i = -t.i;
z_div(&t, &t, &x[i__2]);
zaxpy_(&i__1, &t, &x[i__2], &c__1, &x[l+j* *ldx], &c__1);
}
/* place the l-th row of x into e for the */
/* subsequent calculation of the row transformation. */
d_cnjg(&e[j], &x[l+j* *ldx]);
}
/* place the transformation in u for subsequent back */
/* multiplication. */
if (wantu && l < nct)
for (i = l; i < *n; ++i) {
i__1 = i + l * *ldu; /* index [i,l] */
i__2 = i + l * *ldx; /* index [i,l] */
u[i__1].r = x[i__2].r, u[i__1].i = x[i__2].i;
}
if (l >= nrt) {
continue; /* next l */
}
/* compute the l-th row transformation and place the */
/* l-th super-diagonal in e(l). */
i__1 = *p - l - 1;
e[l].r = dznrm2_(&i__1, &e[l+1], &c__1);
e[l].i = 0.;
if (e[l].r != 0.) {
if (e[l+1].r != 0. || e[l+1].i != 0.) {
d__1 = z_abs(&e[l]); d__2 = z_abs(&e[l+1]);
e[l].r = d__1 * e[l+1].r / d__2,
e[l].i = d__1 * e[l+1].i / d__2;
}
i__1 = *p - l - 1;
z_div(&z__1, &c_1, &e[l]);
zscal_(&i__1, &z__1, &e[l+1], &c__1);
e[l+1].r += 1.;
}
e[l].r = -e[l].r; /* e[l] = - conj(e[l]) */
if (l >= *n-1 || (e[l].r == 0. && e[l].i == 0.)) {
goto L120;
}
/* apply the transformation. */
for (i = l+1; i < *n; ++i) {
work[i].r = 0., work[i].i = 0.;
}
for (j = l+1; j < *p; ++j) {
i__1 = *n - l - 1;
zaxpy_(&i__1, &e[j], &x[l+1 +j* *ldx], &c__1, &work[l+1], &c__1);
}
for (j = l+1; j < *p; ++j) {
z__1.r = -e[j].r, z__1.i = -e[j].i;
z_div(&z__1, &z__1, &e[l+1]);
z__1.i = -z__1.i; /* d_cnjg(&z__1, &z__1); */
i__1 = *n - l - 1;
zaxpy_(&i__1, &z__1, &work[l+1], &c__1, &x[l+1 +j* *ldx], &c__1);
}
/* place the transformation in v for subsequent */
/* back multiplication. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -