changeset 25570:da2b38b7a077 stable

Use LAPACK DTGSEN subrouting for ordered-qz computation (bug #53761) * qz.cc: Use LAPACK's DTGSEN to compute and update generalized eigenvalues. Selection of eigenvalue cluster is now done by filling a vector of booleans, rather than through a selection function. New tests for the four variants of the ordered QZ. * lo-lapack-proto.h (DTGSEN): New prototype. * liboctave/external/ordered-qz: Delete directory. * liboctave/external/module.mk: Update.
author Sébastien Villemot <sebastien@debian.org>
date Sun, 13 May 2018 12:37:37 +0200
parents e8961d677661
children 70fb8e5eabaa 64bcc3ab2f6a
files libinterp/corefcn/qz.cc liboctave/external/module.mk liboctave/external/ordered-qz/README liboctave/external/ordered-qz/dsubsp.f liboctave/external/ordered-qz/exchqz.f liboctave/external/ordered-qz/module.mk liboctave/external/ordered-qz/sexchqz.f liboctave/external/ordered-qz/ssubsp.f liboctave/numeric/lo-lapack-proto.h
diffstat 9 files changed, 103 insertions(+), 989 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/qz.cc	Mon Jul 09 19:11:23 2018 -0700
+++ b/libinterp/corefcn/qz.cc	Sun May 13 12:37:37 2018 +0200
@@ -22,7 +22,8 @@
 
 // Generalized eigenvalue balancing via LAPACK
 
-// Author: A. S. Hodel <scotte@eng.auburn.edu>
+// Originally written by A. S. Hodel <scotte@eng.auburn.edu>, but is
+// substantially different with the change to use LAPACK.
 
 #undef DEBUG
 #undef DEBUG_SORT
@@ -55,79 +56,9 @@
 #  include "pr-output.h"
 #endif
 
-typedef F77_INT (*sort_function) (const F77_INT& LSIZE,
-                                  const double& ALPHA, const double& BETA,
-                                  const double& S, const double& P);
-
-extern "C"
-{
-  // Van Dooren's code (netlib.org: toms/590) for reordering GEP.
-  // Only processes Z, not Q.
-  F77_RET_T
-  F77_FUNC (dsubsp, DSUBSP) (const F77_INT& NMAX, const F77_INT& N,
-                             F77_DBLE *A, F77_DBLE *B, F77_DBLE *Z,
-                             sort_function, const F77_DBLE& EPS,
-                             F77_INT& NDIM, F77_INT& FAIL, F77_INT *IND);
-}
-
-// fcrhp, fin, fout, folhp:
-// Routines for ordering of generalized eigenvalues.
-// Return 1 if test is passed, 0 otherwise.
-//   fin:  |lambda| < 1
-//   fout: |lambda| >= 1
-//   fcrhp: real(lambda) >= 0
-//   folhp: real(lambda) < 0
-
-static F77_INT
-fcrhp (const F77_INT& lsize, const double& alpha, const double& beta,
-       const double& s, const double&)
-{
-  if (lsize == 1)
-    return (alpha * beta >= 0 ? 1 : -1);
-  else
-    return (s >= 0 ? 1 : -1);
-}
+// FIXME: Matlab does not produce lambda as the first output argument.
+// Compatibility problem?
 
-static F77_INT
-fin (const F77_INT& lsize, const double& alpha, const double& beta,
-     const double&, const double& p)
-{
-  F77_INT retval;
-
-  if (lsize == 1)
-    retval = (std::abs (alpha) < std::abs (beta) ? 1 : -1);
-  else
-    retval = (std::abs (p) < 1 ? 1 : -1);
-
-#if defined (DEBUG)
-  std::cout << "qz: fin: retval=" << retval << std::endl;
-#endif
-
-  return retval;
-}
-
-static F77_INT
-folhp (const F77_INT& lsize, const double& alpha, const double& beta,
-       const double& s, const double&)
-{
-  if (lsize == 1)
-    return (alpha * beta < 0 ? 1 : -1);
-  else
-    return (s < 0 ? 1 : -1);
-}
-
-static F77_INT
-fout (const F77_INT& lsize, const double& alpha, const double& beta,
-      const double&, const double& p)
-{
-  if (lsize == 1)
-    return (std::abs (alpha) >= std::abs (beta) ? 1 : -1);
-  else
-    return (std::abs (p) >= 1 ? 1 : -1);
-}
-
-//FIXME: Matlab does not produce lambda as the first output argument.
-//       Compatibility problem?
 DEFUN (qz, args, nargout,
        doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{lambda} =} qz (@var{A}, @var{B})
@@ -254,8 +185,8 @@
 #endif
 
   // Determine ordering option.
-  // declared volatile to avoid compiler warnings about long jumps vforks.
-  volatile char ord_job = 'N';
+
+  char ord_job = 'N';
   double safmin = 0.0;
 
   if (nargin == 3)
@@ -353,9 +284,7 @@
 
   // Both matrices loaded, now check whether to calculate complex or real val.
 
-  // declared volatile to avoid compiler warnings about long jumps vforks.
-  volatile bool complex_case
-    = (args(0).iscomplex () || args(1).iscomplex ());
+  bool complex_case = (args(0).iscomplex () || args(1).iscomplex ());
 
   if (nargin == 3 && complex_case)
     error ("qz: cannot re-order complex qz decomposition");
@@ -657,183 +586,61 @@
                 << ord_job << std::endl;
 #endif
 
-      // Declared static to avoid vfork/long jump compiler complaints.
-      static sort_function sort_test;
-      sort_test = nullptr;
+      Array<F77_LOGICAL> select (dim_vector (nn, 1));
 
-      switch (ord_job)
+      for (int j = 0; j < nn; j++)
         {
-        case 'S':
-          sort_test = &fin;
-          break;
+          switch (ord_job)
+            {
+            case 'S':
+              select(j) = alphar(j)*alphar(j) + alphai(j)*alphai(j) < betar(j)*betar(j);
+              break;
 
-        case 'B':
-          sort_test = &fout;
-          break;
+            case 'B':
+              select(j) = alphar(j)*alphar(j) + alphai(j)*alphai(j) >= betar(j)*betar(j);
+              break;
 
-        case '+':
-          sort_test = &fcrhp;
-          break;
+            case '+':
+              select(j) = alphar(j) * betar(j) >= 0;
+              break;
 
-        case '-':
-          sort_test = &folhp;
-          break;
+            case '-':
+              select(j) = alphar(j) * betar(j) < 0;
+              break;
 
-        default:
-          // Invalid order option
-          // (should never happen since options were checked at the top).
-          panic_impossible ();
-          break;
+            default:
+              // Invalid order option
+              // (should never happen since options were checked at the top).
+              panic_impossible ();
+              break;
+            }
         }
 
-      double inf_norm;
+      F77_LOGICAL wantq = 0, wantz = (comp_z == 'V');
+      F77_INT ijob = 0, mm, lrwork3 = 4*nn+16, liwork = nn;
+      F77_DBLE pl, pr;
+      RowVector rwork3(lrwork3);
+      Array<F77_INT> iwork (dim_vector (liwork, 1));
 
-      F77_XFCN (xdlange, XDLANGE,
-                (F77_CONST_CHAR_ARG2 ("I", 1),
-                 nn, nn, aa.data (), nn, work.fortran_vec (), inf_norm
-                 F77_CHAR_ARG_LEN (1)));
-
-      double eps = std::numeric_limits<double>::epsilon () * inf_norm * nn;
+      F77_XFCN (dtgsen, DTGSEN,
+                (ijob, wantq, wantz,
+                 select.fortran_vec (), nn,
+                 aa.fortran_vec (), nn,
+                 bb.fortran_vec (), nn,
+                 alphar.fortran_vec (),
+                 alphai.fortran_vec (),
+                 betar.fortran_vec (),
+                 nullptr, nn,
+                 ZZ.fortran_vec (), nn,
+                 mm,
+                 pl, pr,
+                 nullptr,
+                 rwork3.fortran_vec (), lrwork3,
+                 iwork.fortran_vec (), liwork,
+                 info));
 
 #if defined (DEBUG_SORT)
-      std::cout << "qz: calling dsubsp: aa=" << std::endl;
-      octave_print_internal (std::cout, aa, 0);
-      std::cout << std::endl << "bb="  << std::endl;
-      octave_print_internal (std::cout, bb, 0);
-      if (comp_z == 'V')
-        {
-          std::cout << std::endl << "ZZ="  << std::endl;
-          octave_print_internal (std::cout, ZZ, 0);
-        }
-      std::cout << std::endl;
-      std::cout << "alphar = " << std::endl;
-      octave_print_internal (std::cout, (Matrix) alphar, 0);
-      std::cout << std::endl << "alphai = " << std::endl;
-      octave_print_internal (std::cout, (Matrix) alphai, 0);
-      std::cout << std::endl << "beta = " << std::endl;
-      octave_print_internal (std::cout, (Matrix) betar, 0);
-      std::cout << std::endl;
-#endif
-
-      Array<F77_INT> ind (dim_vector (nn, 1));
-
-      F77_INT ndim, fail;
-
-      F77_XFCN (dsubsp, DSUBSP,
-                (nn, nn, aa.fortran_vec (), bb.fortran_vec (),
-                 ZZ.fortran_vec (), sort_test, eps, ndim, fail,
-                 ind.fortran_vec ()));
-
-#if defined (DEBUG)
-      std::cout << "qz: back from dsubsp: aa=" << std::endl;
-      octave_print_internal (std::cout, aa, 0);
-      std::cout << std::endl << "bb="  << std::endl;
-      octave_print_internal (std::cout, bb, 0);
-      if (comp_z == 'V')
-        {
-          std::cout << std::endl << "ZZ="  << std::endl;
-          octave_print_internal (std::cout, ZZ, 0);
-        }
-      std::cout << std::endl;
-#endif
-
-      // Manually update alphar, alphai, betar.
-      static F77_INT j;
-
-      j = 0;
-      while (j < nn)
-        {
-#if defined (DEBUG_EIG)
-          std::cout << "computing gen eig #" << j << std::endl;
-#endif
-
-          // Number of zeros in this block.
-          static F77_INT zcnt;
-
-          if (j == (nn-1))
-            zcnt = 1;
-          else if (aa(j+1,j) == 0)
-            zcnt = 1;
-          else zcnt = 2;
-
-          if (zcnt == 1)
-            {
-              // Real zero.
-#if defined (DEBUG_EIG)
-              std::cout << "  single gen eig:" << std::endl;
-              std::cout << "  alphar(" << j << ") = " << aa(j,j)
-                        << std::endl;
-              std::cout << "  betar(" << j << ") = " << bb(j,j)
-                        << std::endl;
-              std::cout << "  alphai(" << j << ") = 0" << std::endl;
-#endif
-
-              alphar(j) = aa(j,j);
-              alphai(j) = 0;
-              betar(j) = bb(j,j);
-            }
-          else
-            {
-              // Complex conjugate pair.
-#if defined (DEBUG_EIG)
-              std::cout << "qz: calling dlag2:" << std::endl;
-              std::cout << "safmin="
-                        << setiosflags (std::ios::scientific)
-                        << safmin << std::endl;
-
-              for (F77_INT idr = j; idr <= j+1; idr++)
-                {
-                  for (F77_INT idc = j; idc <= j+1; idc++)
-                    {
-                      std::cout << "aa(" << idr << ',' << idc << ")="
-                                << aa(idr,idc) << std::endl;
-                      std::cout << "bb(" << idr << ',' << idc << ")="
-                                << bb(idr,idc) << std::endl;
-                    }
-                }
-#endif
-
-              // FIXME: probably should be using
-              // fortran_vec instead of &aa(j,j) here.
-
-              double scale1, scale2, wr1, wr2, wi;
-              const double *aa_ptr = aa.data () + j * nn + j;
-              const double *bb_ptr = bb.data () + j * nn + j;
-              F77_XFCN (dlag2, DLAG2,
-                        (aa_ptr, nn, bb_ptr, nn, safmin,
-                         scale1, scale2, wr1, wr2, wi));
-
-#if defined (DEBUG_EIG)
-              std::cout << "dlag2 returns: scale1=" << scale1
-                        << "\tscale2=" << scale2 << std::endl
-                        << "\twr1=" << wr1 << "\twr2=" << wr2
-                        << "\twi=" << wi << std::endl;
-#endif
-
-              // Just to be safe, check if it's a real pair.
-              if (wi == 0)
-                {
-                  alphar(j) = wr1;
-                  alphai(j) = 0;
-                  betar(j) = scale1;
-                  alphar(j+1) = wr2;
-                  alphai(j+1) = 0;
-                  betar(j+1) = scale2;
-                }
-              else
-                {
-                  alphar(j) = alphar(j+1) = wr1;
-                  alphai(j) = -(alphai(j+1) = wi);
-                  betar(j)  = betar(j+1) = scale1;
-                }
-            }
-
-          // Advance past this block.
-          j += zcnt;
-        }
-
-#if defined (DEBUG_SORT)
-      std::cout << "qz: back from dsubsp: aa=" << std::endl;
+      std::cout << "qz: back from dtgsen: aa=" << std::endl;
       octave_print_internal (std::cout, aa, 0);
       std::cout << std::endl << "bb="  << std::endl;
       octave_print_internal (std::cout, bb, 0);
@@ -843,8 +650,7 @@
           std::cout << std::endl << "ZZ="  << std::endl;
           octave_print_internal (std::cout, ZZ, 0);
         }
