54 #if defined (DEBUG) || defined (DEBUG_SORT)
63 const double&
BETA,
const double& S,
230 const octave_idx_type&,
const double*,
231 const octave_idx_type&,
double*,
double&
245 const double& beta,
const double& s,
const double&)
248 return (alpha * beta >= 0 ? 1 : -1);
250 return (s >= 0 ? 1 : -1);
255 const double& beta,
const double&,
const double& p)
260 retval = (fabs (alpha) < fabs (beta) ? 1 : -1);
262 retval = (fabs (p) < 1 ? 1 : -1);
265 std::cout <<
"qz: fin: retval=" << retval << std::endl;
273 const double& beta,
const double& s,
const double&)
276 return (alpha * beta < 0 ? 1 : -1);
278 return (s < 0 ? 1 : -1);
283 const double& beta,
const double&,
const double& p)
286 return (fabs (alpha) >= fabs (beta) ? 1 : -1);
288 return (fabs (p) >= 1 ? 1 : -1);
294 DEFUN (qz, args, nargout,
296 @deftypefn {Built-in Function} {@var{lambda} =} qz (@var{A}, @var{B})\n\
297 @deftypefnx {Built-in Function} {@var{lambda} =} qz (@var{A}, @var{B}, @var{opt})\n\
298 QZ@tie{}decomposition of the generalized eigenvalue problem\n\
299 (@math{A x = s B x}). There are three ways to call this function:\n\
301 @item @code{@var{lambda} = qz (@var{A}, @var{B})}\n\
303 Computes the generalized eigenvalues\n\
310 of @math{(A - s B)}.\n\
312 @item @code{[AA, BB, Q, Z, V, W, @var{lambda}] = qz (@var{A}, @var{B})}\n\
314 Computes QZ@tie{}decomposition, generalized eigenvectors, and\n\
315 generalized eigenvalues of @math{(A - s B)}\n\
317 $$ AV = BV{ \\rm diag }(\\lambda) $$\n\
318 $$ W^T A = { \\rm diag }(\\lambda)W^T B $$\n\
319 $$ AA = Q^T AZ, BB = Q^T BZ $$\n\
326 A * V = B * V * diag (@var{lambda})\n\
327 W' * A = diag (@var{lambda}) * W' * B\n\
328 AA = Q * A * Z, BB = Q * B * Z\n\
334 with @var{Q} and @var{Z} orthogonal (unitary)= @var{I}\n\
336 @item @code{[AA,BB,Z@{, @var{lambda}@}] = qz (@var{A}, @var{B}, @var{opt})}\n\
338 As in form [2], but allows ordering of generalized eigenpairs\n\
339 for (e.g.) solution of discrete time algebraic Riccati equations.\n\
340 Form 3 is not available for complex matrices, and does not compute\n\
341 the generalized eigenvectors @var{V}, @var{W}, nor the orthogonal matrix\n\
346 for ordering eigenvalues of the @nospell{GEP} pencil. The leading block\n\
347 of the revised pencil contains all eigenvalues that satisfy:\n\
350 @item @qcode{\"N\"}\n\
351 = unordered (default)\n\
353 @item @qcode{\"S\"}\n\
354 = small: leading block has all |lambda| @leq{} 1\n\
356 @item @qcode{\"B\"}\n\
357 = big: leading block has all |lambda| @geq{} 1\n\
359 @item @qcode{\"-\"}\n\
360 = negative real part: leading block has all eigenvalues\n\
361 in the open left half-plane\n\
363 @item @qcode{\"+\"}\n\
364 = non-negative real part: leading block has all eigenvalues\n\
365 in the closed right half-plane\n\
370 Note: @code{qz} performs permutation balancing, but not scaling\n\
371 (@pxref{XREFbalance}). The order of output arguments was selected for\n\
372 compatibility with @sc{matlab}.\n\
373 @seealso{eig, balance, lu, chol, hess, qr, qzhess, schur, svd}\n\
377 int nargin = args.
length ();
380 std::cout <<
"qz: nargin = " << nargin
381 <<
", nargout = " << nargout << std::endl;
384 if (nargin < 2 || nargin > 3 || nargout > 7)
389 else if (nargin == 3 && (nargout < 3 || nargout > 4))
391 error (
"qz: invalid number of output arguments for form [3] call");
396 std::cout <<
"qz: determine ordering option" << std::endl;
400 volatile char ord_job = 0;
401 static double safmin;
405 else if (!args(2).is_string ())
407 error (
"qz: OPT must be a string");
412 std::string tmp = args(2).string_value ();
417 if (! (ord_job ==
'N' || ord_job ==
'n'
418 || ord_job ==
'S' || ord_job ==
's'
419 || ord_job ==
'B' || ord_job ==
'b'
420 || ord_job ==
'+' || ord_job ==
'-'))
422 error (
"qz: invalid order option");
432 std::cout <<
"qz: initial value of safmin="
433 << setiosflags (std::ios::scientific)
434 << safmin << std::endl;
442 std::cout <<
"qz: DANGER WILL ROBINSON: safmin is 0!" << std::endl;
450 std::cout <<
"qz: safmin set to "
451 << setiosflags (std::ios::scientific)
452 << safmin << std::endl;
458 std::cout <<
"qz: check argument 1" << std::endl;
465 std::cout <<
"argument 1 dimensions: ("
466 << nn <<
"," << args(0).columns () <<
")"
470 int arg_is_empty =
empty_arg (
"qz", nn, args(0).columns ());
472 if (arg_is_empty < 0)
477 else if (arg_is_empty > 0)
482 else if (args(0).columns () != nn)
492 if (args(0).is_complex_type ())
493 caa = args(0).complex_matrix_value ();
495 aa = args(0).matrix_value ();
501 std::cout <<
"qz: check argument 2" << std::endl;
505 if ((nn != args(1).columns ()) || (nn != args(1).rows ()))
514 if (args(1).is_complex_type ())
515 cbb = args(1).complex_matrix_value ();
517 bb = args(1).matrix_value ();
526 volatile int complex_case
527 = (args(0).is_complex_type () || args(1).is_complex_type ());
529 if (nargin == 3 && complex_case)
531 error (
"qz: cannot re-order complex qz decomposition");
536 Matrix QQ(nn,nn), ZZ(nn,nn),
VR(nn,nn),
VL(nn,nn);
537 RowVector alphar(nn), alphai(nn), betar(nn);
541 char compq = (nargout >= 3 ?
'V' :
'N');
542 char compz = ((nargout >= 4 || nargin == 3)?
'V' :
'N');
545 if (compq ==
'V' || compz ==
'V')
550 QQ(ii,jj) = ZZ(ii,jj) = (ii == jj ? 1.0 : 0.0);
554 const char bal_job =
'P';
555 RowVector lscale (nn), rscale (nn), work (6 * nn), rwork (nn);
561 std::cout <<
"qz: performing balancing; CQ=" << std::endl
564 if (args(0).is_real_type ())
567 if (args(1).is_real_type ())
579 nn, ilo, ihi, lscale.fortran_vec (),
580 rscale.fortran_vec (), work.fortran_vec (), info
587 std::cout <<
"qz: performing balancing; QQ=" << std::endl
594 nn, ilo, ihi, lscale.fortran_vec (),
595 rscale.fortran_vec (), work.fortran_vec (), info
608 nn, ilo, ihi, lscale.data (), rscale.data (),
609 nn, QQ.fortran_vec (),
nn, info
615 std::cout <<
"qz: balancing done; QQ=" << std::endl << QQ << std::endl;
625 nn, ilo, ihi, lscale.data (), rscale.data (),
626 nn, ZZ.fortran_vec (),
nn, info
632 std::cout <<
"qz: balancing done; ZZ=" << std::endl << ZZ << std::endl;
638 qz_job = (nargout < 2 ?
'E' :
'S');
657 CZ.fortran_vec (),
nn, info
671 CQ.fortran_vec (),
nn,
672 CZ.fortran_vec (),
nn,
684 nn, ilo, ihi, lscale.data (), rscale.data (),
685 nn,
CQ.fortran_vec (),
nn, info
696 nn, ilo, ihi, lscale.data (), rscale.data (),
697 nn,
CZ.fortran_vec (),
nn, info
706 std::cout <<
"qz: peforming qr decomposition of bb" << std::endl;
713 std::cout <<
"qz: qr (bb) done; now peforming qz decomposition"
720 std::cout <<
"qz: extracted bb" << std::endl;
726 std::cout <<
"qz: updated aa " << std::endl;
727 std::cout <<
"bqr.Q () = " << std::endl << bqr.
Q () << std::endl;
730 std::cout <<
"QQ =" << QQ << std::endl;
737 std::cout <<
"qz: precursors done..." << std::endl;
741 std::cout <<
"qz: compq = " << compq <<
", compz = " << compz
751 ZZ.fortran_vec (),
nn, info
764 nn, alphar.fortran_vec (), alphai.fortran_vec (),
766 ZZ.fortran_vec (),
nn, work.fortran_vec (),
nn, info
776 nn, ilo, ihi, lscale.data (), rscale.data (),
777 nn, QQ.fortran_vec (),
nn, info
783 std::cout <<
"qz: balancing done; QQ=" << std::endl
794 nn, ilo, ihi, lscale.data (), rscale.data (),
795 nn, ZZ.fortran_vec (),
nn, info
801 std::cout <<
"qz: balancing done; ZZ=" << std::endl
809 if (! (ord_job ==
'N' || ord_job ==
'n'))
814 error (
"qz: cannot re-order complex qz decomposition");
820 std::cout <<
"qz: ordering eigenvalues: ord_job = "
821 << ord_job << std::endl;
860 nn, nn, aa.
data (),
nn, work.fortran_vec (), inf_norm
863 double eps = std::numeric_limits<double>::epsilon () * inf_norm *
nn;
866 std::cout <<
"qz: calling dsubsp: aa=" << std::endl;
868 std::cout << std::endl <<
"bb=" << std::endl;
872 std::cout << std::endl <<
"ZZ=" << std::endl;
875 std::cout << std::endl;
876 std::cout <<
"alphar = " << std::endl;
878 std::cout << std::endl <<
"alphai = " << std::endl;
880 std::cout << std::endl <<
"beta = " << std::endl;
882 std::cout << std::endl;
889 ZZ.fortran_vec (), sort_test,
eps, ndim, fail,
893 std::cout <<
"qz: back from dsubsp: aa=" << std::endl;
895 std::cout << std::endl <<
"bb=" << std::endl;
899 std::cout << std::endl <<
"ZZ=" << std::endl;
902 std::cout << std::endl;
912 std::cout <<
"computing gen eig #" << jj << std::endl;
920 else if (aa(jj+1,jj) == 0)
928 std::cout <<
" single gen eig:" << std::endl;
929 std::cout <<
" alphar(" << jj <<
") = " << aa(jj,jj)
931 std::cout <<
" betar( " << jj <<
") = " << bb(jj,jj)
933 std::cout <<
" alphai(" << jj <<
") = 0" << std::endl;
936 alphar(jj) = aa(jj,jj);
938 betar(jj) = bb(jj,jj);
944 std::cout <<
"qz: calling dlag2:" << std::endl;
945 std::cout <<
"safmin="
946 << setiosflags (std::ios::scientific)
947 << safmin << std::endl;
949 for (
int idr = jj; idr <= jj+1; idr++)
951 for (
int idc = jj; idc <= jj+1; idc++)
953 std::cout <<
"aa(" << idr <<
"," << idc <<
")="
954 << aa(idr,idc) << std::endl;
955 std::cout <<
"bb(" << idr <<
"," << idc <<
")="
956 << bb(idr,idc) << std::endl;
964 double scale1, scale2, wr1, wr2,
wi;
965 const double *aa_ptr = aa.
data () + jj * nn + jj;
966 const double *bb_ptr = bb.
data () + jj * nn + jj;
968 (aa_ptr, nn, bb_ptr, nn, safmin,
969 scale1, scale2, wr1, wr2, wi));
972 std::cout <<
"dlag2 returns: scale1=" << scale1
973 <<
"\tscale2=" << scale2 << std::endl
974 <<
"\twr1=" << wr1 <<
"\twr2=" << wr2
975 <<
"\twi=" << wi << std::endl;
986 betar(jj+1) = scale2;
990 alphar(jj) = alphar(jj+1) = wr1;
991 alphai(jj) = -(alphai(jj+1) =
wi);
992 betar(jj) = betar(jj+1) = scale1;
1001 std::cout <<
"qz: back from dsubsp: aa=" << std::endl;
1003 std::cout << std::endl <<
"bb=" << std::endl;
1008 std::cout << std::endl <<
"ZZ=" << std::endl;
1011 std::cout << std::endl <<
"qz: ndim=" << ndim << std::endl
1012 <<
"fail=" << fail << std::endl;
1013 std::cout <<
"alphar = " << std::endl;
1015 std::cout << std::endl <<
"alphai = " << std::endl;
1017 std::cout << std::endl <<
"beta = " << std::endl;
1019 std::cout << std::endl;
1027 if (nargout < 2 || nargout == 7 || (nargin == 3 && nargout == 4))
1033 for (
int ii = 0; ii <
nn; ii++)
1039 for (
int ii = 0; ii <
nn; ii++)
1040 tmp(cnt++) = xalpha(ii) / xbeta(ii);
1047 std::cout <<
"qz: computing generalized eigenvalues" << std::endl;
1053 for (
int ii = 0; ii <
nn; ii++)
1060 for (
int ii = 0; ii <
nn; ii++)
1062 tmp(cnt++) =
Complex(alphar(ii), alphai(ii))/betar(ii);
1072 char side = (nargout == 5 ?
'R' :
'B');
1098 std::cout <<
"qz: computing generalized eigenvectors" << std::endl;
1110 m, work.fortran_vec (), info
1129 else if (aa(jj+1,jj) == 0)
1135 for (
int ii = 0; ii <
nn; ii++)
1136 CVR(ii,jj) =
VR(ii,jj);
1139 for (
int ii = 0; ii <
nn; ii++)
1140 CVL(ii,jj) =
VL(ii,jj);
1146 for (
int ii = 0; ii <
nn; ii++)
1153 for (
int ii = 0; ii <
nn; ii++)
1183 std::cout <<
"qz: sort: retval(3) = gev = " << std::endl;
1185 std::cout << std::endl;
1208 retval(2) =
CQ.hermitian ();
1210 retval(2) = QQ.transpose ();
1218 std::cout <<
"qz: retval(1) = cbb = " << std::endl;
1220 std::cout << std::endl <<
"qz: retval(0) = caa = " <<std::endl;
1222 std::cout << std::endl;
1230 std::cout <<
"qz: retval(1) = bb = " << std::endl;
1232 std::cout << std::endl <<
"qz: retval(0) = aa = " <<std::endl;
1234 std::cout << std::endl;
1246 std::cout <<
"qz: retval(0) = gev = " << gev << std::endl;
1252 error (
"qz: too many return arguments");
1257 std::cout <<
"qz: exiting (at long last)" << std::endl;