Example #1
0
def solve_ideal_equation(gamma, I, D, N, O):
    """Find mu_0 in Rj such that (O* gamma / NO)[mu_0] = I / NO.

    Args:
        gamma: An element of O.
        I: A left O-ideal.
        D: The index [O : R + Rj].
        N: The norm of I. Must be prime.
        O: An order in a rational quaternion algebra containing 1, i, j, k.

    Returns:
        mu_0 in Rj such that 0 != gamma * mu_0 in I.
    """
    assert N == I.norm()
    assert is_prime(N)

    # d = D*c + N*_
    d, c, _ = xgcd(D, N)
    assert d == 1

    a, b = [Integer(x) for x in O.quaternion_algebra().invariants()]

    F = GF(N)
    # The suffix _ff means that this element is over a finite field, not the
    # rationals.
    B_ff = QuaternionAlgebra(F, a, b)
    i_ff, j_ff, k_ff = B_ff.gens()

    # phi is homomorphism O -> (a, b | F) with kernel NO.
    def phi(alpha):
        # alpha + NO = alpha_prime + NO.
        alpha_prime = D * c * alpha
        t, x, y, z = [
            Integer(coeff) for coeff in alpha_prime.coefficient_tuple()
        ]
        return t + x * i_ff + y * j_ff + z * k_ff

    gamma_ff = phi(gamma)
    gamma_ff_mat = gamma_ff.matrix(action="left")
    I_basis_ff = [phi(alpha).coefficient_tuple() for alpha in I.basis()]
    # Only use 2nd and 3rd rows of gamma_ff_mat so solution is in Rj.
    lin_system = matrix(F, [gamma_ff_mat[2], gamma_ff_mat[3]] + I_basis_ff)
    sol = lin_system.left_kernel().basis()[0]
    y, z = sol[0], sol[1]
    mu_ff = y * j_ff + z * k_ff
    assert vector(F, (gamma_ff * mu_ff).coefficient_tuple()) in span(
        I_basis_ff, F)

    B = O.quaternion_algebra()
    i, j, k = B.gens()
    mu_0 = sum(
        Integer(coeff) * elem
        for coeff, elem in zip(mu_ff.coefficient_tuple(), [1, i, j, k]))

    assert 0 != mu_0
    assert gamma * mu_0 in I

    return mu_0
Example #2
0
def complete_column(a, c, i=1):
    """
    Completes a column a,c with gcd(a,c) = 1 to an SL_2(Z)-matrix.
    INPUT:
    - a - int, the top entry of the column.
    - c - int, the bottom entry of the column.
    - i - int.
    OUTPUT:
    - A matrix in SL_2(Z) with i-th column [a,c]
    """
    if gcd(a, c) > 1:
        raise ValueError('Input needs to be coprime')
    _, d, b = xgcd(a, c)
    b = -b
    if i == 1:
        return Matrix([[a, b], [c, d]])
    elif i == 2:
        return Matrix([[-b, a], [-d, c]])
Example #3
0
    def __add__(self, other):
        if isinstance(other, Integer):
            other *= IdentityEndomorphismMod(self.E, self.psi)
        if isinstance(other, ZeroEndomorphismMod):
            return self
        if self.fx == other.fx:
            if self.fy == other.fy:
                m = (3 * self.fx ** 2 + self.A) / (2 * self.fy * self.f)
            else:
                return ZeroEndomorphismMod(self.E, self.psi)

        else:
            div, inv, _ = xgcd(self.fx.parent().lift(self.fx - other.fx), (self.psi))
            if div.is_constant():
                m = (self.fy - other.fy) * inv
            else:
                raise ZeroDivisionError(div)
        fx = m ** 2 * self.f - self.fx - other.fx
        fy = m * (self.fx - fx) - self.fy
        return EndomorphismMod(self.E, fx, fy, self.psi)
Example #4
0
def AL(N, S):
    r"""
    INPUT:

    - N - a positive integer
    - S - a maximal divisor of N or a set of primes

    OUPUT:

    - A matrix representing the partial Atkin-Lehner operator W_S

    """
    try:
        S = prod([p**(N.valuation(p)) for p in S])
    except TypeError:
        if gcd(S, N / S) > 1:
            S = S.prime_divisors()
            S = prod([p**(N.valuation(p)) for p in S])

    _, w, z = xgcd(S, N / S)
    z = -z
    return Matrix([[S, 1], [N * z, S * w]])
