Mercurial > octave-nkf
annotate src/DLD-FUNCTIONS/qz.cc @ 8927:d75f4ee0538d
qz.cc (Fqz): avoid maybe clobbred by vfork warning from GCC
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Sat, 07 Mar 2009 13:45:39 -0500 |
parents | eb63fbe60fab |
children | 7c02ec148a3c |
rev | line source |
---|---|
3183 | 1 /* |
2 | |
8920 | 3 Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007, |
4 2008, 2009 A. S. Hodel | |
3183 | 5 |
6 This file is part of Octave. | |
7 | |
8 Octave is free software; you can redistribute it and/or modify it | |
9 under the terms of the GNU General Public License as published by the | |
7016 | 10 Free Software Foundation; either version 3 of the License, or (at your |
11 option) any later version. | |
3183 | 12 |
13 Octave is distributed in the hope that it will be useful, but WITHOUT | |
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 for more details. | |
17 | |
18 You should have received a copy of the GNU General Public License | |
7016 | 19 along with Octave; see the file COPYING. If not, see |
20 <http://www.gnu.org/licenses/>. | |
3183 | 21 |
22 */ | |
23 | |
24 // Generalized eigenvalue balancing via LAPACK | |
3911 | 25 |
26 // Author: A. S. Hodel <scotte@eng.auburn.edu> | |
3183 | 27 |
28 #undef DEBUG | |
29 #undef DEBUG_SORT | |
30 #undef DEBUG_EIG | |
31 | |
32 #include "config.h" | |
33 | |
34 #include <cfloat> | |
4051 | 35 |
3523 | 36 #include <iostream> |
4051 | 37 #include <iomanip> |
3183 | 38 |
39 #include "CmplxQRP.h" | |
40 #include "dbleQR.h" | |
4153 | 41 #include "f77-fcn.h" |
7231 | 42 #include "lo-math.h" |
4153 | 43 #include "quit.h" |
44 | |
3183 | 45 #include "defun-dld.h" |
46 #include "error.h" | |
47 #include "gripes.h" | |
48 #include "oct-obj.h" | |
49 #include "oct-map.h" | |
50 #include "ov.h" | |
51 #include "pager.h" | |
3185 | 52 #if defined (DEBUG) || defined (DEBUG_SORT) |
3183 | 53 #include "pr-output.h" |
54 #endif | |
55 #include "symtab.h" | |
56 #include "utils.h" | |
57 #include "variables.h" | |
58 | |
5275 | 59 typedef octave_idx_type (*sort_function) (const octave_idx_type& LSIZE, const double& ALPHA, |
3185 | 60 const double& BETA, const double& S, |
61 const double& P); | |
3183 | 62 |
63 extern "C" | |
64 { | |
4552 | 65 F77_RET_T |
66 F77_FUNC (dggbal, DGGBAL) (F77_CONST_CHAR_ARG_DECL, | |
5275 | 67 const octave_idx_type& N, double* A, const octave_idx_type& LDA, |
68 double* B, const octave_idx_type& LDB, octave_idx_type& ILO, | |
69 octave_idx_type& IHI, double* LSCALE, double* RSCALE, | |
70 double* WORK, octave_idx_type& INFO | |
4552 | 71 F77_CHAR_ARG_LEN_DECL); |
3183 | 72 |
4552 | 73 F77_RET_T |
74 F77_FUNC (dggbak, DGGBAK) (F77_CONST_CHAR_ARG_DECL, | |
75 F77_CONST_CHAR_ARG_DECL, | |
5275 | 76 const octave_idx_type& N, const octave_idx_type& ILO, |
77 const octave_idx_type& IHI, const double* LSCALE, | |
78 const double* RSCALE, octave_idx_type& M, double* V, | |
79 const octave_idx_type& LDV, octave_idx_type& INFO | |
4552 | 80 F77_CHAR_ARG_LEN_DECL |
81 F77_CHAR_ARG_LEN_DECL); | |
3183 | 82 |
4552 | 83 F77_RET_T |
84 F77_FUNC (dgghrd, DGGHRD) (F77_CONST_CHAR_ARG_DECL, | |
85 F77_CONST_CHAR_ARG_DECL, | |
5275 | 86 const octave_idx_type& N, const octave_idx_type& ILO, |
87 const octave_idx_type& IHI, double* A, | |
88 const octave_idx_type& LDA, double* B, | |
89 const octave_idx_type& LDB, double* Q, | |
90 const octave_idx_type& LDQ, double* Z, | |
91 const octave_idx_type& LDZ, octave_idx_type& INFO | |
4552 | 92 F77_CHAR_ARG_LEN_DECL |
93 F77_CHAR_ARG_LEN_DECL); | |
3183 | 94 |
4552 | 95 F77_RET_T |
96 F77_FUNC (dhgeqz, DHGEQZ) (F77_CONST_CHAR_ARG_DECL, | |
97 F77_CONST_CHAR_ARG_DECL, | |
98 F77_CONST_CHAR_ARG_DECL, | |
5275 | 99 const octave_idx_type& N, const octave_idx_type& ILO, const octave_idx_type& IHI, |
100 double* A, const octave_idx_type& LDA, double* B, | |
101 const octave_idx_type& LDB, double* ALPHAR, | |
4552 | 102 double* ALPHAI, double* BETA, double* Q, |
5275 | 103 const octave_idx_type& LDQ, double* Z, |
104 const octave_idx_type& LDZ, double* WORK, | |
105 const octave_idx_type& LWORK, octave_idx_type& INFO | |
4552 | 106 F77_CHAR_ARG_LEN_DECL |
107 F77_CHAR_ARG_LEN_DECL | |
108 F77_CHAR_ARG_LEN_DECL); | |
3183 | 109 |
4552 | 110 F77_RET_T |
5275 | 111 F77_FUNC (dlag2, DLAG2) (const double* A, const octave_idx_type& LDA, const double* B, |
112 const octave_idx_type& LDB, const double& SAFMIN, | |
4552 | 113 double& SCALE1, double& SCALE2, |
114 double& WR1, double& WR2, double& WI); | |
3183 | 115 |
116 // Van Dooren's code (netlib.org: toms/590) for reordering | |
117 // GEP. Only processes Z, not Q. | |
4552 | 118 F77_RET_T |
5275 | 119 F77_FUNC (dsubsp, DSUBSP) (const octave_idx_type& NMAX, const octave_idx_type& N, double* A, |
4552 | 120 double* B, double* Z, sort_function, |
5275 | 121 const double& EPS, octave_idx_type& NDIM, octave_idx_type& FAIL, |
122 octave_idx_type* IND); | |
3183 | 123 |
124 // documentation for DTGEVC incorrectly states that VR, VL are | |
125 // complex*16; they are declared in DTGEVC as double precision | |
126 // (probably a cut and paste problem fro ZTGEVC) | |
4552 | 127 F77_RET_T |
128 F77_FUNC (dtgevc, DTGEVC) (F77_CONST_CHAR_ARG_DECL, | |
129 F77_CONST_CHAR_ARG_DECL, | |
5275 | 130 octave_idx_type* SELECT, const octave_idx_type& N, double* A, |
131 const octave_idx_type& LDA, double* B, | |
132 const octave_idx_type& LDB, double* VL, | |
133 const octave_idx_type& LDVL, double* VR, | |
134 const octave_idx_type& LDVR, const octave_idx_type& MM, | |
135 octave_idx_type& M, double* WORK, octave_idx_type& INFO | |
4552 | 136 F77_CHAR_ARG_LEN_DECL |
137 F77_CHAR_ARG_LEN_DECL); | |
3183 | 138 |
4552 | 139 F77_RET_T |
140 F77_FUNC (xdlamch, XDLAMCH) (F77_CONST_CHAR_ARG_DECL, | |
141 double& retval | |
142 F77_CHAR_ARG_LEN_DECL); | |
3185 | 143 |
4552 | 144 F77_RET_T |
145 F77_FUNC (xdlange, XDLANGE) (F77_CONST_CHAR_ARG_DECL, | |
5275 | 146 const octave_idx_type&, const octave_idx_type&, const double*, |
147 const octave_idx_type&, double*, double& | |
4552 | 148 F77_CHAR_ARG_LEN_DECL); |
3183 | 149 } |
150 | |
151 // fcrhp, fin, fout, folhp: | |
152 // routines for ordering of generalized eigenvalues | |
153 // return 1 if test is passed, 0 otherwise | |
154 // fin: |lambda| < 1 | |
155 // fout: |lambda| >= 1 | |
156 // fcrhp: real(lambda) >= 0 | |
157 // folhp: real(lambda) < 0 | |
158 | |
5275 | 159 static octave_idx_type |
160 fcrhp (const octave_idx_type& lsize, const double& alpha, | |
3185 | 161 const double& beta, const double& s, const double&) |
3183 | 162 { |
3185 | 163 if (lsize == 1) |
3183 | 164 return (alpha*beta >= 0 ? 1 : -1); |
3185 | 165 else |
3183 | 166 return (s >= 0 ? 1 : -1); |
167 } | |
3185 | 168 |
5275 | 169 static octave_idx_type |
170 fin (const octave_idx_type& lsize, const double& alpha, | |
3185 | 171 const double& beta, const double&, const double& p) |
3183 | 172 { |
5275 | 173 octave_idx_type retval; |
3183 | 174 |
3185 | 175 if (lsize == 1) |
176 retval = (fabs (alpha) < fabs (beta) ? 1 : -1); | |
177 else | |
178 retval = (fabs (p) < 1 ? 1 : -1); | |
179 | |
180 #ifdef DEBUG | |
3538 | 181 std::cout << "qz: fin: retval=" << retval << std::endl; |
3185 | 182 #endif |
183 | |
3183 | 184 return retval; |
185 } | |
3185 | 186 |
5275 | 187 static octave_idx_type |
188 folhp (const octave_idx_type& lsize, const double& alpha, | |
3185 | 189 const double& beta, const double& s, const double&) |
3183 | 190 { |
3185 | 191 if (lsize == 1) |
3183 | 192 return (alpha*beta < 0 ? 1 : -1); |
3185 | 193 else |
3183 | 194 return (s < 0 ? 1 : -1); |
195 } | |
3185 | 196 |
5275 | 197 static octave_idx_type |
198 fout (const octave_idx_type& lsize, const double& alpha, | |
3185 | 199 const double& beta, const double&, const double& p) |
3183 | 200 { |
3185 | 201 if (lsize == 1) |
202 return (fabs (alpha) >= fabs (beta) ? 1 : -1); | |
203 else | |
204 return (fabs (p) >= 1 ? 1 : -1); | |
3183 | 205 } |
206 | |
207 DEFUN_DLD (qz, args, nargout, | |
3372 | 208 "-*- texinfo -*-\n\ |
209 @deftypefn {Loadable Function} {@var{lambda} =} qz (@var{a}, @var{b})\n\ | |
210 Generalized eigenvalue problem @math{A x = s B x},\n\ | |
5016 | 211 @var{QZ} decomposition. There are three ways to call this function:\n\ |
3372 | 212 @enumerate\n\ |
213 @item @code{lambda = qz(A,B)}\n\ | |
3185 | 214 \n\ |
5016 | 215 Computes the generalized eigenvalues\n\ |
216 @iftex\n\ | |
217 @tex\n\ | |
218 $\\lambda$\n\ | |
219 @end tex\n\ | |
220 @end iftex\n\ | |
8517
81d6ab3ac93c
Allow documentation tobe built for other formats than tex and info
sh@sh-laptop
parents:
8286
diff
changeset
|
221 @ifnottex\n\ |
5016 | 222 @var{lambda}\n\ |
8517
81d6ab3ac93c
Allow documentation tobe built for other formats than tex and info
sh@sh-laptop
parents:
8286
diff
changeset
|
223 @end ifnottex\n\ |
5016 | 224 of @math{(A - s B)}.\n\ |
3500 | 225 @item @code{[AA, BB, Q, Z, V, W, lambda] = qz (A, B)}\n\ |
3185 | 226 \n\ |
3372 | 227 Computes qz decomposition, generalized eigenvectors, and \n\ |
5481 | 228 generalized eigenvalues of @math{(A - sB)}\n\ |
5016 | 229 @iftex\n\ |
230 @tex\n\ | |
231 $$ AV = BV{ \\rm diag }(\\lambda) $$\n\ | |
232 $$ W^T A = { \\rm diag }(\\lambda)W^T B $$\n\ | |
233 $$ AA = Q^T AZ, BB = Q^T BZ $$\n\ | |
234 @end tex\n\ | |
235 @end iftex\n\ | |
8517
81d6ab3ac93c
Allow documentation tobe built for other formats than tex and info
sh@sh-laptop
parents:
8286
diff
changeset
|
236 @ifnottex\n\ |
3372 | 237 @example\n\ |
238 @group\n\ | |
5481 | 239 \n\ |
240 A*V = B*V*diag(lambda)\n\ | |
241 W'*A = diag(lambda)*W'*B\n\ | |
242 AA = Q'*A*Z, BB = Q'*B*Z\n\ | |
243 \n\ | |
3372 | 244 @end group\n\ |
245 @end example\n\ | |
8517
81d6ab3ac93c
Allow documentation tobe built for other formats than tex and info
sh@sh-laptop
parents:
8286
diff
changeset
|
246 @end ifnottex\n\ |
5016 | 247 with @var{Q} and @var{Z} orthogonal (unitary)= @var{I}\n\ |
3185 | 248 \n\ |
5016 | 249 @item @code{[AA,BB,Z@{, lambda@}] = qz(A,B,opt)}\n\ |
3185 | 250 \n\ |
3372 | 251 As in form [2], but allows ordering of generalized eigenpairs\n\ |
5481 | 252 for (e.g.) solution of discrete time algebraic Riccati equations.\n\ |
253 Form 3 is not available for complex matrices, and does not compute\n\ | |
254 the generalized eigenvectors @var{V}, @var{W}, nor the orthogonal matrix @var{Q}.\n\ | |
3372 | 255 @table @var\n\ |
256 @item opt\n\ | |
5481 | 257 for ordering eigenvalues of the GEP pencil. The leading block\n\ |
258 of the revised pencil contains all eigenvalues that satisfy:\n\ | |
3372 | 259 @table @code\n\ |
260 @item \"N\"\n\ | |
5481 | 261 = unordered (default) \n\ |
3183 | 262 \n\ |
3372 | 263 @item \"S\"\n\ |
264 = small: leading block has all |lambda| <=1 \n\ | |
3185 | 265 \n\ |
3372 | 266 @item \"B\"\n\ |
5481 | 267 = big: leading block has all |lambda| >= 1 \n\ |
3372 | 268 \n\ |
269 @item \"-\"\n\ | |
5481 | 270 = negative real part: leading block has all eigenvalues\n\ |
271 in the open left half-plane\n\ | |
3372 | 272 \n\ |
273 @item \"+\"\n\ | |
5481 | 274 = nonnegative real part: leading block has all eigenvalues\n\ |
275 in the closed right half-plane\n\ | |
3372 | 276 @end table\n\ |
277 @end table\n\ | |
278 @end enumerate\n\ | |
3183 | 279 \n\ |
3372 | 280 Note: qz performs permutation balancing, but not scaling (see balance).\n\ |
5481 | 281 Order of output arguments was selected for compatibility with MATLAB\n\ |
3183 | 282 \n\ |
8286
6f2d95255911
fix @seealso references to point to existing anchors
Thorsten Meyer <thorsten.meyier@gmx.de>
parents:
7520
diff
changeset
|
283 @seealso{balance, eig, schur}\n\ |
3372 | 284 @end deftypefn") |
3183 | 285 { |
286 octave_value_list retval; | |
287 int nargin = args.length (); | |
288 | |
3185 | 289 #ifdef DEBUG |
3538 | 290 std::cout << "qz: nargin = " << nargin << ", nargout = " << nargout << std::endl; |
3185 | 291 #endif |
3183 | 292 |
3185 | 293 if (nargin < 2 || nargin > 3 || nargout > 7) |
294 { | |
5823 | 295 print_usage (); |
3185 | 296 return retval; |
297 } | |
298 else if (nargin == 3 && (nargout < 3 || nargout > 4)) | |
299 { | |
3427 | 300 error ("qz: invalid number of output arguments for form [3] call"); |
3185 | 301 return retval; |
302 } | |
3183 | 303 |
3185 | 304 #ifdef DEBUG |
3538 | 305 std::cout << "qz: determine ordering option" << std::endl; |
3185 | 306 #endif |
3183 | 307 |
308 // Determine ordering option | |
8927
d75f4ee0538d
qz.cc (Fqz): avoid maybe clobbred by vfork warning from GCC
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
309 volatile char ord_job = 0; |
3183 | 310 static double safmin; |
3185 | 311 |
312 if (nargin == 2) | |
8927
d75f4ee0538d
qz.cc (Fqz): avoid maybe clobbred by vfork warning from GCC
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
313 ord_job = 'N'; |
3185 | 314 else if (!args(2).is_string ()) |
315 { | |
316 error ("qz: argument 3 must be a string"); | |
317 return retval; | |
318 } | |
319 else | |
320 { | |
8927
d75f4ee0538d
qz.cc (Fqz): avoid maybe clobbred by vfork warning from GCC
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
321 std::string tmp = args(2).string_value (); |
d75f4ee0538d
qz.cc (Fqz): avoid maybe clobbred by vfork warning from GCC
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
322 |
d75f4ee0538d
qz.cc (Fqz): avoid maybe clobbred by vfork warning from GCC
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
323 if (! tmp.empty ()) |
d75f4ee0538d
qz.cc (Fqz): avoid maybe clobbred by vfork warning from GCC
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
324 ord_job = tmp[0]; |
3183 | 325 |
8927
d75f4ee0538d
qz.cc (Fqz): avoid maybe clobbred by vfork warning from GCC
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
326 if (! (ord_job == 'N' || ord_job == 'n' |
d75f4ee0538d
qz.cc (Fqz): avoid maybe clobbred by vfork warning from GCC
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
327 || ord_job == 'S' || ord_job == 's' |
d75f4ee0538d
qz.cc (Fqz): avoid maybe clobbred by vfork warning from GCC
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
328 || ord_job == 'B' || ord_job == 'b' |
d75f4ee0538d
qz.cc (Fqz): avoid maybe clobbred by vfork warning from GCC
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
329 || ord_job == '+' || ord_job == '-')) |
3185 | 330 { |
3427 | 331 error ("qz: invalid order option"); |
3185 | 332 return retval; |
333 } | |
334 | |
335 // overflow constant required by dlag2 | |
4552 | 336 F77_FUNC (xdlamch, XDLAMCH) (F77_CONST_CHAR_ARG2 ("S", 1), |
337 safmin | |
338 F77_CHAR_ARG_LEN (1)); | |
3183 | 339 |
3185 | 340 #ifdef DEBUG_EIG |
3538 | 341 std::cout << "qz: initial value of safmin=" << setiosflags (std::ios::scientific) |
342 << safmin << std::endl; | |
3185 | 343 #endif |
3183 | 344 |
3185 | 345 // some machines (e.g., DEC alpha) get safmin = 0; |
346 // for these, use eps instead to avoid problems in dlag2 | |
347 if (safmin == 0) | |
348 { | |
349 #ifdef DEBUG_EIG | |
3538 | 350 std::cout << "qz: DANGER WILL ROBINSON: safmin is 0!" << std::endl; |
3185 | 351 #endif |
3183 | 352 |
4552 | 353 F77_FUNC (xdlamch, XDLAMCH) (F77_CONST_CHAR_ARG2 ("E", 1), |
354 safmin | |
355 F77_CHAR_ARG_LEN (1)); | |
3185 | 356 |
357 #ifdef DEBUG_EIG | |
3538 | 358 std::cout << "qz: safmin set to " << setiosflags (std::ios::scientific) |
359 << safmin << std::endl; | |
3185 | 360 #endif |
361 } | |
3183 | 362 } |
363 | |
3185 | 364 #ifdef DEBUG |
3538 | 365 std::cout << "qz: check argument 1" << std::endl; |
3185 | 366 #endif |
3183 | 367 |
368 // Argument 1: check if it's o.k. dimensioned | |
5275 | 369 octave_idx_type nn = args(0).rows (); |
3185 | 370 |
371 #ifdef DEBUG | |
3531 | 372 std::cout << "argument 1 dimensions: (" << nn << "," << args(0).columns () << ")" |
3538 | 373 << std::endl; |
3185 | 374 #endif |
375 | |
376 int arg_is_empty = empty_arg ("qz", nn, args(0).columns ()); | |
377 | |
3183 | 378 if (arg_is_empty < 0) |
3185 | 379 { |
380 gripe_empty_arg ("qz: parameter 1", 0); | |
381 return retval; | |
382 } | |
3183 | 383 else if (arg_is_empty > 0) |
3185 | 384 { |
385 gripe_empty_arg ("qz: parameter 1; continuing", 0); | |
386 return octave_value_list (2, Matrix ()); | |
387 } | |
388 else if (args(0).columns () != nn) | |
389 { | |
390 gripe_square_matrix_required ("qz"); | |
391 return retval; | |
392 } | |
3183 | 393 |
394 // Argument 1: dimensions look good; get the value | |
395 Matrix aa; | |
396 ComplexMatrix caa; | |
3185 | 397 |
398 if (args(0).is_complex_type ()) | |
3183 | 399 caa = args(0).complex_matrix_value (); |
3185 | 400 else |
3183 | 401 aa = args(0).matrix_value (); |
3185 | 402 |
403 if (error_state) | |
3183 | 404 return retval; |
405 | |
3185 | 406 #ifdef DEBUG |
3538 | 407 std::cout << "qz: check argument 2" << std::endl; |
3185 | 408 #endif |
3183 | 409 |
410 // Extract argument 2 (bb, or cbb if complex) | |
3185 | 411 if ((nn != args(1).columns ()) || (nn != args(1).rows ())) |
412 { | |
413 gripe_nonconformant (); | |
414 return retval; | |
415 } | |
416 | |
3183 | 417 Matrix bb; |
418 ComplexMatrix cbb; | |
3185 | 419 |
420 if (args(1).is_complex_type ()) | |
3183 | 421 cbb = args(1).complex_matrix_value (); |
422 else | |
423 bb = args(1).matrix_value (); | |
3185 | 424 |
425 if (error_state) | |
3183 | 426 return retval; |
427 | |
428 // Both matrices loaded, now let's check what kind of arithmetic: | |
429 //declared static to avoid compiler warnings about long jumps, vforks. | |
3185 | 430 |
431 static int complex_case | |
432 = (args(0).is_complex_type () || args(1).is_complex_type ()); | |
3183 | 433 |
3185 | 434 if (nargin == 3 && complex_case) |
435 { | |
436 error ("qz: cannot re-order complex qz decomposition."); | |
437 return retval; | |
438 } | |
3183 | 439 |
440 // first, declare variables used in both the real and complex case | |
441 Matrix QQ(nn,nn), ZZ(nn,nn), VR(nn,nn), VL(nn,nn); | |
442 RowVector alphar(nn), alphai(nn), betar(nn); | |
443 | |
3185 | 444 ComplexMatrix CQ(nn,nn), CZ(nn,nn), CVR(nn,nn), CVL(nn,nn); |
5275 | 445 octave_idx_type ilo, ihi, info; |
3185 | 446 char compq = (nargout >= 3 ? 'V' : 'N'); |
447 char compz = (nargout >= 4 ? 'V' : 'N'); | |
3183 | 448 |
3185 | 449 // initialize Q, Z to identity if we need either of them |
450 if (compq == 'V' || compz == 'V') | |
5275 | 451 for (octave_idx_type ii = 0; ii < nn; ii++) |
452 for (octave_idx_type jj = 0; jj < nn; jj++) | |
4153 | 453 { |
454 OCTAVE_QUIT; | |
455 QQ(ii,jj) = ZZ(ii,jj) = (ii == jj ? 1.0 : 0.0); | |
456 } | |
3183 | 457 |
3185 | 458 // always perform permutation balancing |
4552 | 459 const char bal_job = 'P'; |
3183 | 460 RowVector lscale(nn), rscale(nn), work(6*nn); |
461 | |
3185 | 462 if (complex_case) |
463 { | |
464 error ("Complex case not implemented yet"); | |
465 return retval; | |
466 } | |
3183 | 467 else |
3185 | 468 { |
469 #ifdef DEBUG | |
470 if (compq == 'V') | |
3538 | 471 std::cout << "qz: performing balancing; QQ=" << std::endl << QQ << std::endl; |
3185 | 472 #endif |
3183 | 473 |
3185 | 474 F77_XFCN (dggbal, DGGBAL, |
4552 | 475 (F77_CONST_CHAR_ARG2 (&bal_job, 1), |
476 nn, aa.fortran_vec (), nn, bb.fortran_vec (), | |
477 nn, ilo, ihi, lscale.fortran_vec (), | |
478 rscale.fortran_vec (), work.fortran_vec (), info | |
479 F77_CHAR_ARG_LEN (1))); | |
3185 | 480 } |
3183 | 481 |
482 // Since we just want the balancing matrices, we can use dggbal | |
483 // for both the real and complex cases; | |
484 // left first | |
3185 | 485 |
486 if (compq == 'V') | |
487 { | |
488 F77_XFCN (dggbak, DGGBAK, | |
4552 | 489 (F77_CONST_CHAR_ARG2 (&bal_job, 1), |
490 F77_CONST_CHAR_ARG2 ("L", 1), | |
4566 | 491 nn, ilo, ihi, lscale.data (), rscale.data (), |
492 nn, QQ.fortran_vec (), nn, info | |
4552 | 493 F77_CHAR_ARG_LEN (1) |
494 F77_CHAR_ARG_LEN (1))); | |
3183 | 495 |
3185 | 496 #ifdef DEBUG |
497 if (compq == 'V') | |
3538 | 498 std::cout << "qz: balancing done; QQ=" << std::endl << QQ << std::endl; |
3185 | 499 #endif |
3183 | 500 } |
501 | |
502 // then right | |
3185 | 503 if (compz == 'V') |
504 { | |
4552 | 505 F77_XFCN (dggbak, DGGBAK, |
506 (F77_CONST_CHAR_ARG2 (&bal_job, 1), | |
507 F77_CONST_CHAR_ARG2 ("R", 1), | |
4566 | 508 nn, ilo, ihi, lscale.data (), rscale.data (), |
509 nn, ZZ.fortran_vec (), nn, info | |
4552 | 510 F77_CHAR_ARG_LEN (1) |
511 F77_CHAR_ARG_LEN (1))); | |
3183 | 512 |
3185 | 513 #ifdef DEBUG |
514 if (compz == 'V') | |
3538 | 515 std::cout << "qz: balancing done; ZZ=" << std::endl << ZZ << std::endl; |
3185 | 516 #endif |
517 } | |
3183 | 518 |
519 static char qz_job; | |
520 qz_job = (nargout < 2 ? 'E' : 'S'); | |
3185 | 521 |
3183 | 522 if (complex_case) |
3185 | 523 { |
524 // complex case | |
525 if (args(0).is_real_type ()) | |
3587 | 526 caa = ComplexMatrix (aa); |
3185 | 527 |
528 if (args(1).is_real_type ()) | |
3587 | 529 cbb = ComplexMatrix (bb); |
3185 | 530 |
531 if (compq == 'V') | |
3587 | 532 CQ = ComplexMatrix (QQ); |
3185 | 533 |
534 if (compz == 'V') | |
3587 | 535 CZ = ComplexMatrix (ZZ); |
3185 | 536 |
537 error ("complex case not done yet"); | |
538 return retval; | |
539 } | |
3183 | 540 else // real matrices case |
3185 | 541 { |
542 #ifdef DEBUG | |
3538 | 543 std::cout << "qz: peforming qr decomposition of bb" << std::endl; |
3185 | 544 #endif |
3183 | 545 |
3185 | 546 // compute the QR factorization of bb |
547 QR bqr (bb); | |
548 | |
549 #ifdef DEBUG | |
3538 | 550 std::cout << "qz: qr (bb) done; now peforming qz decomposition" << std::endl; |
3185 | 551 #endif |
3183 | 552 |
3185 | 553 bb = bqr.R (); |
554 | |
555 #ifdef DEBUG | |
3538 | 556 std::cout << "qz: extracted bb" << std::endl; |
3185 | 557 #endif |
3183 | 558 |
3185 | 559 aa = (bqr.Q ()).transpose ()*aa; |
560 | |
561 #ifdef DEBUG | |
3538 | 562 std::cout << "qz: updated aa " << std::endl; |
563 std::cout << "bqr.Q () = " << std::endl << bqr.Q () << std::endl; | |
3183 | 564 |
3185 | 565 if (compq == 'V') |
3538 | 566 std::cout << "QQ =" << QQ << std::endl; |
3185 | 567 #endif |
3183 | 568 |
3185 | 569 if (compq == 'V') |
570 QQ = QQ*bqr.Q (); | |
3183 | 571 |
3185 | 572 #ifdef DEBUG |
3538 | 573 std::cout << "qz: precursors done..." << std::endl; |
3185 | 574 #endif |
3183 | 575 |
3185 | 576 #ifdef DEBUG |
3538 | 577 std::cout << "qz: compq = " << compq << ", compz = " << compz << std::endl; |
3185 | 578 #endif |
3183 | 579 |
3185 | 580 // reduce to generalized hessenberg form |
581 F77_XFCN (dgghrd, DGGHRD, | |
4552 | 582 (F77_CONST_CHAR_ARG2 (&compq, 1), |
583 F77_CONST_CHAR_ARG2 (&compz, 1), | |
584 nn, ilo, ihi, aa.fortran_vec (), | |
585 nn, bb.fortran_vec (), nn, QQ.fortran_vec (), nn, | |
586 ZZ.fortran_vec (), nn, info | |
587 F77_CHAR_ARG_LEN (1) | |
588 F77_CHAR_ARG_LEN (1))); | |
3183 | 589 |
3185 | 590 // check if just computing generalized eigenvalues or if we're |
591 // actually computing the decomposition | |
3183 | 592 |
3185 | 593 // reduce to generalized Schur form |
594 F77_XFCN (dhgeqz, DHGEQZ, | |
4552 | 595 (F77_CONST_CHAR_ARG2 (&qz_job, 1), |
596 F77_CONST_CHAR_ARG2 (&compq, 1), | |
597 F77_CONST_CHAR_ARG2 (&compz, 1), | |
598 nn, ilo, ihi, aa.fortran_vec (), nn, bb.fortran_vec (), | |
599 nn, alphar.fortran_vec (), alphai.fortran_vec (), | |
600 betar.fortran_vec (), QQ.fortran_vec (), nn, | |
601 ZZ.fortran_vec (), nn, work.fortran_vec (), nn, info | |
602 F77_CHAR_ARG_LEN (1) | |
603 F77_CHAR_ARG_LEN (1) | |
604 F77_CHAR_ARG_LEN (1))); | |
3185 | 605 } |
3183 | 606 |
607 // order the QZ decomposition? | |
8927
d75f4ee0538d
qz.cc (Fqz): avoid maybe clobbred by vfork warning from GCC
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
608 if (! (ord_job == 'N' || ord_job == 'n')) |
3183 | 609 { |
3185 | 610 if (complex_case) |
611 { | |
612 // probably not needed, but better be safe | |
613 error ("qz: cannot re-order complex qz decomposition."); | |
614 return retval; | |
615 } | |
616 else | |
617 { | |
618 #ifdef DEBUG_SORT | |
8927
d75f4ee0538d
qz.cc (Fqz): avoid maybe clobbred by vfork warning from GCC
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
619 std::cout << "qz: ordering eigenvalues: ord_job = " |
d75f4ee0538d
qz.cc (Fqz): avoid maybe clobbred by vfork warning from GCC
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
620 << ord_job << std::endl; |
3185 | 621 #endif |
3183 | 622 |
3185 | 623 // declared static to avoid vfork/long jump compiler complaints |
624 static sort_function sort_test; | |
7520 | 625 sort_test = 0; |
3183 | 626 |
8927
d75f4ee0538d
qz.cc (Fqz): avoid maybe clobbred by vfork warning from GCC
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
627 switch (ord_job) |
3185 | 628 { |
629 case 'S': | |
8927
d75f4ee0538d
qz.cc (Fqz): avoid maybe clobbred by vfork warning from GCC
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
630 case 's': |
3185 | 631 sort_test = &fin; |
632 break; | |
3183 | 633 |
3185 | 634 case 'B': |
8927
d75f4ee0538d
qz.cc (Fqz): avoid maybe clobbred by vfork warning from GCC
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
635 case 'b': |
3185 | 636 sort_test = &fout; |
637 break; | |
3183 | 638 |
3185 | 639 case '+': |
640 sort_test = &fcrhp; | |
641 break; | |
3183 | 642 |
3185 | 643 case '-': |
644 sort_test = &folhp; | |
645 break; | |
646 | |
647 default: | |
3427 | 648 // invalid order option (should never happen, since we |
3185 | 649 // checked the options at the top). |
650 panic_impossible (); | |
651 break; | |
3550 | 652 } |
3183 | 653 |
5275 | 654 octave_idx_type ndim, fail; |
3185 | 655 double inf_norm; |
656 | |
657 F77_XFCN (xdlange, XDLANGE, | |
4552 | 658 (F77_CONST_CHAR_ARG2 ("I", 1), |
4566 | 659 nn, nn, aa.data (), nn, work.fortran_vec (), inf_norm |
4552 | 660 F77_CHAR_ARG_LEN (1))); |
3185 | 661 |
662 double eps = DBL_EPSILON*inf_norm*nn; | |
663 | |
664 #ifdef DEBUG_SORT | |
3538 | 665 std::cout << "qz: calling dsubsp: aa=" << std::endl; |
3531 | 666 octave_print_internal (std::cout, aa, 0); |
3538 | 667 std::cout << std::endl << "bb=" << std::endl; |
3531 | 668 octave_print_internal (std::cout, bb, 0); |
3185 | 669 if (compz == 'V') |
670 { | |
3538 | 671 std::cout << std::endl << "ZZ=" << std::endl; |
3531 | 672 octave_print_internal (std::cout, ZZ, 0); |
3185 | 673 } |
3538 | 674 std::cout << std::endl; |
675 std::cout << "alphar = " << std::endl; | |
3531 | 676 octave_print_internal (std::cout, (Matrix) alphar, 0); |
3538 | 677 std::cout << std::endl << "alphai = " << std::endl; |
3531 | 678 octave_print_internal (std::cout, (Matrix) alphai, 0); |
3538 | 679 std::cout << std::endl << "beta = " << std::endl; |
3531 | 680 octave_print_internal (std::cout, (Matrix) betar, 0); |
3538 | 681 std::cout << std::endl; |
3185 | 682 #endif |
683 | |
5275 | 684 Array<octave_idx_type> ind (nn); |
3550 | 685 |
3185 | 686 F77_XFCN (dsubsp, DSUBSP, |
4552 | 687 (nn, nn, aa.fortran_vec (), bb.fortran_vec (), |
688 ZZ.fortran_vec (), sort_test, eps, ndim, fail, | |
3550 | 689 ind.fortran_vec ())); |
3185 | 690 |
691 #ifdef DEBUG | |
3538 | 692 std::cout << "qz: back from dsubsp: aa=" << std::endl; |
3531 | 693 octave_print_internal (std::cout, aa, 0); |
3538 | 694 std::cout << std::endl << "bb=" << std::endl; |
3531 | 695 octave_print_internal (std::cout, bb, 0); |
3185 | 696 if (compz == 'V') |
697 { | |
3538 | 698 std::cout << std::endl << "ZZ=" << std::endl; |
3531 | 699 octave_print_internal (std::cout, ZZ, 0); |
3185 | 700 } |
3538 | 701 std::cout << std::endl; |
3185 | 702 #endif |
703 | |
704 // manually update alphar, alphai, betar | |
705 static int jj; | |
706 | |
707 jj=0; | |
708 while (jj < nn) | |
709 { | |
710 #ifdef DEBUG_EIG | |
3538 | 711 std::cout << "computing gen eig #" << jj << std::endl; |
3185 | 712 #endif |
713 | |
714 static int zcnt; // number of zeros in this block | |
715 | |
716 if (jj == (nn-1)) | |
717 zcnt = 1; | |
718 else if (aa(jj+1,jj) == 0) | |
719 zcnt = 1; | |
720 else zcnt = 2; | |
721 | |
722 if (zcnt == 1) // real zero | |
723 { | |
724 #ifdef DEBUG_EIG | |
3538 | 725 std::cout << " single gen eig:" << std::endl; |
726 std::cout << " alphar(" << jj << ") = " << aa(jj,jj) << std::endl; | |
727 std::cout << " betar( " << jj << ") = " << bb(jj,jj) << std::endl; | |
728 std::cout << " alphai(" << jj << ") = 0" << std::endl; | |
3185 | 729 #endif |
730 | |
731 alphar(jj) = aa(jj,jj); | |
732 alphai(jj) = 0; | |
733 betar(jj) = bb(jj,jj); | |
734 } | |
735 else | |
736 { | |
737 // complex conjugate pair | |
738 #ifdef DEBUG_EIG | |
3538 | 739 std::cout << "qz: calling dlag2:" << std::endl; |
3531 | 740 std::cout << "safmin=" |
3538 | 741 << setiosflags (std::ios::scientific) << safmin << std::endl; |
3185 | 742 |
743 for (int idr = jj; idr <= jj+1; idr++) | |
744 { | |
745 for (int idc = jj; idc <= jj+1; idc++) | |
746 { | |
3531 | 747 std::cout << "aa(" << idr << "," << idc << ")=" |
3538 | 748 << aa(idr,idc) << std::endl; |
3531 | 749 std::cout << "bb(" << idr << "," << idc << ")=" |
3538 | 750 << bb(idr,idc) << std::endl; |
3185 | 751 } |
752 } | |
753 #endif | |
754 | |
5775 | 755 // FIXME -- probably should be using |
4566 | 756 // fortran_vec instead of &aa(jj,jj) here. |
757 | |
3185 | 758 double scale1, scale2, wr1, wr2, wi; |
4629 | 759 const double *aa_ptr = aa.data () + jj*nn+jj; |
760 const double *bb_ptr = bb.data () + jj*nn+jj; | |
3185 | 761 F77_XFCN (dlag2, DLAG2, |
4629 | 762 (aa_ptr, nn, bb_ptr, nn, safmin, |
3185 | 763 scale1, scale2, wr1, wr2, wi)); |
764 | |
765 #ifdef DEBUG_EIG | |
3531 | 766 std::cout << "dlag2 returns: scale1=" << scale1 |
3538 | 767 << "\tscale2=" << scale2 << std::endl |
3185 | 768 << "\twr1=" << wr1 << "\twr2=" << wr2 |
3538 | 769 << "\twi=" << wi << std::endl; |
3185 | 770 #endif |
771 | |
772 // just to be safe, check if it's a real pair | |
773 if (wi == 0) | |
774 { | |
775 alphar(jj) = wr1; | |
776 alphai(jj) = 0; | |
777 betar(jj) = scale1; | |
778 alphar(jj+1) = wr2; | |
779 alphai(jj+1) = 0; | |
780 betar(jj+1) = scale2; | |
781 } | |
782 else | |
783 { | |
784 alphar(jj) = alphar(jj+1)=wr1; | |
785 alphai(jj) = -(alphai(jj+1) = wi); | |
786 betar(jj) = betar(jj+1) = scale1; | |
787 } | |
788 } | |
789 | |
790 // advance past this block | |
791 jj += zcnt; | |
792 } | |
793 | |
794 #ifdef DEBUG_SORT | |
3538 | 795 std::cout << "qz: back from dsubsp: aa=" << std::endl; |
3531 | 796 octave_print_internal (std::cout, aa, 0); |
3538 | 797 std::cout << std::endl << "bb=" << std::endl; |
3531 | 798 octave_print_internal (std::cout, bb, 0); |
3185 | 799 |
800 if (compz == 'V') | |
801 { | |
3538 | 802 std::cout << std::endl << "ZZ=" << std::endl; |
3531 | 803 octave_print_internal (std::cout, ZZ, 0); |
3185 | 804 } |
3538 | 805 std::cout << std::endl << "qz: ndim=" << ndim << std::endl |
806 << "fail=" << fail << std::endl; | |
807 std::cout << "alphar = " << std::endl; | |
3531 | 808 octave_print_internal (std::cout, (Matrix) alphar, 0); |
3538 | 809 std::cout << std::endl << "alphai = " << std::endl; |
3531 | 810 octave_print_internal (std::cout, (Matrix) alphai, 0); |
3538 | 811 std::cout << std::endl << "beta = " << std::endl; |
3531 | 812 octave_print_internal (std::cout, (Matrix) betar, 0); |
3538 | 813 std::cout << std::endl; |
3185 | 814 #endif |
815 } | |
3183 | 816 } |
3185 | 817 |
3183 | 818 // compute generalized eigenvalues? |
819 ComplexColumnVector gev; | |
3185 | 820 |
821 if (nargout < 2 || nargout == 7 || (nargin == 3 && nargout == 4)) | |
3183 | 822 { |
3185 | 823 if (complex_case) |
824 { | |
825 error ("complex case not yet implemented"); | |
826 return retval; | |
827 } | |
828 else | |
829 { | |
830 #ifdef DEBUG | |
3538 | 831 std::cout << "qz: computing generalized eigenvalues" << std::endl; |
3185 | 832 #endif |
3183 | 833 |
3185 | 834 // return finite generalized eigenvalues |
835 int cnt = 0; | |
836 | |
837 for (int ii = 0; ii < nn; ii++) | |
838 if (betar(ii) != 0) | |
839 cnt++; | |
840 | |
841 ComplexColumnVector tmp(cnt); | |
842 | |
3671 | 843 cnt = 0; |
3185 | 844 for (int ii = 0; ii < nn; ii++) |
845 if (betar(ii) != 0) | |
3671 | 846 tmp(cnt++) = Complex(alphar(ii), alphai(ii))/betar(ii); |
3185 | 847 gev = tmp; |
848 } | |
3183 | 849 } |
850 | |
851 // right, left eigenvector matrices | |
3185 | 852 if (nargout >= 5) |
3183 | 853 { |
3185 | 854 char side = (nargout == 5 ? 'R' : 'B'); // which side to compute? |
855 char howmny = 'B'; // compute all of them and backtransform | |
7520 | 856 octave_idx_type *select = 0; // dummy pointer; select is not used. |
5275 | 857 octave_idx_type m; |
3185 | 858 |
859 if (complex_case) | |
860 { | |
861 error ("complex type not yet implemented"); | |
862 return retval; | |
863 } | |
864 else | |
865 { | |
866 #ifdef DEBUG | |
3538 | 867 std::cout << "qz: computing generalized eigenvectors" << std::endl; |
3185 | 868 #endif |
869 | |
870 VL = QQ; | |
871 VR = ZZ; | |
872 | |
873 F77_XFCN (dtgevc, DTGEVC, | |
4552 | 874 (F77_CONST_CHAR_ARG2 (&side, 1), |
875 F77_CONST_CHAR_ARG2 (&howmny, 1), | |
876 select, nn, aa.fortran_vec (), nn, bb.fortran_vec (), | |
877 nn, VL.fortran_vec (), nn, VR.fortran_vec (), nn, nn, | |
878 m, work.fortran_vec (), info | |
879 F77_CHAR_ARG_LEN (1) | |
880 F77_CHAR_ARG_LEN (1))); | |
3185 | 881 |
882 // now construct the complex form of VV, WW | |
883 int jj = 0; | |
884 | |
885 while (jj < nn) | |
886 { | |
4153 | 887 OCTAVE_QUIT; |
888 | |
3185 | 889 // see if real or complex eigenvalue |
890 int cinc = 2; // column increment; assume complex eigenvalue | |
891 | |
892 if (jj == (nn-1)) | |
893 cinc = 1; // single column | |
894 else if (aa(jj+1,jj) == 0) | |
895 cinc = 1; | |
896 | |
897 // now copy the eigenvector (s) to CVR, CVL | |
898 if (cinc == 1) | |
899 { | |
900 for (int ii = 0; ii < nn; ii++) | |
901 CVR(ii,jj) = VR(ii,jj); | |
902 | |
903 if (side == 'B') | |
904 for (int ii = 0; ii < nn; ii++) | |
905 CVL(ii,jj) = VL(ii,jj); | |
906 } | |
907 else | |
908 { | |
909 // double column; complex vector | |
910 | |
911 for (int ii = 0; ii < nn; ii++) | |
912 { | |
913 CVR(ii,jj) = Complex (VR(ii,jj), VR(ii,jj+1)); | |
914 CVR(ii,jj+1) = Complex (VR(ii,jj), -VR(ii,jj+1)); | |
915 } | |
3183 | 916 |
3185 | 917 if (side == 'B') |
918 for (int ii = 0; ii < nn; ii++) | |
919 { | |
920 CVL(ii,jj) = Complex (VL(ii,jj), VL(ii,jj+1)); | |
921 CVL(ii,jj+1) = Complex (VL(ii,jj), -VL(ii,jj+1)); | |
922 } | |
923 } | |
924 | |
925 // advance to next eigenvectors (if any) | |
926 jj += cinc; | |
927 } | |
928 } | |
3183 | 929 } |
3185 | 930 |
931 switch (nargout) | |
932 { | |
933 case 7: | |
934 retval(6) = gev; | |
935 | |
936 case 6: // return eigenvectors | |
937 retval(5) = CVL; | |
938 | |
939 case 5: // return eigenvectors | |
940 retval(4) = CVR; | |
941 | |
942 case 4: | |
943 if (nargin == 3) | |
944 { | |
945 #ifdef DEBUG | |
3538 | 946 std::cout << "qz: sort: retval(3) = gev = " << std::endl; |
3531 | 947 octave_print_internal (std::cout, gev); |
3538 | 948 std::cout << std::endl; |
3185 | 949 #endif |
950 retval(3) = gev; | |
951 } | |
952 else | |
953 retval(3) = ZZ; | |
954 | |
955 case 3: | |
956 if (nargin == 3) | |
957 retval(2) = ZZ; | |
958 else | |
959 retval(2) = QQ; | |
960 | |
961 case 2: | |
962 #ifdef DEBUG | |
3538 | 963 std::cout << "qz: retval (1) = bb = " << std::endl; |
3531 | 964 octave_print_internal (std::cout, bb, 0); |
3538 | 965 std::cout << std::endl << "qz: retval(0) = aa = " <<std::endl; |
3531 | 966 octave_print_internal (std::cout, aa, 0); |
3538 | 967 std::cout << std::endl; |
3185 | 968 #endif |
969 retval(1) = bb; | |
970 retval(0) = aa; | |
971 break; | |
972 | |
973 case 1: | |
974 case 0: | |
975 #ifdef DEBUG | |
3538 | 976 std::cout << "qz: retval(0) = gev = " << gev << std::endl; |
3185 | 977 #endif |
978 retval(0) = gev; | |
979 break; | |
980 | |
981 default: | |
982 error ("qz: too many return arguments."); | |
983 break; | |
3183 | 984 } |
985 | |
3185 | 986 #ifdef DEBUG |
3538 | 987 std::cout << "qz: exiting (at long last)" << std::endl; |
3185 | 988 #endif |
3183 | 989 |
990 return retval; | |
991 } | |
992 | |
993 /* | |
994 ;;; Local Variables: *** | |
995 ;;; mode: C++ *** | |
996 ;;; End: *** | |
997 */ |