def construct_from_generators_indices(generators, filtration, base_ring, check):
    """
    Construct a filtered vector space.

    INPUT:

    - ``generators`` -- a list/tuple/iterable of vectors, or something
      convertible to them. The generators spanning various
      subspaces.

    - ``filtration`` -- a list or iterable of filtration steps. Each
      filtration step is a pair ``(degree, ray_indices)``. The
      ``ray_indices`` are a list or iterable of ray indices, which
      span a subspace of the vector space. The integer ``degree``
      stipulates that all filtration steps of degree higher or equal
      than ``degree`` (up to the next filtration step) are said
      subspace.

    EXAMPLES::

        sage: from sage.modules.filtered_vector_space import construct_from_generators_indices
        sage: gens = [(1,0), (0,1), (-1,-1)]
        sage: V = construct_from_generators_indices(gens, {1:[0,1], 3:[1]}, QQ, True);  V
        QQ^2 >= QQ^1 >= QQ^1 >= 0

    TESTS::

        sage: gens = [(int(1),int(0)), (0,1), (-1,-1)]
        sage: construct_from_generators_indices(iter(gens), {int(0):[0, int(1)], 2:[2]}, QQ, True)
        QQ^2 >= QQ^1 >= QQ^1 >= 0
    """
    # normalize generators
    generators = map(list, generators)

    # deduce dimension
    if len(generators) == 0:
        dim = ZZ(0)
    else:
        dim = ZZ(len(generators[0]))
    ambient = VectorSpace(base_ring, dim)

    # complete generators to a generating set
    if matrix(base_ring, generators).rank() < dim:
        complement = ambient.span(generators).complement()
        generators = generators + list(complement.gens())
    # normalize generators II
    generators = tuple(ambient(v) for v in generators)

    for v in generators:
        v.set_immutable()

    # normalize filtration data
    normalized = dict()
    for deg, gens in iteritems(filtration):
        deg = normalize_degree(deg)
        gens = map(ZZ, gens)
        if any(i < 0 or i >= len(generators) for i in gens):
            raise ValueError('generator index out of bounds')
        normalized[deg] = tuple(sorted(gens))
    try:
        del normalized[minus_infinity]
    except KeyError:
        pass
    filtration = normalized

    return FilteredVectorSpace_class(base_ring, dim, generators, filtration, check=check)
