mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
511 lines
16 KiB
511 lines
16 KiB
/* sbdsdc.f -- translated by f2c (version 20061008). |
|
You must link the resulting object file with libf2c: |
|
on Microsoft Windows system, link with libf2c.lib; |
|
on Linux or Unix systems, link with .../path/to/libf2c.a -lm |
|
or, if you install libf2c.a in a standard place, with -lf2c -lm |
|
-- in that order, at the end of the command line, as in |
|
cc *.o -lf2c -lm |
|
Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., |
|
|
|
http://www.netlib.org/f2c/libf2c.zip |
|
*/ |
|
|
|
#include "clapack.h" |
|
|
|
|
|
/* Table of constant values */ |
|
|
|
static integer c__9 = 9; |
|
static integer c__0 = 0; |
|
static real c_b15 = 1.f; |
|
static integer c__1 = 1; |
|
static real c_b29 = 0.f; |
|
|
|
/* Subroutine */ int sbdsdc_(char *uplo, char *compq, integer *n, real *d__, |
|
real *e, real *u, integer *ldu, real *vt, integer *ldvt, real *q, |
|
integer *iq, real *work, integer *iwork, integer *info) |
|
{ |
|
/* System generated locals */ |
|
integer u_dim1, u_offset, vt_dim1, vt_offset, i__1, i__2; |
|
real r__1; |
|
|
|
/* Builtin functions */ |
|
double r_sign(real *, real *), log(doublereal); |
|
|
|
/* Local variables */ |
|
integer i__, j, k; |
|
real p, r__; |
|
integer z__, ic, ii, kk; |
|
real cs; |
|
integer is, iu; |
|
real sn; |
|
integer nm1; |
|
real eps; |
|
integer ivt, difl, difr, ierr, perm, mlvl, sqre; |
|
extern logical lsame_(char *, char *); |
|
integer poles; |
|
extern /* Subroutine */ int slasr_(char *, char *, char *, integer *, |
|
integer *, real *, real *, real *, integer *); |
|
integer iuplo, nsize, start; |
|
extern /* Subroutine */ int scopy_(integer *, real *, integer *, real *, |
|
integer *), sswap_(integer *, real *, integer *, real *, integer * |
|
), slasd0_(integer *, integer *, real *, real *, real *, integer * |
|
, real *, integer *, integer *, integer *, real *, integer *); |
|
extern doublereal slamch_(char *); |
|
extern /* Subroutine */ int slasda_(integer *, integer *, integer *, |
|
integer *, real *, real *, real *, integer *, real *, integer *, |
|
real *, real *, real *, real *, integer *, integer *, integer *, |
|
integer *, real *, real *, real *, real *, integer *, integer *), |
|
xerbla_(char *, integer *); |
|
extern integer ilaenv_(integer *, char *, char *, integer *, integer *, |
|
integer *, integer *); |
|
extern /* Subroutine */ int slascl_(char *, integer *, integer *, real *, |
|
real *, integer *, integer *, real *, integer *, integer *); |
|
integer givcol; |
|
extern /* Subroutine */ int slasdq_(char *, integer *, integer *, integer |
|
*, integer *, integer *, real *, real *, real *, integer *, real * |
|
, integer *, real *, integer *, real *, integer *); |
|
integer icompq; |
|
extern /* Subroutine */ int slaset_(char *, integer *, integer *, real *, |
|
real *, real *, integer *), slartg_(real *, real *, real * |
|
, real *, real *); |
|
real orgnrm; |
|
integer givnum; |
|
extern doublereal slanst_(char *, integer *, real *, real *); |
|
integer givptr, qstart, smlsiz, wstart, smlszp; |
|
|
|
|
|
/* -- LAPACK routine (version 3.2) -- */ |
|
/* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */ |
|
/* November 2006 */ |
|
|
|
/* .. Scalar Arguments .. */ |
|
/* .. */ |
|
/* .. Array Arguments .. */ |
|
/* .. */ |
|
|
|
/* Purpose */ |
|
/* ======= */ |
|
|
|
/* SBDSDC computes the singular value decomposition (SVD) of a real */ |
|
/* N-by-N (upper or lower) bidiagonal matrix B: B = U * S * VT, */ |
|
/* using a divide and conquer method, where S is a diagonal matrix */ |
|
/* with non-negative diagonal elements (the singular values of B), and */ |
|
/* U and VT are orthogonal matrices of left and right singular vectors, */ |
|
/* respectively. SBDSDC can be used to compute all singular values, */ |
|
/* and optionally, singular vectors or singular vectors in compact form. */ |
|
|
|
/* This code makes very mild assumptions about floating point */ |
|
/* arithmetic. It will work on machines with a guard digit in */ |
|
/* add/subtract, or on those binary machines without guard digits */ |
|
/* which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. */ |
|
/* It could conceivably fail on hexadecimal or decimal machines */ |
|
/* without guard digits, but we know of none. See SLASD3 for details. */ |
|
|
|
/* The code currently calls SLASDQ if singular values only are desired. */ |
|
/* However, it can be slightly modified to compute singular values */ |
|
/* using the divide and conquer method. */ |
|
|
|
/* Arguments */ |
|
/* ========= */ |
|
|
|
/* UPLO (input) CHARACTER*1 */ |
|
/* = 'U': B is upper bidiagonal. */ |
|
/* = 'L': B is lower bidiagonal. */ |
|
|
|
/* COMPQ (input) CHARACTER*1 */ |
|
/* Specifies whether singular vectors are to be computed */ |
|
/* as follows: */ |
|
/* = 'N': Compute singular values only; */ |
|
/* = 'P': Compute singular values and compute singular */ |
|
/* vectors in compact form; */ |
|
/* = 'I': Compute singular values and singular vectors. */ |
|
|
|
/* N (input) INTEGER */ |
|
/* The order of the matrix B. N >= 0. */ |
|
|
|
/* D (input/output) REAL array, dimension (N) */ |
|
/* On entry, the n diagonal elements of the bidiagonal matrix B. */ |
|
/* On exit, if INFO=0, the singular values of B. */ |
|
|
|
/* E (input/output) REAL array, dimension (N-1) */ |
|
/* On entry, the elements of E contain the offdiagonal */ |
|
/* elements of the bidiagonal matrix whose SVD is desired. */ |
|
/* On exit, E has been destroyed. */ |
|
|
|
/* U (output) REAL array, dimension (LDU,N) */ |
|
/* If COMPQ = 'I', then: */ |
|
/* On exit, if INFO = 0, U contains the left singular vectors */ |
|
/* of the bidiagonal matrix. */ |
|
/* For other values of COMPQ, U is not referenced. */ |
|
|
|
/* LDU (input) INTEGER */ |
|
/* The leading dimension of the array U. LDU >= 1. */ |
|
/* If singular vectors are desired, then LDU >= max( 1, N ). */ |
|
|
|
/* VT (output) REAL array, dimension (LDVT,N) */ |
|
/* If COMPQ = 'I', then: */ |
|
/* On exit, if INFO = 0, VT' contains the right singular */ |
|
/* vectors of the bidiagonal matrix. */ |
|
/* For other values of COMPQ, VT is not referenced. */ |
|
|
|
/* LDVT (input) INTEGER */ |
|
/* The leading dimension of the array VT. LDVT >= 1. */ |
|
/* If singular vectors are desired, then LDVT >= max( 1, N ). */ |
|
|
|
/* Q (output) REAL array, dimension (LDQ) */ |
|
/* If COMPQ = 'P', then: */ |
|
/* On exit, if INFO = 0, Q and IQ contain the left */ |
|
/* and right singular vectors in a compact form, */ |
|
/* requiring O(N log N) space instead of 2*N**2. */ |
|
/* In particular, Q contains all the REAL data in */ |
|
/* LDQ >= N*(11 + 2*SMLSIZ + 8*INT(LOG_2(N/(SMLSIZ+1)))) */ |
|
/* words of memory, where SMLSIZ is returned by ILAENV and */ |
|
/* is equal to the maximum size of the subproblems at the */ |
|
/* bottom of the computation tree (usually about 25). */ |
|
/* For other values of COMPQ, Q is not referenced. */ |
|
|
|
/* IQ (output) INTEGER array, dimension (LDIQ) */ |
|
/* If COMPQ = 'P', then: */ |
|
/* On exit, if INFO = 0, Q and IQ contain the left */ |
|
/* and right singular vectors in a compact form, */ |
|
/* requiring O(N log N) space instead of 2*N**2. */ |
|
/* In particular, IQ contains all INTEGER data in */ |
|
/* LDIQ >= N*(3 + 3*INT(LOG_2(N/(SMLSIZ+1)))) */ |
|
/* words of memory, where SMLSIZ is returned by ILAENV and */ |
|
/* is equal to the maximum size of the subproblems at the */ |
|
/* bottom of the computation tree (usually about 25). */ |
|
/* For other values of COMPQ, IQ is not referenced. */ |
|
|
|
/* WORK (workspace) REAL array, dimension (MAX(1,LWORK)) */ |
|
/* If COMPQ = 'N' then LWORK >= (4 * N). */ |
|
/* If COMPQ = 'P' then LWORK >= (6 * N). */ |
|
/* If COMPQ = 'I' then LWORK >= (3 * N**2 + 4 * N). */ |
|
|
|
/* IWORK (workspace) INTEGER array, dimension (8*N) */ |
|
|
|
/* INFO (output) INTEGER */ |
|
/* = 0: successful exit. */ |
|
/* < 0: if INFO = -i, the i-th argument had an illegal value. */ |
|
/* > 0: The algorithm failed to compute an singular value. */ |
|
/* The update process of divide and conquer failed. */ |
|
|
|
/* Further Details */ |
|
/* =============== */ |
|
|
|
/* Based on contributions by */ |
|
/* Ming Gu and Huan Ren, Computer Science Division, University of */ |
|
/* California at Berkeley, USA */ |
|
/* ===================================================================== */ |
|
/* Changed dimension statement in comment describing E from (N) to */ |
|
/* (N-1). Sven, 17 Feb 05. */ |
|
/* ===================================================================== */ |
|
|
|
/* .. Parameters .. */ |
|
/* .. */ |
|
/* .. Local Scalars .. */ |
|
/* .. */ |
|
/* .. External Functions .. */ |
|
/* .. */ |
|
/* .. External Subroutines .. */ |
|
/* .. */ |
|
/* .. Intrinsic Functions .. */ |
|
/* .. */ |
|
/* .. Executable Statements .. */ |
|
|
|
/* Test the input parameters. */ |
|
|
|
/* Parameter adjustments */ |
|
--d__; |
|
--e; |
|
u_dim1 = *ldu; |
|
u_offset = 1 + u_dim1; |
|
u -= u_offset; |
|
vt_dim1 = *ldvt; |
|
vt_offset = 1 + vt_dim1; |
|
vt -= vt_offset; |
|
--q; |
|
--iq; |
|
--work; |
|
--iwork; |
|
|
|
/* Function Body */ |
|
*info = 0; |
|
|
|
iuplo = 0; |
|
if (lsame_(uplo, "U")) { |
|
iuplo = 1; |
|
} |
|
if (lsame_(uplo, "L")) { |
|
iuplo = 2; |
|
} |
|
if (lsame_(compq, "N")) { |
|
icompq = 0; |
|
} else if (lsame_(compq, "P")) { |
|
icompq = 1; |
|
} else if (lsame_(compq, "I")) { |
|
icompq = 2; |
|
} else { |
|
icompq = -1; |
|
} |
|
if (iuplo == 0) { |
|
*info = -1; |
|
} else if (icompq < 0) { |
|
*info = -2; |
|
} else if (*n < 0) { |
|
*info = -3; |
|
} else if (*ldu < 1 || icompq == 2 && *ldu < *n) { |
|
*info = -7; |
|
} else if (*ldvt < 1 || icompq == 2 && *ldvt < *n) { |
|
*info = -9; |
|
} |
|
if (*info != 0) { |
|
i__1 = -(*info); |
|
xerbla_("SBDSDC", &i__1); |
|
return 0; |
|
} |
|
|
|
/* Quick return if possible */ |
|
|
|
if (*n == 0) { |
|
return 0; |
|
} |
|
smlsiz = ilaenv_(&c__9, "SBDSDC", " ", &c__0, &c__0, &c__0, &c__0); |
|
if (*n == 1) { |
|
if (icompq == 1) { |
|
q[1] = r_sign(&c_b15, &d__[1]); |
|
q[smlsiz * *n + 1] = 1.f; |
|
} else if (icompq == 2) { |
|
u[u_dim1 + 1] = r_sign(&c_b15, &d__[1]); |
|
vt[vt_dim1 + 1] = 1.f; |
|
} |
|
d__[1] = dabs(d__[1]); |
|
return 0; |
|
} |
|
nm1 = *n - 1; |
|
|
|
/* If matrix lower bidiagonal, rotate to be upper bidiagonal */ |
|
/* by applying Givens rotations on the left */ |
|
|
|
wstart = 1; |
|
qstart = 3; |
|
if (icompq == 1) { |
|
scopy_(n, &d__[1], &c__1, &q[1], &c__1); |
|
i__1 = *n - 1; |
|
scopy_(&i__1, &e[1], &c__1, &q[*n + 1], &c__1); |
|
} |
|
if (iuplo == 2) { |
|
qstart = 5; |
|
wstart = (*n << 1) - 1; |
|
i__1 = *n - 1; |
|
for (i__ = 1; i__ <= i__1; ++i__) { |
|
slartg_(&d__[i__], &e[i__], &cs, &sn, &r__); |
|
d__[i__] = r__; |
|
e[i__] = sn * d__[i__ + 1]; |
|
d__[i__ + 1] = cs * d__[i__ + 1]; |
|
if (icompq == 1) { |
|
q[i__ + (*n << 1)] = cs; |
|
q[i__ + *n * 3] = sn; |
|
} else if (icompq == 2) { |
|
work[i__] = cs; |
|
work[nm1 + i__] = -sn; |
|
} |
|
/* L10: */ |
|
} |
|
} |
|
|
|
/* If ICOMPQ = 0, use SLASDQ to compute the singular values. */ |
|
|
|
if (icompq == 0) { |
|
slasdq_("U", &c__0, n, &c__0, &c__0, &c__0, &d__[1], &e[1], &vt[ |
|
vt_offset], ldvt, &u[u_offset], ldu, &u[u_offset], ldu, &work[ |
|
wstart], info); |
|
goto L40; |
|
} |
|
|
|
/* If N is smaller than the minimum divide size SMLSIZ, then solve */ |
|
/* the problem with another solver. */ |
|
|
|
if (*n <= smlsiz) { |
|
if (icompq == 2) { |
|
slaset_("A", n, n, &c_b29, &c_b15, &u[u_offset], ldu); |
|
slaset_("A", n, n, &c_b29, &c_b15, &vt[vt_offset], ldvt); |
|
slasdq_("U", &c__0, n, n, n, &c__0, &d__[1], &e[1], &vt[vt_offset] |
|
, ldvt, &u[u_offset], ldu, &u[u_offset], ldu, &work[ |
|
wstart], info); |
|
} else if (icompq == 1) { |
|
iu = 1; |
|
ivt = iu + *n; |
|
slaset_("A", n, n, &c_b29, &c_b15, &q[iu + (qstart - 1) * *n], n); |
|
slaset_("A", n, n, &c_b29, &c_b15, &q[ivt + (qstart - 1) * *n], n); |
|
slasdq_("U", &c__0, n, n, n, &c__0, &d__[1], &e[1], &q[ivt + ( |
|
qstart - 1) * *n], n, &q[iu + (qstart - 1) * *n], n, &q[ |
|
iu + (qstart - 1) * *n], n, &work[wstart], info); |
|
} |
|
goto L40; |
|
} |
|
|
|
if (icompq == 2) { |
|
slaset_("A", n, n, &c_b29, &c_b15, &u[u_offset], ldu); |
|
slaset_("A", n, n, &c_b29, &c_b15, &vt[vt_offset], ldvt); |
|
} |
|
|
|
/* Scale. */ |
|
|
|
orgnrm = slanst_("M", n, &d__[1], &e[1]); |
|
if (orgnrm == 0.f) { |
|
return 0; |
|
} |
|
slascl_("G", &c__0, &c__0, &orgnrm, &c_b15, n, &c__1, &d__[1], n, &ierr); |
|
slascl_("G", &c__0, &c__0, &orgnrm, &c_b15, &nm1, &c__1, &e[1], &nm1, & |
|
ierr); |
|
|
|
eps = slamch_("Epsilon"); |
|
|
|
mlvl = (integer) (log((real) (*n) / (real) (smlsiz + 1)) / log(2.f)) + 1; |
|
smlszp = smlsiz + 1; |
|
|
|
if (icompq == 1) { |
|
iu = 1; |
|
ivt = smlsiz + 1; |
|
difl = ivt + smlszp; |
|
difr = difl + mlvl; |
|
z__ = difr + (mlvl << 1); |
|
ic = z__ + mlvl; |
|
is = ic + 1; |
|
poles = is + 1; |
|
givnum = poles + (mlvl << 1); |
|
|
|
k = 1; |
|
givptr = 2; |
|
perm = 3; |
|
givcol = perm + mlvl; |
|
} |
|
|
|
i__1 = *n; |
|
for (i__ = 1; i__ <= i__1; ++i__) { |
|
if ((r__1 = d__[i__], dabs(r__1)) < eps) { |
|
d__[i__] = r_sign(&eps, &d__[i__]); |
|
} |
|
/* L20: */ |
|
} |
|
|
|
start = 1; |
|
sqre = 0; |
|
|
|
i__1 = nm1; |
|
for (i__ = 1; i__ <= i__1; ++i__) { |
|
if ((r__1 = e[i__], dabs(r__1)) < eps || i__ == nm1) { |
|
|
|
/* Subproblem found. First determine its size and then */ |
|
/* apply divide and conquer on it. */ |
|
|
|
if (i__ < nm1) { |
|
|
|
/* A subproblem with E(I) small for I < NM1. */ |
|
|
|
nsize = i__ - start + 1; |
|
} else if ((r__1 = e[i__], dabs(r__1)) >= eps) { |
|
|
|
/* A subproblem with E(NM1) not too small but I = NM1. */ |
|
|
|
nsize = *n - start + 1; |
|
} else { |
|
|
|
/* A subproblem with E(NM1) small. This implies an */ |
|
/* 1-by-1 subproblem at D(N). Solve this 1-by-1 problem */ |
|
/* first. */ |
|
|
|
nsize = i__ - start + 1; |
|
if (icompq == 2) { |
|
u[*n + *n * u_dim1] = r_sign(&c_b15, &d__[*n]); |
|
vt[*n + *n * vt_dim1] = 1.f; |
|
} else if (icompq == 1) { |
|
q[*n + (qstart - 1) * *n] = r_sign(&c_b15, &d__[*n]); |
|
q[*n + (smlsiz + qstart - 1) * *n] = 1.f; |
|
} |
|
d__[*n] = (r__1 = d__[*n], dabs(r__1)); |
|
} |
|
if (icompq == 2) { |
|
slasd0_(&nsize, &sqre, &d__[start], &e[start], &u[start + |
|
start * u_dim1], ldu, &vt[start + start * vt_dim1], |
|
ldvt, &smlsiz, &iwork[1], &work[wstart], info); |
|
} else { |
|
slasda_(&icompq, &smlsiz, &nsize, &sqre, &d__[start], &e[ |
|
start], &q[start + (iu + qstart - 2) * *n], n, &q[ |
|
start + (ivt + qstart - 2) * *n], &iq[start + k * *n], |
|
&q[start + (difl + qstart - 2) * *n], &q[start + ( |
|
difr + qstart - 2) * *n], &q[start + (z__ + qstart - |
|
2) * *n], &q[start + (poles + qstart - 2) * *n], &iq[ |
|
start + givptr * *n], &iq[start + givcol * *n], n, & |
|
iq[start + perm * *n], &q[start + (givnum + qstart - |
|
2) * *n], &q[start + (ic + qstart - 2) * *n], &q[ |
|
start + (is + qstart - 2) * *n], &work[wstart], & |
|
iwork[1], info); |
|
if (*info != 0) { |
|
return 0; |
|
} |
|
} |
|
start = i__ + 1; |
|
} |
|
/* L30: */ |
|
} |
|
|
|
/* Unscale */ |
|
|
|
slascl_("G", &c__0, &c__0, &c_b15, &orgnrm, n, &c__1, &d__[1], n, &ierr); |
|
L40: |
|
|
|
/* Use Selection Sort to minimize swaps of singular vectors */ |
|
|
|
i__1 = *n; |
|
for (ii = 2; ii <= i__1; ++ii) { |
|
i__ = ii - 1; |
|
kk = i__; |
|
p = d__[i__]; |
|
i__2 = *n; |
|
for (j = ii; j <= i__2; ++j) { |
|
if (d__[j] > p) { |
|
kk = j; |
|
p = d__[j]; |
|
} |
|
/* L50: */ |
|
} |
|
if (kk != i__) { |
|
d__[kk] = d__[i__]; |
|
d__[i__] = p; |
|
if (icompq == 1) { |
|
iq[i__] = kk; |
|
} else if (icompq == 2) { |
|
sswap_(n, &u[i__ * u_dim1 + 1], &c__1, &u[kk * u_dim1 + 1], & |
|
c__1); |
|
sswap_(n, &vt[i__ + vt_dim1], ldvt, &vt[kk + vt_dim1], ldvt); |
|
} |
|
} else if (icompq == 1) { |
|
iq[i__] = i__; |
|
} |
|
/* L60: */ |
|
} |
|
|
|
/* If ICOMPQ = 1, use IQ(N,1) as the indicator for UPLO */ |
|
|
|
if (icompq == 1) { |
|
if (iuplo == 1) { |
|
iq[*n] = 1; |
|
} else { |
|
iq[*n] = 0; |
|
} |
|
} |
|
|
|
/* If B is lower bidiagonal, update U by those Givens rotations */ |
|
/* which rotated B to be upper bidiagonal */ |
|
|
|
if (iuplo == 2 && icompq == 2) { |
|
slasr_("L", "V", "B", n, n, &work[1], &work[*n], &u[u_offset], ldu); |
|
} |
|
|
|
return 0; |
|
|
|
/* End of SBDSDC */ |
|
|
|
} /* sbdsdc_ */
|
|
|