2018-11-20 21:31:40 +01:00
|
|
|
/*
|
|
|
|
Copyright 2013 Timo Hartmann
|
|
|
|
Copyright 2018 Fredrik Johansson
|
|
|
|
|
|
|
|
This file is part of Arb.
|
|
|
|
|
|
|
|
Arb is free software: you can redistribute it and/or modify it under
|
|
|
|
the terms of the GNU Lesser General Public License (LGPL) as published
|
|
|
|
by the Free Software Foundation; either version 2.1 of the License, or
|
|
|
|
(at your option) any later version. See <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
Adapted from eigen.py in mpmath (written by Timo Hartmann)
|
|
|
|
|
|
|
|
Todo items present in the original code:
|
|
|
|
|
|
|
|
- Implement balancing
|
|
|
|
- Aggressive early deflation
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "acb_mat.h"
|
|
|
|
|
2018-11-24 19:27:42 +01:00
|
|
|
static void
|
|
|
|
acb_approx_mag(mag_t res, const acb_t x)
|
|
|
|
{
|
|
|
|
mag_t t;
|
|
|
|
mag_init(t);
|
|
|
|
arf_get_mag(res, arb_midref(acb_realref(x)));
|
|
|
|
arf_get_mag(t, arb_midref(acb_imagref(x)));
|
|
|
|
mag_hypot(res, res, t);
|
|
|
|
mag_clear(t);
|
|
|
|
}
|
|
|
|
|
2018-11-20 21:31:40 +01:00
|
|
|
static void
|
|
|
|
acb_approx_mul(acb_t res, const acb_t x, const acb_t y, slong prec)
|
|
|
|
{
|
|
|
|
arf_complex_mul(arb_midref(acb_realref(res)), arb_midref(acb_imagref(res)),
|
|
|
|
arb_midref(acb_realref(x)), arb_midref(acb_imagref(x)),
|
|
|
|
arb_midref(acb_realref(y)), arb_midref(acb_imagref(y)), prec, ARF_RND_DOWN);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
acb_approx_add(acb_t res, const acb_t x, const acb_t y, slong prec)
|
|
|
|
{
|
|
|
|
arf_add(arb_midref(acb_realref(res)), arb_midref(acb_realref(x)), arb_midref(acb_realref(y)), prec, ARF_RND_DOWN);
|
|
|
|
arf_add(arb_midref(acb_imagref(res)), arb_midref(acb_imagref(x)), arb_midref(acb_imagref(y)), prec, ARF_RND_DOWN);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
acb_approx_sub(acb_t res, const acb_t x, const acb_t y, slong prec)
|
|
|
|
{
|
|
|
|
arf_sub(arb_midref(acb_realref(res)), arb_midref(acb_realref(x)), arb_midref(acb_realref(y)), prec, ARF_RND_DOWN);
|
|
|
|
arf_sub(arb_midref(acb_imagref(res)), arb_midref(acb_imagref(x)), arb_midref(acb_imagref(y)), prec, ARF_RND_DOWN);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
acb_approx_set(acb_t res, const acb_t x)
|
|
|
|
{
|
|
|
|
arf_set(arb_midref(acb_realref(res)), arb_midref(acb_realref(x)));
|
|
|
|
arf_set(arb_midref(acb_imagref(res)), arb_midref(acb_imagref(x)));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
acb_approx_div_arb(acb_t res, const acb_t x, const arb_t y, slong prec)
|
|
|
|
{
|
|
|
|
arf_div(arb_midref(acb_realref(res)), arb_midref(acb_realref(x)), arb_midref(y), prec, ARF_RND_DOWN);
|
|
|
|
arf_div(arb_midref(acb_imagref(res)), arb_midref(acb_imagref(x)), arb_midref(y), prec, ARF_RND_DOWN);
|
|
|
|
}
|
|
|
|
|
2018-11-24 19:27:42 +01:00
|
|
|
static void
|
|
|
|
acb_approx_inv(acb_t z, const acb_t x, slong prec)
|
|
|
|
{
|
|
|
|
arf_set(arb_midref(acb_realref(z)), arb_midref(acb_realref(x)));
|
|
|
|
arf_set(arb_midref(acb_imagref(z)), arb_midref(acb_imagref(x)));
|
|
|
|
|
|
|
|
mag_zero(arb_radref(acb_realref(z)));
|
|
|
|
mag_zero(arb_radref(acb_imagref(z)));
|
|
|
|
|
|
|
|
acb_inv(z, z, prec);
|
|
|
|
|
|
|
|
mag_zero(arb_radref(acb_realref(z)));
|
|
|
|
mag_zero(arb_radref(acb_imagref(z)));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
acb_approx_div(acb_t z, const acb_t x, const acb_t y, slong prec)
|
|
|
|
{
|
|
|
|
acb_t t;
|
|
|
|
acb_init(t);
|
|
|
|
acb_approx_inv(t, y, prec);
|
|
|
|
acb_approx_mul(z, x, t, prec);
|
|
|
|
acb_clear(t);
|
|
|
|
}
|
|
|
|
|
2018-11-20 21:31:40 +01:00
|
|
|
void
|
|
|
|
acb_mat_approx_qr_step(acb_mat_t A, acb_mat_t Q, slong n0, slong n1, const acb_t shift, slong prec)
|
|
|
|
{
|
|
|
|
slong j, k, n;
|
|
|
|
acb_t c, s, negs, cc, cs, negcs, t;
|
|
|
|
acb_struct v1[2];
|
|
|
|
acb_struct v1neg[2];
|
|
|
|
acb_struct v2[2];
|
|
|
|
acb_struct v2neg[2];
|
|
|
|
acb_struct v3[2];
|
|
|
|
arb_t v, u;
|
|
|
|
|
|
|
|
n = acb_mat_nrows(A);
|
|
|
|
|
|
|
|
acb_init(c);
|
|
|
|
acb_init(s);
|
|
|
|
acb_init(negs);
|
|
|
|
acb_init(cc);
|
|
|
|
acb_init(cs);
|
|
|
|
acb_init(negcs);
|
|
|
|
acb_init(t);
|
|
|
|
arb_init(v);
|
|
|
|
arb_init(u);
|
|
|
|
|
|
|
|
/* Calculate Givens rotation */
|
|
|
|
acb_approx_sub(c, acb_mat_entry(A, n0, n0), shift, prec);
|
|
|
|
acb_approx_set(s, acb_mat_entry(A, n0 + 1, n0));
|
|
|
|
|
|
|
|
arf_sosq(arb_midref(v), arb_midref(acb_realref(c)), arb_midref(acb_imagref(c)), prec, ARF_RND_DOWN);
|
|
|
|
arf_sosq(arb_midref(u), arb_midref(acb_realref(s)), arb_midref(acb_imagref(s)), prec, ARF_RND_DOWN);
|
|
|
|
arf_add(arb_midref(v), arb_midref(v), arb_midref(u), prec, ARF_RND_DOWN);
|
|
|
|
arf_sqrt(arb_midref(v), arb_midref(v), prec, ARF_RND_DOWN);
|
|
|
|
|
|
|
|
if (arb_is_zero(v))
|
|
|
|
{
|
|
|
|
arb_one(v);
|
|
|
|
acb_one(c);
|
|
|
|
acb_zero(s);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
acb_approx_div_arb(c, c, v, prec);
|
|
|
|
acb_approx_div_arb(s, s, v, prec);
|
|
|
|
}
|
|
|
|
|
|
|
|
acb_conj(cc, c);
|
|
|
|
acb_conj(cs, s);
|
|
|
|
acb_neg(negs, s);
|
|
|
|
acb_neg(negcs, cs);
|
|
|
|
|
|
|
|
v1[0] = *c;
|
|
|
|
v1[1] = *s;
|
|
|
|
v1neg[0] = *c;
|
|
|
|
v1neg[1] = *negs;
|
|
|
|
v2[0] = *cc;
|
|
|
|
v2[1] = *cs;
|
|
|
|
v2neg[0] = *cc;
|
|
|
|
v2neg[1] = *negcs;
|
|
|
|
|
|
|
|
/* Apply Givens rotation from the left */
|
|
|
|
for (k = n0; k < n; k++)
|
|
|
|
{
|
|
|
|
v3[0] = *acb_mat_entry(A, n0, k);
|
|
|
|
v3[1] = *acb_mat_entry(A, n0 + 1, k);
|
|
|
|
|
|
|
|
/* x = A[n0 ,k] */
|
|
|
|
/* y = A[n0+1,k] */
|
|
|
|
/* A[n0, k] = cc * x + cs * y */
|
|
|
|
/* A[n0 + 1, k] = c * y - s * x */
|
|
|
|
|
|
|
|
acb_approx_dot(t, NULL, 0, v2, 1, v3, 1, 2, prec);
|
|
|
|
acb_approx_dot(acb_mat_entry(A, n0 + 1, k), NULL, 0, v1neg, 1, v3 + 1, -1, 2, prec);
|
|
|
|
acb_swap(t, acb_mat_entry(A, n0, k));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Apply Givens rotation from the right */
|
|
|
|
for (k = 0; k < FLINT_MIN(n1, n0 + 3); k++)
|
|
|
|
{
|
|
|
|
/* x = A[k,n0 ] */
|
|
|
|
/* y = A[k,n0+1] */
|
|
|
|
/* A[k,n0 ] = c * x + s * y */
|
|
|
|
/* A[k,n0+1] = cc * y - cs * x */
|
|
|
|
|
|
|
|
v3[0] = *acb_mat_entry(A, k, n0);
|
|
|
|
v3[1] = *acb_mat_entry(A, k, n0 + 1);
|
|
|
|
|
|
|
|
acb_approx_dot(t, NULL, 0, v1, 1, v3, 1, 2, prec);
|
|
|
|
acb_approx_dot(acb_mat_entry(A, k, n0 + 1), NULL, 0, v2neg, 1, v3 + 1, -1, 2, prec);
|
|
|
|
acb_swap(t, acb_mat_entry(A, k, n0));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Q != NULL)
|
|
|
|
{
|
|
|
|
for (k = 0; k < n; k++)
|
|
|
|
{
|
|
|
|
/* x = Q[k,n0 ] */
|
|
|
|
/* y = Q[k,n0+1] */
|
|
|
|
/* Q[k,n0 ] = c * x + s * y */
|
|
|
|
/* Q[k,n0+1] = cc * y - cs * x */
|
|
|
|
|
|
|
|
v3[0] = *acb_mat_entry(Q, k, n0);
|
|
|
|
v3[1] = *acb_mat_entry(Q, k, n0 + 1);
|
|
|
|
|
|
|
|
acb_approx_dot(t, NULL, 0, v1, 1, v3, 1, 2, prec);
|
|
|
|
acb_approx_dot(acb_mat_entry(Q, k, n0 + 1), NULL, 0, v2neg, 1, v3 + 1, -1, 2, prec);
|
|
|
|
acb_swap(t, acb_mat_entry(Q, k, n0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j = n0; j < n1 - 2; j++)
|
|
|
|
{
|
|
|
|
/* Calculate Givens rotation */
|
|
|
|
acb_set(c, acb_mat_entry(A, j + 1, j));
|
|
|
|
acb_set(s, acb_mat_entry(A, j + 2, j));
|
|
|
|
|
|
|
|
arf_sosq(arb_midref(v), arb_midref(acb_realref(c)), arb_midref(acb_imagref(c)), prec, ARF_RND_DOWN);
|
|
|
|
arf_sosq(arb_midref(u), arb_midref(acb_realref(s)), arb_midref(acb_imagref(s)), prec, ARF_RND_DOWN);
|
|
|
|
arf_add(arb_midref(v), arb_midref(v), arb_midref(u), prec, ARF_RND_DOWN);
|
|
|
|
arf_sqrt(arb_midref(v), arb_midref(v), prec, ARF_RND_DOWN);
|
|
|
|
|
|
|
|
if (arb_is_zero(v))
|
|
|
|
{
|
|
|
|
acb_zero(acb_mat_entry(A, j + 1, j));
|
|
|
|
arb_one(v);
|
|
|
|
acb_one(c);
|
|
|
|
acb_zero(s);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
acb_set_arb(acb_mat_entry(A, j + 1, j), v);
|
|
|
|
acb_approx_div_arb(c, c, v, prec);
|
|
|
|
acb_approx_div_arb(s, s, v, prec);
|
|
|
|
}
|
|
|
|
|
|
|
|
acb_zero(acb_mat_entry(A, j + 2, j));
|
|
|
|
|
|
|
|
acb_conj(cc, c);
|
|
|
|
acb_conj(cs, s);
|
|
|
|
acb_neg(negs, s);
|
|
|
|
acb_neg(negcs, cs);
|
|
|
|
|
|
|
|
v1[0] = *c;
|
|
|
|
v1[1] = *s;
|
|
|
|
v1neg[0] = *c;
|
|
|
|
v1neg[1] = *negs;
|
|
|
|
v2[0] = *cc;
|
|
|
|
v2[1] = *cs;
|
|
|
|
v2neg[0] = *cc;
|
|
|
|
v2neg[1] = *negcs;
|
|
|
|
|
|
|
|
/* Apply Givens rotation from the left */
|
|
|
|
for (k = j + 1; k < n; k++)
|
|
|
|
{
|
|
|
|
v3[0] = *acb_mat_entry(A, j + 1, k);
|
|
|
|
v3[1] = *acb_mat_entry(A, j + 2, k);
|
|
|
|
|
|
|
|
/* x = A[j+1, k] */
|
|
|
|
/* y = A[j+2, k] */
|
|
|
|
/* A[j + 1, k] = cc * x + cs * y */
|
|
|
|
/* A[j + 2, k] = c * y - s * x */
|
|
|
|
|
|
|
|
acb_approx_dot(t, NULL, 0, v2, 1, v3, 1, 2, prec);
|
|
|
|
acb_approx_dot(acb_mat_entry(A, j + 2, k), NULL, 0, v1neg, 1, v3 + 1, -1, 2, prec);
|
|
|
|
acb_swap(t, acb_mat_entry(A, j + 1, k));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Apply Givens rotation from the right */
|
|
|
|
for (k = 0; k < FLINT_MIN(n1, j + 4); k++)
|
|
|
|
{
|
|
|
|
/* x = A[k,j+1] */
|
|
|
|
/* y = A[k,j+2] */
|
|
|
|
/* A[k,j+1] = c * x + s * y */
|
|
|
|
/* A[k,j+2] = cc * y - cs * x */
|
|
|
|
|
|
|
|
v3[0] = *acb_mat_entry(A, k, j + 1);
|
|
|
|
v3[1] = *acb_mat_entry(A, k, j + 2);
|
|
|
|
|
|
|
|
acb_approx_dot(t, NULL, 0, v1, 1, v3, 1, 2, prec);
|
|
|
|
acb_approx_dot(acb_mat_entry(A, k, j + 2), NULL, 0, v2neg, 1, v3 + 1, -1, 2, prec);
|
|
|
|
acb_swap(t, acb_mat_entry(A, k, j + 1));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Q != NULL)
|
|
|
|
{
|
|
|
|
for (k = 0; k < n; k++)
|
|
|
|
{
|
|
|
|
/* x = Q[k,j+1] */
|
|
|
|
/* y = Q[k,j+2] */
|
|
|
|
/* Q[k,j+1] = c * x + s * y */
|
|
|
|
/* Q[k,j+2] = cc * y - cs * x */
|
|
|
|
|
|
|
|
v3[0] = *acb_mat_entry(Q, k, j + 1);
|
|
|
|
v3[1] = *acb_mat_entry(Q, k, j + 2);
|
|
|
|
|
|
|
|
acb_approx_dot(t, NULL, 0, v1, 1, v3, 1, 2, prec);
|
|
|
|
acb_approx_dot(acb_mat_entry(Q, k, j + 2), NULL, 0, v2neg, 1, v3 + 1, -1, 2, prec);
|
|
|
|
acb_swap(t, acb_mat_entry(Q, k, j + 1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
acb_clear(c);
|
|
|
|
acb_clear(s);
|
|
|
|
acb_clear(negs);
|
|
|
|
acb_clear(cc);
|
|
|
|
acb_clear(cs);
|
|
|
|
acb_clear(negcs);
|
|
|
|
acb_clear(t);
|
|
|
|
arb_clear(v);
|
|
|
|
arb_clear(u);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
acb_mat_approx_hessenberg_reduce_0(acb_mat_t A, acb_ptr T, slong prec)
|
|
|
|
{
|
|
|
|
slong i, j, k, n;
|
|
|
|
arf_t scale, scale_inv, tt, H, G, f;
|
|
|
|
acb_ptr V1, V2;
|
|
|
|
acb_t ff, GG, TT;
|
|
|
|
acb_t F;
|
|
|
|
|
|
|
|
n = acb_mat_nrows(A);
|
|
|
|
if (n <= 2)
|
|
|
|
return;
|
|
|
|
|
|
|
|
arf_init(scale);
|
|
|
|
arf_init(scale_inv);
|
|
|
|
arf_init(tt);
|
|
|
|
arf_init(H);
|
|
|
|
arf_init(G);
|
|
|
|
arf_init(f);
|
|
|
|
acb_init(F);
|
|
|
|
V1 = _acb_vec_init(n + 1);
|
|
|
|
V2 = _acb_vec_init(n + 1);
|
|
|
|
acb_init(ff);
|
|
|
|
acb_init(GG);
|
|
|
|
acb_init(TT);
|
|
|
|
|
|
|
|
for (i = n - 1; i >= 2; i--)
|
|
|
|
{
|
|
|
|
/* Scale the vector (todo: is this needed?) */
|
|
|
|
arf_zero(scale);
|
|
|
|
for (k = 0; k < i; k++)
|
|
|
|
{
|
|
|
|
arf_abs(tt, arb_midref(acb_realref(acb_mat_entry(A, i, k))));
|
|
|
|
arf_add(scale, scale, tt, prec, ARF_RND_DOWN);
|
|
|
|
arf_abs(tt, arb_midref(acb_imagref(acb_mat_entry(A, i, k))));
|
|
|
|
arf_add(scale, scale, tt, prec, ARF_RND_DOWN);
|
|
|
|
}
|
|
|
|
|
|
|
|
arf_ui_div(scale_inv, 1, scale, prec, ARF_RND_DOWN);
|
|
|
|
|
2018-11-24 19:27:42 +01:00
|
|
|
if (arf_is_zero(scale))
|
2018-11-20 21:31:40 +01:00
|
|
|
{
|
|
|
|
acb_zero(T + i);
|
|
|
|
acb_zero(acb_mat_entry(A, i, i - 1));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculate parameters for Householder transformation. */
|
|
|
|
arf_zero(H);
|
|
|
|
for (k = 0; k < i; k++)
|
|
|
|
{
|
|
|
|
arf_ptr Aikr, Aiki;
|
|
|
|
|
|
|
|
Aikr = arb_midref(acb_realref(acb_mat_entry(A, i, k)));
|
|
|
|
Aiki = arb_midref(acb_imagref(acb_mat_entry(A, i, k)));
|
|
|
|
|
|
|
|
arf_mul(Aikr, Aikr, scale_inv, prec, ARF_RND_DOWN);
|
|
|
|
arf_mul(Aiki, Aiki, scale_inv, prec, ARF_RND_DOWN);
|
|
|
|
|
|
|
|
arf_addmul(H, Aikr, Aikr, prec, ARF_RND_DOWN);
|
|
|
|
arf_addmul(H, Aiki, Aiki, prec, ARF_RND_DOWN);
|
|
|
|
}
|
|
|
|
|
|
|
|
acb_set(F, acb_mat_entry(A, i, i - 1));
|
|
|
|
|
|
|
|
/* f = abs(F) */
|
|
|
|
arf_mul(f, arb_midref(acb_realref(F)), arb_midref(acb_realref(F)), prec, ARF_RND_DOWN);
|
|
|
|
arf_addmul(f, arb_midref(acb_imagref(F)), arb_midref(acb_imagref(F)), prec, ARF_RND_DOWN);
|
|
|
|
arf_sqrt(f, f, prec, ARF_RND_DOWN);
|
|
|
|
|
|
|
|
arf_sqrt(G, H, prec, ARF_RND_DOWN);
|
|
|
|
|
|
|
|
/* A[i,i-1] = -G scale */
|
|
|
|
arf_mul(arb_midref(acb_realref(acb_mat_entry(A, i, i - 1))), G, scale, prec, ARF_RND_DOWN);
|
|
|
|
arf_neg(arb_midref(acb_realref(acb_mat_entry(A, i, i - 1))), arb_midref(acb_realref(acb_mat_entry(A, i, i - 1))));
|
|
|
|
arf_zero(arb_midref(acb_imagref(acb_mat_entry(A, i, i - 1))));
|
|
|
|
|
|
|
|
if (arf_is_zero(f))
|
|
|
|
{
|
|
|
|
arb_set_arf(acb_realref(T + i), G);
|
|
|
|
arb_zero(acb_imagref(T + i));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* ff = F / f */
|
|
|
|
arf_div(arb_midref(acb_realref(ff)), arb_midref(acb_realref(F)), f, prec, ARF_RND_DOWN);
|
|
|
|
arf_div(arb_midref(acb_imagref(ff)), arb_midref(acb_imagref(F)), f, prec, ARF_RND_DOWN);
|
|
|
|
|
|
|
|
/* T[i] = F + G ff */
|
|
|
|
acb_set(T + i, F);
|
|
|
|
arf_addmul(arb_midref(acb_realref(T + i)), arb_midref(acb_realref(ff)), G, prec, ARF_RND_DOWN);
|
|
|
|
arf_addmul(arb_midref(acb_imagref(T + i)), arb_midref(acb_imagref(ff)), G, prec, ARF_RND_DOWN);
|
|
|
|
|
|
|
|
/* A[i,i-1] *= ff */
|
|
|
|
acb_approx_mul(acb_mat_entry(A, i, i - 1), acb_mat_entry(A, i, i - 1), ff, prec);
|
|
|
|
}
|
|
|
|
|
|
|
|
arf_addmul(H, G, f, prec, ARF_RND_DOWN);
|
|
|
|
arf_rsqrt(H, H, prec, ARF_RND_DOWN);
|
|
|
|
|
|
|
|
arf_mul(arb_midref(acb_realref(T + i)), arb_midref(acb_realref(T + i)), H, prec, ARF_RND_DOWN);
|
|
|
|
arf_mul(arb_midref(acb_imagref(T + i)), arb_midref(acb_imagref(T + i)), H, prec, ARF_RND_DOWN);
|
|
|
|
|
|
|
|
for (k = 0; k < i - 1; k++)
|
|
|
|
{
|
|
|
|
arf_mul(arb_midref(acb_realref(acb_mat_entry(A, i, k))),
|
|
|
|
arb_midref(acb_realref(acb_mat_entry(A, i, k))),
|
|
|
|
H, prec, ARF_RND_DOWN);
|
|
|
|
arf_mul(arb_midref(acb_imagref(acb_mat_entry(A, i, k))),
|
|
|
|
arb_midref(acb_imagref(acb_mat_entry(A, i, k))),
|
|
|
|
H, prec, ARF_RND_DOWN);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* todo: optimize copies below */
|
|
|
|
/* todo: conj mid etc... */
|
|
|
|
|
|
|
|
/* Apply Householder transformation (from the right). */
|
|
|
|
for (j = 0; j < i; j++)
|
|
|
|
{
|
|
|
|
acb_conj(V1, T + i);
|
|
|
|
acb_set(V2, acb_mat_entry(A, j, i - 1));
|
|
|
|
for (k = 0; k < i - 1; k++)
|
|
|
|
{
|
|
|
|
acb_conj(V1 + k + 1, acb_mat_entry(A, i, k));
|
|
|
|
acb_set(V2 + k + 1, acb_mat_entry(A, j, k));
|
|
|
|
}
|
|
|
|
acb_approx_dot(GG, NULL, 0, V1, 1, V2, 1, i, prec);
|
|
|
|
|
|
|
|
acb_approx_mul(TT, GG, T + i, prec);
|
|
|
|
acb_approx_sub(acb_mat_entry(A, j, i - 1),
|
|
|
|
acb_mat_entry(A, j, i - 1), TT, prec);
|
|
|
|
for (k = 0; k < i - 1; k++)
|
|
|
|
{
|
|
|
|
acb_approx_mul(TT, GG, acb_mat_entry(A, i, k), prec);
|
|
|
|
acb_approx_sub(acb_mat_entry(A, j, k),
|
|
|
|
acb_mat_entry(A, j, k), TT, prec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j = 0; j < n; j++)
|
|
|
|
{
|
|
|
|
acb_set(V1, T + i);
|
|
|
|
acb_set(V2, acb_mat_entry(A, i - 1, j));
|
|
|
|
for (k = 0; k < i - 1; k++)
|
|
|
|
{
|
|
|
|
acb_set(V1 + k + 1, acb_mat_entry(A, i, k));
|
|
|
|
acb_set(V2 + k + 1, acb_mat_entry(A, k, j));
|
|
|
|
}
|
|
|
|
acb_approx_dot(GG, NULL, 0, V1, 1, V2, 1, i, prec);
|
|
|
|
|
|
|
|
acb_conj(TT, T + i);
|
|
|
|
acb_approx_mul(TT, GG, TT, prec);
|
|
|
|
acb_approx_sub(acb_mat_entry(A, i - 1, j),
|
|
|
|
acb_mat_entry(A, i - 1, j), TT, prec);
|
|
|
|
for (k = 0; k < i - 1; k++)
|
|
|
|
{
|
|
|
|
acb_conj(TT, acb_mat_entry(A, i, k));
|
|
|
|
acb_approx_mul(TT, GG, TT, prec);
|
|
|
|
acb_approx_sub(acb_mat_entry(A, k, j),
|
|
|
|
acb_mat_entry(A, k, j), TT, prec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
arf_clear(scale);
|
|
|
|
arf_clear(scale_inv);
|
|
|
|
arf_clear(tt);
|
|
|
|
arf_clear(H);
|
|
|
|
arf_clear(G);
|
|
|
|
arf_clear(f);
|
|
|
|
acb_clear(F);
|
|
|
|
_acb_vec_clear(V1, n + 1);
|
|
|
|
_acb_vec_clear(V2, n + 1);
|
|
|
|
acb_clear(ff);
|
|
|
|
acb_clear(GG);
|
|
|
|
acb_clear(TT);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
acb_mat_approx_hessenberg_reduce_1(acb_mat_t A, acb_srcptr T, slong prec)
|
|
|
|
{
|
|
|
|
slong i, j, k, n;
|
|
|
|
acb_t G, t;
|
|
|
|
|
|
|
|
n = acb_mat_nrows(A);
|
|
|
|
|
|
|
|
if (n <= 1)
|
|
|
|
{
|
|
|
|
if (n == 1)
|
|
|
|
acb_one(acb_mat_entry(A, 0, 0));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
acb_one(acb_mat_entry(A, 0, 0));
|
|
|
|
acb_one(acb_mat_entry(A, 1, 1));
|
|
|
|
acb_zero(acb_mat_entry(A, 0, 1));
|
|
|
|
acb_zero(acb_mat_entry(A, 1, 0));
|
|
|
|
|
|
|
|
acb_init(G);
|
|
|
|
acb_init(t);
|
|
|
|
|
|
|
|
for (i = 2; i < n; i++)
|
|
|
|
{
|
|
|
|
if (!acb_is_zero(T + i))
|
|
|
|
{
|
|
|
|
/* todo: rewrite using approx_dot */
|
|
|
|
for (j = 0; j < i; j++)
|
|
|
|
{
|
|
|
|
acb_approx_mul(G, T + i, acb_mat_entry(A, i - 1, j), prec);
|
|
|
|
for (k = 0; k < i - 1; k++)
|
|
|
|
{
|
|
|
|
acb_approx_mul(t, acb_mat_entry(A, i, k), acb_mat_entry(A, k, j), prec);
|
|
|
|
acb_approx_add(G, G, t, prec);
|
|
|
|
}
|
|
|
|
|
|
|
|
acb_conj(t, T + i);
|
|
|
|
acb_approx_mul(t, G, t, prec);
|
|
|
|
acb_approx_sub(acb_mat_entry(A, i - 1, j), acb_mat_entry(A, i - 1, j), t, prec);
|
|
|
|
for (k = 0; k < i - 1; k++)
|
|
|
|
{
|
|
|
|
acb_conj(t, acb_mat_entry(A, i, k));
|
|
|
|
acb_approx_mul(t, G, t, prec);
|
|
|
|
acb_approx_sub(acb_mat_entry(A, k, j), acb_mat_entry(A, k, j), t, prec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
acb_one(acb_mat_entry(A, i, i));
|
|
|
|
for (j = 0; j < i; j++)
|
|
|
|
{
|
|
|
|
acb_zero(acb_mat_entry(A, j, i));
|
|
|
|
acb_zero(acb_mat_entry(A, i, j));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
acb_clear(G);
|
|
|
|
acb_clear(t);
|
|
|
|
}
|
|
|
|
|
2018-11-24 19:27:42 +01:00
|
|
|
/* Right eigenvectors of a triu matrix. No aliasing. */
|
|
|
|
void
|
|
|
|
acb_mat_approx_eig_triu_r(acb_mat_t ER, const acb_mat_t A, slong prec)
|
|
|
|
{
|
|
|
|
slong i, j, k, n;
|
|
|
|
mag_t tm, smin, unfl, simin, smlnum, rmax;
|
|
|
|
acb_t r, s, t;
|
|
|
|
|
|
|
|
n = acb_mat_nrows(A);
|
|
|
|
|
|
|
|
acb_mat_one(ER);
|
|
|
|
|
|
|
|
acb_init(r);
|
|
|
|
acb_init(s);
|
|
|
|
acb_init(t);
|
|
|
|
mag_init(tm);
|
|
|
|
mag_init(smin);
|
|
|
|
mag_init(smlnum);
|
|
|
|
mag_init(unfl);
|
|
|
|
mag_init(simin);
|
|
|
|
mag_init(rmax);
|
|
|
|
|
|
|
|
mag_set_ui_2exp_si(unfl, 1, -30 * prec);
|
|
|
|
mag_mul_ui(smlnum, unfl, n);
|
|
|
|
mag_mul_2exp_si(smlnum, smlnum, prec);
|
|
|
|
mag_set_ui_2exp_si(simin, 1, prec / 2);
|
|
|
|
mag_one(rmax);
|
|
|
|
|
|
|
|
for (i = 1; i < n; i++)
|
|
|
|
{
|
|
|
|
acb_set(s, acb_mat_entry(A, i, i));
|
|
|
|
|
|
|
|
/* smin = max(eps * abs(s), smlnum) */
|
|
|
|
acb_approx_mag(smin, s);
|
|
|
|
mag_mul_2exp_si(smin, smin, -prec);
|
|
|
|
mag_max(smin, smin, smlnum);
|
|
|
|
|
|
|
|
for (j = i - 1; j >= 0; j--)
|
|
|
|
{
|
|
|
|
acb_approx_dot(r, NULL, 0, A->rows[j] + j + 1, 1, ER->rows[i] + j + 1, 1, i - j, prec);
|
|
|
|
acb_approx_sub(t, acb_mat_entry(A, j, j), s, prec);
|
|
|
|
|
|
|
|
/* if abs(t) < smin: t = smin */
|
|
|
|
acb_approx_mag(tm, t);
|
|
|
|
if (mag_cmp(tm, smin) < 0)
|
|
|
|
{
|
|
|
|
acb_zero(t);
|
|
|
|
arf_set_mag(arb_midref(acb_realref(t)), smin);
|
|
|
|
}
|
|
|
|
|
|
|
|
acb_approx_div(acb_mat_entry(ER, i, j), r, t, prec);
|
|
|
|
acb_neg(acb_mat_entry(ER, i, j), acb_mat_entry(ER, i, j));
|
|
|
|
|
|
|
|
acb_approx_mag(tm, r);
|
|
|
|
mag_max(rmax, rmax, tm);
|
|
|
|
if (mag_cmp(rmax, simin) > 0)
|
|
|
|
{
|
|
|
|
arb_t b;
|
|
|
|
arb_init(b);
|
|
|
|
arf_set_mag(arb_midref(b), rmax);
|
|
|
|
|
|
|
|
for (k = j; k < i + 1; k++)
|
|
|
|
{
|
|
|
|
acb_approx_div_arb(acb_mat_entry(ER, i, k),
|
|
|
|
acb_mat_entry(ER, i, k), b, prec);
|
|
|
|
}
|
|
|
|
|
|
|
|
mag_one(rmax);
|
2018-11-24 19:49:53 +01:00
|
|
|
arb_clear(b);
|
2018-11-24 19:27:42 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mag_cmp_2exp_si(rmax, 0) != 0)
|
|
|
|
{
|
|
|
|
arb_t b;
|
|
|
|
arb_init(b);
|
|
|
|
arf_set_mag(arb_midref(b), rmax);
|
|
|
|
|
|
|
|
for (k = 0; k < i + 1; k++)
|
|
|
|
{
|
|
|
|
acb_approx_div_arb(acb_mat_entry(ER, i, k),
|
|
|
|
acb_mat_entry(ER, i, k), b, prec);
|
|
|
|
}
|
|
|
|
|
|
|
|
arb_clear(b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
acb_mat_transpose(ER, ER);
|
|
|
|
|
|
|
|
acb_clear(r);
|
|
|
|
acb_clear(s);
|
|
|
|
acb_clear(t);
|
|
|
|
mag_clear(tm);
|
|
|
|
mag_clear(smin);
|
|
|
|
mag_clear(smlnum);
|
|
|
|
mag_clear(unfl);
|
|
|
|
mag_clear(simin);
|
|
|
|
mag_clear(rmax);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Left eigenvectors of a triu matrix. No aliasing. */
|
|
|
|
void
|
|
|
|
acb_mat_approx_eig_triu_l(acb_mat_t EL, const acb_mat_t A, slong prec)
|
|
|
|
{
|
|
|
|
slong i, j, k, n;
|
|
|
|
mag_t tm, smin, unfl, simin, smlnum, rmax;
|
|
|
|
acb_t r, s, t;
|
|
|
|
acb_mat_t AT;
|
|
|
|
|
|
|
|
n = acb_mat_nrows(A);
|
|
|
|
acb_mat_init(AT, n, n);
|
|
|
|
|
|
|
|
acb_mat_one(EL);
|
|
|
|
acb_mat_transpose(AT, A);
|
|
|
|
|
|
|
|
acb_init(r);
|
|
|
|
acb_init(s);
|
|
|
|
acb_init(t);
|
|
|
|
mag_init(tm);
|
|
|
|
mag_init(smin);
|
|
|
|
mag_init(smlnum);
|
|
|
|
mag_init(unfl);
|
|
|
|
mag_init(simin);
|
|
|
|
mag_init(rmax);
|
|
|
|
|
|
|
|
mag_set_ui_2exp_si(unfl, 1, -30 * prec);
|
|
|
|
mag_mul_ui(smlnum, unfl, n);
|
|
|
|
mag_mul_2exp_si(smlnum, smlnum, prec);
|
|
|
|
mag_set_ui_2exp_si(simin, 1, prec / 2);
|
|
|
|
mag_one(rmax);
|
|
|
|
|
|
|
|
for (i = 0; i < n - 1; i++)
|
|
|
|
{
|
|
|
|
acb_set(s, acb_mat_entry(AT, i, i));
|
|
|
|
|
|
|
|
/* smin = max(eps * abs(s), smlnum) */
|
|
|
|
acb_approx_mag(smin, s);
|
|
|
|
mag_mul_2exp_si(smin, smin, -prec);
|
|
|
|
mag_max(smin, smin, smlnum);
|
|
|
|
|
|
|
|
for (j = i + 1; j < n; j++)
|
|
|
|
{
|
|
|
|
acb_approx_dot(r, NULL, 0, EL->rows[i] + i, 1, AT->rows[j] + i, 1, j - i, prec);
|
|
|
|
acb_approx_sub(t, acb_mat_entry(AT, j, j), s, prec);
|
|
|
|
|
|
|
|
/* if abs(t) < smin: t = smin */
|
|
|
|
acb_approx_mag(tm, t);
|
|
|
|
if (mag_cmp(tm, smin) < 0)
|
|
|
|
{
|
|
|
|
acb_zero(t);
|
|
|
|
arf_set_mag(arb_midref(acb_realref(t)), smin);
|
|
|
|
}
|
|
|
|
|
|
|
|
acb_approx_div(acb_mat_entry(EL, i, j), r, t, prec);
|
|
|
|
acb_neg(acb_mat_entry(EL, i, j), acb_mat_entry(EL, i, j));
|
|
|
|
|
|
|
|
acb_approx_mag(tm, r);
|
|
|
|
mag_max(rmax, rmax, tm);
|
|
|
|
if (mag_cmp(rmax, simin) > 0)
|
|
|
|
{
|
|
|
|
arb_t b;
|
|
|
|
arb_init(b);
|
|
|
|
arf_set_mag(arb_midref(b), rmax);
|
|
|
|
|
|
|
|
for (k = i; k < j + 1; k++)
|
|
|
|
{
|
|
|
|
acb_approx_div_arb(acb_mat_entry(EL, i, k),
|
|
|
|
acb_mat_entry(EL, i, k), b, prec);
|
|
|
|
}
|
|
|
|
|
|
|
|
mag_one(rmax);
|
2018-11-24 19:49:53 +01:00
|
|
|
arb_clear(b);
|
2018-11-24 19:27:42 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mag_cmp_2exp_si(rmax, 0) != 0)
|
|
|
|
{
|
|
|
|
arb_t b;
|
|
|
|
arb_init(b);
|
|
|
|
arf_set_mag(arb_midref(b), rmax);
|
|
|
|
|
|
|
|
for (k = i; k < n; k++)
|
|
|
|
{
|
|
|
|
acb_approx_div_arb(acb_mat_entry(EL, i, k),
|
|
|
|
acb_mat_entry(EL, i, k), b, prec);
|
|
|
|
}
|
|
|
|
|
|
|
|
arb_clear(b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
acb_clear(r);
|
|
|
|
acb_clear(s);
|
|
|
|
acb_clear(t);
|
|
|
|
mag_clear(tm);
|
|
|
|
mag_clear(smin);
|
|
|
|
mag_clear(smlnum);
|
|
|
|
mag_clear(unfl);
|
|
|
|
mag_clear(simin);
|
|
|
|
mag_clear(rmax);
|
|
|
|
}
|
|
|
|
|
2018-11-20 21:31:40 +01:00
|
|
|
int
|
|
|
|
acb_mat_approx_hessenberg_qr(acb_mat_t A, acb_mat_t Q, const mag_t tol, slong maxiter, slong prec)
|
|
|
|
{
|
|
|
|
slong n, i, j, k, n0, n1, iter, total_iter;
|
|
|
|
mag_t norm, tm, um, eps, ts;
|
|
|
|
acb_t shift, s, t, a, b;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
n = acb_mat_nrows(A);
|
|
|
|
|
|
|
|
if (n <= 1)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
mag_init(norm);
|
|
|
|
mag_init(tm);
|
|
|
|
mag_init(um);
|
|
|
|
mag_init(eps);
|
|
|
|
mag_init(ts);
|
|
|
|
acb_init(shift);
|
|
|
|
acb_init(s);
|
|
|
|
acb_init(t);
|
|
|
|
acb_init(a);
|
|
|
|
acb_init(b);
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
for (j = 0; j < FLINT_MIN(i + 2, n); j++)
|
|
|
|
{
|
|
|
|
arf_get_mag(tm, arb_midref(acb_realref(acb_mat_entry(A, j, i))));
|
|
|
|
arf_get_mag(um, arb_midref(acb_imagref(acb_mat_entry(A, j, i))));
|
|
|
|
mag_addmul(norm, tm, tm);
|
|
|
|
mag_addmul(norm, um, um);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mag_sqrt(norm, norm);
|
|
|
|
mag_div_ui(norm, norm, n);
|
|
|
|
|
|
|
|
if (mag_is_zero(norm))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (mag_is_inf(norm))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (tol == NULL)
|
|
|
|
{
|
|
|
|
mag_one(eps);
|
|
|
|
mag_mul_2exp_si(eps, eps, -prec);
|
|
|
|
mag_div_ui(eps, eps, 100 * n);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mag_set(eps, tol);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (maxiter <= 0)
|
2018-12-06 16:32:56 +01:00
|
|
|
{
|
2018-11-20 21:31:40 +01:00
|
|
|
maxiter = 14 * n;
|
2018-12-06 16:32:56 +01:00
|
|
|
maxiter += prec / 10;
|
|
|
|
}
|
2018-11-20 21:31:40 +01:00
|
|
|
|
|
|
|
/* The active submatrix is A[n0:n1,n0:n1]. */
|
|
|
|
n0 = 0;
|
|
|
|
n1 = n;
|
|
|
|
|
|
|
|
iter = total_iter = 0;
|
|
|
|
result = 0;
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
k = n0;
|
|
|
|
|
|
|
|
/* flint_printf("total_iter %wd active %wd\n", total_iter, n1 - n0); */
|
|
|
|
|
|
|
|
while (k + 1 < n1)
|
|
|
|
{
|
|
|
|
mag_zero(ts);
|
|
|
|
arf_get_mag(tm, arb_midref(acb_realref(acb_mat_entry(A, k, k))));
|
|
|
|
mag_add(ts, ts, tm);
|
|
|
|
arf_get_mag(tm, arb_midref(acb_imagref(acb_mat_entry(A, k, k))));
|
|
|
|
mag_add(ts, ts, tm);
|
|
|
|
arf_get_mag(tm, arb_midref(acb_realref(acb_mat_entry(A, k + 1, k + 1))));
|
|
|
|
mag_add(ts, ts, tm);
|
|
|
|
arf_get_mag(tm, arb_midref(acb_imagref(acb_mat_entry(A, k + 1, k + 1))));
|
|
|
|
mag_add(ts, ts, tm);
|
|
|
|
|
|
|
|
/* if s < eps * norm, s = norm */
|
|
|
|
mag_mul(tm, eps, norm);
|
|
|
|
if (mag_cmp(ts, tm) < 0)
|
|
|
|
mag_set(ts, norm);
|
|
|
|
|
|
|
|
/* if abs(A[k+1,k]) < eps * s, break */
|
|
|
|
arf_get_mag(tm, arb_midref(acb_realref(acb_mat_entry(A, k + 1, k))));
|
|
|
|
arf_get_mag(um, arb_midref(acb_imagref(acb_mat_entry(A, k + 1, k))));
|
|
|
|
mag_hypot(tm, tm, um);
|
|
|
|
mag_mul(um, eps, ts);
|
|
|
|
if (mag_cmp(tm, um) < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
k++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Deflation found at position (k+1, k). */
|
|
|
|
if (k + 1 < n1)
|
|
|
|
{
|
|
|
|
acb_zero(acb_mat_entry(A, k + 1, k));
|
|
|
|
n0 = k + 1;
|
|
|
|
iter = 0;
|
|
|
|
|
|
|
|
if (n0 + 1 >= n1)
|
|
|
|
{
|
|
|
|
/* Block of size at most two has converged. */
|
|
|
|
n0 = 0;
|
|
|
|
n1 = k + 1;
|
|
|
|
if (n1 < 2)
|
|
|
|
{
|
|
|
|
/* QR algorithm has converged. */
|
|
|
|
result = 1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (iter % 30 == 10)
|
|
|
|
{
|
|
|
|
/* Exceptional shift */
|
|
|
|
acb_set(shift, acb_mat_entry(A, n1 - 1, n1 - 2));
|
|
|
|
}
|
|
|
|
else if (iter % 30 == 20)
|
|
|
|
{
|
|
|
|
/* Exceptional shift */
|
|
|
|
acb_abs(acb_realref(shift), acb_mat_entry(A, n1 - 1, n1 - 2), prec);
|
|
|
|
arb_zero(acb_imagref(shift));
|
|
|
|
}
|
|
|
|
else if (iter % 30 == 29)
|
|
|
|
{
|
|
|
|
/* Exceptional shift */
|
|
|
|
acb_zero(shift);
|
|
|
|
arf_set_mag(arb_midref(acb_realref(shift)), norm);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
acb_approx_add(t, acb_mat_entry(A, n1 - 2, n1 - 2), acb_mat_entry(A, n1 - 1, n1 - 1), prec);
|
|
|
|
acb_approx_sub(a, acb_mat_entry(A, n1 - 1, n1 - 1), acb_mat_entry(A, n1 - 2, n1 - 2), prec);
|
|
|
|
acb_approx_mul(a, a, a, prec);
|
|
|
|
acb_approx_mul(b, acb_mat_entry(A, n1 - 1, n1 - 2), acb_mat_entry(A, n1 - 2, n1 - 1), prec);
|
|
|
|
acb_mul_2exp_si(b, b, 2);
|
|
|
|
acb_approx_add(s, a, b, prec);
|
|
|
|
|
|
|
|
if (arb_is_positive(acb_realref(s)))
|
|
|
|
{
|
|
|
|
acb_sqrt(s, s, prec);
|
|
|
|
acb_get_mid(s, s);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
acb_neg(s, s);
|
|
|
|
acb_sqrt(s, s, prec);
|
|
|
|
acb_get_mid(s, s);
|
|
|
|
acb_mul_onei(s, s);
|
|
|
|
}
|
|
|
|
|
|
|
|
acb_approx_add(a, t, s, prec);
|
|
|
|
acb_approx_sub(b, t, s, prec);
|
|
|
|
acb_mul_2exp_si(a, a, -1);
|
|
|
|
acb_mul_2exp_si(b, b, -1);
|
|
|
|
|
|
|
|
acb_approx_sub(s, acb_mat_entry(A, n1 - 1, n1 - 1), a, prec);
|
|
|
|
acb_approx_sub(t, acb_mat_entry(A, n1 - 1, n1 - 1), b, prec);
|
|
|
|
acb_get_mag(tm, s);
|
|
|
|
acb_get_mag(um, t);
|
|
|
|
|
|
|
|
if (mag_cmp(tm, um) > 0)
|
|
|
|
acb_set(shift, b);
|
|
|
|
else
|
|
|
|
acb_set(shift, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
mag_zero(arb_radref(acb_realref(shift)));
|
|
|
|
mag_zero(arb_radref(acb_imagref(shift)));
|
|
|
|
|
|
|
|
iter++;
|
|
|
|
total_iter++;
|
|
|
|
|
|
|
|
acb_mat_approx_qr_step(A, Q, n0, n1, shift, prec);
|
|
|
|
|
|
|
|
if (iter > maxiter)
|
|
|
|
{
|
|
|
|
result = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
mag_clear(norm);
|
|
|
|
mag_clear(tm);
|
|
|
|
mag_clear(um);
|
|
|
|
mag_clear(ts);
|
|
|
|
mag_clear(eps);
|
|
|
|
acb_clear(shift);
|
|
|
|
acb_clear(s);
|
|
|
|
acb_clear(t);
|
|
|
|
acb_clear(a);
|
|
|
|
acb_clear(b);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
acb_mat_approx_eig_qr(acb_ptr E, acb_mat_t L, acb_mat_t R, const acb_mat_t A, const mag_t tol, slong maxiter, slong prec)
|
|
|
|
{
|
|
|
|
slong n, i, j;
|
|
|
|
acb_ptr T;
|
2018-11-24 19:27:42 +01:00
|
|
|
acb_mat_t Acopy, Q;
|
2018-11-20 21:31:40 +01:00
|
|
|
int result;
|
|
|
|
|
|
|
|
n = acb_mat_nrows(A);
|
|
|
|
|
|
|
|
T = _acb_vec_init(n);
|
|
|
|
acb_mat_init(Acopy, n, n);
|
|
|
|
acb_mat_get_mid(Acopy, A);
|
|
|
|
|
|
|
|
acb_mat_approx_hessenberg_reduce_0(Acopy, T, prec);
|
|
|
|
|
2018-11-24 19:27:42 +01:00
|
|
|
if (L != NULL || R != NULL)
|
|
|
|
{
|
|
|
|
acb_mat_init(Q, n, n);
|
|
|
|
acb_mat_set(Q, Acopy);
|
|
|
|
acb_mat_approx_hessenberg_reduce_1(Q, T, prec);
|
|
|
|
}
|
|
|
|
|
2018-11-20 21:31:40 +01:00
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
for (j = i + 2; j < n; j++)
|
|
|
|
acb_zero(acb_mat_entry(Acopy, j, i));
|
|
|
|
|
2018-11-24 19:27:42 +01:00
|
|
|
result = acb_mat_approx_hessenberg_qr(Acopy,
|
|
|
|
(L != NULL || R != NULL) ? Q : NULL, tol, maxiter, prec);
|
2018-11-20 21:31:40 +01:00
|
|
|
|
|
|
|
for (i = 0; i < n; i++)
|
2018-11-28 17:21:23 +01:00
|
|
|
acb_get_mid(E + i, acb_mat_entry(Acopy, i, i));
|
2018-11-20 21:31:40 +01:00
|
|
|
|
2018-11-24 19:27:42 +01:00
|
|
|
if (R != NULL)
|
|
|
|
{
|
|
|
|
acb_mat_t ER;
|
|
|
|
acb_mat_init(ER, n, n);
|
|
|
|
acb_mat_approx_eig_triu_r(ER, Acopy, prec);
|
|
|
|
acb_mat_approx_mul(R, Q, ER, prec);
|
2018-11-28 17:21:23 +01:00
|
|
|
acb_mat_get_mid(R, R); /* zero radii */
|
2018-11-24 19:27:42 +01:00
|
|
|
acb_mat_clear(ER);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (L != NULL)
|
|
|
|
{
|
|
|
|
acb_mat_t EL;
|
|
|
|
acb_mat_init(EL, n, n);
|
|
|
|
acb_mat_approx_eig_triu_l(EL, Acopy, prec);
|
|
|
|
acb_mat_conjugate_transpose(Q, Q);
|
|
|
|
acb_mat_approx_mul(L, EL, Q, prec);
|
2018-11-28 17:21:23 +01:00
|
|
|
acb_mat_get_mid(L, L); /* zero radii */
|
2018-11-24 19:27:42 +01:00
|
|
|
acb_mat_clear(EL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (L != NULL || R != NULL)
|
|
|
|
acb_mat_clear(Q);
|
|
|
|
|
2018-11-20 21:31:40 +01:00
|
|
|
_acb_vec_clear(T, n);
|
|
|
|
acb_mat_clear(Acopy);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|