-      std::cout << std::endl << "qz: ndim=" << ndim << std::endl
-                << "fail=" << fail << std::endl;
+      std::cout << std::endl << "qz: info=" << info << std::endl;
       std::cout << "alphar = " << std::endl;
       octave_print_internal (std::cout, (Matrix) alphar, 0);
       std::cout << std::endl << "alphai = " << std::endl;
@@ -1122,4 +928,26 @@
 %! [AA, BB, Q, Z1] = qz (A, B);
 %! [AA, BB, Z2] = qz (A, B, "-");
 %! assert (Z1, Z2);
+
+%!test
+%! A = [ -1.03428  0.24929  0.43205 -0.12860;
+%!        1.16228  0.27870  2.12954  0.69250;
+%!       -0.51524 -0.34939 -0.77820  2.13721;
+%!       -1.32941  2.11870  0.72005  1.00835 ];
+%! B = [  1.407302 -0.632956 -0.360628  0.068534;
+%!        0.149898  0.298248  0.991777  0.023652;
+%!        0.169281 -0.405205 -1.775834  1.511730;
+%!        0.717770  1.291390 -1.766607 -0.531352 ];
+%! [AA, BB, Z, lambda] = qz (A, B, "+");
+%! assert (all (real (lambda(1:3)) >= 0))
+%! assert (real (lambda(4) < 0))
+%! [AA, BB, Z, lambda] = qz (A, B, "-");
+%! assert (real (lambda(1) < 0))
+%! assert (all (real (lambda(2:4)) >= 0))
+%! [AA, BB, Z, lambda] = qz (A, B, "B");
+%! assert (all (abs (lambda(1:3)) >= 1))
+%! assert (abs (lambda(4) < 1))
+%! [AA, BB, Z, lambda] = qz (A, B, "S");
+%! assert (abs (lambda(1) < 1))
+%! assert (all (abs (lambda(2:4)) >= 1))
 */
--- a/liboctave/external/module.mk	Mon Jul 09 19:11:23 2018 -0700
+++ b/liboctave/external/module.mk	Sun May 13 12:37:37 2018 +0200
@@ -17,7 +17,6 @@
 include %reldir%/fftpack/module.mk
 include %reldir%/lapack-xtra/module.mk
 include %reldir%/odepack/module.mk
-include %reldir%/ordered-qz/module.mk
 include %reldir%/quadpack/module.mk
 include %reldir%/ranlib/module.mk
 include %reldir%/slatec-err/module.mk
