GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
qz.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1998-2024 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 // Generalized eigenvalue balancing via LAPACK
27 
28 // Originally written by A. S. Hodel <scotte@eng.auburn.edu>, but is
29 // substantially different with the change to use LAPACK.
30 
31 #undef DEBUG
32 #undef DEBUG_SORT
33 #undef DEBUG_EIG
34 
35 #if defined (HAVE_CONFIG_H)
36 # include "config.h"
37 #endif
38 
39 #include <cctype>
40 #include <cmath>
41 
42 #if defined (DEBUG_EIG)
43 # include <iomanip>
44 #endif
45 
46 #include "f77-fcn.h"
47 #include "lo-lapack-proto.h"
48 #include "qr.h"
49 #include "quit.h"
50 
51 #include "defun.h"
52 #include "error.h"
53 #include "errwarn.h"
54 #include "ovl.h"
55 #if defined (DEBUG) || defined (DEBUG_SORT)
56 # include "pager.h"
57 # include "pr-output.h"
58 #endif
59 
61 
62 DEFUN (qz, args, nargout,
63  doc: /* -*- texinfo -*-
64 @deftypefn {} {[@var{AA}, @var{BB}, @var{Q}, @var{Z}, @var{V}, @var{W}] =} qz (@var{A}, @var{B})
65 @deftypefnx {} {[@var{AA}, @var{BB}, @var{Q}, @var{Z}, @var{V}, @var{W}] =} qz (@var{A}, @var{B}, @var{opt})
66 Compute the QZ@tie{}decomposition of a generalized eigenvalue problem.
67 
68 The generalized eigenvalue problem is defined as
69 
70 @tex
71 $$A x = \lambda B x$$
72 @end tex
73 @ifnottex
74 
75 @math{A x = @var{lambda} B x}
76 
77 @end ifnottex
78 
79 There are two calling forms of the function:
80 
81 @enumerate
82 @item @code{[@var{AA}, @var{BB}, @var{Q}, @var{Z}, @var{V}, @var{W}, @var{lambda}] = qz (@var{A}, @var{B})}
83 
84 Compute the complex QZ@tie{}decomposition, generalized eigenvectors, and
85 generalized eigenvalues.
86 @tex
87 $$ AA = Q^T AZ, BB = Q^T BZ $$
88 $$ { \rm diag }(BB)AV = BV{ \rm diag }(AA) $$
89 $$ { \rm diag }(BB) W^T A = { \rm diag }(AA) W^T B $$
90 @end tex
91 @ifnottex
92 
93 @example
94 @group
95 
96 @var{AA} = @var{Q} * @var{A} * @var{Z}, @var{BB} = @var{Q} * @var{B} * @var{Z}
97 @var{A} * @var{V} * diag (diag (@var{BB})) = @var{B} * @var{V} * diag (diag (@var{AA}))
98 diag (diag (@var{BB})) * @var{W}' * @var{A} = diag (diag (@var{AA})) * @var{W}' * @var{B}
99 
100 @end group
101 @end example
102 
103 @end ifnottex
104 with @var{AA} and @var{BB} upper triangular, and @var{Q} and @var{Z}
105 unitary. The matrices @var{V} and @var{W} respectively contain the right
106 and left generalized eigenvectors.
107 
108 @item @code{[@var{AA}, @var{BB}, @var{Z} @{, @var{lambda}@}] = qz (@var{A}, @var{B}, @var{opt})}
109 
110 The @var{opt} argument must be equal to either @qcode{"real"} or
111 @qcode{"complex"}. If it is equal to @qcode{"complex"}, then this
112 calling form is equivalent to the first one with only two input
113 arguments.
114 
115 If @var{opt} is equal to @qcode{"real"}, then the real QZ decomposition
116 is computed. In particular, @var{AA} is only guaranteed to be
117 quasi-upper triangular with 1-by-1 and 2-by-2 blocks on the diagonal,
118 and @var{Q} and @var{Z} are orthogonal. The identities mentioned above
119 for right and left generalized eigenvectors are only verified if
120 @var{AA} is upper triangular (i.e., when all the generalized eigenvalues
121 are real, in which case the real and complex QZ coincide).
122 
123 @end enumerate
124 
125 Note: @code{qz} performs permutation balancing, but not scaling
126 (@pxref{XREFbalance,,@code{balance}}), which may be lead to less accurate
127 results than @code{eig}. The order of output arguments was selected for
128 compatibility with @sc{matlab}.
129 @seealso{eig, gsvd, balance, chol, hess, lu, qr, qzhess, schur}
130 @end deftypefn */)
131 {
132  int nargin = args.length ();
133 
134 #if defined (DEBUG)
135  octave_stdout << "qz: nargin = " << nargin
136  << ", nargout = " << nargout << std::endl;
137 #endif
138 
139  if (nargin < 2 || nargin > 3 || nargout > 6)
140  print_usage ();
141 
142  bool complex_case = true;
143 
144  if (nargin == 3)
145  {
146  std::string opt = args(2).xstring_value ("qz: OPT must be a string");
147 
148  if (opt == "real")
149  {
150  if (args(0).iscomplex () || args(1).iscomplex ())
151  {
152  warning ("qz: ignoring 'real' option with complex matrices");
153  complex_case = true;
154  }
155  else
156  complex_case = false;
157  }
158  else if (opt == "complex")
159  complex_case = true;
160  else
161  error ("qz: OPT must be 'real' or 'complex'");
162  }
163 
164 #if defined (DEBUG)
165  octave_stdout << "qz: check matrix A" << std::endl;
166 #endif
167 
168  // Matrix A: check dimensions.
169  F77_INT nn = to_f77_int (args(0).rows ());
170  F77_INT nc = to_f77_int (args(0).columns ());
171 
172 #if defined (DEBUG)
173  octave_stdout << "Matrix A dimensions: (" << nn << ',' << nc << ')'
174  << std::endl;
175 #endif
176 
177  if (nc != nn)
178  err_square_matrix_required ("qz", "A");
179 
180  // Matrix A: get value.
181  Matrix aa;
182  ComplexMatrix caa;
183 
184  if (args(0).iscomplex ())
185  caa = args(0).complex_matrix_value ();
186  else
187  aa = args(0).matrix_value ();
188 
189 #if defined (DEBUG)
190  octave_stdout << "qz: check matrix B" << std::endl;
191 #endif
192 
193  // Extract argument 2 (bb, or cbb if complex).
194  F77_INT b_nr = to_f77_int (args(1).rows ());
195  F77_INT b_nc = to_f77_int (args(1).columns ());
196 
197  if (nn != b_nc || nn != b_nr)
199 
200  Matrix bb;
201  ComplexMatrix cbb;
202 
203  if (args(1).iscomplex ())
204  cbb = args(1).complex_matrix_value ();
205  else
206  bb = args(1).matrix_value ();
207 
208  // First, declare variables used in both the real and complex cases.
209  // FIXME: There are a lot of excess variables declared.
210  // Probably a better way to handle this.
211  Matrix QQ (nn, nn), ZZ (nn, nn), VR (nn, nn), VL (nn, nn);
212  RowVector alphar (nn), alphai (nn), betar (nn);
213  ComplexRowVector xalpha (nn), xbeta (nn);
214  ComplexMatrix CQ (nn, nn), CZ (nn, nn), CVR (nn, nn), CVL (nn, nn);
215  F77_INT ilo, ihi, info;
216  char comp_q = (nargout >= 3 ? 'V' : 'N');
217  char comp_z = (nargout >= 4 ? 'V' : 'N');
218 
219  // Initialize Q, Z to identity matrix if either is needed
220  if (comp_q == 'V' || comp_z == 'V')
221  {
222  double *QQptr = QQ.fortran_vec ();
223  double *ZZptr = ZZ.fortran_vec ();
224  std::fill_n (QQptr, QQ.numel (), 0.0);
225  std::fill_n (ZZptr, ZZ.numel (), 0.0);
226  for (F77_INT i = 0; i < nn; i++)
227  {
228  QQ(i, i) = 1.0;
229  ZZ(i, i) = 1.0;
230  }
231  }
232 
233  // Always perform permutation balancing.
234  const char bal_job = 'P';
235  RowVector lscale (nn), rscale (nn), work (6 * nn), rwork (nn);
236 
237  if (complex_case)
238  {
239 #if defined (DEBUG)
240  if (comp_q == 'V')
241  octave_stdout << "qz: performing balancing; CQ =\n" << CQ << std::endl;
242 #endif
243  if (args(0).isreal ())
244  caa = ComplexMatrix (aa);
245 
246  if (args(1).isreal ())
247  cbb = ComplexMatrix (bb);
248 
249  if (comp_q == 'V')
250  CQ = ComplexMatrix (QQ);
251 
252  if (comp_z == 'V')
253  CZ = ComplexMatrix (ZZ);
254 
255  F77_XFCN (zggbal, ZGGBAL,
256  (F77_CONST_CHAR_ARG2 (&bal_job, 1),
257  nn, F77_DBLE_CMPLX_ARG (caa.fortran_vec ()), nn,
259  nn, ilo, ihi, lscale.fortran_vec (),
260  rscale.fortran_vec (), work.fortran_vec (), info
261  F77_CHAR_ARG_LEN (1)));
262  }
263  else
264  {
265 #if defined (DEBUG)
266  if (comp_q == 'V')
267  octave_stdout << "qz: performing balancing; QQ =\n" << QQ << std::endl;
268 #endif
269 
270  F77_XFCN (dggbal, DGGBAL,
271  (F77_CONST_CHAR_ARG2 (&bal_job, 1),
272  nn, aa.fortran_vec (), nn, bb.fortran_vec (),
273  nn, ilo, ihi, lscale.fortran_vec (),
274  rscale.fortran_vec (), work.fortran_vec (), info
275  F77_CHAR_ARG_LEN (1)));
276  }
277 
278  // Only permutation balance above is done. Skip scaling balance.
279 
280  char qz_job = (nargout < 2 ? 'E' : 'S');
281 
282  if (complex_case)
283  {
284  // Complex case.
285 
286  // The QR decomposition of cbb.
287  math::qr<ComplexMatrix> cbqr (cbb);
288  // The R matrix of QR decomposition for cbb.
289  cbb = cbqr.R ();
290  // (Q*)caa for following work.
291  caa = (cbqr.Q ().hermitian ()) * caa;
292  CQ = CQ * cbqr.Q ();
293 
294  F77_XFCN (zgghrd, ZGGHRD,
295  (F77_CONST_CHAR_ARG2 (&comp_q, 1),
296  F77_CONST_CHAR_ARG2 (&comp_z, 1),
297  nn, ilo, ihi, F77_DBLE_CMPLX_ARG (caa.fortran_vec ()),
298  nn, F77_DBLE_CMPLX_ARG (cbb.fortran_vec ()), nn,
299  F77_DBLE_CMPLX_ARG (CQ.fortran_vec ()), nn,
300  F77_DBLE_CMPLX_ARG (CZ.fortran_vec ()), nn, info
301  F77_CHAR_ARG_LEN (1)
302  F77_CHAR_ARG_LEN (1)));
303 
304  ComplexRowVector cwork (nn);
305 
306  F77_XFCN (zhgeqz, ZHGEQZ,
307  (F77_CONST_CHAR_ARG2 (&qz_job, 1),
308  F77_CONST_CHAR_ARG2 (&comp_q, 1),
309  F77_CONST_CHAR_ARG2 (&comp_z, 1),
310  nn, ilo, ihi,
311  F77_DBLE_CMPLX_ARG (caa.fortran_vec ()), nn,
312  F77_DBLE_CMPLX_ARG (cbb.fortran_vec ()), nn,
313  F77_DBLE_CMPLX_ARG (xalpha.fortran_vec ()),
314  F77_DBLE_CMPLX_ARG (xbeta.fortran_vec ()),
315  F77_DBLE_CMPLX_ARG (CQ.fortran_vec ()), nn,
316  F77_DBLE_CMPLX_ARG (CZ.fortran_vec ()), nn,
317  F77_DBLE_CMPLX_ARG (cwork.fortran_vec ()), nn,
318  rwork.fortran_vec (), info
319  F77_CHAR_ARG_LEN (1)
320  F77_CHAR_ARG_LEN (1)
321  F77_CHAR_ARG_LEN (1)));
322 
323  if (comp_q == 'V')
324  {
325  // Left eigenvector.
326  F77_XFCN (zggbak, ZGGBAK,
327  (F77_CONST_CHAR_ARG2 (&bal_job, 1),
328  F77_CONST_CHAR_ARG2 ("L", 1),
329  nn, ilo, ihi, lscale.data (), rscale.data (),
330  nn, F77_DBLE_CMPLX_ARG (CQ.fortran_vec ()), nn, info
331  F77_CHAR_ARG_LEN (1)
332  F77_CHAR_ARG_LEN (1)));
333  }
334 
335  if (comp_z == 'V')
336  {
337  // Right eigenvector.
338  F77_XFCN (zggbak, ZGGBAK,
339  (F77_CONST_CHAR_ARG2 (&bal_job, 1),
340  F77_CONST_CHAR_ARG2 ("R", 1),
341  nn, ilo, ihi, lscale.data (), rscale.data (),
342  nn, F77_DBLE_CMPLX_ARG (CZ.fortran_vec ()), nn, info
343  F77_CHAR_ARG_LEN (1)
344  F77_CHAR_ARG_LEN (1)));
345  }
346 
347  }
348  else
349  {
350 #if defined (DEBUG)
351  octave_stdout << "qz: performing qr decomposition of bb" << std::endl;
352 #endif
353 
354  // Compute the QR factorization of bb.
355  math::qr<Matrix> bqr (bb);
356 
357 #if defined (DEBUG)
358  octave_stdout << "qz: qr (bb) done; now performing qz decomposition"
359  << std::endl;
360 #endif
361 
362  bb = bqr.R ();
363 
364 #if defined (DEBUG)
365  octave_stdout << "qz: extracted bb" << std::endl;
366 #endif
367 
368  aa = (bqr.Q ()).transpose () * aa;
369 
370 #if defined (DEBUG)
371  octave_stdout << "qz: updated aa " << std::endl;
372  octave_stdout << "bqr.Q () =\n" << bqr.Q () << std::endl;
373 
374  if (comp_q == 'V')
375  octave_stdout << "QQ =" << QQ << std::endl;
376 #endif
377 
378  if (comp_q == 'V')
379  QQ = QQ * bqr.Q ();
380 
381 #if defined (DEBUG)
382  octave_stdout << "qz: precursors done..." << std::endl;
383 #endif
384 
385 #if defined (DEBUG)
386  octave_stdout << "qz: comp_q = " << comp_q << ", comp_z = " << comp_z
387  << std::endl;
388 #endif
389 
390  // Reduce to generalized Hessenberg form.
391  F77_XFCN (dgghrd, DGGHRD,
392  (F77_CONST_CHAR_ARG2 (&comp_q, 1),
393  F77_CONST_CHAR_ARG2 (&comp_z, 1),
394  nn, ilo, ihi, aa.fortran_vec (),
395  nn, bb.fortran_vec (), nn, QQ.fortran_vec (), nn,
396  ZZ.fortran_vec (), nn, info
397  F77_CHAR_ARG_LEN (1)
398  F77_CHAR_ARG_LEN (1)));
399 
400  // Check if just computing generalized eigenvalues,
401  // or if we're actually computing the decomposition.
402 
403  // Reduce to generalized Schur form.
404  F77_XFCN (dhgeqz, DHGEQZ,
405  (F77_CONST_CHAR_ARG2 (&qz_job, 1),
406  F77_CONST_CHAR_ARG2 (&comp_q, 1),
407  F77_CONST_CHAR_ARG2 (&comp_z, 1),
408  nn, ilo, ihi, aa.fortran_vec (), nn, bb.fortran_vec (),
409  nn, alphar.fortran_vec (), alphai.fortran_vec (),
410  betar.fortran_vec (), QQ.fortran_vec (), nn,
411  ZZ.fortran_vec (), nn, work.fortran_vec (), nn, info
412  F77_CHAR_ARG_LEN (1)
413  F77_CHAR_ARG_LEN (1)
414  F77_CHAR_ARG_LEN (1)));
415 
416  if (comp_q == 'V')
417  {
418  F77_XFCN (dggbak, DGGBAK,
419  (F77_CONST_CHAR_ARG2 (&bal_job, 1),
420  F77_CONST_CHAR_ARG2 ("L", 1),
421  nn, ilo, ihi, lscale.data (), rscale.data (),
422  nn, QQ.fortran_vec (), nn, info
423  F77_CHAR_ARG_LEN (1)
424  F77_CHAR_ARG_LEN (1)));
425 
426 #if defined (DEBUG)
427  if (comp_q == 'V')
428  octave_stdout << "qz: balancing done; QQ=\n" << QQ << std::endl;
429 #endif
430  }
431 
432  // then right
433  if (comp_z == 'V')
434  {
435  F77_XFCN (dggbak, DGGBAK,
436  (F77_CONST_CHAR_ARG2 (&bal_job, 1),
437  F77_CONST_CHAR_ARG2 ("R", 1),
438  nn, ilo, ihi, lscale.data (), rscale.data (),
439  nn, ZZ.fortran_vec (), nn, info
440  F77_CHAR_ARG_LEN (1)
441  F77_CHAR_ARG_LEN (1)));
442 
443 #if defined (DEBUG)
444  if (comp_z == 'V')
445  octave_stdout << "qz: balancing done; ZZ=\n" << ZZ << std::endl;
446 #endif
447  }
448 
449  }
450 
451  // Right, left eigenvector matrices.
452  if (nargout >= 5)
453  {
454  // Which side to compute?
455  char side = (nargout == 5 ? 'R' : 'B');
456  // Compute all of them and backtransform
457  char howmany = 'B';
458  // Dummy pointer; select is not used.
459  F77_INT *select = nullptr;
460 
461  if (complex_case)
462  {
463  CVL = CQ;
464  CVR = CZ;
465  ComplexRowVector cwork2 (2 * nn);
466  RowVector rwork2 (8 * nn);
467  F77_INT m;
468 
469  F77_XFCN (ztgevc, ZTGEVC,
470  (F77_CONST_CHAR_ARG2 (&side, 1),
471  F77_CONST_CHAR_ARG2 (&howmany, 1),
472  select, nn, F77_DBLE_CMPLX_ARG (caa.fortran_vec ()), nn,
474  nn, F77_DBLE_CMPLX_ARG (CVL.fortran_vec ()), nn,
475  F77_DBLE_CMPLX_ARG (CVR.fortran_vec ()), nn, nn,
476  m, F77_DBLE_CMPLX_ARG (cwork2.fortran_vec ()),
477  rwork2.fortran_vec (), info
478  F77_CHAR_ARG_LEN (1)
479  F77_CHAR_ARG_LEN (1)));
480  }
481  else
482  {
483 #if defined (DEBUG)
484  octave_stdout << "qz: computing generalized eigenvectors" << std::endl;
485 #endif
486 
487  VL = QQ;
488  VR = ZZ;
489  F77_INT m;
490 
491  F77_XFCN (dtgevc, DTGEVC,
492  (F77_CONST_CHAR_ARG2 (&side, 1),
493  F77_CONST_CHAR_ARG2 (&howmany, 1),
494  select, nn, aa.fortran_vec (), nn, bb.fortran_vec (),
495  nn, VL.fortran_vec (), nn, VR.fortran_vec (), nn, nn,
496  m, work.fortran_vec (), info
497  F77_CHAR_ARG_LEN (1)
498  F77_CHAR_ARG_LEN (1)));
499  }
500  }
501 
502  octave_value_list retval (nargout);
503 
504  switch (nargout)
505  {
506  case 6:
507  // Return left eigenvectors.
508  if (complex_case)
509  retval(5) = CVL;
510  else
511  retval(5) = VL;
512  OCTAVE_FALLTHROUGH;
513 
514  case 5:
515  // Return right eigenvectors.
516  if (complex_case)
517  retval(4) = CVR;
518  else
519  retval(4) = VR;
520  OCTAVE_FALLTHROUGH;
521 
522  case 4:
523  if (complex_case)
524  retval(3) = CZ;
525  else
526  retval(3) = ZZ;
527  OCTAVE_FALLTHROUGH;
528 
529  case 3:
530  if (complex_case)
531  retval(2) = CQ.hermitian ();
532  else
533  retval(2) = QQ.transpose ();
534  OCTAVE_FALLTHROUGH;
535 
536  case 2:
537  case 1:
538  case 0:
539  {
540  if (complex_case)
541  {
542 #if defined (DEBUG)
543  octave_stdout << "qz: retval(1) = cbb =\n";
545  octave_stdout << "\nqz: retval(0) = caa =\n";
547  octave_stdout << std::endl;
548 #endif
549  retval(1) = cbb;
550  retval(0) = caa;
551  }
552  else
553  {
554 #if defined (DEBUG)
555  octave_stdout << "qz: retval(1) = bb =\n";
557  octave_stdout << "\nqz: retval(0) = aa =\n";
559  octave_stdout << std::endl;
560 #endif
561  retval(1) = bb;
562  retval(0) = aa;
563  }
564  }
565  break;
566 
567  }
568 
569  // FIXME: The API for qz changed in version 9.
570  // These warnings can be removed in Octave version 11.
571  if (nargout == 1)
572  {
573  warning_with_id ("Octave:qz:single-arg-out",
574  "qz: requesting a single output argument no longer returns eigenvalues since version 9");
575  disable_warning ("Octave:qz:single-arg-out");
576  }
577 
578  if (nargin == 2 && args(0).isreal () && args(1).isreal ()
579  && retval(0).iscomplex ())
580  {
581  warning_with_id ("Octave:qz:complex-default",
582  "qz: returns the complex QZ by default on real matrices since version 9");
583  disable_warning ("Octave:qz:complex-default");
584  }
585 
586 #if defined (DEBUG)
587  octave_stdout << "qz: exiting (at long last)" << std::endl;
588 #endif
589 
590  return retval;
591 }
592 
593 /*
594 ## Example 7.7.3 in Golub & Van Loan (3rd ed.; not present in 4th ed.)
595 ## The generalized eigenvalues are real, so the real and complex QZ coincide.
596 %!test
597 %! a = [ 10 1 2;
598 %! 1 2 -1;
599 %! 1 1 2 ];
600 %! b = reshape (1:9, 3,3);
601 %! [aa, bb, q, z, v, w] = qz (a, b);
602 %! assert (isreal (aa) && isreal (bb) && isreal (q) && isreal (z) ...
603 %! && isreal (v) && isreal (w));
604 %! assert (istriu (aa) && istriu (bb));
605 %! assert (q * q', eye(3), 1e-15);
606 %! assert (z * z', eye(3), 1e-15);
607 %! assert (q * a * z, aa, norm (aa) * 1e-14);
608 %! assert (q * b * z, bb, norm (bb) * 1e-14);
609 %! assert (a * v * diag (diag (bb)), b * v * diag (diag (aa)), 1e-13);
610 %! assert (diag (diag (bb)) * w' * a, diag (diag (aa)) * w' * b, 1e-13);
611 
612 ## An example with real matrices where some generalized eigenvalues are
613 ## complex, so the real and complex QZ differ.
614 %!test
615 %! A = [ -1.03428 0.24929 0.43205 -0.12860;
616 %! 1.16228 0.27870 2.12954 0.69250;
617 %! -0.51524 -0.34939 -0.77820 2.13721;
618 %! -1.32941 2.11870 0.72005 1.00835 ];
619 %! B = [ 1.407302 -0.632956 -0.360628 0.068534;
620 %! 0.149898 0.298248 0.991777 0.023652;
621 %! 0.169281 -0.405205 -1.775834 1.511730;
622 %! 0.717770 1.291390 -1.766607 -0.531352 ];
623 %! [CAA, CBB, CQ, CZ, CV, CW] = qz (A, B, 'complex');
624 %! assert (iscomplex (CAA) && iscomplex (CBB) && iscomplex (CQ) ...
625 %! && iscomplex (CZ) && iscomplex (CV) && iscomplex (CW));
626 %! assert (istriu (CAA) && istriu (CBB));
627 %! assert (CQ * CQ', eye(4), 1e-14);
628 %! assert (CZ * CZ', eye(4), 1e-14);
629 %! assert (CQ * A * CZ, CAA, norm (CAA) * 1e-14);
630 %! assert (CQ * B * CZ, CBB, norm (CBB) * 1e-14);
631 %! assert (A * CV * diag (diag (CBB)), B * CV * diag (diag (CAA)), 1e-13);
632 %! assert (diag (diag (CBB)) * CW' * A, diag (diag (CAA)) * CW' * B, 1e-13);
633 %! [AA, BB, Q, Z, V, W] = qz (A, B, 'real');
634 %! assert (isreal (AA) && isreal (BB) && isreal (Q) && isreal (Z) ...
635 %! && isreal (V) && isreal (W));
636 %! assert (istriu (BB));
637 %! assert (Q * Q', eye(4), 1e-14);
638 %! assert (Z * Z', eye(4), 1e-14);
639 %! assert (Q * A * Z, AA, norm (AA) * 1e-14);
640 %! assert (Q * B * Z, BB, norm (BB) * 1e-14);
641 
642 ## Test input validation
643 %!error <Invalid call> qz ()
644 %!error <Invalid call> qz (1)
645 %!error <Invalid call> qz (1,2,3,4)
646 %!error <Invalid call> [r1,r2,r3,r4,r5,r6,r7] = qz (1,2)
647 %!error <OPT must be a string> qz (1,2, 3)
648 %!error <OPT must be 'real' or 'complex'> qz (1,2, 'foobar')
649 %!warning <ignoring 'real' option with complex matrices> qz (2i, 3, 'real');
650 %!warning <ignoring 'real' option with complex matrices> qz (2, 3i, 'real');
651 
652 */
653 
654 OCTAVE_END_NAMESPACE(octave)
T * fortran_vec()
Size of the specified dimension.
Definition: Array-base.cc:1764
Definition: dMatrix.h:42
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage(void)
Definition: defun-int.h:72
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:56
void warning(const char *fmt,...)
Definition: error.cc:1063
void warning_with_id(const char *id, const char *fmt,...)
Definition: error.cc:1078
void() error(const char *fmt,...)
Definition: error.cc:988
void disable_warning(const std::string &id)
void err_square_matrix_required(const char *fcn, const char *name)
Definition: errwarn.cc:122
#define F77_DBLE_CMPLX_ARG(x)
Definition: f77-fcn.h:316
#define F77_XFCN(f, F, args)
Definition: f77-fcn.h:45
octave_f77_int_type F77_INT
Definition: f77-fcn.h:306
void err_nonconformant(const char *op, octave_idx_type op1_len, octave_idx_type op2_len)
F77_RET_T F77_INT const F77_INT F77_DBLE const F77_INT F77_DBLE const F77_INT F77_DBLE const F77_INT F77_DBLE * VR
F77_RET_T const F77_INT const F77_INT const F77_INT F77_DBLE_CMPLX const F77_INT F77_DBLE_CMPLX const F77_INT F77_DBLE_CMPLX F77_DBLE_CMPLX F77_DBLE_CMPLX const F77_INT F77_DBLE_CMPLX * CZ
F77_RET_T const F77_INT const F77_INT const F77_INT F77_DBLE_CMPLX const F77_INT F77_DBLE_CMPLX const F77_INT F77_DBLE_CMPLX F77_DBLE_CMPLX F77_DBLE_CMPLX * CQ
F77_RET_T F77_INT const F77_INT F77_DBLE const F77_INT F77_DBLE const F77_INT F77_DBLE * VL
T octave_idx_type m
Definition: mx-inlines.cc:781
#define octave_stdout
Definition: pager.h:309
void octave_print_internal(std::ostream &os, const float_display_format &fmt, bool d, bool pr_as_read_syntax)
Definition: pr-output.cc:1761