Example #5
0
    def find_monic_replacements(self, p, t, pt_generators, prev_nu):
        r"""
        Replace possibly non-monic generators of `N_{(p^t)}(B)` by monic
        generators.

        INPUT:

        - ``p`` -- a prime element of `D`

        - ``t`` -- a non-negative integer

        - ``pt_generators`` -- a list `(g_1, \ldots, g_s)` of polynomials in
          `D[X]` such that `N_{(p^t)}(B) = (g_1, \ldots, g_s) + pN_{(p^{t-1})}(B)`

        - ``prev_nu`` -- a `(p^{t-1})`-minimal polynomial of `B`

        OUTPUT:

        A list `(h_1, \ldots, h_r)` of monic polynomials such that
        `N_{(p^t)}(B) = (h_1, \ldots, h_r) + pN_{(p^{t-1})}(B)`.

        EXAMPLES::

            sage: from sage.matrix.compute_J_ideal import ComputeMinimalPolynomials
            sage: B = matrix(ZZ, [[1, 0, 1], [1, -2, -1], [10, 0, 0]])
            sage: C = ComputeMinimalPolynomials(B)
            sage: x = polygen(ZZ, 'x')
            sage: nu_1 = x^2 + x
            sage: generators_4 = [2*x^2 + 2*x, x^2 + 3*x + 2]
            sage: C.find_monic_replacements(2, 2, generators_4, nu_1)
            [x^2 + 3*x + 2]

        TESTS::

            sage: C.find_monic_replacements(2, 3, generators_4, nu_1)
            Traceback (most recent call last):
            ...
            ValueError: [2*x^2 + 2*x, x^2 + 3*x + 2] not in N_{(2^3)}(B)
            sage: C.find_monic_replacements(2, 2, generators_4, x^2)
            Traceback (most recent call last):
            ...
            ValueError: x^2 not in N_{(2^1)}(B)

        ALGORITHM:

        [HR2016]_, Algorithms 2 and 3.
        """
        from sage.arith.misc import xgcd

        if not all((g(self._B) % p**t).is_zero() for g in pt_generators):
            raise ValueError("%s not in N_{(%s^%s)}(B)" %
                             (pt_generators, p, t))

        if not (prev_nu(self._B) % p**(t - 1)).is_zero():
            raise ValueError("%s not in N_{(%s^%s)}(B)" % (prev_nu, p, t - 1))

        (X, ) = self._DX.gens()

        replacements = []
        for f in pt_generators:
            g = f
            p_prt = p_part(g, p)

            while g != p * p_prt:
                r = p_prt.quo_rem(prev_nu)[1]
                g1 = g - p * p_prt
                d, u, v = xgcd(g1.leading_coefficient(), p)
                h = u * (p * r + g1) + v * p * prev_nu * X**(g1.degree() -
                                                             prev_nu.degree())
                replacements.append(h % p**t)
                #reduce coefficients mod p^t to keep coefficients small
                g = g.quo_rem(h)[1]
                p_prt = p_part(g, p)

        replacements = list(set(replacements))
        assert all(g.is_monic() for g in replacements),\
            "Something went wrong in find_monic_replacements"

        return replacements
Example #6
0
    def find_monic_replacements(self, p, t, pt_generators, prev_nu):
        r"""
        Replace possibly non-monic generators of `N_{(p^t)}(B)` by monic
        generators.

        INPUT:

        - ``p`` -- a prime element of `D`

        - ``t`` -- a non-negative integer

        - ``pt_generators`` -- a list `(g_1, \ldots, g_s)` of polynomials in
          `D[X]` such that `N_{(p^t)}(B) = (g_1, \ldots, g_s) + pN_{(p^{t-1})}(B)`

        - ``prev_nu`` -- a `(p^{t-1})`-minimal polynomial of `B`

        OUTPUT:

        A list `(h_1, \ldots, h_r)` of monic polynomials such that
        `N_{(p^t)}(B) = (h_1, \ldots, h_r) + pN_{(p^{t-1})}(B)`.

        EXAMPLES::

            sage: from sage.matrix.compute_J_ideal import ComputeMinimalPolynomials
            sage: B = matrix(ZZ, [[1, 0, 1], [1, -2, -1], [10, 0, 0]])
            sage: C = ComputeMinimalPolynomials(B)
            sage: x = polygen(ZZ, 'x')
            sage: nu_1 = x^2 + x
            sage: generators_4 = [2*x^2 + 2*x, x^2 + 3*x + 2]
            sage: C.find_monic_replacements(2, 2, generators_4, nu_1)
            [x^2 + 3*x + 2]

        TESTS::

            sage: C.find_monic_replacements(2, 3, generators_4, nu_1)
            Traceback (most recent call last):
            ...
            ValueError: [2*x^2 + 2*x, x^2 + 3*x + 2] not in N_{(2^3)}(B)
            sage: C.find_monic_replacements(2, 2, generators_4, x^2)
            Traceback (most recent call last):
            ...
            ValueError: x^2 not in N_{(2^1)}(B)

        ALGORITHM:

        [HR2016]_, Algorithms 2 and 3.
        """
        from sage.arith.misc import xgcd

        if not all((g(self._B) % p**t).is_zero()
                   for g in pt_generators):
            raise ValueError("%s not in N_{(%s^%s)}(B)" %
                             (pt_generators, p, t))

        if not (prev_nu(self._B) % p**(t-1)).is_zero():
            raise ValueError("%s not in N_{(%s^%s)}(B)" % (prev_nu, p, t-1))

        (X,) = self._DX.gens()

        replacements = []
        for f in pt_generators:
            g = f
            p_prt = p_part(g, p)

            while g != p*p_prt:
                r = p_prt.quo_rem(prev_nu)[1]
                g1 = g - p*p_prt
                d, u, v = xgcd(g1.leading_coefficient(), p)
                h = u*(p*r + g1) + v*p*prev_nu*X**(g1.degree()-prev_nu.degree())
                replacements.append(h % p**t)
                #reduce coefficients mod p^t to keep coefficients small
                g = g.quo_rem(h)[1]
                p_prt = p_part(g, p)

        replacements = list(set(replacements))
        assert all(g.is_monic() for g in replacements),\
            "Something went wrong in find_monic_replacements"

        return replacements