Beispiel #2
0
def _possible_normalizers(E, SA):
    r"""Find a list containing all primes `l` such that the Galois image at `l`
    is contained in the normalizer of a Cartan subgroup, such that the
    corresponding quadratic character is ramified only at the given primes.

    INPUT:

    - ``E`` - EllipticCurve - over a number field K.

    - ``SA`` - list - a list of primes of K.

    OUTPUT:

    - list - A list of primes, which contains all primes `l` such that the
             Galois image at `l` is contained in the normalizer of a Cartan
             subgroup, such that the corresponding quadratic character is
             ramified only at primes in SA.

    - If `E` has geometric CM that is not defined over its ground field, a
      ValueError is raised.

    EXAMPLES::

        sage: E = EllipticCurve([0,0,0,-56,4848])
        sage: 5 in sage.schemes.elliptic_curves.gal_reps_number_field._possible_normalizers(E, [ZZ.ideal(2)])
        True
    """

    E = _over_numberfield(E)
    K = E.base_field()
    SA = [K.ideal(I.gens()) for I in SA]

    x = K['x'].gen()
    selmer_group = K.selmer_group(SA, 2) # Generators of the selmer group.

    if selmer_group == []:
        return []

    V = VectorSpace(GF(2), len(selmer_group))
    # We think of this as the character group of the selmer group.

    traces_list = []
    W = V.zero_subspace()

    deg_one_primes = K.primes_of_degree_one_iter()

    while W.dimension() < V.dimension() - 1:
        P = deg_one_primes.next()

        k = P.residue_field()

        defines_valid_character = True
        # A prime P defines a quadratic residue character
        # on the Selmer group. This variable will be set
        # to zero if any elements of the selmer group are
        # zero mod P (i.e. the character is ramified).

        splitting_vector = [] # This will be the values of this
        # character on the generators of the Selmer group.

        for a in selmer_group:
            abar = k(a)
            if abar == 0:
                # Ramification.
                defines_valid_character = False
                break

            if abar.is_square():
                splitting_vector.append(GF(2)(0))
            else:
                splitting_vector.append(GF(2)(1))

        if not defines_valid_character:
            continue

        if splitting_vector in W:
            continue

        try:
            Etilde = E.change_ring(k)
        except ArithmeticError: # Bad reduction.
            continue

        tr = Etilde.trace_of_frobenius()

        if tr == 0:
            continue

        traces_list.append(tr)

        W = W + V.span([splitting_vector])

    bad_primes = set([])

    for i in traces_list:
        for p in i.prime_factors():
            bad_primes.add(p)

    # We find the unique vector v in V orthogonal to W:
    v = W.matrix().transpose().kernel().basis()[0]

    # We find the element a of the selmer group corresponding to v:
    a = 1
    for i in xrange(len(selmer_group)):
        if v[i] == 1:
            a *= selmer_group[i]

    # Since we've already included the above bad primes, we can assume
    # that the quadratic character corresponding to the exceptional primes
    # we're looking for is given by mapping into Gal(K[\sqrt{a}]/K).

    patience = 5 * K.degree()
    # Number of Frobenius elements to check before suspecting that E
    # has CM and computing the set of CM j-invariants of K to check.
    # TODO: Is this the best value for this parameter?

    while True:
        P = deg_one_primes.next()

        k = P.residue_field()

        if not k(a).is_square():
            try:
                tr = E.change_ring(k).trace_of_frobenius()
            except ArithmeticError: # Bad reduction.
                continue

            if tr == 0:
                patience -= 1

                if patience == 0:
                    # We suspect E has CM, so we check:
                    if E.j_invariant() in cm_j_invariants(K):
                        raise ValueError("The curve E should not have CM.")

            else:
                for p in tr.prime_factors():
                    bad_primes.add(p)

                bad_primes = sorted(bad_primes)
                return bad_primes
Beispiel #3
0
def construct_from_generators_indices(generators, filtration, base_ring,
                                      check):
    """
    Construct a filtered vector space.

    INPUT:

    - ``generators`` -- a list/tuple/iterable of vectors, or something
      convertible to them. The generators spanning various
      subspaces.

    - ``filtration`` -- a list or iterable of filtration steps. Each
      filtration step is a pair ``(degree, ray_indices)``. The
      ``ray_indices`` are a list or iterable of ray indices, which
      span a subspace of the vector space. The integer ``degree``
      stipulates that all filtration steps of degree higher or equal
      than ``degree`` (up to the next filtration step) are said
      subspace.

    EXAMPLES::

        sage: from sage.modules.filtered_vector_space import construct_from_generators_indices
        sage: gens = [(1,0), (0,1), (-1,-1)]
        sage: V = construct_from_generators_indices(gens, {1:[0,1], 3:[1]}, QQ, True);  V
        QQ^2 >= QQ^1 >= QQ^1 >= 0

    TESTS::

        sage: gens = [(int(1),int(0)), (0,1), (-1,-1)]
        sage: construct_from_generators_indices(iter(gens), {int(0):[0, int(1)], 2:[2]}, QQ, True)
        QQ^2 >= QQ^1 >= QQ^1 >= 0
    """
    # normalize generators
    generators = [list(g) for g in generators]

    # deduce dimension
    if len(generators) == 0:
        dim = ZZ(0)
    else:
        dim = ZZ(len(generators[0]))
    ambient = VectorSpace(base_ring, dim)

    # complete generators to a generating set
    if matrix(base_ring, generators).rank() < dim:
        complement = ambient.span(generators).complement()
        generators = generators + list(complement.gens())
    # normalize generators II
    generators = tuple(ambient(v) for v in generators)

    for v in generators:
        v.set_immutable()

    # normalize filtration data
    normalized = dict()
    for deg, gens in filtration.items():
        deg = normalize_degree(deg)
        gens = [ZZ(i) for i in gens]
        if any(i < 0 or i >= len(generators) for i in gens):
            raise ValueError('generator index out of bounds')
        normalized[deg] = tuple(sorted(gens))
    try:
        del normalized[minus_infinity]
    except KeyError:
        pass
    filtration = normalized

    return FilteredVectorSpace_class(base_ring,
                                     dim,
                                     generators,
                                     filtration,
                                     check=check)
