MAST
lapack_dggev_interface.h
Go to the documentation of this file.
1 /*
2  * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit
3  * Copyright (C) 2013-2019 Manav Bhatia
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 #ifndef __mast__lapack_dggev_interface_h__
21 #define __mast__lapack_dggev_interface_h__
22 
23 
24 // MAST includes
25 #include "base/mast_data_types.h"
26 
27 
28 extern "C" {
29 
30  /*
31  * =====================================================================
32  * Purpose
33  * =======
34  *
35  * DGGEV computes for a pair of N-by-N real nonsymmetric matrices (A,B)
36  * the generalized eigenvalues, and optionally, the left and/or right
37  * generalized eigenvectors.
38  *
39  * A generalized eigenvalue for a pair of matrices (A,B) is a scalar
40  * lambda or a ratio alpha/beta = lambda, such that A - lambda*B is
41  * singular. It is usually represented as the pair (alpha,beta), as
42  * there is a reasonable interpretation for beta=0, and even for both
43  * being zero.
44  *
45  * The right eigenvector v(j) corresponding to the eigenvalue lambda(j)
46  * of (A,B) satisfies
47  *
48  * A * v(j) = lambda(j) * B * v(j).
49  *
50  * The left eigenvector u(j) corresponding to the eigenvalue lambda(j)
51  * of (A,B) satisfies
52  *
53  * u(j)**H * A = lambda(j) * u(j)**H * B .
54  *
55  * where u(j)**H is the conjugate-transpose of u(j).
56  *
57  *
58  * Arguments
59  * =========
60  *
61  * JOBVL (input) CHARACTER*1
62  * = 'N': do not compute the left generalized eigenvectors;
63  * = 'V': compute the left generalized eigenvectors.
64  *
65  * JOBVR (input) CHARACTER*1
66  * = 'N': do not compute the right generalized eigenvectors;
67  * = 'V': compute the right generalized eigenvectors.
68  *
69  * N (input) INTEGER
70  * The order of the matrices A, B, VL, and VR. N >= 0.
71  *
72  * A (input/output) DOUBLE PRECISION array, dimension (LDA, N)
73  * On entry, the matrix A in the pair (A,B).
74  * On exit, A has been overwritten.
75  *
76  * LDA (input) INTEGER
77  * The leading dimension of A. LDA >= max(1,N).
78  *
79  * B (input/output) DOUBLE PRECISION array, dimension (LDB, N)
80  * On entry, the matrix B in the pair (A,B).
81  * On exit, B has been overwritten.
82  *
83  * LDB (input) INTEGER
84  * The leading dimension of B. LDB >= max(1,N).
85  *
86  * ALPHAR (output) DOUBLE PRECISION array, dimension (N)
87  * ALPHAI (output) DOUBLE PRECISION array, dimension (N)
88  * BETA (output) DOUBLE PRECISION array, dimension (N)
89  * On exit, (ALPHAR(j) + ALPHAI(j)*i)/BETA(j), j=1,...,N, will
90  * be the generalized eigenvalues. If ALPHAI(j) is zero, then
91  * the j-th eigenvalue is real; if positive, then the j-th and
92  * (j+1)-st eigenvalues are a complex conjugate pair, with
93  * ALPHAI(j+1) negative.
94  *
95  * Note: the quotients ALPHAR(j)/BETA(j) and ALPHAI(j)/BETA(j)
96  * may easily over- or underflow, and BETA(j) may even be zero.
97  * Thus, the user should avoid naively computing the ratio
98  * alpha/beta. However, ALPHAR and ALPHAI will be always less
99  * than and usually comparable with norm(A) in magnitude, and
100  * BETA always less than and usually comparable with norm(B).
101  *
102  * VL (output) DOUBLE PRECISION array, dimension (LDVL,N)
103  * If JOBVL = 'V', the left eigenvectors u(j) are stored one
104  * after another in the columns of VL, in the same order as
105  * their eigenvalues. If the j-th eigenvalue is real, then
106  * u(j) = VL(:,j), the j-th column of VL. If the j-th and
107  * (j+1)-th eigenvalues form a complex conjugate pair, then
108  * u(j) = VL(:,j)+i*VL(:,j+1) and u(j+1) = VL(:,j)-i*VL(:,j+1).
109  * Each eigenvector is scaled so the largest component has
110  * abs(real part)+abs(imag. part)=1.
111  * Not referenced if JOBVL = 'N'.
112  *
113  * LDVL (input) INTEGER
114  * The leading dimension of the matrix VL. LDVL >= 1, and
115  * if JOBVL = 'V', LDVL >= N.
116  *
117  * VR (output) DOUBLE PRECISION array, dimension (LDVR,N)
118  * If JOBVR = 'V', the right eigenvectors v(j) are stored one
119  * after another in the columns of VR, in the same order as
120  * their eigenvalues. If the j-th eigenvalue is real, then
121  * v(j) = VR(:,j), the j-th column of VR. If the j-th and
122  * (j+1)-th eigenvalues form a complex conjugate pair, then
123  * v(j) = VR(:,j)+i*VR(:,j+1) and v(j+1) = VR(:,j)-i*VR(:,j+1).
124  * Each eigenvector is scaled so the largest component has
125  * abs(real part)+abs(imag. part)=1.
126  * Not referenced if JOBVR = 'N'.
127  *
128  * LDVR (input) INTEGER
129  * The leading dimension of the matrix VR. LDVR >= 1, and
130  * if JOBVR = 'V', LDVR >= N.
131  *
132  * WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK))
133  * On exit, if INFO = 0, WORK(1) returns the optimal LWORK.
134  *
135  * LWORK (input) INTEGER
136  * The dimension of the array WORK. LWORK >= max(1,8*N).
137  * For good performance, LWORK must generally be larger.
138  *
139  * If LWORK = -1, then a workspace query is assumed; the routine
140  * only calculates the optimal size of the WORK array, returns
141  * this value as the first entry of the WORK array, and no error
142  * message related to LWORK is issued by XERBLA.
143  *
144  * INFO (output) INTEGER
145  * = 0: successful exit
146  * < 0: if INFO = -i, the i-th argument had an illegal value.
147  * = 1,...,N:
148  * The QZ iteration failed. No eigenvectors have been
149  * calculated, but ALPHAR(j), ALPHAI(j), and BETA(j)
150  * should be correct for j=INFO+1,...,N.
151  * > N: =N+1: other than QZ iteration failed in DHGEQZ.
152  * =N+2: error return from DTGEVC.
153  *
154  * =====================================================================
155  */
156  extern int dggev_(char* jobvl,
157  char* jobvr,
158  int* n,
159  double* a,
160  int* lda,
161  double* b,
162  int* ldb,
163  double* alpha_r,
164  double* alpha_i,
165  double* beta,
166  double* vl,
167  int* ldvl,
168  double* vr,
169  int* ldvr,
170  double* work,
171  int* lwork,
172  int* info);
173 
174 }
175 
176 
177 namespace MAST {
178 
179 
181 
182  public:
183 
185  info_val(-1)
186  { }
187 
192  void compute(const RealMatrixX& A,
193  const RealMatrixX& B,
194  bool computeEigenvectors = true);
195 
196  ComputationInfo info() const;
197 
198  const RealMatrixX& A() const {
199  libmesh_assert(info_val == 0);
200  return this->_A;
201  }
202 
203 
204  const RealMatrixX& B() const {
205  libmesh_assert(info_val == 0);
206  return this->_B;
207  }
208 
209 
210  const ComplexVectorX& alphas() const {
211  libmesh_assert(info_val == 0);
212  return this->alpha;
213  }
214 
215  const RealVectorX& betas() const {
216  libmesh_assert(info_val == 0);
217  return this->beta;
218  }
219 
221  libmesh_assert(info_val == 0);
222  return this->VL;
223  }
224 
226  libmesh_assert(info_val == 0);
227  return this->VR;
228  }
229 
236  libmesh_assert(info_val == 0);
237 
238  // this product should be an identity matrix
239  ComplexMatrixX r = this->VL.conjugate().transpose() * _B * this->VR;
240 
241  // scale the right eigenvectors by the inverse of the inner-product
242  // diagonal
243  Complex val;
244  for (unsigned int i=0; i<_B.cols(); i++) {
245  val = r(i,i);
246  if (std::abs(val) > 0.)
247  this->VR.col(i) *= (1./val);
248  }
249  }
250 
251  void print_inner_product(std::ostream& out) const {
252  libmesh_assert(info_val == 0);
253  ComplexMatrixX r;
254  r = this->VL.conjugate().transpose() * _A * this->VR;
255  out << "conj(VL)' * A * VR" << std::endl
256  << r << std::endl;
257 
258  r = this->VL.conjugate().transpose() * _B * this->VR;
259  out << "conj(VL)' * B * VR" << std::endl
260  << r << std::endl;
261 
262  }
263 
264  protected:
265 
267 
269 
271 
273 
275 
277 
278  int info_val;
279  };
280 
281 }
282 
283 #endif // __mast__lapack_dggev_interface_h__
void scale_eigenvectors_to_identity_innerproduct()
Scales the right eigenvector so that the inner product with respect to the B matrix is equal to an Id...
ComputationInfo info() const
Matrix< Complex, Dynamic, 1 > ComplexVectorX
libMesh::Complex Complex
const RealVectorX & betas() const
const ComplexMatrixX & right_eigenvectors() const
void print_inner_product(std::ostream &out) const
const RealMatrixX & B() const
const ComplexVectorX & alphas() const
const ComplexMatrixX & left_eigenvectors() const
Matrix< Real, Dynamic, Dynamic > RealMatrixX
Matrix< Complex, Dynamic, Dynamic > ComplexMatrixX
Matrix< Real, Dynamic, 1 > RealVectorX
const RealMatrixX & A() const
void compute(const RealMatrixX &A, const RealMatrixX &B, bool computeEigenvectors=true)
computes the eigensolution for .
int dggev_(char *jobvl, char *jobvr, int *n, double *a, int *lda, double *b, int *ldb, double *alpha_r, double *alpha_i, double *beta, double *vl, int *ldvl, double *vr, int *ldvr, double *work, int *lwork, int *info)