--- a/liboctave/external/ordered-qz/README	Mon Jul 09 19:11:23 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-Code in this directory is adapted from Paul Van Dooren's toms/590
-code.  Modifications are listed in the comment header sections.
--- a/liboctave/external/ordered-qz/dsubsp.f	Mon Jul 09 19:11:23 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-      SUBROUTINE DSUBSP(NMAX, N, A, B, Z, FTEST, EPS, NDIM, FAIL, IND)
-      INTEGER NMAX, N, FTEST, NDIM, IND(N)
-      LOGICAL FAIL
-      DOUBLE PRECISION A(NMAX,N), B(NMAX,N), Z(NMAX,N), EPS
-C*
-C* GIVEN THE UPPER TRIANGULAR MATRIX B AND UPPER HESSENBERG MATRIX A
-C* WITH 1X1 OR 2X2 DIAGONAL BLOCKS, THIS ROUTINE REORDERS THE DIAGONAL
-C* BLOCKS ALONG WITH THEIR GENERALIZED EIGENVALUES BY CONSTRUCTING EQUI-
-C* VALENCE TRANSFORMATIONS QT AND ZT. THE ROW TRANSFORMATION ZT IS ALSO
-C* PERFORMED ON THE GIVEN (INITIAL) TRANSFORMATION Z (RESULTING FROM A
-C* POSSIBLE PREVIOUS STEP OR INITIALIZED WITH THE IDENTITY MATRIX).
-C* AFTER REORDERING, THE EIGENVALUES INSIDE THE REGION SPECIFIED BY THE
-C* FUNCTION FTEST APPEAR AT THE TOP. IF NDIM IS THEIR NUMBER THEN THE
-C* NDIM FIRST COLUMNS OF Z SPAN THE REQUESTED SUBSPACE. DSUBSP REQUIRES
-C* THE SUBROUTINE EXCHQZ AND THE INTEGER FUNCTION FTEST WHICH HAS TO BE
-C* PROVIDED BY THE USER. THE PARAMETERS IN THE CALLING SEQUENCE ARE :
-C* (STARRED PARAMETERS ARE ALTERED BY THE SUBROUTINE)
-C*
-C*    NMAX     THE FIRST DIMENSION OF A, B AND Z
-C*    N        THE ORDER OF A, B AND Z
-C*   *A,*B     THE MATRIX PAIR WHOSE BLOCKS ARE TO BE REORDERED.
-C*   *Z        UPON RETURN THIS ARRAY IS MULTIPLIED BY THE COLUMN
-C*             TRANSFORMATION ZT.
-C*    FTEST(LS,ALPHA,BETA,S,P) AN INTEGER FUNCTION DESCRIBING THE
-C*             SPECTRUM OF THE DEFLATING SUBSPACE TO BE COMPUTED:
-C*             WHEN LS=1 FTEST CHECKS IF ALPHA/BETA IS IN THAT SPECTRUM
-C*             WHEN LS=2 FTEST CHECKS IF THE TWO COMPLEX CONJUGATE
-C*             ROOTS WITH SUM S AND PRODUCT P ARE IN THAT SPECTRUM
-C*             IF THE ANSWER IS POSITIVE, FTEST=1, OTHERWISE FTEST=-1
-C*    EPS      THE REQUIRED ABSOLUTE ACCURACY OF THE RESULT
-C*   *NDIM     AN INTEGER GIVING THE DIMENSION OF THE COMPUTED
-C*             DEFLATING SUBSPACE
-C*   *FAIL     A LOGICAL VARIABLE WHICH IS FALSE ON A NORMAL RETURN,
-C*             TRUE OTHERWISE (WHEN EXCHQZ FAILS)
-C*   *IND      AN INTEGER WORKING ARRAY OF DIMENSION AT LEAST N
-C*
-      INTEGER L, LS, LS1, LS2, L1, LL, NUM, IS, L2I, L2K, I, K, II,
-     * ISTEP, IFIRST
-      DOUBLE PRECISION S, P, D, ALPHA, BETA
-      FAIL = .TRUE.
-      NDIM = 0
-      NUM = 0
-      L = 0
-      LS = 1
-C*** CONSTRUCT ARRAY IND(I) WHERE :
-C***     IABS(IND(I)) IS THE SIZE OF THE BLOCK I
-C***     SIGN(IND(I)) INDICATES THE LOCATION OF ITS EIGENVALUES
-C***                  (AS DETERMINED BY FTEST).
-C*** NUM IS THE NUMBER OF ELEMENTS IN THIS ARRAY
-      DO 30 LL=1,N
-        L = L + LS
-        IF (L.GT.N) GO TO 40
-        L1 = L + 1
-        IF (L1.GT.N) GO TO 10
-        IF (A(L1,L).EQ.0.) GO TO 10
-C* HERE A 2X2  BLOCK IS CHECKED *
-        LS = 2
-        D = B(L,L)*B(L1,L1)
-        S = (A(L,L)*B(L1,L1)+A(L1,L1)*B(L,L)-A(L1,L)*B(L,L1))/D
-        P = (A(L,L)*A(L1,L1)-A(L,L1)*A(L1,L))/D
-        IS = FTEST(LS,ALPHA,BETA,S,P)
-        GO TO 20
-C* HERE A 1X1  BLOCK IS CHECKED *
-   10   LS = 1
-        IS = FTEST(LS,A(L,L),B(L,L),S,P)
-   20   NUM = NUM + 1
-        IF (IS.EQ.1) NDIM = NDIM + LS
-        IND(NUM) = LS*IS
-   30 CONTINUE
-C***  REORDER BLOCKS SUCH THAT THOSE WITH POSITIVE VALUE
-C***    OF IND(.) APPEAR FIRST.
-   40 L2I = 1
-      DO 100 I=1,NUM
-        IF (IND(I).GT.0) GO TO 90
-C* IF A NEGATIVE IND(I) IS ENCOUNTERED, THEN SEARCH FOR THE FIRST
-C* POSITIVE IND(K) FOLLOWING ON IT
-        L2K = L2I
-        DO 60 K=I,NUM
-          IF (IND(K).LT.0) GO TO 50
-          GO TO 70
-   50     L2K = L2K - IND(K)
-   60   CONTINUE
-C* IF THERE ARE NO POSITIVE INDICES FOLLOWING ON A NEGATIVE ONE
-C* THEN STOP
-        GO TO 110
-C* IF A POSITIVE IND(K) FOLLOWS ON A NEGATIVE IND(I) THEN
-C* INTERCHANGE BLOCK K BEFORE BLOCK I BY PERFORMING K-I SWAPS
-   70   ISTEP = K - I
-        LS2 = IND(K)
-        L = L2K
-        DO 80 II=1,ISTEP
-          IFIRST = K - II
-          LS1 = -IND(IFIRST)
-          L = L - LS1
-          CALL EXCHQZ(NMAX, N, A, B, Z, L, LS1, LS2, EPS, FAIL)
-          IF (FAIL) RETURN
-          IND(IFIRST+1) = IND(IFIRST)
-   80   CONTINUE
-        IND(I) = LS2
-   90   L2I = L2I + IND(I)
-  100 CONTINUE
-  110 FAIL = .FALSE.
-      RETURN
-      END
--- a/liboctave/external/ordered-qz/exchqz.f	Mon Jul 09 19:11:23 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,263 +0,0 @@
-      SUBROUTINE EXCHQZ(NMAX, N, A, B, Z, L, LS1, LS2, EPS, FAIL)
-      INTEGER NMAX, N, L, LS1, LS2
-      DOUBLE PRECISION A(NMAX,N), B(NMAX,N), Z(NMAX,N), EPS
-      LOGICAL FAIL
-c modified july 9, 1998 a.s.hodel@eng.auburn.edu:
-c     REAL changed to DOUBLE PRECISION
-c     calls to AMAX1 changed to call MAX instead.
-c     calls to SROT  changed to DROT  (both in BLAS)
-c     calls to giv changed to dlartg (LAPACK); required new variable tempr
-C*
-C* GIVEN THE UPPER TRIANGULAR MATRIX B AND UPPER HESSENBERG MATRIX A
-C* WITH CONSECUTIVE LS1XLS1 AND LS2XLS2 DIAGONAL BLOCKS (LS1,LS2.LE.2)
-C* STARTING AT ROW/COLUMN L, EXCHQZ PRODUCES EQUIVALENCE TRANSFORMA-
-C* TIONS QT AND ZT THAT EXCHANGE THE BLOCKS ALONG WITH THEIR GENERALIZED
-C* EIGENVALUES. EXCHQZ REQUIRES THE SUBROUTINES DROT (BLAS) AND GIV.
-C* THE PARAMETERS IN THE CALLING SEQUENCE ARE (STARRED PARAMETERS ARE
-C* ALTERED BY THE SUBROUTINE):
-C*
-C*    NMAX     THE FIRST DIMENSION OF A, B AND Z
-C*    N        THE ORDER OF A, B AND Z
-C*   *A,*B     THE MATRIX PAIR WHOSE BLOCKS ARE TO BE INTERCHANGED
-C*   *Z        UPON RETURN THIS ARRAY IS MULTIPLIED BY THE COLUMN
-C*             TRANSFORMATION ZT.
-C*    L        THE POSITION OF THE BLOCKS
-C*    LS1      THE SIZE OF THE FIRST BLOCK
-C*    LS2      THE SIZE OF THE SECOND BLOCK
-C*    EPS      THE REQUIRED ABSOLUTE ACCURACY OF THE RESULT
-C*   *FAIL     A LOGICAL VARIABLE WHICH IS FALSE ON A NORMAL RETURN,
-C*             TRUE OTHERWISE.
-C*
-      INTEGER I, J, L1, L2, L3, LI, LJ, LL, IT1, IT2
-      DOUBLE PRECISION U(3,3), D, E, F, G, SA, SB, A11B11, A21B11,
-     * A12B22, B12B22,
-     * A22B22, AMMBMM, ANMBMM, AMNBNN, BMNBNN, ANNBNN, TEMPR
-      LOGICAL ALTB
-      FAIL = .FALSE.
-      L1 = L + 1
-      LL = LS1 + LS2
-      IF (LL.GT.2) GO TO 10
-C*** INTERCHANGE 1X1 AND 1X1 BLOCKS VIA AN EQUIVALENCE
-C*** TRANSFORMATION       A:=Q*A*Z , B:=Q*B*Z
-C*** WHERE Q AND Z ARE GIVENS ROTATIONS
-      F = MAX(ABS(A(L1,L1)),ABS(B(L1,L1)))
-      ALTB = .TRUE.
-      IF (ABS(A(L1,L1)).GE.F) ALTB = .FALSE.
-      SA = A(L1,L1)/F
-      SB = B(L1,L1)/F
-      F = SA*B(L,L) - SB*A(L,L)
-C* CONSTRUCT THE COLUMN TRANSFORMATION Z
-      G = SA*B(L,L1) - SB*A(L,L1)
-      CALL DLARTG(F, G, D, E,TEMPR)
-      CALL DROT(L1, A(1,L), 1, A(1,L1), 1, E, -D)
-      CALL DROT(L1, B(1,L), 1, B(1,L1), 1, E, -D)
-      CALL DROT(N, Z(1,L), 1, Z(1,L1), 1, E, -D)
-C* CONSTRUCT THE ROW TRANSFORMATION Q
-      IF (ALTB) CALL DLARTG(B(L,L), B(L1,L), D, E,TEMPR)
-      IF (.NOT.ALTB) CALL DLARTG(A(L,L), A(L1,L), D, E,TEMPR)
-      CALL DROT(N-L+1, A(L,L), NMAX, A(L1,L), NMAX, D, E)
-      CALL DROT(N-L+1, B(L,L), NMAX, B(L1,L), NMAX, D, E)
-      A(L1,L) = 0.
-      B(L1,L) = 0.
-      RETURN
-C*** INTERCHANGE 1X1 AND 2X2 BLOCKS VIA AN EQUIVALENCE
-C*** TRANSFORMATION  A:=Q2*Q1*A*Z1*Z2 , B:=Q2*Q1*B*Z1*Z2
-C*** WHERE EACH QI AND ZI IS A GIVENS ROTATION
-   10 L2 = L + 2
-      IF (LS1.EQ.2) GO TO 60
-      G = MAX(ABS(A(L,L)),ABS(B(L,L)))
-      ALTB = .TRUE.
-      IF (ABS(A(L,L)).LT.G) GO TO 20
-      ALTB = .FALSE.
-      CALL DLARTG(A(L1,L1), A(L2,L1), D, E,TEMPR)
-      CALL DROT(N-L, A(L1,L1), NMAX, A(L2,L1), NMAX, D, E)
-      CALL DROT(N-L, B(L1,L1), NMAX, B(L2,L1), NMAX, D, E)
-C**  EVALUATE THE PENCIL AT THE EIGENVALUE CORRESPONDING
-C**  TO THE 1X1 BLOCK
-   20 SA = A(L,L)/G
-      SB = B(L,L)/G
-      DO 40 J=1,2
-        LJ = L + J
-        DO 30 I=1,3
-          LI = L + I - 1
-          U(I,J) = SA*B(LI,LJ) - SB*A(LI,LJ)
-   30   CONTINUE
-   40 CONTINUE
-      CALL DLARTG(U(3,1), U(3,2), D, E,TEMPR)
-      CALL DROT(3, U(1,1), 1, U(1,2), 1, E, -D)
-C* PERFORM THE ROW TRANSFORMATION Q1
-      CALL DLARTG(U(1,1), U(2,1), D, E,TEMPR)
-      U(2,2) = -U(1,2)*E + U(2,2)*D
-      CALL DROT(N-L+1, A(L,L), NMAX, A(L1,L), NMAX, D, E)
-      CALL DROT(N-L+1, B(L,L), NMAX, B(L1,L), NMAX, D, E)
-C* PERFORM THE COLUMN TRANSFORMATION Z1
-      IF (ALTB) CALL DLARTG(B(L1,L), B(L1,L1), D, E,TEMPR)
-      IF (.NOT.ALTB) CALL DLARTG(A(L1,L), A(L1,L1), D, E,TEMPR)
-      CALL DROT(L2, A(1,L), 1, A(1,L1), 1, E, -D)
-      CALL DROT(L2, B(1,L), 1, B(1,L1), 1, E, -D)
-      CALL DROT(N, Z(1,L), 1, Z(1,L1), 1, E, -D)
-C* PERFORM THE ROW TRANSFORMATION Q2
-      CALL DLARTG(U(2,2), U(3,2), D, E,TEMPR)
-      CALL DROT(N-L+1, A(L1,L), NMAX, A(L2,L), NMAX, D, E)
-      CALL DROT(N-L+1, B(L1,L), NMAX, B(L2,L), NMAX, D, E)
-C* PERFORM THE COLUMN TRANSFORMATION Z2
-      IF (ALTB) CALL DLARTG(B(L2,L1), B(L2,L2), D, E,TEMPR)
-      IF (.NOT.ALTB) CALL DLARTG(A(L2,L1), A(L2,L2), D, E,TEMPR)
-      CALL DROT(L2, A(1,L1), 1, A(1,L2), 1, E, -D)
-      CALL DROT(L2, B(1,L1), 1, B(1,L2), 1, E, -D)
-      CALL DROT(N, Z(1,L1), 1, Z(1,L2), 1, E, -D)
-      IF (ALTB) GO TO 50
-      CALL DLARTG(B(L,L), B(L1,L), D, E,TEMPR)
-      CALL DROT(N-L+1, A(L,L), NMAX, A(L1,L), NMAX, D, E)
-      CALL DROT(N-L+1, B(L,L), NMAX, B(L1,L), NMAX, D, E)
-C*  PUT THE NEGLECTABLE ELEMENTS EQUAL TO ZERO
-   50 A(L2,L) = 0.
-      A(L2,L1) = 0.
-      B(L1,L) = 0.
-      B(L2,L) = 0.
-      B(L2,L1) = 0.
-      RETURN
-C*** INTERCHANGE 2X2 AND 1X1 BLOCKS VIA AN EQUIVALENCE
-C*** TRANSFORMATION  A:=Q2*Q1*A*Z1*Z2 , B:=Q2*Q1*B*Z1*Z2
-C*** WHERE EACH QI AND ZI IS A GIVENS ROTATION
-   60 IF (LS2.EQ.2) GO TO 110
-      G = MAX(ABS(A(L2,L2)),ABS(B(L2,L2)))
-      ALTB = .TRUE.
-      IF (ABS(A(L2,L2)).LT.G) GO TO 70
-      ALTB = .FALSE.
-      CALL DLARTG(A(L,L), A(L1,L), D, E,TEMPR)
-      CALL DROT(N-L+1, A(L,L), NMAX, A(L1,L), NMAX, D, E)
-      CALL DROT(N-L+1, B(L,L), NMAX, B(L1,L), NMAX, D, E)
-C**  EVALUATE THE PENCIL AT THE EIGENVALUE CORRESPONDING
-C**  TO THE 1X1 BLOCK
-   70 SA = A(L2,L2)/G
-      SB = B(L2,L2)/G
-      DO 90 I=1,2
-        LI = L + I - 1
-        DO 80 J=1,3
-          LJ = L + J - 1
-          U(I,J) = SA*B(LI,LJ) - SB*A(LI,LJ)
-   80   CONTINUE
-   90 CONTINUE
-      CALL DLARTG(U(1,1), U(2,1), D, E,TEMPR)
-      CALL DROT(3, U(1,1), 3, U(2,1), 3, D, E)
-C* PERFORM THE COLUMN TRANSFORMATION Z1
-      CALL DLARTG(U(2,2), U(2,3), D, E,TEMPR)
-      U(1,2) = U(1,2)*E - U(1,3)*D
-      CALL DROT(L2, A(1,L1), 1, A(1,L2), 1, E, -D)
-      CALL DROT(L2, B(1,L1), 1, B(1,L2), 1, E, -D)
-      CALL DROT(N, Z(1,L1), 1, Z(1,L2), 1, E, -D)
-C* PERFORM THE ROW TRANSFORMATION Q1
-      IF (ALTB) CALL DLARTG(B(L1,L1), B(L2,L1), D, E,TEMPR)
-      IF (.NOT.ALTB) CALL DLARTG(A(L1,L1), A(L2,L1), D, E,TEMPR)
-      CALL DROT(N-L+1, A(L1,L), NMAX, A(L2,L), NMAX, D, E)
-      CALL DROT(N-L+1, B(L1,L), NMAX, B(L2,L), NMAX, D, E)
-C* PERFORM THE COLUMN TRANSFORMATION Z2
-      CALL DLARTG(U(1,1), U(1,2), D, E,TEMPR)
-      CALL DROT(L2, A(1,L), 1, A(1,L1), 1, E, -D)
-      CALL DROT(L2, B(1,L), 1, B(1,L1), 1, E, -D)
-      CALL DROT(N, Z(1,L), 1, Z(1,L1), 1, E, -D)
-C* PERFORM THE ROW TRANSFORMATION Q2
-      IF (ALTB) CALL DLARTG(B(L,L), B(L1,L), D, E,TEMPR)
-      IF (.NOT.ALTB) CALL DLARTG(A(L,L), A(L1,L), D, E,TEMPR)
-      CALL DROT(N-L+1, A(L,L), NMAX, A(L1,L), NMAX, D, E)
-      CALL DROT(N-L+1, B(L,L), NMAX, B(L1,L), NMAX, D, E)
-      IF (ALTB) GO TO 100
-      CALL DLARTG(B(L1,L1), B(L2,L1), D, E,TEMPR)
-      CALL DROT(N-L, A(L1,L1), NMAX, A(L2,L1), NMAX, D, E)
-      CALL DROT(N-L, B(L1,L1), NMAX, B(L2,L1), NMAX, D, E)
-C*  PUT THE NEGLECTABLE ELEMENTS EQUAL TO ZERO
-  100 A(L1,L) = 0.
-      A(L2,L) = 0.
-      B(L1,L) = 0.
-      B(L2,1) = 0.
-      B(L2,L1) = 0.
-      RETURN
-C*** INTERCHANGE 2X2 AND 2X2 BLOCKS VIA A SEQUENCE OF
-C*** QZ-STEPS REALIZED BY THE EQUIVALENCE TRANSFORMATIONS
-C***          A:=Q5*Q4*Q3*Q2*Q1*A*Z1*Z2*Z3*Z4*Z5
-C***          B:=Q5*Q4*Q3*Q2*Q1*B*Z1*Z2*Z3*Z4*Z5
-C*** WHERE EACH QI AND ZI IS A GIVENS ROTATION
-  110 L3 = L + 3
-C* COMPUTE IMPLICIT SHIFT
-      AMMBMM = A(L,L)/B(L,L)
-      ANMBMM = A(L1,L)/B(L,L)
-      AMNBNN = A(L,L1)/B(L1,L1)
-      ANNBNN = A(L1,L1)/B(L1,L1)
-      BMNBNN = B(L,L1)/B(L1,L1)
-      DO 130 IT1=1,3
-        U(1,1) = 1.
-        U(2,1) = 1.
-        U(3,1) = 1.
-        DO 120 IT2=1,10
-C* PERFORM ROW TRANSFORMATIONS Q1 AND Q2
-          CALL DLARTG(U(2,1), U(3,1), D, E,TEMPR)
-          CALL DROT(N-L+1, A(L1,L), NMAX, A(L2,L), NMAX, D, E)
-          CALL DROT(N-L, B(L1,L1), NMAX, B(L2,L1), NMAX, D, E)
-          U(2,1) = D*U(2,1) + E*U(3,1)
-          CALL DLARTG(U(1,1), U(2,1), D, E,TEMPR)
-          CALL DROT(N-L+1, A(L,L), NMAX, A(L1,L), NMAX, D, E)
-          CALL DROT(N-L+1, B(L,L), NMAX, B(L1,L), NMAX, D, E)
-C* PERFORM COLUMN TRANSFORMATIONS Z1 AND Z2
-          CALL DLARTG(B(L2,L1), B(L2,L2), D, E,TEMPR)
-          CALL DROT(L3, A(1,L1), 1, A(1,L2), 1, E, -D)
-          CALL DROT(L2, B(1,L1), 1, B(1,L2), 1, E, -D)
-          CALL DROT(N, Z(1,L1), 1, Z(1,L2), 1, E, -D)
-          CALL DLARTG(B(L1,L), B(L1,L1), D, E,TEMPR)
-          CALL DROT(L3, A(1,L), 1, A(1,L1), 1, E, -D)
-          CALL DROT(L1, B(1,L), 1, B(1,L1), 1, E, -D)
-          CALL DROT(N, Z(1,L), 1, Z(1,L1), 1, E, -D)
-C* PERFORM TRANSFORMATIONS Q3,Z3,Q4,Z4,Q5 AND Z5 IN
-C* ORDER TO REDUCE THE PENCIL TO HESSENBERG FORM
-          CALL DLARTG(A(L2,L), A(L3,L), D, E,TEMPR)
-          CALL DROT(N-L+1, A(L2,L), NMAX, A(L3,L), NMAX, D, E)
-          CALL DROT(N-L1, B(L2,L2), NMAX, B(L3,L2), NMAX, D, E)
-          CALL DLARTG(B(L3,L2), B(L3,L3), D, E,TEMPR)
-          CALL DROT(L3, A(1,L2), 1, A(1,L3), 1, E, -D)
-          CALL DROT(L3, B(1,L2), 1, B(1,L3), 1, E, -D)
-          CALL DROT(N, Z(1,L2), 1, Z(1,L3), 1, E, -D)
-          CALL DLARTG(A(L1,L), A(L2,L), D, E,TEMPR)
-          CALL DROT(N-L+1, A(L1,L), NMAX, A(L2,L), NMAX, D, E)
-          CALL DROT(N-L, B(L1,L1), NMAX, B(L2,L1), NMAX, D, E)
-          CALL DLARTG(B(L2,L1), B(L2,L2), D, E,TEMPR)
-          CALL DROT(L3, A(1,L1), 1, A(1,L2), 1, E, -D)
-          CALL DROT(L2, B(1,L1), 1, B(1,L2), 1, E, -D)
-          CALL DROT(N, Z(1,L1), 1, Z(1,L2), 1, E, -D)
-          CALL DLARTG(A(L2,L1), A(L3,L1), D, E,TEMPR)
-          CALL DROT(N-L, A(L2,L1), NMAX, A(L3,L1), NMAX, D, E)
-          CALL DROT(N-L1, B(L2,L2), NMAX, B(L3,L2), NMAX, D, E)
-          CALL DLARTG(B(L3,L2), B(L3,L3), D, E,TEMPR)
-          CALL DROT(L3, A(1,L2), 1, A(1,L3), 1, E, -D)
-          CALL DROT(L3, B(1,L2), 1, B(1,L3), 1, E, -D)
-          CALL DROT(N, Z(1,L2), 1, Z(1,L3), 1, E, -D)
-C* TEST OF CONVERGENCE ON THE ELEMENT SEPARATING THE BLOCKS
-          IF (ABS(A(L2,L1)).LE.EPS) GO TO 140
-C* COMPUTE A NEW SHIFT IN CASE OF NO CONVERGENCE
-          A11B11 = A(L,L)/B(L,L)
-          A12B22 = A(L,L1)/B(L1,L1)
-          A21B11 = A(L1,L)/B(L,L)
-          A22B22 = A(L1,L1)/B(L1,L1)
-          B12B22 = B(L,L1)/B(L1,L1)
-          U(1,1) = ((AMMBMM-A11B11)*(ANNBNN-A11B11)-AMNBNN*
-     *     ANMBMM+ANMBMM*BMNBNN*A11B11)/A21B11 + A12B22 - A11B11*B12B22
-          U(2,1) = (A22B22-A11B11) - A21B11*B12B22 - (AMMBMM-A11B11) -
-     *     (ANNBNN-A11B11) + ANMBMM*BMNBNN
-          U(3,1) = A(L2,L1)/B(L1,L1)
-  120   CONTINUE
-  130 CONTINUE
-      FAIL = .TRUE.
-      RETURN
-C*  PUT THE NEGLECTABLE ELEMENTS EQUAL TO ZERO IN
-C*  CASE OF CONVERGENCE
-  140 A(L2,L) = 0.
-      A(L2,L1) = 0.
-      A(L3,L) = 0.
-      A(L3,L1) = 0.
-      B(L1,L) = 0.
-      B(L2,L) = 0.
-      B(L2,L1) = 0.
-      B(L3,L) = 0.
-      B(L3,L1) = 0.
-      B(L3,L2) = 0.
-      RETURN
-      END
--- a/liboctave/external/ordered-qz/module.mk	Mon Jul 09 19:11:23 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-EXTERNAL_SOURCES += \
-  %reldir%/dsubsp.f \
-  %reldir%/exchqz.f \
-  %reldir%/ssubsp.f \
-  %reldir%/sexchqz.f
-
-liboctave_EXTRA_DIST += \
-  %reldir%/README
--- a/liboctave/external/ordered-qz/sexchqz.f	Mon Jul 09 19:11:23 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,261 +0,0 @@
-      SUBROUTINE SEXCHQZ(NMAX, N, A, B, Z, L, LS1, LS2, EPS, FAIL)
-      INTEGER NMAX, N, L, LS1, LS2
-      REAL A(NMAX,N), B(NMAX,N), Z(NMAX,N), EPS
-      LOGICAL FAIL
-c modified july 9, 1998 a.s.hodel@eng.auburn.edu:
-c     calls to AMAX1 changed to call MAX instead.
-c     calls to giv changed to slartg (LAPACK); required new variable tempr
-C*
-C* GIVEN THE UPPER TRIANGULAR MATRIX B AND UPPER HESSENBERG MATRIX A
-C* WITH CONSECUTIVE LS1XLS1 AND LS2XLS2 DIAGONAL BLOCKS (LS1,LS2.LE.2)
-C* STARTING AT ROW/COLUMN L, EXCHQZ PRODUCES EQUIVALENCE TRANSFORMA-
-C* TIONS QT AND ZT THAT EXCHANGE THE BLOCKS ALONG WITH THEIR GENERALIZED
-C* EIGENVALUES. EXCHQZ REQUIRES THE SUBROUTINES SROT (BLAS) AND GIV.
-C* THE PARAMETERS IN THE CALLING SEQUENCE ARE (STARRED PARAMETERS ARE
-C* ALTERED BY THE SUBROUTINE):
-C*
-C*    NMAX     THE FIRST DIMENSION OF A, B AND Z
-C*    N        THE ORDER OF A, B AND Z
-C*   *A,*B     THE MATRIX PAIR WHOSE BLOCKS ARE TO BE INTERCHANGED
-C*   *Z        UPON RETURN THIS ARRAY IS MULTIPLIED BY THE COLUMN
-C*             TRANSFORMATION ZT.
-C*    L        THE POSITION OF THE BLOCKS
-C*    LS1      THE SIZE OF THE FIRST BLOCK
-C*    LS2      THE SIZE OF THE SECOND BLOCK
-C*    EPS      THE REQUIRED ABSOLUTE ACCURACY OF THE RESULT
-C*   *FAIL     A LOGICAL VARIABLE WHICH IS FALSE ON A NORMAL RETURN,
-C*             TRUE OTHERWISE.
-C*
-      INTEGER I, J, L1, L2, L3, LI, LJ, LL, IT1, IT2
-      REAL U(3,3), D, E, F, G, SA, SB, A11B11, A21B11,
-     * A12B22, B12B22,
-     * A22B22, AMMBMM, ANMBMM, AMNBNN, BMNBNN, ANNBNN, TEMPR
-      LOGICAL ALTB
-      FAIL = .FALSE.
-      L1 = L + 1
-      LL = LS1 + LS2
-      IF (LL.GT.2) GO TO 10
-C*** INTERCHANGE 1X1 AND 1X1 BLOCKS VIA AN EQUIVALENCE
-C*** TRANSFORMATION       A:=Q*A*Z , B:=Q*B*Z
-C*** WHERE Q AND Z ARE GIVENS ROTATIONS
-      F = MAX(ABS(A(L1,L1)),ABS(B(L1,L1)))
-      ALTB = .TRUE.
-      IF (ABS(A(L1,L1)).GE.F) ALTB = .FALSE.
-      SA = A(L1,L1)/F
-      SB = B(L1,L1)/F
-      F = SA*B(L,L) - SB*A(L,L)
-C* CONSTRUCT THE COLUMN TRANSFORMATION Z
-      G = SA*B(L,L1) - SB*A(L,L1)
-      CALL SLARTG(F, G, D, E,TEMPR)
-      CALL SROT(L1, A(1,L), 1, A(1,L1), 1, E, -D)
-      CALL SROT(L1, B(1,L), 1, B(1,L1), 1, E, -D)
-      CALL SROT(N, Z(1,L), 1, Z(1,L1), 1, E, -D)
-C* CONSTRUCT THE ROW TRANSFORMATION Q
-      IF (ALTB) CALL SLARTG(B(L,L), B(L1,L), D, E,TEMPR)
-      IF (.NOT.ALTB) CALL SLARTG(A(L,L), A(L1,L), D, E,TEMPR)
-      CALL SROT(N-L+1, A(L,L), NMAX, A(L1,L), NMAX, D, E)
-      CALL SROT(N-L+1, B(L,L), NMAX, B(L1,L), NMAX, D, E)
-      A(L1,L) = 0.
-      B(L1,L) = 0.
-      RETURN
-C*** INTERCHANGE 1X1 AND 2X2 BLOCKS VIA AN EQUIVALENCE
-C*** TRANSFORMATION  A:=Q2*Q1*A*Z1*Z2 , B:=Q2*Q1*B*Z1*Z2
-C*** WHERE EACH QI AND ZI IS A GIVENS ROTATION
-   10 L2 = L + 2
-      IF (LS1.EQ.2) GO TO 60
-      G = MAX(ABS(A(L,L)),ABS(B(L,L)))
-      ALTB = .TRUE.
-      IF (ABS(A(L,L)).LT.G) GO TO 20
-      ALTB = .FALSE.
-      CALL SLARTG(A(L1,L1), A(L2,L1), D, E,TEMPR)
-      CALL SROT(N-L, A(L1,L1), NMAX, A(L2,L1), NMAX, D, E)
-      CALL SROT(N-L, B(L1,L1), NMAX, B(L2,L1), NMAX, D, E)
-C**  EVALUATE THE PENCIL AT THE EIGENVALUE CORRESPONDING
-C**  TO THE 1X1 BLOCK
-   20 SA = A(L,L)/G
-      SB = B(L,L)/G
-      DO 40 J=1,2
-        LJ = L + J
-        DO 30 I=1,3
-          LI = L + I - 1
-          U(I,J) = SA*B(LI,LJ) - SB*A(LI,LJ)
-   30   CONTINUE
-   40 CONTINUE
-      CALL SLARTG(U(3,1), U(3,2), D, E,TEMPR)
-      CALL SROT(3, U(1,1), 1, U(1,2), 1, E, -D)
-C* PERFORM THE ROW TRANSFORMATION Q1
-      CALL SLARTG(U(1,1), U(2,1), D, E,TEMPR)
-      U(2,2) = -U(1,2)*E + U(2,2)*D
-      CALL SROT(N-L+1, A(L,L), NMAX, A(L1,L), NMAX, D, E)
-      CALL SROT(N-L+1, B(L,L), NMAX, B(L1,L), NMAX, D, E)
-C* PERFORM THE COLUMN TRANSFORMATION Z1
-      IF (ALTB) CALL SLARTG(B(L1,L), B(L1,L1), D, E,TEMPR)
-      IF (.NOT.ALTB) CALL SLARTG(A(L1,L), A(L1,L1), D, E,TEMPR)
-      CALL SROT(L2, A(1,L), 1, A(1,L1), 1, E, -D)
-      CALL SROT(L2, B(1,L), 1, B(1,L1), 1, E, -D)
-      CALL SROT(N, Z(1,L), 1, Z(1,L1), 1, E, -D)
-C* PERFORM THE ROW TRANSFORMATION Q2
-      CALL SLARTG(U(2,2), U(3,2), D, E,TEMPR)
-      CALL SROT(N-L+1, A(L1,L), NMAX, A(L2,L), NMAX, D, E)
-      CALL SROT(N-L+1, B(L1,L), NMAX, B(L2,L), NMAX, D, E)
-C* PERFORM THE COLUMN TRANSFORMATION Z2
-      IF (ALTB) CALL SLARTG(B(L2,L1), B(L2,L2), D, E,TEMPR)
-      IF (.NOT.ALTB) CALL SLARTG(A(L2,L1), A(L2,L2), D, E,TEMPR)
-      CALL SROT(L2, A(1,L1), 1, A(1,L2), 1, E, -D)
-      CALL SROT(L2, B(1,L1), 1, B(1,L2), 1, E, -D)
-      CALL SROT(N, Z(1,L1), 1, Z(1,L2), 1, E, -D)
-      IF (ALTB) GO TO 50
-      CALL SLARTG(B(L,L), B(L1,L), D, E,TEMPR)
-      CALL SROT(N-L+1, A(L,L), NMAX, A(L1,L), NMAX, D, E)
-      CALL SROT(N-L+1, B(L,L), NMAX, B(L1,L), NMAX, D, E)
-C*  PUT THE NEGLECTABLE ELEMENTS EQUAL TO ZERO
-   50 A(L2,L) = 0.
-      A(L2,L1) = 0.
-      B(L1,L) = 0.
-      B(L2,L) = 0.
-      B(L2,L1) = 0.
-      RETURN
-C*** INTERCHANGE 2X2 AND 1X1 BLOCKS VIA AN EQUIVALENCE
-C*** TRANSFORMATION  A:=Q2*Q1*A*Z1*Z2 , B:=Q2*Q1*B*Z1*Z2
-C*** WHERE EACH QI AND ZI IS A GIVENS ROTATION
-   60 IF (LS2.EQ.2) GO TO 110
-      G = MAX(ABS(A(L2,L2)),ABS(B(L2,L2)))
-      ALTB = .TRUE.
-      IF (ABS(A(L2,L2)).LT.G) GO TO 70
-      ALTB = .FALSE.
-      CALL SLARTG(A(L,L), A(L1,L), D, E,TEMPR)
-      CALL SROT(N-L+1, A(L,L), NMAX, A(L1,L), NMAX, D, E)
-      CALL SROT(N-L+1, B(L,L), NMAX, B(L1,L), NMAX, D, E)
-C**  EVALUATE THE PENCIL AT THE EIGENVALUE CORRESPONDING
-C**  TO THE 1X1 BLOCK
-   70 SA = A(L2,L2)/G
-      SB = B(L2,L2)/G
-      DO 90 I=1,2
-        LI = L + I - 1
-        DO 80 J=1,3
-          LJ = L + J - 1
-          U(I,J) = SA*B(LI,LJ) - SB*A(LI,LJ)
-   80   CONTINUE
-   90 CONTINUE
-      CALL SLARTG(U(1,1), U(2,1), D, E,TEMPR)
-      CALL SROT(3, U(1,1), 3, U(2,1), 3, D, E)
-C* PERFORM THE COLUMN TRANSFORMATION Z1
-      CALL SLARTG(U(2,2), U(2,3), D, E,TEMPR)
-      U(1,2) = U(1,2)*E - U(1,3)*D
-      CALL SROT(L2, A(1,L1), 1, A(1,L2), 1, E, -D)
-      CALL SROT(L2, B(1,L1), 1, B(1,L2), 1, E, -D)
-      CALL SROT(N, Z(1,L1), 1, Z(1,L2), 1, E, -D)
-C* PERFORM THE ROW TRANSFORMATION Q1
-      IF (ALTB) CALL SLARTG(B(L1,L1), B(L2,L1), D, E,TEMPR)
-      IF (.NOT.ALTB) CALL SLARTG(A(L1,L1), A(L2,L1), D, E,TEMPR)
-      CALL SROT(N-L+1, A(L1,L), NMAX, A(L2,L), NMAX, D, E)
-      CALL SROT(N-L+1, B(L1,L), NMAX, B(L2,L), NMAX, D, E)
-C* PERFORM THE COLUMN TRANSFORMATION Z2
-      CALL SLARTG(U(1,1), U(1,2), D, E,TEMPR)
-      CALL SROT(L2, A(1,L), 1, A(1,L1), 1, E, -D)
-      CALL SROT(L2, B(1,L), 1, B(1,L1), 1, E, -D)
-      CALL SROT(N, Z(1,L), 1, Z(1,L1), 1, E, -D)
-C* PERFORM THE ROW TRANSFORMATION Q2
-      IF (ALTB) CALL SLARTG(B(L,L), B(L1,L), D, E,TEMPR)
-      IF (.NOT.ALTB) CALL SLARTG(A(L,L), A(L1,L), D, E,TEMPR)
-      CALL SROT(N-L+1, A(L,L), NMAX, A(L1,L), NMAX, D, E)
-      CALL SROT(N-L+1, B(L,L), NMAX, B(L1,L), NMAX, D, E)
-      IF (ALTB) GO TO 100
-      CALL SLARTG(B(L1,L1), B(L2,L1), D, E,TEMPR)
-      CALL SROT(N-L, A(L1,L1), NMAX, A(L2,L1), NMAX, D, E)
-      CALL SROT(N-L, B(L1,L1), NMAX, B(L2,L1), NMAX, D, E)
-C*  PUT THE NEGLECTABLE ELEMENTS EQUAL TO ZERO
-  100 A(L1,L) = 0.
-      A(L2,L) = 0.
-      B(L1,L) = 0.
-      B(L2,1) = 0.
-      B(L2,L1) = 0.
-      RETURN
-C*** INTERCHANGE 2X2 AND 2X2 BLOCKS VIA A SEQUENCE OF
-C*** QZ-STEPS REALIZED BY THE EQUIVALENCE TRANSFORMATIONS
-C***          A:=Q5*Q4*Q3*Q2*Q1*A*Z1*Z2*Z3*Z4*Z5
-C***          B:=Q5*Q4*Q3*Q2*Q1*B*Z1*Z2*Z3*Z4*Z5
-C*** WHERE EACH QI AND ZI IS A GIVENS ROTATION
-  110 L3 = L + 3
-C* COMPUTE IMPLICIT SHIFT
-      AMMBMM = A(L,L)/B(L,L)
-      ANMBMM = A(L1,L)/B(L,L)
-      AMNBNN = A(L,L1)/B(L1,L1)
-      ANNBNN = A(L1,L1)/B(L1,L1)
-      BMNBNN = B(L,L1)/B(L1,L1)
-      DO 130 IT1=1,3
-        U(1,1) = 1.
-        U(2,1) = 1.
-        U(3,1) = 1.
-        DO 120 IT2=1,10
-C* PERFORM ROW TRANSFORMATIONS Q1 AND Q2
-          CALL SLARTG(U(2,1), U(3,1), D, E,TEMPR)
-          CALL SROT(N-L+1, A(L1,L), NMAX, A(L2,L), NMAX, D, E)
-          CALL SROT(N-L, B(L1,L1), NMAX, B(L2,L1), NMAX, D, E)
-          U(2,1) = D*U(2,1) + E*U(3,1)
-          CALL SLARTG(U(1,1), U(2,1), D, E,TEMPR)
-          CALL SROT(N-L+1, A(L,L), NMAX, A(L1,L), NMAX, D, E)
-          CALL SROT(N-L+1, B(L,L), NMAX, B(L1,L), NMAX, D, E)
-C* PERFORM COLUMN TRANSFORMATIONS Z1 AND Z2
-          CALL SLARTG(B(L2,L1), B(L2,L2), D, E,TEMPR)
-          CALL SROT(L3, A(1,L1), 1, A(1,L2), 1, E, -D)
-          CALL SROT(L2, B(1,L1), 1, B(1,L2), 1, E, -D)
-          CALL SROT(N, Z(1,L1), 1, Z(1,L2), 1, E, -D)
-          CALL SLARTG(B(L1,L), B(L1,L1), D, E,TEMPR)
-          CALL SROT(L3, A(1,L), 1, A(1,L1), 1, E, -D)
-          CALL SROT(L1, B(1,L), 1, B(1,L1), 1, E, -D)
-          CALL SROT(N, Z(1,L), 1, Z(1,L1), 1, E, -D)
-C* PERFORM TRANSFORMATIONS Q3,Z3,Q4,Z4,Q5 AND Z5 IN
-C* ORDER TO REDUCE THE PENCIL TO HESSENBERG FORM
-          CALL SLARTG(A(L2,L), A(L3,L), D, E,TEMPR)
-          CALL SROT(N-L+1, A(L2,L), NMAX, A(L3,L), NMAX, D, E)
-          CALL SROT(N-L1, B(L2,L2), NMAX, B(L3,L2), NMAX, D, E)
-          CALL SLARTG(B(L3,L2), B(L3,L3), D, E,TEMPR)
-          CALL SROT(L3, A(1,L2), 1, A(1,L3), 1, E, -D)
-          CALL SROT(L3, B(1,L2), 1, B(1,L3), 1, E, -D)
-          CALL SROT(N, Z(1,L2), 1, Z(1,L3), 1, E, -D)
-          CALL SLARTG(A(L1,L), A(L2,L), D, E,TEMPR)
-          CALL SROT(N-L+1, A(L1,L), NMAX, A(L2,L), NMAX, D, E)
-          CALL SROT(N-L, B(L1,L1), NMAX, B(L2,L1), NMAX, D, E)
-          CALL SLARTG(B(L2,L1), B(L2,L2), D, E,TEMPR)
-          CALL SROT(L3, A(1,L1), 1, A(1,L2), 1, E, -D)
-          CALL SROT(L2, B(1,L1), 1, B(1,L2), 1, E, -D)
-          CALL SROT(N, Z(1,L1), 1, Z(1,L2), 1, E, -D)
-          CALL SLARTG(A(L2,L1), A(L3,L1), D, E,TEMPR)
-          CALL SROT(N-L, A(L2,L1), NMAX, A(L3,L1), NMAX, D, E)
-          CALL SROT(N-L1, B(L2,L2), NMAX, B(L3,L2), NMAX, D, E)
-          CALL SLARTG(B(L3,L2), B(L3,L3), D, E,TEMPR)
-          CALL SROT(L3, A(1,L2), 1, A(1,L3), 1, E, -D)
-          CALL SROT(L3, B(1,L2), 1, B(1,L3), 1, E, -D)
-          CALL SROT(N, Z(1,L2), 1, Z(1,L3), 1, E, -D)
-C* TEST OF CONVERGENCE ON THE ELEMENT SEPARATING THE BLOCKS
-          IF (ABS(A(L2,L1)).LE.EPS) GO TO 140
-C* COMPUTE A NEW SHIFT IN CASE OF NO CONVERGENCE
-          A11B11 = A(L,L)/B(L,L)
-          A12B22 = A(L,L1)/B(L1,L1)
-          A21B11 = A(L1,L)/B(L,L)
-          A22B22 = A(L1,L1)/B(L1,L1)
-          B12B22 = B(L,L1)/B(L1,L1)
-          U(1,1) = ((AMMBMM-A11B11)*(ANNBNN-A11B11)-AMNBNN*
-     *     ANMBMM+ANMBMM*BMNBNN*A11B11)/A21B11 + A12B22 - A11B11*B12B22
-          U(2,1) = (A22B22-A11B11) - A21B11*B12B22 - (AMMBMM-A11B11) -
-     *     (ANNBNN-A11B11) + ANMBMM*BMNBNN
-          U(3,1) = A(L2,L1)/B(L1,L1)
-  120   CONTINUE
-  130 CONTINUE
-      FAIL = .TRUE.
-      RETURN
-C*  PUT THE NEGLECTABLE ELEMENTS EQUAL TO ZERO IN
-C*  CASE OF CONVERGENCE
-  140 A(L2,L) = 0.
-      A(L2,L1) = 0.
-      A(L3,L) = 0.
-      A(L3,L1) = 0.
-      B(L1,L) = 0.
-      B(L2,L) = 0.
-      B(L2,L1) = 0.
-      B(L3,L) = 0.
-      B(L3,L1) = 0.
-      B(L3,L2) = 0.
-      RETURN
-      END
--- a/liboctave/external/ordered-qz/ssubsp.f	Mon Jul 09 19:11:23 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-      SUBROUTINE SSUBSP(NMAX, N, A, B, Z, FTEST, EPS, NDIM, FAIL, IND)
-      INTEGER NMAX, N, FTEST, NDIM, IND(N)
-      LOGICAL FAIL
-      REAL A(NMAX,N), B(NMAX,N), Z(NMAX,N), EPS
-C*
-C* GIVEN THE UPPER TRIANGULAR MATRIX B AND UPPER HESSENBERG MATRIX A
-C* WITH 1X1 OR 2X2 DIAGONAL BLOCKS, THIS ROUTINE REORDERS THE DIAGONAL
-C* BLOCKS ALONG WITH THEIR GENERALIZED EIGENVALUES BY CONSTRUCTING EQUI-
-C* VALENCE TRANSFORMATIONS QT AND ZT. THE ROW TRANSFORMATION ZT IS ALSO
-C* PERFORMED ON THE GIVEN (INITIAL) TRANSFORMATION Z (RESULTING FROM A
-C* POSSIBLE PREVIOUS STEP OR INITIALIZED WITH THE IDENTITY MATRIX).
-C* AFTER REORDERING, THE EIGENVALUES INSIDE THE REGION SPECIFIED BY THE
-C* FUNCTION FTEST APPEAR AT THE TOP. IF NDIM IS THEIR NUMBER THEN THE
-C* NDIM FIRST COLUMNS OF Z SPAN THE REQUESTED SUBSPACE. DSUBSP REQUIRES
-C* THE SUBROUTINE EXCHQZ AND THE INTEGER FUNCTION FTEST WHICH HAS TO BE
-C* PROVIDED BY THE USER. THE PARAMETERS IN THE CALLING SEQUENCE ARE :
-C* (STARRED PARAMETERS ARE ALTERED BY THE SUBROUTINE)
-C*
-C*    NMAX     THE FIRST DIMENSION OF A, B AND Z
-C*    N        THE ORDER OF A, B AND Z
-C*   *A,*B     THE MATRIX PAIR WHOSE BLOCKS ARE TO BE REORDERED.
-C*   *Z        UPON RETURN THIS ARRAY IS MULTIPLIED BY THE COLUMN
-C*             TRANSFORMATION ZT.
-C*    FTEST(LS,ALPHA,BETA,S,P) AN INTEGER FUNCTION DESCRIBING THE
-C*             SPECTRUM OF THE DEFLATING SUBSPACE TO BE COMPUTED:
-C*             WHEN LS=1 FTEST CHECKS IF ALPHA/BETA IS IN THAT SPECTRUM
-C*             WHEN LS=2 FTEST CHECKS IF THE TWO COMPLEX CONJUGATE
-C*             ROOTS WITH SUM S AND PRODUCT P ARE IN THAT SPECTRUM
-C*             IF THE ANSWER IS POSITIVE, FTEST=1, OTHERWISE FTEST=-1
-C*    EPS      THE REQUIRED ABSOLUTE ACCURACY OF THE RESULT
-C*   *NDIM     AN INTEGER GIVING THE DIMENSION OF THE COMPUTED
-C*             DEFLATING SUBSPACE
-C*   *FAIL     A LOGICAL VARIABLE WHICH IS FALSE ON A NORMAL RETURN,
-C*             TRUE OTHERWISE (WHEN SEXCHQZ FAILS)
-C*   *IND      AN INTEGER WORKING ARRAY OF DIMENSION AT LEAST N
-C*
-      INTEGER L, LS, LS1, LS2, L1, LL, NUM, IS, L2I, L2K, I, K, II,
-     * ISTEP, IFIRST
-      REAL S, P, D, ALPHA, BETA
-      FAIL = .TRUE.
-      NDIM = 0
-      NUM = 0
-      L = 0
-      LS = 1
-C*** CONSTRUCT ARRAY IND(I) WHERE :
-C***     IABS(IND(I)) IS THE SIZE OF THE BLOCK I
-C***     SIGN(IND(I)) INDICATES THE LOCATION OF ITS EIGENVALUES
-C***                  (AS DETERMINED BY FTEST).
-C*** NUM IS THE NUMBER OF ELEMENTS IN THIS ARRAY
-      DO 30 LL=1,N
-        L = L + LS
-        IF (L.GT.N) GO TO 40
-        L1 = L + 1
-        IF (L1.GT.N) GO TO 10
-        IF (A(L1,L).EQ.0.) GO TO 10
-C* HERE A 2X2  BLOCK IS CHECKED *
-        LS = 2
-        D = B(L,L)*B(L1,L1)
-        S = (A(L,L)*B(L1,L1)+A(L1,L1)*B(L,L)-A(L1,L)*B(L,L1))/D
-        P = (A(L,L)*A(L1,L1)-A(L,L1)*A(L1,L))/D
-        IS = FTEST(LS,ALPHA,BETA,S,P)
-        GO TO 20
-C* HERE A 1X1  BLOCK IS CHECKED *
-   10   LS = 1
-        IS = FTEST(LS,A(L,L),B(L,L),S,P)
-   20   NUM = NUM + 1
-        IF (IS.EQ.1) NDIM = NDIM + LS
-        IND(NUM) = LS*IS
-   30 CONTINUE
-C***  REORDER BLOCKS SUCH THAT THOSE WITH POSITIVE VALUE
-C***    OF IND(.) APPEAR FIRST.
-   40 L2I = 1
-      DO 100 I=1,NUM
-        IF (IND(I).GT.0) GO TO 90
-C* IF A NEGATIVE IND(I) IS ENCOUNTERED, THEN SEARCH FOR THE FIRST
-C* POSITIVE IND(K) FOLLOWING ON IT
-        L2K = L2I
-        DO 60 K=I,NUM
-          IF (IND(K).LT.0) GO TO 50
-          GO TO 70
-   50     L2K = L2K - IND(K)
-   60   CONTINUE
-C* IF THERE ARE NO POSITIVE INDICES FOLLOWING ON A NEGATIVE ONE
-C* THEN STOP
-        GO TO 110
-C* IF A POSITIVE IND(K) FOLLOWS ON A NEGATIVE IND(I) THEN
-C* INTERCHANGE BLOCK K BEFORE BLOCK I BY PERFORMING K-I SWAPS
-   70   ISTEP = K - I
-        LS2 = IND(K)
-        L = L2K
-        DO 80 II=1,ISTEP
-          IFIRST = K - II
-          LS1 = -IND(IFIRST)
-          L = L - LS1
-          CALL SEXCHQZ(NMAX, N, A, B, Z, L, LS1, LS2, EPS, FAIL)
-          IF (FAIL) RETURN
-          IND(IFIRST+1) = IND(IFIRST)
-   80   CONTINUE
-        IND(I) = LS2
-   90   L2I = L2I + IND(I)
-  100 CONTINUE
-  110 FAIL = .FALSE.
-      RETURN
-      END
--- a/liboctave/numeric/lo-lapack-proto.h	Mon Jul 09 19:11:23 2018 -0700
+++ b/liboctave/numeric/lo-lapack-proto.h	Sun May 13 12:37:37 2018 +0200
@@ -1608,6 +1608,35 @@
                              F77_CHAR_ARG_LEN_DECL
                              F77_CHAR_ARG_LEN_DECL);
 
+  // TGSEN
+
+  F77_RET_T
+  F77_FUNC (dtgsen, DTGSEN) (const F77_INT& IJOB,
+                             const F77_LOGICAL& WANTQ,
+                             const F77_LOGICAL& WANTZ,
+                             const F77_LOGICAL *SELECT,
+                             const F77_INT& N,
+                             F77_DBLE *A,
+                             const F77_INT& LDA,
+                             F77_DBLE *B,
+                             const F77_INT& LDB,
+                             F77_DBLE *ALPHAR,
+                             F77_DBLE *ALPHAI,
+                             F77_DBLE *BETA,
+                             F77_DBLE *Q,
+                             const F77_INT& LDQ,
+                             F77_DBLE *Z,
+                             const F77_INT& LDZ,
+                             F77_INT& M,
+                             F77_DBLE& PL,
+                             F77_DBLE& PR,
+                             F77_DBLE *DIF,
+                             F77_DBLE *WORK,
+                             const F77_INT& LWORK,
+                             F77_INT *IWORK,
+                             const F77_INT& LIWORK,
+                             F77_INT& INFO);
+
   // TRCON
 
   F77_RET_T