def _possible_normalizers(E, SA):
    r"""Find a list containing all primes `l` such that the Galois image at `l`
    is contained in the normalizer of a Cartan subgroup, such that the
    corresponding quadratic character is ramified only at the given primes.

    INPUT:

    - ``E`` - EllipticCurve - over a number field K.

    - ``SA`` - list - a list of primes of K.

    OUTPUT:

    - list - A list of primes, which contains all primes `l` such that the
             Galois image at `l` is contained in the normalizer of a Cartan
             subgroup, such that the corresponding quadratic character is
             ramified only at primes in SA.

    - If `E` has geometric CM that is not defined over its ground field, a
      ValueError is raised.

    EXAMPLES::

        sage: E = EllipticCurve([0,0,0,-56,4848])
        sage: 5 in sage.schemes.elliptic_curves.gal_reps_number_field._possible_normalizers(E, [ZZ.ideal(2)])
        True
    """

    E = _over_numberfield(E)
    K = E.base_field()
    SA = [K.ideal(I.gens()) for I in SA]

    x = K['x'].gen()
    selmer_group = K.selmer_group(SA, 2)  # Generators of the selmer group.

    if selmer_group == []:
        return []

    V = VectorSpace(GF(2), len(selmer_group))
    # We think of this as the character group of the selmer group.

    traces_list = []
    W = V.zero_subspace()

    deg_one_primes = K.primes_of_degree_one_iter()

    while W.dimension() < V.dimension() - 1:
        P = next(deg_one_primes)

        k = P.residue_field()

        defines_valid_character = True
        # A prime P defines a quadratic residue character
        # on the Selmer group. This variable will be set
        # to zero if any elements of the selmer group are
        # zero mod P (i.e. the character is ramified).

        splitting_vector = []  # This will be the values of this
        # character on the generators of the Selmer group.

        for a in selmer_group:
            abar = k(a)
            if abar == 0:
                # Ramification.
                defines_valid_character = False
                break

            if abar.is_square():
                splitting_vector.append(GF(2)(0))
            else:
                splitting_vector.append(GF(2)(1))

        if not defines_valid_character:
            continue

        if splitting_vector in W:
            continue

        try:
            Etilde = E.change_ring(k)
        except ArithmeticError:  # Bad reduction.
            continue

        tr = Etilde.trace_of_frobenius()

        if tr == 0:
            continue

        traces_list.append(tr)

        W = W + V.span([splitting_vector])

    bad_primes = set([])

    for i in traces_list:
        for p in i.prime_factors():
            bad_primes.add(p)

    # We find the unique vector v in V orthogonal to W:
    v = W.matrix().transpose().kernel().basis()[0]

    # We find the element a of the selmer group corresponding to v:
    a = 1
    for i in xrange(len(selmer_group)):
        if v[i] == 1:
            a *= selmer_group[i]

    # Since we've already included the above bad primes, we can assume
    # that the quadratic character corresponding to the exceptional primes
    # we're looking for is given by mapping into Gal(K[\sqrt{a}]/K).

    patience = 5 * K.degree()
    # Number of Frobenius elements to check before suspecting that E
    # has CM and computing the set of CM j-invariants of K to check.
    # TODO: Is this the best value for this parameter?

    while True:
        P = next(deg_one_primes)

        k = P.residue_field()

        if not k(a).is_square():
            try:
                tr = E.change_ring(k).trace_of_frobenius()
            except ArithmeticError:  # Bad reduction.
                continue

            if tr == 0:
                patience -= 1

                if patience == 0:
                    # We suspect E has CM, so we check:
                    if E.j_invariant() in cm_j_invariants(K):
                        raise ValueError("The curve E should not have CM.")

            else:
                for p in tr.prime_factors():
                    bad_primes.add(p)

                bad_primes = sorted(bad_primes)
                return bad_primes