diff options
author | shmel1k <shmel1k@ydb.tech> | 2022-09-02 12:44:59 +0300 |
---|---|---|
committer | shmel1k <shmel1k@ydb.tech> | 2022-09-02 12:44:59 +0300 |
commit | 90d450f74722da7859d6f510a869f6c6908fd12f (patch) | |
tree | 538c718dedc76cdfe37ad6d01ff250dd930d9278 /contrib/libs/clapack/cstedc.c | |
parent | 01f64c1ecd0d4ffa9e3a74478335f1745f26cc75 (diff) | |
download | ydb-90d450f74722da7859d6f510a869f6c6908fd12f.tar.gz |
[] add metering mode to CLI
Diffstat (limited to 'contrib/libs/clapack/cstedc.c')
-rw-r--r-- | contrib/libs/clapack/cstedc.c | 496 |
1 files changed, 496 insertions, 0 deletions
diff --git a/contrib/libs/clapack/cstedc.c b/contrib/libs/clapack/cstedc.c new file mode 100644 index 0000000000..6c499a474d --- /dev/null +++ b/contrib/libs/clapack/cstedc.c @@ -0,0 +1,496 @@ +/* cstedc.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 "f2c.h" +#include "blaswrap.h" + +/* Table of constant values */ + +static integer c__9 = 9; +static integer c__0 = 0; +static integer c__2 = 2; +static real c_b17 = 0.f; +static real c_b18 = 1.f; +static integer c__1 = 1; + +/* Subroutine */ int cstedc_(char *compz, integer *n, real *d__, real *e, + complex *z__, integer *ldz, complex *work, integer *lwork, real * + rwork, integer *lrwork, integer *iwork, integer *liwork, integer * + info) +{ + /* System generated locals */ + integer z_dim1, z_offset, i__1, i__2, i__3, i__4; + real r__1, r__2; + + /* Builtin functions */ + double log(doublereal); + integer pow_ii(integer *, integer *); + double sqrt(doublereal); + + /* Local variables */ + integer i__, j, k, m; + real p; + integer ii, ll, lgn; + real eps, tiny; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int cswap_(integer *, complex *, integer *, + complex *, integer *); + integer lwmin; + extern /* Subroutine */ int claed0_(integer *, integer *, real *, real *, + complex *, integer *, complex *, integer *, real *, integer *, + integer *); + integer start; + extern /* Subroutine */ int clacrm_(integer *, integer *, complex *, + integer *, real *, integer *, complex *, integer *, real *); + extern doublereal slamch_(char *); + extern /* Subroutine */ int clacpy_(char *, integer *, integer *, complex + *, integer *, complex *, integer *), xerbla_(char *, + integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *); + integer finish; + extern /* Subroutine */ int slascl_(char *, integer *, integer *, real *, + real *, integer *, integer *, real *, integer *, integer *), sstedc_(char *, integer *, real *, real *, real *, + integer *, real *, integer *, integer *, integer *, integer *), slaset_(char *, integer *, integer *, real *, real *, + real *, integer *); + integer liwmin, icompz; + extern /* Subroutine */ int csteqr_(char *, integer *, real *, real *, + complex *, integer *, real *, integer *); + real orgnrm; + extern doublereal slanst_(char *, integer *, real *, real *); + extern /* Subroutine */ int ssterf_(integer *, real *, real *, integer *); + integer lrwmin; + logical lquery; + integer smlsiz; + extern /* Subroutine */ int ssteqr_(char *, integer *, real *, real *, + real *, integer *, real *, integer *); + + +/* -- LAPACK routine (version 3.2) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */ +/* November 2006 */ + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* CSTEDC computes all eigenvalues and, optionally, eigenvectors of a */ +/* symmetric tridiagonal matrix using the divide and conquer method. */ +/* The eigenvectors of a full or band complex Hermitian matrix can also */ +/* be found if CHETRD or CHPTRD or CHBTRD has been used to reduce this */ +/* matrix to tridiagonal 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 SLAED3 for details. */ + +/* Arguments */ +/* ========= */ + +/* COMPZ (input) CHARACTER*1 */ +/* = 'N': Compute eigenvalues only. */ +/* = 'I': Compute eigenvectors of tridiagonal matrix also. */ +/* = 'V': Compute eigenvectors of original Hermitian matrix */ +/* also. On entry, Z contains the unitary matrix used */ +/* to reduce the original matrix to tridiagonal form. */ + +/* N (input) INTEGER */ +/* The dimension of the symmetric tridiagonal matrix. N >= 0. */ + +/* D (input/output) REAL array, dimension (N) */ +/* On entry, the diagonal elements of the tridiagonal matrix. */ +/* On exit, if INFO = 0, the eigenvalues in ascending order. */ + +/* E (input/output) REAL array, dimension (N-1) */ +/* On entry, the subdiagonal elements of the tridiagonal matrix. */ +/* On exit, E has been destroyed. */ + +/* Z (input/output) COMPLEX array, dimension (LDZ,N) */ +/* On entry, if COMPZ = 'V', then Z contains the unitary */ +/* matrix used in the reduction to tridiagonal form. */ +/* On exit, if INFO = 0, then if COMPZ = 'V', Z contains the */ +/* orthonormal eigenvectors of the original Hermitian matrix, */ +/* and if COMPZ = 'I', Z contains the orthonormal eigenvectors */ +/* of the symmetric tridiagonal matrix. */ +/* If COMPZ = 'N', then Z is not referenced. */ + +/* LDZ (input) INTEGER */ +/* The leading dimension of the array Z. LDZ >= 1. */ +/* If eigenvectors are desired, then LDZ >= max(1,N). */ + +/* WORK (workspace/output) COMPLEX array, dimension (MAX(1,LWORK)) */ +/* On exit, if INFO = 0, WORK(1) returns the optimal LWORK. */ + +/* LWORK (input) INTEGER */ +/* The dimension of the array WORK. */ +/* If COMPZ = 'N' or 'I', or N <= 1, LWORK must be at least 1. */ +/* If COMPZ = 'V' and N > 1, LWORK must be at least N*N. */ +/* Note that for COMPZ = 'V', then if N is less than or */ +/* equal to the minimum divide size, usually 25, then LWORK need */ +/* only be 1. */ + +/* If LWORK = -1, then a workspace query is assumed; the routine */ +/* only calculates the optimal sizes of the WORK, RWORK and */ +/* IWORK arrays, returns these values as the first entries of */ +/* the WORK, RWORK and IWORK arrays, and no error message */ +/* related to LWORK or LRWORK or LIWORK is issued by XERBLA. */ + +/* RWORK (workspace/output) REAL array, dimension (MAX(1,LRWORK)) */ +/* On exit, if INFO = 0, RWORK(1) returns the optimal LRWORK. */ + +/* LRWORK (input) INTEGER */ +/* The dimension of the array RWORK. */ +/* If COMPZ = 'N' or N <= 1, LRWORK must be at least 1. */ +/* If COMPZ = 'V' and N > 1, LRWORK must be at least */ +/* 1 + 3*N + 2*N*lg N + 3*N**2 , */ +/* where lg( N ) = smallest integer k such */ +/* that 2**k >= N. */ +/* If COMPZ = 'I' and N > 1, LRWORK must be at least */ +/* 1 + 4*N + 2*N**2 . */ +/* Note that for COMPZ = 'I' or 'V', then if N is less than or */ +/* equal to the minimum divide size, usually 25, then LRWORK */ +/* need only be max(1,2*(N-1)). */ + +/* If LRWORK = -1, then a workspace query is assumed; the */ +/* routine only calculates the optimal sizes of the WORK, RWORK */ +/* and IWORK arrays, returns these values as the first entries */ +/* of the WORK, RWORK and IWORK arrays, and no error message */ +/* related to LWORK or LRWORK or LIWORK is issued by XERBLA. */ + +/* IWORK (workspace/output) INTEGER array, dimension (MAX(1,LIWORK)) */ +/* On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK. */ + +/* LIWORK (input) INTEGER */ +/* The dimension of the array IWORK. */ +/* If COMPZ = 'N' or N <= 1, LIWORK must be at least 1. */ +/* If COMPZ = 'V' or N > 1, LIWORK must be at least */ +/* 6 + 6*N + 5*N*lg N. */ +/* If COMPZ = 'I' or N > 1, LIWORK must be at least */ +/* 3 + 5*N . */ +/* Note that for COMPZ = 'I' or 'V', then if N is less than or */ +/* equal to the minimum divide size, usually 25, then LIWORK */ +/* need only be 1. */ + +/* If LIWORK = -1, then a workspace query is assumed; the */ +/* routine only calculates the optimal sizes of the WORK, RWORK */ +/* and IWORK arrays, returns these values as the first entries */ +/* of the WORK, RWORK and IWORK arrays, and no error message */ +/* related to LWORK or LRWORK or LIWORK is issued by XERBLA. */ + +/* 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 eigenvalue while */ +/* working on the submatrix lying in rows and columns */ +/* INFO/(N+1) through mod(INFO,N+1). */ + +/* Further Details */ +/* =============== */ + +/* Based on contributions by */ +/* Jeff Rutter, Computer Science Division, University of California */ +/* at Berkeley, USA */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ +/* .. Executable Statements .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + --d__; + --e; + z_dim1 = *ldz; + z_offset = 1 + z_dim1; + z__ -= z_offset; + --work; + --rwork; + --iwork; + + /* Function Body */ + *info = 0; + lquery = *lwork == -1 || *lrwork == -1 || *liwork == -1; + + if (lsame_(compz, "N")) { + icompz = 0; + } else if (lsame_(compz, "V")) { + icompz = 1; + } else if (lsame_(compz, "I")) { + icompz = 2; + } else { + icompz = -1; + } + if (icompz < 0) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*ldz < 1 || icompz > 0 && *ldz < max(1,*n)) { + *info = -6; + } + + if (*info == 0) { + +/* Compute the workspace requirements */ + + smlsiz = ilaenv_(&c__9, "CSTEDC", " ", &c__0, &c__0, &c__0, &c__0); + if (*n <= 1 || icompz == 0) { + lwmin = 1; + liwmin = 1; + lrwmin = 1; + } else if (*n <= smlsiz) { + lwmin = 1; + liwmin = 1; + lrwmin = *n - 1 << 1; + } else if (icompz == 1) { + lgn = (integer) (log((real) (*n)) / log(2.f)); + if (pow_ii(&c__2, &lgn) < *n) { + ++lgn; + } + if (pow_ii(&c__2, &lgn) < *n) { + ++lgn; + } + lwmin = *n * *n; +/* Computing 2nd power */ + i__1 = *n; + lrwmin = *n * 3 + 1 + (*n << 1) * lgn + i__1 * i__1 * 3; + liwmin = *n * 6 + 6 + *n * 5 * lgn; + } else if (icompz == 2) { + lwmin = 1; +/* Computing 2nd power */ + i__1 = *n; + lrwmin = (*n << 2) + 1 + (i__1 * i__1 << 1); + liwmin = *n * 5 + 3; + } + work[1].r = (real) lwmin, work[1].i = 0.f; + rwork[1] = (real) lrwmin; + iwork[1] = liwmin; + + if (*lwork < lwmin && ! lquery) { + *info = -8; + } else if (*lrwork < lrwmin && ! lquery) { + *info = -10; + } else if (*liwork < liwmin && ! lquery) { + *info = -12; + } + } + + if (*info != 0) { + i__1 = -(*info); + xerbla_("CSTEDC", &i__1); + return 0; + } else if (lquery) { + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + if (*n == 1) { + if (icompz != 0) { + i__1 = z_dim1 + 1; + z__[i__1].r = 1.f, z__[i__1].i = 0.f; + } + return 0; + } + +/* If the following conditional clause is removed, then the routine */ +/* will use the Divide and Conquer routine to compute only the */ +/* eigenvalues, which requires (3N + 3N**2) real workspace and */ +/* (2 + 5N + 2N lg(N)) integer workspace. */ +/* Since on many architectures SSTERF is much faster than any other */ +/* algorithm for finding eigenvalues only, it is used here */ +/* as the default. If the conditional clause is removed, then */ +/* information on the size of workspace needs to be changed. */ + +/* If COMPZ = 'N', use SSTERF to compute the eigenvalues. */ + + if (icompz == 0) { + ssterf_(n, &d__[1], &e[1], info); + goto L70; + } + +/* If N is smaller than the minimum divide size (SMLSIZ+1), then */ +/* solve the problem with another solver. */ + + if (*n <= smlsiz) { + + csteqr_(compz, n, &d__[1], &e[1], &z__[z_offset], ldz, &rwork[1], + info); + + } else { + +/* If COMPZ = 'I', we simply call SSTEDC instead. */ + + if (icompz == 2) { + slaset_("Full", n, n, &c_b17, &c_b18, &rwork[1], n); + ll = *n * *n + 1; + i__1 = *lrwork - ll + 1; + sstedc_("I", n, &d__[1], &e[1], &rwork[1], n, &rwork[ll], &i__1, & + iwork[1], liwork, info); + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__ + j * z_dim1; + i__4 = (j - 1) * *n + i__; + z__[i__3].r = rwork[i__4], z__[i__3].i = 0.f; +/* L10: */ + } +/* L20: */ + } + goto L70; + } + +/* From now on, only option left to be handled is COMPZ = 'V', */ +/* i.e. ICOMPZ = 1. */ + +/* Scale. */ + + orgnrm = slanst_("M", n, &d__[1], &e[1]); + if (orgnrm == 0.f) { + goto L70; + } + + eps = slamch_("Epsilon"); + + start = 1; + +/* while ( START <= N ) */ + +L30: + if (start <= *n) { + +/* Let FINISH be the position of the next subdiagonal entry */ +/* such that E( FINISH ) <= TINY or FINISH = N if no such */ +/* subdiagonal exists. The matrix identified by the elements */ +/* between START and FINISH constitutes an independent */ +/* sub-problem. */ + + finish = start; +L40: + if (finish < *n) { + tiny = eps * sqrt((r__1 = d__[finish], dabs(r__1))) * sqrt(( + r__2 = d__[finish + 1], dabs(r__2))); + if ((r__1 = e[finish], dabs(r__1)) > tiny) { + ++finish; + goto L40; + } + } + +/* (Sub) Problem determined. Compute its size and solve it. */ + + m = finish - start + 1; + if (m > smlsiz) { + +/* Scale. */ + + orgnrm = slanst_("M", &m, &d__[start], &e[start]); + slascl_("G", &c__0, &c__0, &orgnrm, &c_b18, &m, &c__1, &d__[ + start], &m, info); + i__1 = m - 1; + i__2 = m - 1; + slascl_("G", &c__0, &c__0, &orgnrm, &c_b18, &i__1, &c__1, &e[ + start], &i__2, info); + + claed0_(n, &m, &d__[start], &e[start], &z__[start * z_dim1 + + 1], ldz, &work[1], n, &rwork[1], &iwork[1], info); + if (*info > 0) { + *info = (*info / (m + 1) + start - 1) * (*n + 1) + *info % + (m + 1) + start - 1; + goto L70; + } + +/* Scale back. */ + + slascl_("G", &c__0, &c__0, &c_b18, &orgnrm, &m, &c__1, &d__[ + start], &m, info); + + } else { + ssteqr_("I", &m, &d__[start], &e[start], &rwork[1], &m, & + rwork[m * m + 1], info); + clacrm_(n, &m, &z__[start * z_dim1 + 1], ldz, &rwork[1], &m, & + work[1], n, &rwork[m * m + 1]); + clacpy_("A", n, &m, &work[1], n, &z__[start * z_dim1 + 1], + ldz); + if (*info > 0) { + *info = start * (*n + 1) + finish; + goto L70; + } + } + + start = finish + 1; + goto L30; + } + +/* endwhile */ + +/* If the problem split any number of times, then the eigenvalues */ +/* will not be properly ordered. Here we permute the eigenvalues */ +/* (and the associated eigenvectors) into ascending order. */ + + if (m != *n) { + +/* Use Selection Sort to minimize swaps of eigenvectors */ + + i__1 = *n; + for (ii = 2; ii <= i__1; ++ii) { + i__ = ii - 1; + k = i__; + p = d__[i__]; + i__2 = *n; + for (j = ii; j <= i__2; ++j) { + if (d__[j] < p) { + k = j; + p = d__[j]; + } +/* L50: */ + } + if (k != i__) { + d__[k] = d__[i__]; + d__[i__] = p; + cswap_(n, &z__[i__ * z_dim1 + 1], &c__1, &z__[k * z_dim1 + + 1], &c__1); + } +/* L60: */ + } + } + } + +L70: + work[1].r = (real) lwmin, work[1].i = 0.f; + rwork[1] = (real) lrwmin; + iwork[1] = liwmin; + + return 0; + +/* End of CSTEDC */ + +} /* cstedc_ */ |