Esempio n. 1
0
def fast_determinant_of_laurent_poly_matrix(A):
    """
    Return the determinant of the given matrix up to
    a power of t^n, using the faster algorithm for
    polynomial entries.
    """
    R = A.base_ring()
    if not hasattr(R, 'polynomial_ring'):
        assert False
        return det(A)

    expshift = -minimum_exponents(A.list())
    P = PolynomialRing(
        R.base_ring(),
        R.variable_names())  # Note: P.polynomial_ring() doesn't work here!
    Ap = matrix(P, A.nrows(), A.ncols(),
                [convert_laurent_to_poly(p, expshift, P) for p in A.list()])
    return det(Ap)
Esempio n. 2
0
def compute_torsion(G,
                    bits_prec,
                    alpha=None,
                    phi=None,
                    phialpha=None,
                    return_parts=False,
                    return_as_poly=True,
                    wada_conventions=False,
                    symmetry_test=True):
    if alpha:
        F = alpha('a').base_ring()
    elif phialpha:
        F = phialpha('a').base_ring().base_ring()
    epsilon = ZZ(2)**(-bits_prec // 3) if not F.is_exact() else None
    big_epsilon = ZZ(2)**(-bits_prec // 5) if not F.is_exact() else None
    gens, rels = G.generators(), G.relators()
    k = len(gens)
    if phi == None:
        phi = MapToGroupRingOfFreeAbelianization(G, F)

    # Make sure this special algorithm applies.
    assert len(rels) == len(gens) - 1 and len(phi.range().gens()) == 1

    # Want the first variable to be homologically nontrivial
    i0 = [i for i, g in enumerate(gens) if phi(g) != 1][0]
    gens = gens[i0:] + gens[:i0]
    if phialpha == None:
        phialpha = PhiAlpha(phi, alpha)

    # Boundary maps for chain complex

    if not wada_conventions:  # Using the conventions of our paper.
        d2 = [[fox_derivative_with_involution(R, phialpha, g) for R in rels]
              for g in gens]
        d2 = block_matrix(d2, nrows=k, ncols=k - 1)
        d1 = [phialpha(g.swapcase()) - 1 for g in gens]
        d1 = block_matrix(d1, nrows=1, ncols=k)
        dsquared = d1 * d2

    else:  # Using those implicit in Wada's paper.
        d2 = [[fox_derivative(R, phialpha, g) for g in gens] for R in rels]
        d2 = block_matrix(sum(d2, []), nrows=k - 1, ncols=k)
        d1 = [phialpha(g) - 1 for g in gens]
        d1 = block_matrix(d1, nrows=k, ncols=1)
        dsquared = d2 * d1

    if not matrix_has_small_entries(dsquared, epsilon):
        raise TorsionComputationError("(boundary)^2 != 0")

    T = last_square_submatrix(d2)
    if return_as_poly:
        T = fast_determinant_of_laurent_poly_matrix(T)
    else:
        T = det(T)
    B = first_square_submatrix(d1)
    B = det(B)
    if return_as_poly:
        T = clean_laurent_to_poly(T, epsilon)
        B = clean_laurent_to_poly(B, epsilon)
    else:
        T = clean_laurent(T, epsilon)
        B = clean_laurent(B, epsilon)

    if return_parts:
        return (T, B)

    q, r = T.quo_rem(B)
    ans = clean_laurent_to_poly(q, epsilon)
    if univ_abs(r) > epsilon:
        raise TorsionComputationError("Division failed")

    # Now do a quick sanity check

    if symmetry_test:
        coeffs = ans.coefficients()
        error = max(
            [univ_abs(a - b) for a, b in zip(coeffs, reversed(coeffs))])
        if error > epsilon:
            raise TorsionComputationError(
                "Torsion polynomial doesn't seem symmetric")

    return ans
Esempio n. 3
0
 def isDegenerate(self):
     return det(self.matrix) == 0
Esempio n. 4
0
 def __init__(self, m):
     self.matrix = matrix(m)
     self.dim = self.matrix.nrows()
     if (self.dim != self.matrix.ncols() or not symmetric(self.matrix)):
         raise ValueError("Matrix must be square and symmetric.")
     self.det = det(self.matrix)