packages feed

haskell-igraph-0.8.0: igraph/src/dtrsen.c

/*  -- translated by f2c (version 20100827).
   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"

/* Table of constant values */

static integer c_n1 = -1;

/* > \brief \b DTRSEN   

    =========== DOCUMENTATION ===========   

   Online html documentation available at   
              http://www.netlib.org/lapack/explore-html/   

   > \htmlonly   
   > Download DTRSEN + dependencies   
   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dtrsen.
f">   
   > [TGZ]</a>   
   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dtrsen.
f">   
   > [ZIP]</a>   
   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dtrsen.
f">   
   > [TXT]</a>   
   > \endhtmlonly   

    Definition:   
    ===========   

         SUBROUTINE DTRSEN( JOB, COMPQ, SELECT, N, T, LDT, Q, LDQ, WR, WI,   
                            M, S, SEP, WORK, LWORK, IWORK, LIWORK, INFO )   

         CHARACTER          COMPQ, JOB   
         INTEGER            INFO, LDQ, LDT, LIWORK, LWORK, M, N   
         DOUBLE PRECISION   S, SEP   
         LOGICAL            SELECT( * )   
         INTEGER            IWORK( * )   
         DOUBLE PRECISION   Q( LDQ, * ), T( LDT, * ), WI( * ), WORK( * ),   
        $                   WR( * )   


   > \par Purpose:   
    =============   
   >   
   > \verbatim   
   >   
   > DTRSEN reorders the real Schur factorization of a real matrix   
   > A = Q*T*Q**T, so that a selected cluster of eigenvalues appears in   
   > the leading diagonal blocks of the upper quasi-triangular matrix T,   
   > and the leading columns of Q form an orthonormal basis of the   
   > corresponding right invariant subspace.   
   >   
   > Optionally the routine computes the reciprocal condition numbers of   
   > the cluster of eigenvalues and/or the invariant subspace.   
   >   
   > T must be in Schur canonical form (as returned by DHSEQR), that is,   
   > block upper triangular with 1-by-1 and 2-by-2 diagonal blocks; each   
   > 2-by-2 diagonal block has its diagonal elements equal and its   
   > off-diagonal elements of opposite sign.   
   > \endverbatim   

    Arguments:   
    ==========   

   > \param[in] JOB   
   > \verbatim   
   >          JOB is CHARACTER*1   
   >          Specifies whether condition numbers are required for the   
   >          cluster of eigenvalues (S) or the invariant subspace (SEP):   
   >          = 'N': none;   
   >          = 'E': for eigenvalues only (S);   
   >          = 'V': for invariant subspace only (SEP);   
   >          = 'B': for both eigenvalues and invariant subspace (S and   
   >                 SEP).   
   > \endverbatim   
   >   
   > \param[in] COMPQ   
   > \verbatim   
   >          COMPQ is CHARACTER*1   
   >          = 'V': update the matrix Q of Schur vectors;   
   >          = 'N': do not update Q.   
   > \endverbatim   
   >   
   > \param[in] SELECT   
   > \verbatim   
   >          SELECT is LOGICAL array, dimension (N)   
   >          SELECT specifies the eigenvalues in the selected cluster. To   
   >          select a real eigenvalue w(j), SELECT(j) must be set to   
   >          .TRUE.. To select a complex conjugate pair of eigenvalues   
   >          w(j) and w(j+1), corresponding to a 2-by-2 diagonal block,   
   >          either SELECT(j) or SELECT(j+1) or both must be set to   
   >          .TRUE.; a complex conjugate pair of eigenvalues must be   
   >          either both included in the cluster or both excluded.   
   > \endverbatim   
   >   
   > \param[in] N   
   > \verbatim   
   >          N is INTEGER   
   >          The order of the matrix T. N >= 0.   
   > \endverbatim   
   >   
   > \param[in,out] T   
   > \verbatim   
   >          T is DOUBLE PRECISION array, dimension (LDT,N)   
   >          On entry, the upper quasi-triangular matrix T, in Schur   
   >          canonical form.   
   >          On exit, T is overwritten by the reordered matrix T, again in   
   >          Schur canonical form, with the selected eigenvalues in the   
   >          leading diagonal blocks.   
   > \endverbatim   
   >   
   > \param[in] LDT   
   > \verbatim   
   >          LDT is INTEGER   
   >          The leading dimension of the array T. LDT >= max(1,N).   
   > \endverbatim   
   >   
   > \param[in,out] Q   
   > \verbatim   
   >          Q is DOUBLE PRECISION array, dimension (LDQ,N)   
   >          On entry, if COMPQ = 'V', the matrix Q of Schur vectors.   
   >          On exit, if COMPQ = 'V', Q has been postmultiplied by the   
   >          orthogonal transformation matrix which reorders T; the   
   >          leading M columns of Q form an orthonormal basis for the   
   >          specified invariant subspace.   
   >          If COMPQ = 'N', Q is not referenced.   
   > \endverbatim   
   >   
   > \param[in] LDQ   
   > \verbatim   
   >          LDQ is INTEGER   
   >          The leading dimension of the array Q.   
   >          LDQ >= 1; and if COMPQ = 'V', LDQ >= N.   
   > \endverbatim   
   >   
   > \param[out] WR   
   > \verbatim   
   >          WR is DOUBLE PRECISION array, dimension (N)   
   > \endverbatim   
   > \param[out] WI   
   > \verbatim   
   >          WI is DOUBLE PRECISION array, dimension (N)   
   >   
   >          The real and imaginary parts, respectively, of the reordered   
   >          eigenvalues of T. The eigenvalues are stored in the same   
   >          order as on the diagonal of T, with WR(i) = T(i,i) and, if   
   >          T(i:i+1,i:i+1) is a 2-by-2 diagonal block, WI(i) > 0 and   
   >          WI(i+1) = -WI(i). Note that if a complex eigenvalue is   
   >          sufficiently ill-conditioned, then its value may differ   
   >          significantly from its value before reordering.   
   > \endverbatim   
   >   
   > \param[out] M   
   > \verbatim   
   >          M is INTEGER   
   >          The dimension of the specified invariant subspace.   
   >          0 < = M <= N.   
   > \endverbatim   
   >   
   > \param[out] S   
   > \verbatim   
   >          S is DOUBLE PRECISION   
   >          If JOB = 'E' or 'B', S is a lower bound on the reciprocal   
   >          condition number for the selected cluster of eigenvalues.   
   >          S cannot underestimate the true reciprocal condition number   
   >          by more than a factor of sqrt(N). If M = 0 or N, S = 1.   
   >          If JOB = 'N' or 'V', S is not referenced.   
   > \endverbatim   
   >   
   > \param[out] SEP   
   > \verbatim   
   >          SEP is DOUBLE PRECISION   
   >          If JOB = 'V' or 'B', SEP is the estimated reciprocal   
   >          condition number of the specified invariant subspace. If   
   >          M = 0 or N, SEP = norm(T).   
   >          If JOB = 'N' or 'E', SEP is not referenced.   
   > \endverbatim   
   >   
   > \param[out] WORK   
   > \verbatim   
   >          WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK))   
   >          On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   
   > \endverbatim   
   >   
   > \param[in] LWORK   
   > \verbatim   
   >          LWORK is INTEGER   
   >          The dimension of the array WORK.   
   >          If JOB = 'N', LWORK >= max(1,N);   
   >          if JOB = 'E', LWORK >= max(1,M*(N-M));   
   >          if JOB = 'V' or 'B', LWORK >= max(1,2*M*(N-M)).   
   >   
   >          If LWORK = -1, then a workspace query is assumed; the routine   
   >          only calculates the optimal size of the WORK array, returns   
   >          this value as the first entry of the WORK array, and no error   
   >          message related to LWORK is issued by XERBLA.   
   > \endverbatim   
   >   
   > \param[out] IWORK   
   > \verbatim   
   >          IWORK is INTEGER array, dimension (MAX(1,LIWORK))   
   >          On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK.   
   > \endverbatim   
   >   
   > \param[in] LIWORK   
   > \verbatim   
   >          LIWORK is INTEGER   
   >          The dimension of the array IWORK.   
   >          If JOB = 'N' or 'E', LIWORK >= 1;   
   >          if JOB = 'V' or 'B', LIWORK >= max(1,M*(N-M)).   
   >   
   >          If LIWORK = -1, then a workspace query is assumed; the   
   >          routine only calculates the optimal size of the IWORK array,   
   >          returns this value as the first entry of the IWORK array, and   
   >          no error message related to LIWORK is issued by XERBLA.   
   > \endverbatim   
   >   
   > \param[out] INFO   
   > \verbatim   
   >          INFO is INTEGER   
   >          = 0: successful exit   
   >          < 0: if INFO = -i, the i-th argument had an illegal value   
   >          = 1: reordering of T failed because some eigenvalues are too   
   >               close to separate (the problem is very ill-conditioned);   
   >               T may have been partially reordered, and WR and WI   
   >               contain the eigenvalues in the same order as in T; S and   
   >               SEP (if requested) are set to zero.   
   > \endverbatim   

    Authors:   
    ========   

   > \author Univ. of Tennessee   
   > \author Univ. of California Berkeley   
   > \author Univ. of Colorado Denver   
   > \author NAG Ltd.   

   > \date April 2012   

   > \ingroup doubleOTHERcomputational   

   > \par Further Details:   
    =====================   
   >   
   > \verbatim   
   >   
   >  DTRSEN first collects the selected eigenvalues by computing an   
   >  orthogonal transformation Z to move them to the top left corner of T.   
   >  In other words, the selected eigenvalues are the eigenvalues of T11   
   >  in:   
   >   
   >          Z**T * T * Z = ( T11 T12 ) n1   
   >                         (  0  T22 ) n2   
   >                            n1  n2   
   >   
   >  where N = n1+n2 and Z**T means the transpose of Z. The first n1 columns   
   >  of Z span the specified invariant subspace of T.   
   >   
   >  If T has been obtained from the real Schur factorization of a matrix   
   >  A = Q*T*Q**T, then the reordered real Schur factorization of A is given   
   >  by A = (Q*Z)*(Z**T*T*Z)*(Q*Z)**T, and the first n1 columns of Q*Z span   
   >  the corresponding invariant subspace of A.   
   >   
   >  The reciprocal condition number of the average of the eigenvalues of   
   >  T11 may be returned in S. S lies between 0 (very badly conditioned)   
   >  and 1 (very well conditioned). It is computed as follows. First we   
   >  compute R so that   
   >   
   >                         P = ( I  R ) n1   
   >                             ( 0  0 ) n2   
   >                               n1 n2   
   >   
   >  is the projector on the invariant subspace associated with T11.   
   >  R is the solution of the Sylvester equation:   
   >   
   >                        T11*R - R*T22 = T12.   
   >   
   >  Let F-norm(M) denote the Frobenius-norm of M and 2-norm(M) denote   
   >  the two-norm of M. Then S is computed as the lower bound   
   >   
   >                      (1 + F-norm(R)**2)**(-1/2)   
   >   
   >  on the reciprocal of 2-norm(P), the true reciprocal condition number.   
   >  S cannot underestimate 1 / 2-norm(P) by more than a factor of   
   >  sqrt(N).   
   >   
   >  An approximate error bound for the computed average of the   
   >  eigenvalues of T11 is   
   >   
   >                         EPS * norm(T) / S   
   >   
   >  where EPS is the machine precision.   
   >   
   >  The reciprocal condition number of the right invariant subspace   
   >  spanned by the first n1 columns of Z (or of Q*Z) is returned in SEP.   
   >  SEP is defined as the separation of T11 and T22:   
   >   
   >                     sep( T11, T22 ) = sigma-min( C )   
   >   
   >  where sigma-min(C) is the smallest singular value of the   
   >  n1*n2-by-n1*n2 matrix   
   >   
   >     C  = kprod( I(n2), T11 ) - kprod( transpose(T22), I(n1) )   
   >   
   >  I(m) is an m by m identity matrix, and kprod denotes the Kronecker   
   >  product. We estimate sigma-min(C) by the reciprocal of an estimate of   
   >  the 1-norm of inverse(C). The true reciprocal 1-norm of inverse(C)   
   >  cannot differ from sigma-min(C) by more than a factor of sqrt(n1*n2).   
   >   
   >  When SEP is small, small changes in T can cause large changes in   
   >  the invariant subspace. An approximate bound on the maximum angular   
   >  error in the computed right invariant subspace is   
   >   
   >                      EPS * norm(T) / SEP   
   > \endverbatim   
   >   
    =====================================================================   
   Subroutine */ int igraphdtrsen_(char *job, char *compq, logical *select, integer 
	*n, doublereal *t, integer *ldt, doublereal *q, integer *ldq, 
	doublereal *wr, doublereal *wi, integer *m, doublereal *s, doublereal 
	*sep, doublereal *work, integer *lwork, integer *iwork, integer *
	liwork, integer *info)
{
    /* System generated locals */
    integer q_dim1, q_offset, t_dim1, t_offset, i__1, i__2;
    doublereal d__1, d__2;

    /* Builtin functions */
    double sqrt(doublereal);

    /* Local variables */
    integer k, n1, n2, kk, nn, ks;
    doublereal est;
    integer kase;
    logical pair;
    integer ierr;
    logical swap;
    doublereal scale;
    extern logical igraphlsame_(char *, char *);
    integer isave[3], lwmin = 0;
    logical wantq, wants;
    doublereal rnorm;
    extern /* Subroutine */ int igraphdlacn2_(integer *, doublereal *, doublereal *,
	     integer *, doublereal *, integer *, integer *);
    extern doublereal igraphdlange_(char *, integer *, integer *, doublereal *, 
	    integer *, doublereal *);
    extern /* Subroutine */ int igraphdlacpy_(char *, integer *, integer *, 
	    doublereal *, integer *, doublereal *, integer *), 
	    igraphxerbla_(char *, integer *, ftnlen);
    logical wantbh;
    extern /* Subroutine */ int igraphdtrexc_(char *, integer *, doublereal *, 
	    integer *, doublereal *, integer *, integer *, integer *, 
	    doublereal *, integer *);
    integer liwmin;
    logical wantsp, lquery;
    extern /* Subroutine */ int igraphdtrsyl_(char *, char *, integer *, integer *, 
	    integer *, doublereal *, integer *, doublereal *, integer *, 
	    doublereal *, integer *, doublereal *, integer *);


/*  -- LAPACK computational routine (version 3.4.1) --   
    -- LAPACK is a software package provided by Univ. of Tennessee,    --   
    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   
       April 2012   


    =====================================================================   


       Decode and test the input parameters   

       Parameter adjustments */
    --select;
    t_dim1 = *ldt;
    t_offset = 1 + t_dim1;
    t -= t_offset;
    q_dim1 = *ldq;
    q_offset = 1 + q_dim1;
    q -= q_offset;
    --wr;
    --wi;
    --work;
    --iwork;

    /* Function Body */
    wantbh = igraphlsame_(job, "B");
    wants = igraphlsame_(job, "E") || wantbh;
    wantsp = igraphlsame_(job, "V") || wantbh;
    wantq = igraphlsame_(compq, "V");

    *info = 0;
    lquery = *lwork == -1;
    if (! igraphlsame_(job, "N") && ! wants && ! wantsp) {
	*info = -1;
    } else if (! igraphlsame_(compq, "N") && ! wantq) {
	*info = -2;
    } else if (*n < 0) {
	*info = -4;
    } else if (*ldt < max(1,*n)) {
	*info = -6;
    } else if (*ldq < 1 || wantq && *ldq < *n) {
	*info = -8;
    } else {

/*        Set M to the dimension of the specified invariant subspace,   
          and test LWORK and LIWORK. */

	*m = 0;
	pair = FALSE_;
	i__1 = *n;
	for (k = 1; k <= i__1; ++k) {
	    if (pair) {
		pair = FALSE_;
	    } else {
		if (k < *n) {
		    if (t[k + 1 + k * t_dim1] == 0.) {
			if (select[k]) {
			    ++(*m);
			}
		    } else {
			pair = TRUE_;
			if (select[k] || select[k + 1]) {
			    *m += 2;
			}
		    }
		} else {
		    if (select[*n]) {
			++(*m);
		    }
		}
	    }
/* L10: */
	}

	n1 = *m;
	n2 = *n - *m;
	nn = n1 * n2;

	if (wantsp) {
/* Computing MAX */
	    i__1 = 1, i__2 = nn << 1;
	    lwmin = max(i__1,i__2);
	    liwmin = max(1,nn);
	} else if (igraphlsame_(job, "N")) {
	    lwmin = max(1,*n);
	    liwmin = 1;
	} else if (igraphlsame_(job, "E")) {
	    lwmin = max(1,nn);
	    liwmin = 1;
	}

	if (*lwork < lwmin && ! lquery) {
	    *info = -15;
	} else if (*liwork < liwmin && ! lquery) {
	    *info = -17;
	}
    }

    if (*info == 0) {
	work[1] = (doublereal) lwmin;
	iwork[1] = liwmin;
    }

    if (*info != 0) {
	i__1 = -(*info);
	igraphxerbla_("DTRSEN", &i__1, (ftnlen)6);
	return 0;
    } else if (lquery) {
	return 0;
    }

/*     Quick return if possible. */

    if (*m == *n || *m == 0) {
	if (wants) {
	    *s = 1.;
	}
	if (wantsp) {
	    *sep = igraphdlange_("1", n, n, &t[t_offset], ldt, &work[1]);
	}
	goto L40;
    }

/*     Collect the selected blocks at the top-left corner of T. */

    ks = 0;
    pair = FALSE_;
    i__1 = *n;
    for (k = 1; k <= i__1; ++k) {
	if (pair) {
	    pair = FALSE_;
	} else {
	    swap = select[k];
	    if (k < *n) {
		if (t[k + 1 + k * t_dim1] != 0.) {
		    pair = TRUE_;
		    swap = swap || select[k + 1];
		}
	    }
	    if (swap) {
		++ks;

/*              Swap the K-th block to position KS. */

		ierr = 0;
		kk = k;
		if (k != ks) {
		    igraphdtrexc_(compq, n, &t[t_offset], ldt, &q[q_offset], ldq, &
			    kk, &ks, &work[1], &ierr);
		}
		if (ierr == 1 || ierr == 2) {

/*                 Blocks too close to swap: exit. */

		    *info = 1;
		    if (wants) {
			*s = 0.;
		    }
		    if (wantsp) {
			*sep = 0.;
		    }
		    goto L40;
		}
		if (pair) {
		    ++ks;
		}
	    }
	}
/* L20: */
    }

    if (wants) {

/*        Solve Sylvester equation for R:   

             T11*R - R*T22 = scale*T12 */

	igraphdlacpy_("F", &n1, &n2, &t[(n1 + 1) * t_dim1 + 1], ldt, &work[1], &n1);
	igraphdtrsyl_("N", "N", &c_n1, &n1, &n2, &t[t_offset], ldt, &t[n1 + 1 + (n1 
		+ 1) * t_dim1], ldt, &work[1], &n1, &scale, &ierr);

/*        Estimate the reciprocal of the condition number of the cluster   
          of eigenvalues. */

	rnorm = igraphdlange_("F", &n1, &n2, &work[1], &n1, &work[1]);
	if (rnorm == 0.) {
	    *s = 1.;
	} else {
	    *s = scale / (sqrt(scale * scale / rnorm + rnorm) * sqrt(rnorm));
	}
    }

    if (wantsp) {

/*        Estimate sep(T11,T22). */

	est = 0.;
	kase = 0;
L30:
	igraphdlacn2_(&nn, &work[nn + 1], &work[1], &iwork[1], &est, &kase, isave);
	if (kase != 0) {
	    if (kase == 1) {

/*              Solve  T11*R - R*T22 = scale*X. */

		igraphdtrsyl_("N", "N", &c_n1, &n1, &n2, &t[t_offset], ldt, &t[n1 + 
			1 + (n1 + 1) * t_dim1], ldt, &work[1], &n1, &scale, &
			ierr);
	    } else {

/*              Solve T11**T*R - R*T22**T = scale*X. */

		igraphdtrsyl_("T", "T", &c_n1, &n1, &n2, &t[t_offset], ldt, &t[n1 + 
			1 + (n1 + 1) * t_dim1], ldt, &work[1], &n1, &scale, &
			ierr);
	    }
	    goto L30;
	}

	*sep = scale / est;
    }

L40:

/*     Store the output eigenvalues in WR and WI. */

    i__1 = *n;
    for (k = 1; k <= i__1; ++k) {
	wr[k] = t[k + k * t_dim1];
	wi[k] = 0.;
/* L50: */
    }
    i__1 = *n - 1;
    for (k = 1; k <= i__1; ++k) {
	if (t[k + 1 + k * t_dim1] != 0.) {
	    wi[k] = sqrt((d__1 = t[k + (k + 1) * t_dim1], abs(d__1))) * sqrt((
		    d__2 = t[k + 1 + k * t_dim1], abs(d__2)));
	    wi[k + 1] = -wi[k];
	}
/* L60: */
    }

    work[1] = (doublereal) lwmin;
    iwork[1] = liwmin;

    return 0;

/*     End of DTRSEN */

} /* igraphdtrsen_ */