Example #1
0
File: pow_ui.c Project: isuruf/arb
void
arb_mat_pow_ui(arb_mat_t B, const arb_mat_t A, ulong exp, slong prec)
{
    slong d = arb_mat_nrows(A);

    if (exp <= 2 || d <= 1)
    {
        if (exp == 0 || d == 0)
        {
            arb_mat_one(B);
        }
        else if (d == 1)
        {
            arb_pow_ui(arb_mat_entry(B, 0, 0),
                 arb_mat_entry(A, 0, 0), exp, prec);
        }
        else if (exp == 1)
        {
            arb_mat_set(B, A);
        }
        else if (exp == 2)
        {
            arb_mat_sqr(B, A, prec);
        }
    }
    else
    {
        arb_mat_t T, U;
        slong i;

        arb_mat_init(T, d, d);
        arb_mat_set(T, A);
        arb_mat_init(U, d, d);

        for (i = ((slong) FLINT_BIT_COUNT(exp)) - 2; i >= 0; i--)
        {
            arb_mat_sqr(U, T, prec);

            if (exp & (WORD(1) << i))
                arb_mat_mul(T, U, A, prec);
            else
                arb_mat_swap(T, U);
        }

        arb_mat_swap(B, T);
        arb_mat_clear(T);
        arb_mat_clear(U);
    }
}
Example #2
0
File: inv.c Project: isuruf/arb
int
arb_mat_inv(arb_mat_t X, const arb_mat_t A, slong prec)
{
    if (X == A)
    {
        int r;
        arb_mat_t T;
        arb_mat_init(T, arb_mat_nrows(A), arb_mat_ncols(A));
        r = arb_mat_inv(T, A, prec);
        arb_mat_swap(T, X);
        arb_mat_clear(T);
        return r;
    }

    arb_mat_one(X);
    return arb_mat_solve(X, A, X, prec);
}
Example #3
0
int main()
{
    slong iter;
    flint_rand_t state;

    flint_printf("ldl....");
    fflush(stdout);

    flint_randinit(state);

    /* check special matrices */
    {
        slong n;
        for (n = 1; n < 10; n++)
        {
            slong lprec;
            arb_mat_t L, A;
            arb_mat_init(L, n, n);
            arb_mat_init(A, n, n);
            for (lprec = 2; lprec < 10; lprec++)
            {
                int result;
                slong prec;
                prec = 1 << lprec;

                /* zero */
                arb_mat_zero(A);
                result = arb_mat_ldl(L, A, prec);
                if (result)
                {
                    flint_printf("FAIL (zero):\n");
                    flint_printf("n = %wd, prec = %wd\n", n, prec);
                    flint_printf("L = \n"); arb_mat_printd(L, 15);
                    flint_printf("\n\n");
                }

                /* negative identity */
                arb_mat_one(A);
                arb_mat_neg(A, A);
                result = arb_mat_ldl(L, A, prec);
                if (result)
                {
                    flint_printf("FAIL (negative identity):\n");
                    flint_printf("n = %wd, prec = %wd\n", n, prec);
                    flint_printf("L = \n"); arb_mat_printd(L, 15);
                    flint_printf("\n\n");
                }

                /* identity */
                arb_mat_one(A);
                result = arb_mat_ldl(L, A, prec);
                if (!result || !arb_mat_equal(L, A))
                {
                    flint_printf("FAIL (identity):\n");
                    flint_printf("n = %wd, prec = %wd\n", n, prec);
                    flint_printf("L = \n"); arb_mat_printd(L, 15);
                    flint_printf("\n\n");
                }
            }
            arb_mat_clear(L);
            arb_mat_clear(A);
        }
    }

    for (iter = 0; iter < 10000 * arb_test_multiplier(); iter++)
    {
        fmpq_mat_t Q;
        arb_mat_t A, L, D, U, T;
        slong n, qbits, prec;
        int q_invertible, r_invertible;

        n = n_randint(state, 8);
        qbits = 1 + n_randint(state, 100);
        prec = 2 + n_randint(state, 202);

        fmpq_mat_init(Q, n, n);
        arb_mat_init(A, n, n);
        arb_mat_init(L, n, n);
        arb_mat_init(D, n, n);
        arb_mat_init(U, n, n);
        arb_mat_init(T, n, n);

        _fmpq_mat_randtest_positive_semidefinite(Q, state, qbits);
        q_invertible = fmpq_mat_is_invertible(Q);

        if (!q_invertible)
        {
            arb_mat_set_fmpq_mat(A, Q, prec);
            r_invertible = arb_mat_ldl(L, A, prec);
            if (r_invertible)
            {
                flint_printf("FAIL: matrix is singular over Q but not over R\n");
                flint_printf("n = %wd, prec = %wd\n", n, prec);
                flint_printf("\n");

                flint_printf("Q = \n"); fmpq_mat_print(Q); flint_printf("\n\n");
                flint_printf("A = \n"); arb_mat_printd(A, 15); flint_printf("\n\n");
                flint_printf("L = \n"); arb_mat_printd(L, 15); flint_printf("\n\n");
            }
        }
        else
        {
            /* now this must converge */
            while (1)
            {
                arb_mat_set_fmpq_mat(A, Q, prec);
                r_invertible = arb_mat_ldl(L, A, prec);
                if (r_invertible)
                {
                    break;
                }
                else
                {
                    if (prec > 10000)
                    {
                        flint_printf("FAIL: failed to converge at 10000 bits\n");
                        flint_printf("n = %wd, prec = %wd\n", n, prec);
                        flint_printf("Q = \n"); fmpq_mat_print(Q); flint_printf("\n\n");
                        flint_printf("A = \n"); arb_mat_printd(A, 15); flint_printf("\n\n");
                        abort();
                    }
                    prec *= 2;
                }
            }

            /* multiply out the decomposition */
            {
                slong i;
                arb_mat_zero(D);
                arb_mat_transpose(U, L);
                for (i = 0; i < n; i++)
                {
                    arb_set(arb_mat_entry(D, i, i), arb_mat_entry(L, i, i));
                    arb_one(arb_mat_entry(L, i, i));
                    arb_one(arb_mat_entry(U, i, i));
                }
                arb_mat_mul(T, L, D, prec);
                arb_mat_mul(T, T, U, prec);
            }

            if (!arb_mat_contains_fmpq_mat(T, Q))
            {
                flint_printf("FAIL (containment, iter = %wd)\n", iter);
                flint_printf("n = %wd, prec = %wd\n", n, prec);
                flint_printf("\n");

                flint_printf("Q = \n"); fmpq_mat_print(Q); flint_printf("\n\n");
                flint_printf("A = \n"); arb_mat_printd(A, 15); flint_printf("\n\n");
                flint_printf("L = \n"); arb_mat_printd(L, 15); flint_printf("\n\n");
                flint_printf("U = \n"); arb_mat_printd(U, 15); flint_printf("\n\n");
                flint_printf("L*U = \n"); arb_mat_printd(T, 15); flint_printf("\n\n");

                abort();
            }
        }

        fmpq_mat_clear(Q);
        arb_mat_clear(A);
        arb_mat_clear(L);
        arb_mat_clear(D);
        arb_mat_clear(U);
        arb_mat_clear(T);
    }

    flint_randclear(state);
    flint_cleanup();
    flint_printf("PASS\n");
    return EXIT_SUCCESS;
}
Example #4
0
int arb_mat_jacobi(arb_mat_t D, arb_mat_t P, const arb_mat_t A, slong prec) {
    //
    // Given a d x d real symmetric matrix A, compute an orthogonal matrix
    // P and a diagonal D such that A = P D P^t = P D P^(-1).
    //
    // D should have already been initialized as a d x 1 matrix, and Pp
    // should have already been initialized as a d x d matrix.
    //
    // If the eigenvalues can be certified as unique, then a nonzero int is
    // returned, and the eigenvectors should have reasonable error bounds. If
    // the eigenvalues cannot be certified as unique, then some of the
    // eigenvectors will have infinite error radius.

#define B(i,j) arb_mat_entry(B, i, j)
#define D(i) arb_mat_entry(D, i, 0)
#define P(i,j) arb_mat_entry(P, i, j)
    int dim = arb_mat_nrows(A);
    if(dim == 1) {
        arb_mat_set(D, A);
        arb_mat_one(P);
        return 0;
    }
    arb_mat_t B;
    arb_mat_init(B, dim, dim);

    arf_t * B1 = (arf_t*)malloc(dim * sizeof(arf_t));
    arf_t * B2 = (arf_t*)malloc(dim * sizeof(arf_t));
    arf_t * row_max = (arf_t*)malloc((dim - 1) * sizeof(arf_t));
    int * row_max_indices = (int*)malloc((dim - 1) * sizeof(int));

    for(int k = 0; k < dim; k++) {
        arf_init(B1[k]);
        arf_init(B2[k]);
    }
    for(int k = 0; k < dim - 1; k++) {
        arf_init(row_max[k]);
    }

    arf_t x1, x2;
    arf_init(x1);
    arf_init(x2);

    arf_t Gii, Gij, Gji, Gjj;
    arf_init(Gii);
    arf_init(Gij);
    arf_init(Gji);
    arf_init(Gjj);

    arb_mat_set(B, A);
    arb_mat_one(P);

    for(int i = 0; i < dim - 1; i++) {
        for(int j = i + 1; j < dim; j++) {
            arf_abs(x1, arb_midref(B(i,j)));
            if(arf_cmp(row_max[i], x1) < 0) {
                arf_set(row_max[i], x1);
                row_max_indices[i] = j;
            }
        }
    }


    int finished = 0;

    while(!finished) {
        arf_zero(x1);
        int i = 0;
        int j = 0;
        for(int k = 0; k < dim - 1; k++) {
            if(arf_cmp(x1, row_max[k]) < 0) {
                arf_set(x1, row_max[k]);
                i = k;
            }
        }
        j = row_max_indices[i];

        slong bound = arf_abs_bound_lt_2exp_si(x1);
        if(bound < -prec * .9) {
            finished = 1;
            break;
        }
        else {
            //printf("%ld\n", arf_abs_bound_lt_2exp_si(x1));
            //arb_mat_printd(B, 10);
            //printf("\n");
        }

        arf_twobytwo_diag(Gii, Gij, arb_midref(B(i,i)), arb_midref(B(i,j)), arb_midref(B(j,j)), 2*prec);
        arf_neg(Gji, Gij);
        arf_set(Gjj, Gii);

        //printf("%d %d\n", i, j);
        //arf_printd(Gii, 100);
        //printf(" ");
        //arf_printd(Gij, 100);
        //printf("\n");
        if(arf_is_zero(Gij)) {  // If this happens, we're
            finished = 1;       // not going to do any better
            break;              // without increasing the precision.
        }

        for(int k = 0; k < dim; k++) {
            arf_mul(B1[k], Gii, arb_midref(B(i,k)), prec, ARF_RND_NEAR);
            arf_addmul(B1[k], Gji, arb_midref(B(j,k)), prec, ARF_RND_NEAR);

            arf_mul(B2[k], Gij, arb_midref(B(i,k)), prec, ARF_RND_NEAR);
            arf_addmul(B2[k], Gjj, arb_midref(B(j,k)), prec, ARF_RND_NEAR);
        }
        for(int k = 0; k < dim; k++) {
            arf_set(arb_midref(B(i,k)), B1[k]);
            arf_set(arb_midref(B(j,k)), B2[k]);
        }
        for(int k = 0; k < dim; k++) {
            arf_mul(B1[k], Gii, arb_midref(B(k,i)), prec, ARF_RND_NEAR);
            arf_addmul(B1[k], Gji, arb_midref(B(k,j)), prec, ARF_RND_NEAR);

            arf_mul(B2[k], Gij, arb_midref(B(k,i)), prec, ARF_RND_NEAR);
            arf_addmul(B2[k], Gjj, arb_midref(B(k,j)), prec, ARF_RND_NEAR);
        }
        for(int k = 0; k < dim; k++) {
            arf_set(arb_midref(B(k,i)), B1[k]);
            arf_set(arb_midref(B(k,j)), B2[k]);
        }

        for(int k = 0; k < dim; k++) {
            arf_mul(B1[k], Gii, arb_midref(P(k,i)), prec, ARF_RND_NEAR);
            arf_addmul(B1[k], Gji, arb_midref(P(k,j)), prec, ARF_RND_NEAR);

            arf_mul(B2[k], Gij, arb_midref(P(k,i)), prec, ARF_RND_NEAR);
            arf_addmul(B2[k], Gjj, arb_midref(P(k,j)), prec, ARF_RND_NEAR);
        }
        for(int k = 0; k < dim; k++) {
            arf_set(arb_midref(P(k,i)), B1[k]);
            arf_set(arb_midref(P(k,j)), B2[k]);
        }

        if(i < dim - 1)
            arf_set_ui(row_max[i], 0);
        if(j < dim - 1)
            arf_set_ui(row_max[j], 0);

        // Update the max in any row where the maximum
        // was in a column that changed.
        for(int k = 0; k < dim - 1; k++) {
            if(row_max_indices[k] == j || row_max_indices[k] == i) {
                arf_abs(row_max[k], arb_midref(B(k,k+1)));
                row_max_indices[k] = k+1;
                for(int l = k+2; l < dim; l++) {
                    arf_abs(x1, arb_midref(B(k,l)));
                    if(arf_cmp(row_max[k], x1) < 0) {
                        arf_set(row_max[k], x1);
                        row_max_indices[k] = l;
                    }
                }
            }
        }

        // Update the max in the ith row.
        for(int k = i + 1; k < dim; k++) {
            arf_abs(x1, arb_midref(B(i, k)));
            if(arf_cmp(row_max[i], x1) < 0) {
                arf_set(row_max[i], x1);
                row_max_indices[i] = k;
            }
        }

        // Update the max in the jth row.
        for(int k = j + 1; k < dim; k++) {
            arf_abs(x1, arb_midref(B(j, k)));
            if(arf_cmp(row_max[j], x1) < 0) {
                arf_set(row_max[j], x1);
                row_max_indices[j] = k;
            }
        }

        // Go through column i to see if any of
        // the new entries are larger than the
        // max of their row.
        for(int k = 0; k < i; k++) {
            if(k == dim) continue;
            arf_abs(x1, arb_midref(B(k, i)));
            if(arf_cmp(row_max[k], x1) < 0) {
                arf_set(row_max[k], x1);
                row_max_indices[k] = i;
            }
        }

        // And then column j.
        for(int k = 0; k < j; k++) {
            if(k == dim) continue;
            arf_abs(x1, arb_midref(B(k, j)));
            if(arf_cmp(row_max[k], x1) < 0) {
                arf_set(row_max[k], x1);
                row_max_indices[k] = j;
            }
        }
    }

    for(int k = 0; k < dim; k++) {
        arb_set(D(k), B(k,k));
        arb_set_exact(D(k));
    }

    // At this point we've done that diagonalization and all that remains is
    // to certify the correctness and compute error bounds.

    arb_mat_t e;

    arb_t error_norms[dim];
    for(int k = 0; k < dim; k++) arb_init(error_norms[k]);

    arb_mat_init(e, dim, 1);

    arb_t z1, z2;
    arb_init(z1);
    arb_init(z2);
    for(int j = 0; j < dim; j++) {
        arb_mat_set(B, A);
        for(int k = 0; k < dim; k++) {
            arb_sub(B(k, k), B(k, k), D(j), prec);
        }
        for(int k = 0; k < dim; k++) {
            arb_set(arb_mat_entry(e, k, 0), P(k, j));
        }
        arb_mat_L2norm(z2, e, prec);
        arb_mat_mul(e, B, e, prec);
        arb_mat_L2norm(error_norms[j], e, prec);

        arb_div(z2, error_norms[j], z2, prec); // and now z1 is an upper bound for the
                                               // error in the eigenvalue
        arb_add_error(D(j), z2);
    }

    int unique_eigenvalues = 1;
    for(int j = 0; j < dim; j++) {
        if(j == 0) {
            arb_sub(z1, D(j), D(1), prec);
        }
        else {
            arb_sub(z1, D(j), D(0), prec);
        }
        arb_get_abs_lbound_arf(x1, z1, prec);
        for(int k = 1; k < dim; k++) {
            if(k == j) continue;
            arb_sub(z1, D(j), D(k), prec);
            arb_get_abs_lbound_arf(x2, z1, prec);
            if(arf_cmp(x2, x1) < 0) {
                arf_set(x1, x2);
            }
        }
        if(arf_is_zero(x1)) {
            unique_eigenvalues = 0;
        }
        arb_div_arf(z1, error_norms[j], x1, prec);
        for(int k = 0; k < dim; k++) {
            arb_add_error(P(k, j), z1);
        }
    }

    arb_mat_clear(e);
    arb_clear(z1);
    arb_clear(z2);
    for(int k = 0; k < dim; k++) arb_clear(error_norms[k]);

    arf_clear(x1);
    arf_clear(x2);
    arb_mat_clear(B);
    for(int k = 0; k < dim; k++) {
        arf_clear(B1[k]);
        arf_clear(B2[k]);
    }
    for(int k = 0; k < dim - 1; k++) {
        arf_clear(row_max[k]);
    }
    arf_clear(Gii);
    arf_clear(Gij);
    arf_clear(Gji);
    arf_clear(Gjj);
    free(B1);
    free(B2);
    free(row_max);
    free(row_max_indices);

    if(unique_eigenvalues) return 0;
    else return 1;
#undef B
#undef D
#undef P
}
Example #5
0
File: exp.c Project: wbhart/arb
/* evaluates the truncated Taylor series (assumes no aliasing) */
void
_arb_mat_exp_taylor(arb_mat_t S, const arb_mat_t A, slong N, slong prec)
{
    if (N == 1)
    {
        arb_mat_one(S);
    }
    else if (N == 2)
    {
        arb_mat_one(S);
        arb_mat_add(S, S, A, prec);
    }
    else if (N == 3)
    {
        arb_mat_t T;
        arb_mat_init(T, arb_mat_nrows(A), arb_mat_nrows(A));
        arb_mat_mul(T, A, A, prec);
        arb_mat_scalar_mul_2exp_si(T, T, -1);
        arb_mat_add(S, A, T, prec);
        arb_mat_one(T);
        arb_mat_add(S, S, T, prec);
        arb_mat_clear(T);
    }
    else
    {
        slong i, lo, hi, m, w, dim;
        arb_mat_struct * pows;
        arb_mat_t T, U;
        fmpz_t c, f;

        dim = arb_mat_nrows(A);
        m = n_sqrt(N);
        w = (N + m - 1) / m;

        fmpz_init(c);
        fmpz_init(f);
        pows = flint_malloc(sizeof(arb_mat_t) * (m + 1));
        arb_mat_init(T, dim, dim);
        arb_mat_init(U, dim, dim);

        for (i = 0; i <= m; i++)
        {
            arb_mat_init(pows + i, dim, dim);
            if (i == 0)
                arb_mat_one(pows + i);
            else if (i == 1)
                arb_mat_set(pows + i, A);
            else
                arb_mat_mul(pows + i, pows + i - 1, A, prec);
        }

        arb_mat_zero(S);
        fmpz_one(f);

        for (i = w - 1; i >= 0; i--)
        {
            lo = i * m;
            hi = FLINT_MIN(N - 1, lo + m - 1);

            arb_mat_zero(T);
            fmpz_one(c);

            while (hi >= lo)
            {
                arb_mat_scalar_addmul_fmpz(T, pows + hi - lo, c, prec);
                if (hi != 0)
                    fmpz_mul_ui(c, c, hi);
                hi--;
            }

            arb_mat_mul(U, pows + m, S, prec);
            arb_mat_scalar_mul_fmpz(S, T, f, prec);
            arb_mat_add(S, S, U, prec);
            fmpz_mul(f, f, c);
        }

        arb_mat_scalar_div_fmpz(S, S, f, prec);

        fmpz_clear(c);
        fmpz_clear(f);
        for (i = 0; i <= m; i++)
            arb_mat_clear(pows + i);
        flint_free(pows);
        arb_mat_clear(T);
        arb_mat_clear(U);
    }
}
Example #6
0
File: exp.c Project: wbhart/arb
void
arb_mat_exp(arb_mat_t B, const arb_mat_t A, slong prec)
{
    slong i, j, dim, wp, N, q, r;
    mag_t norm, err;
    arb_mat_t T;

    dim = arb_mat_nrows(A);

    if (dim != arb_mat_ncols(A))
    {
        flint_printf("arb_mat_exp: a square matrix is required!\n");
        abort();
    }

    if (dim == 0)
    {
        return;
    }
    else if (dim == 1)
    {
        arb_exp(arb_mat_entry(B, 0, 0), arb_mat_entry(A, 0, 0), prec);
        return;
    }

    wp = prec + 3 * FLINT_BIT_COUNT(prec);

    mag_init(norm);
    mag_init(err);
    arb_mat_init(T, dim, dim);

    arb_mat_bound_inf_norm(norm, A);

    if (mag_is_zero(norm))
    {
        arb_mat_one(B);
    }
    else
    {
        q = pow(wp, 0.25);  /* wanted magnitude */

        if (mag_cmp_2exp_si(norm, 2 * wp) > 0) /* too big */
            r = 2 * wp;
        else if (mag_cmp_2exp_si(norm, -q) < 0) /* tiny, no need to reduce */
            r = 0;
        else
            r = FLINT_MAX(0, q + MAG_EXP(norm)); /* reduce to magnitude 2^(-r) */

        arb_mat_scalar_mul_2exp_si(T, A, -r);
        mag_mul_2exp_si(norm, norm, -r);

        N = _arb_mat_exp_choose_N(norm, wp);
        mag_exp_tail(err, norm, N);

        _arb_mat_exp_taylor(B, T, N, wp);

        for (i = 0; i < dim; i++)
            for (j = 0; j < dim; j++)
                arb_add_error_mag(arb_mat_entry(B, i, j), err);

        for (i = 0; i < r; i++)
        {
            arb_mat_mul(T, B, B, wp);
            arb_mat_swap(T, B);
        }

        for (i = 0; i < dim; i++)
            for (j = 0; j < dim; j++)
                arb_set_round(arb_mat_entry(B, i, j),
                    arb_mat_entry(B, i, j), prec);
    }

    mag_clear(norm);
    mag_clear(err);
    arb_mat_clear(T);
}
Example #7
0
File: t-lu.c Project: isuruf/arb
int main()
{
    slong iter;
    flint_rand_t state;

    flint_printf("lu....");
    fflush(stdout);

    flint_randinit(state);

    for (iter = 0; iter < 100000; iter++)
    {
        fmpq_mat_t Q;
        arb_mat_t A, LU, P, L, U, T;
        slong i, j, n, qbits, prec, *perm;
        int q_invertible, r_invertible;

        n = n_randint(state, 8);
        qbits = 1 + n_randint(state, 100);
        prec = 2 + n_randint(state, 202);

        fmpq_mat_init(Q, n, n);
        arb_mat_init(A, n, n);
        arb_mat_init(LU, n, n);
        arb_mat_init(P, n, n);
        arb_mat_init(L, n, n);
        arb_mat_init(U, n, n);
        arb_mat_init(T, n, n);
        perm = _perm_init(n);

        fmpq_mat_randtest(Q, state, qbits);
        q_invertible = fmpq_mat_is_invertible(Q);

        if (!q_invertible)
        {
            arb_mat_set_fmpq_mat(A, Q, prec);
            r_invertible = arb_mat_lu(perm, LU, A, prec);
            if (r_invertible)
            {
                flint_printf("FAIL: matrix is singular over Q but not over R\n");
                flint_printf("n = %wd, prec = %wd\n", n, prec);
                flint_printf("\n");

                flint_printf("Q = \n"); fmpq_mat_print(Q); flint_printf("\n\n");
                flint_printf("A = \n"); arb_mat_printd(A, 15); flint_printf("\n\n");
                flint_printf("LU = \n"); arb_mat_printd(LU, 15); flint_printf("\n\n");
            }
        }
        else
        {
            /* now this must converge */
            while (1)
            {
                arb_mat_set_fmpq_mat(A, Q, prec);
                r_invertible = arb_mat_lu(perm, LU, A, prec);
                if (r_invertible)
                {
                    break;
                }
                else
                {
                    if (prec > 10000)
                    {
                        flint_printf("FAIL: failed to converge at 10000 bits\n");
                        abort();
                    }
                    prec *= 2;
                }
            }

            arb_mat_one(L);
            for (i = 0; i < n; i++)
                for (j = 0; j < i; j++)
                    arb_set(arb_mat_entry(L, i, j),
                        arb_mat_entry(LU, i, j));

            for (i = 0; i < n; i++)
                for (j = i; j < n; j++)
                    arb_set(arb_mat_entry(U, i, j),
                        arb_mat_entry(LU, i, j));

            for (i = 0; i < n; i++)
                arb_one(arb_mat_entry(P, perm[i], i));

            arb_mat_mul(T, P, L, prec);
            arb_mat_mul(T, T, U, prec);

            if (!arb_mat_contains_fmpq_mat(T, Q))
            {
                flint_printf("FAIL (containment, iter = %wd)\n", iter);
                flint_printf("n = %wd, prec = %wd\n", n, prec);
                flint_printf("\n");

                flint_printf("Q = \n"); fmpq_mat_print(Q); flint_printf("\n\n");
                flint_printf("A = \n"); arb_mat_printd(A, 15); flint_printf("\n\n");
                flint_printf("LU = \n"); arb_mat_printd(LU, 15); flint_printf("\n\n");
                flint_printf("L = \n"); arb_mat_printd(L, 15); flint_printf("\n\n");
                flint_printf("U = \n"); arb_mat_printd(U, 15); flint_printf("\n\n");
                flint_printf("P*L*U = \n"); arb_mat_printd(T, 15); flint_printf("\n\n");

                abort();
            }
        }

        fmpq_mat_clear(Q);
        arb_mat_clear(A);
        arb_mat_clear(LU);
        arb_mat_clear(P);
        arb_mat_clear(L);
        arb_mat_clear(U);
        arb_mat_clear(T);
        _perm_clear(perm);
    }

    flint_randclear(state);
    flint_cleanup();
    flint_printf("PASS\n");
    return EXIT_SUCCESS;
}