265 lines
10 KiB
C++
265 lines
10 KiB
C++
// Copyright (C) 2010 Davis E. King (davis@dlib.net)
|
|
// License: Boost Software License See LICENSE.txt for the full license.
|
|
#ifndef DLIB_LAPACk_ES_Hh_
|
|
#define DLIB_LAPACk_ES_Hh_
|
|
|
|
#include "fortran_id.h"
|
|
#include "../matrix.h"
|
|
|
|
namespace dlib
|
|
{
|
|
namespace lapack
|
|
{
|
|
namespace binding
|
|
{
|
|
#if defined(__alpha__) || defined(__sparc64__) || defined(__x86_64__) || defined(__ia64__)
|
|
typedef int logical;
|
|
#else
|
|
typedef long int logical;
|
|
#endif
|
|
typedef logical (*L_fp)(...);
|
|
|
|
extern "C"
|
|
{
|
|
void DLIB_FORTRAN_ID(dgees) (const char *jobvs, const char *sort, const L_fp select, const integer *n,
|
|
double *a, const integer *lda, integer *sdim, double *wr,
|
|
double *wi, double *vs, const integer *ldvs, double *work,
|
|
const integer *lwork, logical *bwork, integer *info);
|
|
|
|
void DLIB_FORTRAN_ID(sgees) (const char *jobvs, const char *sort, const L_fp select, const integer *n,
|
|
float *a, const integer *lda, integer *sdim, float *wr,
|
|
float *wi, float *vs, const integer *ldvs, float *work,
|
|
const integer *lwork, logical *bwork, integer *info);
|
|
|
|
}
|
|
|
|
inline int gees (char jobvs, integer n,
|
|
double *a, integer lda, double *wr,
|
|
double *wi, double *vs, integer ldvs, double *work,
|
|
integer lwork)
|
|
{
|
|
// No sorting allowed
|
|
integer info = 0;
|
|
char sort = 'N';
|
|
L_fp fnil = 0;
|
|
logical bwork = 0;
|
|
integer sdim = 0;
|
|
DLIB_FORTRAN_ID(dgees)(&jobvs, &sort, fnil, &n,
|
|
a, &lda, &sdim, wr,
|
|
wi, vs, &ldvs, work,
|
|
&lwork, &bwork, &info);
|
|
return info;
|
|
}
|
|
|
|
|
|
inline int gees (char jobvs, integer n,
|
|
float *a, integer lda, float *wr,
|
|
float *wi, float *vs, integer ldvs, float *work,
|
|
integer lwork)
|
|
{
|
|
// No sorting allowed
|
|
integer info = 0;
|
|
char sort = 'N';
|
|
L_fp fnil = 0;
|
|
logical bwork = 0;
|
|
integer sdim = 0;
|
|
DLIB_FORTRAN_ID(sgees)(&jobvs, &sort, fnil, &n,
|
|
a, &lda, &sdim, wr,
|
|
wi, vs, &ldvs, work,
|
|
&lwork, &bwork, &info);
|
|
return info;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
|
|
/* -- LAPACK driver routine (version 3.1) -- */
|
|
/* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
|
|
/* November 2006 */
|
|
|
|
/* .. Scalar Arguments .. */
|
|
/* .. */
|
|
/* .. Array Arguments .. */
|
|
/* .. */
|
|
/* .. Function Arguments .. */
|
|
/* .. */
|
|
|
|
/* Purpose */
|
|
/* ======= */
|
|
|
|
/* DGEES computes for an N-by-N real nonsymmetric matrix A, the */
|
|
/* eigenvalues, the real Schur form T, and, optionally, the matrix of */
|
|
/* Schur vectors Z. This gives the Schur factorization A = Z*T*(Z**T). */
|
|
|
|
/* Optionally, it also orders the eigenvalues on the diagonal of the */
|
|
/* real Schur form so that selected eigenvalues are at the top left. */
|
|
/* The leading columns of Z then form an orthonormal basis for the */
|
|
/* invariant subspace corresponding to the selected eigenvalues. */
|
|
|
|
/* A matrix is in real Schur form if it is upper quasi-triangular with */
|
|
/* 1-by-1 and 2-by-2 blocks. 2-by-2 blocks will be standardized in the */
|
|
/* form */
|
|
/* [ a b ] */
|
|
/* [ c a ] */
|
|
|
|
/* where b*c < 0. The eigenvalues of such a block are a +- sqrt(bc). */
|
|
|
|
/* Arguments */
|
|
/* ========= */
|
|
|
|
/* JOBVS (input) CHARACTER*1 */
|
|
/* = 'N': Schur vectors are not computed; */
|
|
/* = 'V': Schur vectors are computed. */
|
|
|
|
/* SORT (input) CHARACTER*1 */
|
|
/* Specifies whether or not to order the eigenvalues on the */
|
|
/* diagonal of the Schur form. */
|
|
/* = 'N': Eigenvalues are not ordered; */
|
|
/* = 'S': Eigenvalues are ordered (see SELECT). */
|
|
|
|
/* SELECT (external procedure) LOGICAL FUNCTION of two DOUBLE PRECISION arguments */
|
|
/* SELECT must be declared EXTERNAL in the calling subroutine. */
|
|
/* If SORT = 'S', SELECT is used to select eigenvalues to sort */
|
|
/* to the top left of the Schur form. */
|
|
/* If SORT = 'N', SELECT is not referenced. */
|
|
/* An eigenvalue WR(j)+sqrt(-1)*WI(j) is selected if */
|
|
/* SELECT(WR(j),WI(j)) is true; i.e., if either one of a complex */
|
|
/* conjugate pair of eigenvalues is selected, then both complex */
|
|
/* eigenvalues are selected. */
|
|
/* Note that a selected complex eigenvalue may no longer */
|
|
/* satisfy SELECT(WR(j),WI(j)) = .TRUE. after ordering, since */
|
|
/* ordering may change the value of complex eigenvalues */
|
|
/* (especially if the eigenvalue is ill-conditioned); in this */
|
|
/* case INFO is set to N+2 (see INFO below). */
|
|
|
|
/* N (input) INTEGER */
|
|
/* The order of the matrix A. N >= 0. */
|
|
|
|
/* A (input/output) DOUBLE PRECISION array, dimension (LDA,N) */
|
|
/* On entry, the N-by-N matrix A. */
|
|
/* On exit, A has been overwritten by its real Schur form T. */
|
|
|
|
/* LDA (input) INTEGER */
|
|
/* The leading dimension of the array A. LDA >= max(1,N). */
|
|
|
|
/* SDIM (output) INTEGER */
|
|
/* If SORT = 'N', SDIM = 0. */
|
|
/* If SORT = 'S', SDIM = number of eigenvalues (after sorting) */
|
|
/* for which SELECT is true. (Complex conjugate */
|
|
/* pairs for which SELECT is true for either */
|
|
/* eigenvalue count as 2.) */
|
|
|
|
/* WR (output) DOUBLE PRECISION array, dimension (N) */
|
|
/* WI (output) DOUBLE PRECISION array, dimension (N) */
|
|
/* WR and WI contain the real and imaginary parts, */
|
|
/* respectively, of the computed eigenvalues in the same order */
|
|
/* that they appear on the diagonal of the output Schur form T. */
|
|
/* Complex conjugate pairs of eigenvalues will appear */
|
|
/* consecutively with the eigenvalue having the positive */
|
|
/* imaginary part first. */
|
|
|
|
/* VS (output) DOUBLE PRECISION array, dimension (LDVS,N) */
|
|
/* If JOBVS = 'V', VS contains the orthogonal matrix Z of Schur */
|
|
/* vectors. */
|
|
/* If JOBVS = 'N', VS is not referenced. */
|
|
|
|
/* LDVS (input) INTEGER */
|
|
/* The leading dimension of the array VS. LDVS >= 1; if */
|
|
/* JOBVS = 'V', LDVS >= N. */
|
|
|
|
/* WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */
|
|
/* On exit, if INFO = 0, WORK(1) contains the optimal LWORK. */
|
|
|
|
/* LWORK (input) INTEGER */
|
|
/* The dimension of the array WORK. LWORK >= max(1,3*N). */
|
|
/* For good performance, LWORK must generally be larger. */
|
|
|
|
/* 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. */
|
|
|
|
/* BWORK (workspace) LOGICAL array, dimension (N) */
|
|
/* Not referenced if SORT = 'N'. */
|
|
|
|
/* INFO (output) INTEGER */
|
|
/* = 0: successful exit */
|
|
/* < 0: if INFO = -i, the i-th argument had an illegal value. */
|
|
/* > 0: if INFO = i, and i is */
|
|
/* <= N: the QR algorithm failed to compute all the */
|
|
/* eigenvalues; elements 1:ILO-1 and i+1:N of WR and WI */
|
|
/* contain those eigenvalues which have converged; if */
|
|
/* JOBVS = 'V', VS contains the matrix which reduces A */
|
|
/* to its partially converged Schur form. */
|
|
/* = N+1: the eigenvalues could not be reordered because some */
|
|
/* eigenvalues were too close to separate (the problem */
|
|
/* is very ill-conditioned); */
|
|
/* = N+2: after reordering, roundoff changed values of some */
|
|
/* complex eigenvalues so that leading eigenvalues in */
|
|
/* the Schur form no longer satisfy SELECT=.TRUE. This */
|
|
/* could also be caused by underflow due to scaling. */
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
long NR1, long NR2, long NR3, long NR4,
|
|
long NC1, long NC2, long NC3, long NC4,
|
|
typename MM,
|
|
typename layout
|
|
>
|
|
int gees (
|
|
const char jobz,
|
|
matrix<T,NR1,NC1,MM,column_major_layout>& a,
|
|
matrix<T,NR2,NC2,MM,layout>& wr,
|
|
matrix<T,NR3,NC3,MM,layout>& wi,
|
|
matrix<T,NR4,NC4,MM,column_major_layout>& vs
|
|
)
|
|
{
|
|
matrix<T,0,1,MM,column_major_layout> work;
|
|
|
|
const long n = a.nr();
|
|
|
|
wr.set_size(n,1);
|
|
wi.set_size(n,1);
|
|
|
|
if (jobz == 'V')
|
|
vs.set_size(n,n);
|
|
else
|
|
vs.set_size(NR4?NR4:1, NC4?NC4:1);
|
|
|
|
// figure out how big the workspace needs to be.
|
|
T work_size = 1;
|
|
int info = binding::gees(jobz, n,
|
|
&a(0,0), a.nr(), &wr(0,0),
|
|
&wi(0,0), &vs(0,0), vs.nr(), &work_size,
|
|
-1);
|
|
|
|
if (info != 0)
|
|
return info;
|
|
|
|
if (work.size() < work_size)
|
|
work.set_size(static_cast<long>(work_size), 1);
|
|
|
|
// compute the actual decomposition
|
|
info = binding::gees(jobz, n,
|
|
&a(0,0), a.nr(), &wr(0,0),
|
|
&wi(0,0), &vs(0,0), vs.nr(), &work(0,0),
|
|
work.size());
|
|
|
|
return info;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
#endif // DLIB_LAPACk_ES_Hh_
|
|
|