private static int qzit(int n, double[][] a, double[][] b, double eps1, bool matz, double[][] z, ref int ierr)
{
int i, j, k, l = 0;
double r, s, t, a1, a2, a3 = 0;
int k1, k2, l1, ll;
double u1, u2, u3;
double v1, v2, v3;
double a11, a12, a21, a22, a33, a34, a43, a44;
double b11, b12, b22, b33, b34, b44;
int na, en, ld;
double ep;
double sh = 0;
int km1, lm1 = 0;
double ani, bni;
int ish, itn, its, enm2, lor1;
double epsa, epsb, anorm = 0, bnorm = 0;
int enorn;
bool notlas;
ierr = 0;
#region Compute epsa and epsb
for (i = 0; i < n; ++i)
{
ani = 0.0;
bni = 0.0;
if (i != 0)
ani = (Math.Abs(a[i][(i - 1)]));
for (j = i; j < n; ++j)
{
ani += Math.Abs(a[i][j]);
bni += Math.Abs(b[i][j]);
}
if (ani > anorm) anorm = ani;
if (bni > bnorm) bnorm = bni;
}
if (anorm == 0.0) anorm = 1.0;
if (bnorm == 0.0) bnorm = 1.0;
ep = eps1;
if (ep == 0.0)
{
// Use round-off level if eps1 is zero
ep = Special.Epslon(1.0);
}
epsa = ep * anorm;
epsb = ep * bnorm;
#endregion
// Reduce a to quasi-triangular form][while keeping b triangular
lor1 = 0;
enorn = n;
en = n - 1;
itn = n * 30;
// Begin QZ step
L60:
if (en <= 1) goto L1001;
if (!matz) enorn = en + 1;
its = 0;
na = en - 1;
enm2 = na;
L70:
ish = 2;
// Check for convergence or reducibility.
for (ll = 0; ll <= en; ++ll)
{
lm1 = en - ll - 1;
l = lm1 + 1;
if (l + 1 == 1)
goto L95;
if ((Math.Abs(a[l][lm1])) <= epsa)
break;
}
L90:
a[l][lm1] = 0.0;
if (l < na) goto L95;
// 1-by-1 or 2-by-2 block isolated
en = lm1;
goto L60;
// Check for small top of b
L95:
ld = l;
L100:
l1 = l + 1;
b11 = b[l][l];
if (Math.Abs(b11) > epsb) goto L120;
b[l][l] = 0.0;
s = (Math.Abs(a[l][l]) + Math.Abs(a[l1][l]));
u1 = a[l][l] / s;
u2 = a[l1][l] / s;
r = Special.Sign(Math.Sqrt(u1 * u1 + u2 * u2), u1);
v1 = -(u1 + r) / r;
v2 = -u2 / r;
u2 = v2 / v1;
for (j = l; j < enorn; ++j)
{
t = a[l][j] + u2 * a[l1][j];
a[l][j] += t * v1;
a[l1][j] += t * v2;
t = b[l][j] + u2 * b[l1][j];
b[l][j] += t * v1;
b[l1][j] += t * v2;
}
if (l != 0)
a[l][lm1] = -a[l][lm1];
lm1 = l;
l = l1;
goto L90;
L120:
a11 = a[l][l] / b11;
a21 = a[l1][l] / b11;
if (ish == 1) goto L140;
// Iteration strategy
if (itn == 0) goto L1000;
if (its == 10) goto L155;
// Determine type of shift
b22 = b[l1][l1];
if (Math.Abs(b22) < epsb) b22 = epsb;
b33 = b[na][na];
if (Math.Abs(b33) < epsb) b33 = epsb;
b44 = b[en][en];
if (Math.Abs(b44) < epsb) b44 = epsb;
a33 = a[na][na] / b33;
a34 = a[na][en] / b44;
a43 = a[en][na] / b33;
a44 = a[en][en] / b44;
b34 = b[na][en] / b44;
t = (a43 * b34 - a33 - a44) * .5;
r = t * t + a34 * a43 - a33 * a44;
if (r < 0.0) goto L150;
// Determine single shift zero-th column of a
ish = 1;
r = Math.Sqrt(r);
sh = -t + r;
s = -t - r;
if (Math.Abs(s - a44) < Math.Abs(sh - a44))
sh = s;
// Look for two consecutive small sub-diagonal elements of a.
for (ll = ld; ll + 1 <= enm2; ++ll)
{
l = enm2 + ld - ll - 1;
if (l == ld)
goto L140;
lm1 = l - 1;
l1 = l + 1;
t = a[l + 1][l + 1];
if (Math.Abs(b[l][l]) > epsb)
t -= sh * b[l][l];
if (Math.Abs(a[l][lm1]) <= (Math.Abs(t / a[l1][l])) * epsa)
goto L100;
}
L140:
a1 = a11 - sh;
a2 = a21;
if (l != ld)
a[l][lm1] = -a[l][lm1];
goto L160;
// Determine double shift zero-th column of a
L150:
a12 = a[l][l1] / b22;
a22 = a[l1][l1] / b22;
b12 = b[l][l1] / b22;
a1 = ((a33 - a11) * (a44 - a11) - a34 * a43 + a43 * b34 * a11) / a21 + a12 - a11 * b12;
a2 = a22 - a11 - a21 * b12 - (a33 - a11) - (a44 - a11) + a43 * b34;
a3 = a[l1 + 1][l1] / b22;
goto L160;
// Ad hoc shift
L155:
a1 = 0.0;
a2 = 1.0;
a3 = 1.1605;
L160:
++its;
--itn;
if (!matz) lor1 = ld;
// Main loop
for (k = l; k <= na; ++k)
{
notlas = k != na && ish == 2;
k1 = k + 1;
k2 = k + 2;
km1 = Math.Max(k, l + 1) - 1; // Computing MAX
ll = Math.Min(en, k1 + ish); // Computing MIN
if (notlas) goto L190;
// Zero a(k+1,k-1)
if (k == l) goto L170;
a1 = a[k][km1];
a2 = a[k1][km1];
L170:
s = Math.Abs(a1) + Math.Abs(a2);
if (s == 0.0) goto L70;
u1 = a1 / s;
u2 = a2 / s;
r = Special.Sign(Math.Sqrt(u1 * u1 + u2 * u2), u1);
v1 = -(u1 + r) / r;
v2 = -u2 / r;
u2 = v2 / v1;
for (j = km1; j < enorn; ++j)
{
t = a[k][j] + u2 * a[k1][j];
a[k][j] += t * v1;
a[k1][j] += t * v2;
t = b[k][j] + u2 * b[k1][j];
b[k][j] += t * v1;
b[k1][j] += t * v2;
}
if (k != l)
a[k1][km1] = 0.0;
goto L240;
// Zero a(k+1,k-1) and a(k+2,k-1)
L190:
if (k == l) goto L200;
a1 = a[k][km1];
a2 = a[k1][km1];
a3 = a[k2][km1];
L200:
s = Math.Abs(a1) + Math.Abs(a2) + Math.Abs(a3);
if (s == 0.0) goto L260;
u1 = a1 / s;
u2 = a2 / s;
u3 = a3 / s;
r = Special.Sign(Math.Sqrt(u1 * u1 + u2 * u2 + u3 * u3), u1);
v1 = -(u1 + r) / r;
v2 = -u2 / r;
v3 = -u3 / r;
u2 = v2 / v1;
u3 = v3 / v1;
for (j = km1; j < enorn; ++j)
{
t = a[k][j] + u2 * a[k1][j] + u3 * a[k2][j];
a[k][j] += t * v1;
a[k1][j] += t * v2;
a[k2][j] += t * v3;
t = b[k][j] + u2 * b[k1][j] + u3 * b[k2][j];
b[k][j] += t * v1;
b[k1][j] += t * v2;
b[k2][j] += t * v3;
}
if (k == l) goto L220;
a[k1][km1] = 0.0;
a[k2][km1] = 0.0;
// Zero b(k+2,k+1) and b(k+2,k)
L220:
s = (Math.Abs(b[k2][k2])) + (Math.Abs(b[k2][k1])) + (Math.Abs(b[k2][k]));
if (s == 0.0) goto L240;
u1 = b[k2][k2] / s;
u2 = b[k2][k1] / s;
u3 = b[k2][k] / s;
r = Special.Sign(Math.Sqrt(u1 * u1 + u2 * u2 + u3 * u3), u1);
v1 = -(u1 + r) / r;
v2 = -u2 / r;
v3 = -u3 / r;
u2 = v2 / v1;
u3 = v3 / v1;
for (i = lor1; i < ll + 1; ++i)
{
t = a[i][k2] + u2 * a[i][k1] + u3 * a[i][k];
a[i][k2] += t * v1;
a[i][k1] += t * v2;
a[i][k] += t * v3;
t = b[i][k2] + u2 * b[i][k1] + u3 * b[i][k];
b[i][k2] += t * v1;
b[i][k1] += t * v2;
b[i][k] += t * v3;
}
b[k2][k] = 0.0;
b[k2][k1] = 0.0;
if (matz)
{
for (i = 0; i < n; ++i)
{
t = z[i][k2] + u2 * z[i][k1] + u3 * z[i][k];
z[i][k2] += t * v1;
z[i][k1] += t * v2;
z[i][k] += t * v3;
}
}
// Zero b(k+1,k)
L240:
s = (Math.Abs(b[k1][k1])) + (Math.Abs(b[k1][k]));
if (s == 0.0) goto L260;
u1 = b[k1][k1] / s;
u2 = b[k1][k] / s;
r = Special.Sign(Math.Sqrt(u1 * u1 + u2 * u2), u1);
v1 = -(u1 + r) / r;
v2 = -u2 / r;
u2 = v2 / v1;
for (i = lor1; i < ll + 1; ++i)
{
t = a[i][k1] + u2 * a[i][k];
a[i][k1] += t * v1;
a[i][k] += t * v2;
t = b[i][k1] + u2 * b[i][k];
b[i][k1] += t * v1;
b[i][k] += t * v2;
}
b[k1][k] = 0.0;
if (matz)
{
for (i = 0; i < n; ++i)
{
t = z[i][k1] + u2 * z[i][k];
z[i][k1] += t * v1;
z[i][k] += t * v2;
}
}
L260:
;
}
goto L70; // End QZ step
// Set error -- all eigenvalues have not converged after 30*n iterations
L1000:
ierr = en + 1;
// Save epsb for use by qzval and qzvec
L1001:
if (n > 1)
b[n - 1][0] = epsb;
return 0;
}