# sage.doctest: needs sage.libs.pari
r"""
Generic spaces of modular forms

EXAMPLES (computation of base ring): Return the base ring of this
space of modular forms.

EXAMPLES: For spaces of modular forms for `\Gamma_0(N)` or
`\Gamma_1(N)`, the default base ring is
`\QQ`::

    sage: ModularForms(11,2).base_ring()
    Rational Field
    sage: ModularForms(1,12).base_ring()
    Rational Field
    sage: CuspForms(Gamma1(13),3).base_ring()
    Rational Field

The base ring can be explicitly specified in the constructor
function.

::

    sage: ModularForms(11,2,base_ring=GF(13)).base_ring()
    Finite Field of size 13

For modular forms with character the default base ring is the field
generated by the image of the character.

::

    sage: ModularForms(DirichletGroup(13).0,3).base_ring()
    Cyclotomic Field of order 12 and degree 4

For example, if the character is quadratic then the field is
`\QQ` (if the characteristic is `0`).

::

    sage: ModularForms(DirichletGroup(13).0^6,3).base_ring()
    Rational Field

An example in characteristic `7`::

    sage: ModularForms(13,3,base_ring=GF(7)).base_ring()
    Finite Field of size 7

AUTHORS:

- William Stein (2007): first version
"""

#########################################################################
#       Copyright (C) 2004--2006 William Stein <wstein@gmail.com>
#
#  Distributed under the terms of the GNU General Public License (GPL)
#
#                  https://www.gnu.org/licenses/
#########################################################################

from sage.arith.misc import gcd
from sage.matrix.constructor import zero_matrix
from sage.misc.cachefunc import cached_method

import sage.modular.hecke.all as hecke
import sage.modular.arithgroup.all as arithgroup
from sage.modular import dirichlet

from sage.rings.infinity import PlusInfinity
from sage.rings.integer import Integer
from sage.rings.integer_ring import ZZ
from sage.rings.power_series_ring import PowerSeriesRing
from sage.rings.power_series_ring_element import PowerSeries
from sage.rings.rational_field import QQ
from sage.categories.rings import Rings

from sage.structure.all import Sequence
from sage.structure.richcmp import (richcmp_method, richcmp, rich_to_bool,
                                    richcmp_not_equal)

from .element import ModularFormElement, Newform
from . import defaults
from . import hecke_operator_on_qexp

WARN = False


@richcmp_method
class ModularFormsSpace(hecke.HeckeModule_generic):
    """
    A generic space of modular forms.
    """
    Element = ModularFormElement

    def __init__(self, group, weight, character, base_ring, category=None):
        r"""
        Generic spaces of modular forms. For spaces of modular forms for
        `\Gamma_0(N)` or `\Gamma_1(N)`, the default base
        ring is `\QQ`.

        EXAMPLES::

            sage: ModularForms(11,2)
            Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field

        ::

            sage: ModularForms(11,2,base_ring=GF(13))
            Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(11) of weight 2 over Finite Field of size 13

        ::

            sage: ModularForms(DirichletGroup(13).0,3)
            Modular Forms space of dimension 3, character [zeta12] and weight 3 over Cyclotomic Field of order 12 and degree 4

        ::

            sage: M = ModularForms(11,2)
            sage: M == loads(dumps(M))
            True
        """
        global WARN
        if WARN:
            print("Modular forms -- under development -- do not trust yet.")
            WARN = False
        if not isinstance(group, arithgroup.CongruenceSubgroupBase):
            raise TypeError("group (=%s) must be a congruence subgroup" % group)
        weight = Integer(weight)
        if not ((character is None) or isinstance(character, dirichlet.DirichletCharacter)):
            raise TypeError("character must be a Dirichlet character")
        if base_ring not in Rings():
            raise TypeError("base_ring must be a ring")
        self.__sturm_bound = None
        self.__weight, self.__group, self.__character = weight, group, character
        hecke.HeckeModule_generic.__init__(self, base_ring, group.level(), category=category)

    def prec(self, new_prec=None):
        """
        Return or set the default precision used for displaying
        `q`-expansions of elements of this space.

        INPUT:

        - ``new_prec`` -- positive integer (default: ``None``)

        OUTPUT: if new_prec is None, returns the current precision

        EXAMPLES::

            sage: M = ModularForms(1,12)
            sage: S = M.cuspidal_subspace()
            sage: S.prec()
            6
            sage: S.basis()
            [q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6)]
            sage: S.prec(8)
            8
            sage: S.basis()
            [q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + O(q^8)]
        """
        return self.ambient().prec(new_prec)

    def set_precision(self, new_prec):
        """
        Set the default precision used for displaying
        `q`-expansions.

        INPUT:

        - ``new_prec`` -- positive integer

        EXAMPLES::

            sage: M = ModularForms(Gamma0(37),2)
            sage: M.set_precision(10)
            sage: S = M.cuspidal_subspace()
            sage: S.basis()
            [q + q^3 - 2*q^4 - q^7 - 2*q^9 + O(q^10),
             q^2 + 2*q^3 - 2*q^4 + q^5 - 3*q^6 - 4*q^9 + O(q^10)]

        ::

            sage: S.set_precision(0)
            sage: S.basis()
            [O(q^0), O(q^0)]

        The precision of subspaces is the same as the precision of the
        ambient space.

        ::

            sage: S.set_precision(2)
            sage: M.basis()
            [q + O(q^2), O(q^2), 1 + 2/3*q + O(q^2)]

        The precision must be nonnegative::

            sage: S.set_precision(-1)
            Traceback (most recent call last):
            ...
            ValueError: n (=-1) must be >= 0

        We do another example with nontrivial character.

        ::

            sage: M = ModularForms(DirichletGroup(13).0^2)
            sage: M.set_precision(10)
            sage: M.cuspidal_subspace().0
            q + (-zeta6 - 1)*q^2 + (2*zeta6 - 2)*q^3 + zeta6*q^4 + (-2*zeta6 + 1)*q^5 + (-2*zeta6 + 4)*q^6 + (2*zeta6 - 1)*q^8 - zeta6*q^9 + O(q^10)
        """
        self.ambient().set_precision(new_prec)

    def weight(self):
        """
        Return the weight of this space of modular forms.

        EXAMPLES::

            sage: M = ModularForms(Gamma1(13),11)
            sage: M.weight()
            11

        ::

            sage: M = ModularForms(Gamma0(997),100)
            sage: M.weight()
            100

        ::

            sage: M = ModularForms(Gamma0(97),4)
            sage: M.weight()
            4
            sage: M.eisenstein_submodule().weight()
            4
        """
        return self.__weight

    def group(self):
        r"""
        Return the congruence subgroup associated to this space of modular
        forms.

        EXAMPLES::

            sage: ModularForms(Gamma0(12),4).group()
            Congruence Subgroup Gamma0(12)

        ::

            sage: CuspForms(Gamma1(113),2).group()
            Congruence Subgroup Gamma1(113)

        Note that `\Gamma_1(1)` and `\Gamma_0(1)` are replaced by
        `\SL_2(\ZZ)`.

        ::

            sage: CuspForms(Gamma1(1),12).group()
            Modular Group SL(2,Z)
            sage: CuspForms(SL2Z,12).group()
            Modular Group SL(2,Z)
        """
        return self.__group

    def character(self):
        r"""
        Return the Dirichlet character corresponding to this space of
        modular forms. Returns None if there is no specific character
        corresponding to this space, e.g., if this is a space of modular
        forms on `\Gamma_1(N)` with `N>1`.

        EXAMPLES: The trivial character::

            sage: ModularForms(Gamma0(11),2).character()
            Dirichlet character modulo 11 of conductor 1 mapping 2 |--> 1

        Spaces of forms with nontrivial character::

            sage: ModularForms(DirichletGroup(20).0,3).character()
            Dirichlet character modulo 20 of conductor 4 mapping 11 |--> -1, 17 |--> 1

            sage: M = ModularForms(DirichletGroup(11).0, 3)
            sage: M.character()
            Dirichlet character modulo 11 of conductor 11 mapping 2 |--> zeta10
            sage: s = M.cuspidal_submodule()
            sage: s.character()
            Dirichlet character modulo 11 of conductor 11 mapping 2 |--> zeta10
            sage: CuspForms(DirichletGroup(11).0,3).character()
            Dirichlet character modulo 11 of conductor 11 mapping 2 |--> zeta10

        A space of forms with no particular character (hence None is
        returned)::

            sage: print(ModularForms(Gamma1(11),2).character())
            None

        If the level is one then the character is trivial.

        ::

            sage: ModularForms(Gamma1(1),12).character()
            Dirichlet character modulo 1 of conductor 1
        """
        return self.__character

    def has_character(self) -> bool:
        r"""
        Return ``True`` if this space of modular forms has a specific
        character.

        This is ``True`` exactly when the ``character()`` function does not
        return ``None``.

        EXAMPLES: A space for `\Gamma_0(N)` has trivial character,
        hence has a character.

        ::

            sage: CuspForms(Gamma0(11),2).has_character()
            True

        A space for `\Gamma_1(N)` (for `N\geq 2`) never
        has a specific character.

        ::

            sage: CuspForms(Gamma1(11),2).has_character()
            False
            sage: CuspForms(DirichletGroup(11).0,3).has_character()
            True
        """
        return self.character() is not None

    def is_ambient(self) -> bool:
        """
        Return ``True`` if this an ambient space of modular forms.

        EXAMPLES::

            sage: M = ModularForms(Gamma1(4),4)
            sage: M.is_ambient()
            True

        ::

            sage: E = M.eisenstein_subspace()
            sage: E.is_ambient()
            False
        """
        return False   # returning True is defined in the derived AmbientSpace class.

    def __normalize_prec(self, prec):
        """
        If prec=None, return self.prec(). Otherwise, make sure prec is a
        sensible choice of precision and return it.

        EXAMPLES::

            sage: N = ModularForms(6,4)
            sage: N._ModularFormsSpace__normalize_prec(int(3))
            3

        ::

            sage: type(N._ModularFormsSpace__normalize_prec(int(3)))
            <class 'sage.rings.integer.Integer'>
        """
        if prec is None:
            prec = self.prec()
        else:
            prec = Integer(prec)
        if prec < 0:
            raise ValueError("prec (=%s) must be at least 0" % prec)
        return prec

    @cached_method
    def echelon_form(self):
        r"""
        Return a space of modular forms isomorphic to ``self`` but with basis
        of `q`-expansions in reduced echelon form.

        This is useful, e.g., the default basis for spaces of modular forms
        is rarely in echelon form, but echelon form is useful for quickly
        recognizing whether a `q`-expansion is in the space.

        EXAMPLES: We first illustrate two ambient spaces and their echelon
        forms.

        ::

            sage: M = ModularForms(11)
            sage: M.basis()
            [q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6),
             1 + 12/5*q + 36/5*q^2 + 48/5*q^3 + 84/5*q^4 + 72/5*q^5 + O(q^6)]
            sage: M.echelon_form().basis()
            [1 + 12*q^2 + 12*q^3 + 12*q^4 + 12*q^5 + O(q^6),
             q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6)]

        ::

            sage: M = ModularForms(Gamma1(6),4)
            sage: M.basis()
            [q - 2*q^2 - 3*q^3 + 4*q^4 + 6*q^5 + O(q^6),
             1 + O(q^6),
             q - 8*q^4 + 126*q^5 + O(q^6),
             q^2 + 9*q^4 + O(q^6),
             q^3 + O(q^6)]
            sage: M.echelon_form().basis()
            [1 + O(q^6),
             q + 94*q^5 + O(q^6),
             q^2 + 36*q^5 + O(q^6),
             q^3 + O(q^6),
             q^4 - 4*q^5 + O(q^6)]

        We create a space with a funny basis then compute the corresponding
        echelon form.

        ::

            sage: M = ModularForms(11,4)
            sage: M.basis()
            [q + 3*q^3 - 6*q^4 - 7*q^5 + O(q^6),
             q^2 - 4*q^3 + 2*q^4 + 8*q^5 + O(q^6),
             1 + O(q^6),
             q + 9*q^2 + 28*q^3 + 73*q^4 + 126*q^5 + O(q^6)]
            sage: F = M.span_of_basis([M.0 + 1/3*M.1, M.2 + M.3]); F.basis()
            [q + 1/3*q^2 + 5/3*q^3 - 16/3*q^4 - 13/3*q^5 + O(q^6),
             1 + q + 9*q^2 + 28*q^3 + 73*q^4 + 126*q^5 + O(q^6)]
            sage: E = F.echelon_form(); E.basis()
            [1 + 26/3*q^2 + 79/3*q^3 + 235/3*q^4 + 391/3*q^5 + O(q^6),
             q + 1/3*q^2 + 5/3*q^3 - 16/3*q^4 - 13/3*q^5 + O(q^6)]
        """
        return self.span_of_basis(self.echelon_basis())

    @cached_method
    def echelon_basis(self):
        """
        Return a basis for ``self`` in reduced echelon form. This means that if
        we view the `q`-expansions of the basis as defining rows of
        a matrix (with infinitely many columns), then this matrix is in
        reduced echelon form.

        EXAMPLES::

            sage: M = ModularForms(Gamma0(11),4)
            sage: M.echelon_basis()
            [1 + O(q^6),
             q - 9*q^4 - 10*q^5 + O(q^6),
             q^2 + 6*q^4 + 12*q^5 + O(q^6),
             q^3 + q^4 + q^5 + O(q^6)]
            sage: M.cuspidal_subspace().echelon_basis()
            [q + 3*q^3 - 6*q^4 - 7*q^5 + O(q^6), q^2 - 4*q^3 + 2*q^4 + 8*q^5 + O(q^6)]

        ::

            sage: M = ModularForms(SL2Z, 12)
            sage: M.echelon_basis()
            [1 + 196560*q^2 + 16773120*q^3 + 398034000*q^4 + 4629381120*q^5 + O(q^6),
             q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6)]

        ::

            sage: M = CuspForms(Gamma0(17),4, prec=10)
            sage: M.echelon_basis()
            [q + 2*q^5 - 8*q^7 - 8*q^8 + 7*q^9 + O(q^10),
             q^2 - 3/2*q^5 - 7/2*q^6 + 9/2*q^7 + q^8 - 4*q^9 + O(q^10),
             q^3 - 2*q^6 + q^7 - 4*q^8 - 2*q^9 + O(q^10),
             q^4 - 1/2*q^5 - 5/2*q^6 + 3/2*q^7 + 2*q^9 + O(q^10)]
        """
        F = self.free_module()
        W = self._q_expansion_module()
        pr = W.degree()
        B = self.q_echelon_basis(pr)
        E = [self(F.linear_combination_of_basis(W.coordinates(f.padded_list(pr))))
             for f in B]
        return Sequence(E, cr=True, immutable=True)

    @cached_method
    def integral_basis(self):
        """
        Return an integral basis for this space of modular forms.

        EXAMPLES:

        In this example the integral and echelon bases are
        different. ::

            sage: m = ModularForms(97,2,prec=10)
            sage: s = m.cuspidal_subspace()
            sage: s.integral_basis()
            [q + 2*q^7 + 4*q^8 - 2*q^9 + O(q^10),
             q^2 + q^4 + q^7 + 3*q^8 - 3*q^9 + O(q^10),
             q^3 + q^4 - 3*q^8 + q^9 + O(q^10),
             2*q^4 - 2*q^8 + O(q^10),
             q^5 - 2*q^8 + 2*q^9 + O(q^10),
             q^6 + 2*q^7 + 5*q^8 - 5*q^9 + O(q^10),
             3*q^7 + 6*q^8 - 4*q^9 + O(q^10)]
            sage: s.echelon_basis()
            [q + 2/3*q^9 + O(q^10),
             q^2 + 2*q^8 - 5/3*q^9 + O(q^10),
             q^3 - 2*q^8 + q^9 + O(q^10),
             q^4 - q^8 + O(q^10),
             q^5 - 2*q^8 + 2*q^9 + O(q^10),
             q^6 + q^8 - 7/3*q^9 + O(q^10),
             q^7 + 2*q^8 - 4/3*q^9 + O(q^10)]

        Here's another example where there is a big gap in the valuations::

            sage: m = CuspForms(64,2)
            sage: m.integral_basis()
            [q + O(q^6), q^2 + O(q^6), q^5 + O(q^6)]

        TESTS::

            sage: m = CuspForms(11*2^4,2, prec=13); m
            Cuspidal subspace of dimension 19 of Modular Forms space of dimension 30 for Congruence Subgroup Gamma0(176) of weight 2 over Rational Field
            sage: m.integral_basis()          # takes a long time (3 or 4 seconds)
            [q + O(q^13),
             q^2 + O(q^13),
             q^3 + O(q^13),
             q^4 + O(q^13),
             q^5 + O(q^13),
             q^6 + O(q^13),
             q^7 + O(q^13),
             q^8 + O(q^13),
             q^9 + O(q^13),
             q^10 + O(q^13),
             q^11 + O(q^13),
             q^12 + O(q^13),
             O(q^13),
             O(q^13),
             O(q^13),
             O(q^13),
             O(q^13),
             O(q^13),
             O(q^13)]
        """
        W = self._q_expansion_module()
        pr = W.degree()
        B = self.q_integral_basis(pr)
        I = [self.linear_combination_of_basis(
            W.coordinates(f.padded_list(pr))) for f in B]
        return Sequence(I, cr=True, immutable=True)

    @cached_method
    def _q_expansion_module(self):
        """
        Return module spanned by coefficients of `q`-expansions to sufficient
        precision to determine elements of this space.

        EXAMPLES::

            sage: M = ModularForms(11,2)
            sage: M._q_expansion_module()
            Vector space of degree 3 and dimension 2 over Rational Field
            User basis matrix:
            [   0    1   -2]
            [   1 12/5 36/5]
            sage: CuspForms(1,12)._q_expansion_module()
            Vector space of degree 2 and dimension 1 over Rational Field
            User basis matrix:
            [0 1]
        """
        prec = self.sturm_bound()
        C = self.q_expansion_basis(prec)
        V = self.base_ring()**prec
        return V.span_of_basis([f.padded_list(prec) for f in C])

    def q_expansion_basis(self, prec=None):
        """
        Return a sequence of `q`-expansions for the basis of this space
        computed to the given input precision.

        INPUT:

        - ``prec`` -- integer (>=0) or None

        If prec is None, the prec is computed to be *at least* large
        enough so that each `q`-expansion determines the form as an element
        of this space.

        .. NOTE::

           In fact, the `q`-expansion basis is always computed to
           *at least* ``self.prec()``.

        EXAMPLES::

            sage: S = ModularForms(11,2).cuspidal_submodule()
            sage: S.q_expansion_basis()
            [q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6)]
            sage: S.q_expansion_basis(5)
            [q - 2*q^2 - q^3 + 2*q^4 + O(q^5)]
            sage: S = ModularForms(1,24).cuspidal_submodule()
            sage: S.q_expansion_basis(8)
            [q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 - 982499328*q^6 - 147247240*q^7 + O(q^8),
             q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + 143820*q^6 - 985824*q^7 + O(q^8)]

        An example which used to be buggy::

            sage: M = CuspForms(128, 2, prec=3)
            sage: M.q_expansion_basis()
            [q - q^17 + O(q^22),
             q^2 - 3*q^18 + O(q^22),
             q^3 - q^11 + q^19 + O(q^22),
             q^4 - 2*q^20 + O(q^22),
             q^5 - 3*q^21 + O(q^22),
             q^7 - q^15 + O(q^22),
             q^9 - q^17 + O(q^22),
             q^10 + O(q^22),
             q^13 - q^21 + O(q^22)]
        """
        if prec is None:
            try:  # don't care about precision -- just must be big enough to determine forms
                return self.__q_expansion_basis[1]
            except AttributeError:
                pass
            prec = -1  # big enough to determine forms
        else:
            prec = Integer(self.__normalize_prec(prec))

        if prec == 0:
            z = self._q_expansion_ring()(0, prec)
            return Sequence([z] * int(self.dimension()), immutable=True, cr=True)
        if prec != -1:
            try:
                current_prec, B = self.__q_expansion_basis
                if current_prec == prec:
                    return B
                if current_prec > prec:
                    return Sequence([f.add_bigoh(prec) for f in B], immutable=True, cr=True)
            except AttributeError:
                pass

        d = self.dimension()
        current_prec = max(prec, self.prec(), int(1.2 * d) + 3)  # +3 for luck.
        tries = 0
        while True:
            B = [f for f in self._compute_q_expansion_basis(current_prec) if f != 0]
            if len(B) == d:
                break
            tries += 1
            current_prec += d
            if tries > 5:
                print("WARNING: possible bug in q_expansion_basis for modular forms space %s" % self)
        if prec == -1:
            prec = current_prec
        B = Sequence(B, immutable=True, cr=True)
        self.__q_expansion_basis = (current_prec, B)
        if current_prec == prec:
            return B
        return Sequence([f.add_bigoh(prec) for f in B], immutable=True, cr=True)

    def _compute_q_expansion_basis(self, prec):
        """
        EXAMPLES::

            sage: # needs sage.rings.number_field
            sage: sage.modular.modform.space.ModularFormsSpace(Gamma0(11), 2, DirichletGroup(1)[0], QQ)._compute_q_expansion_basis(5)
            Traceback (most recent call last):
            ...
            NotImplementedError: this must be implemented in the derived class
        """
        raise NotImplementedError("this must be implemented in the derived class")

    def q_echelon_basis(self, prec=None):
        r"""
        Return the echelon form of the basis of `q`-expansions of
        ``self`` up to precision ``prec``.

        The `q`-expansions are power series (not actual modular
        forms). The number of `q`-expansions returned equals the
        dimension.

        EXAMPLES::

            sage: M = ModularForms(11,2)
            sage: M.q_expansion_basis()
            [q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6),
             1 + 12/5*q + 36/5*q^2 + 48/5*q^3 + 84/5*q^4 + 72/5*q^5 + O(q^6)]

        ::

            sage: M.q_echelon_basis()
            [1 + 12*q^2 + 12*q^3 + 12*q^4 + 12*q^5 + O(q^6),
             q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6)]
        """
        prec = self.__normalize_prec(prec)
        if prec == 0:
            z = self._q_expansion_ring()(0, 0)
            return Sequence([z] * int(self.dimension()), cr=True)
        try:
            current_prec, B = self.__q_echelon_basis
        except AttributeError:
            current_prec, B = -1, []
        if current_prec == prec:
            return B
        if current_prec > prec:
            return Sequence([f.add_bigoh(prec) for f in B], cr=True)

        B = self.q_expansion_basis(prec)
        R = self.base_ring()
        A = R**prec
        gens = [f.padded_list(prec) for f in B]
        C = A.span(gens)

        T = self._q_expansion_ring()
        S = [T(f.list(), prec) for f in C.basis()]
        for _ in range(self.dimension() - len(S)):
            S.append(T(0, prec))
        S = Sequence(S, immutable=True, cr=True)
        self.__q_echelon_basis = (prec, S)
        return S

    def q_integral_basis(self, prec=None):
        r"""
        Return a `\ZZ`-reduced echelon basis of
        `q`-expansions for ``self``.

        The `q`-expansions are power series with coefficients in
        `\ZZ`; they are *not* actual modular forms.

        The base ring of ``self`` must be `\QQ`. The number of
        `q`-expansions returned equals the dimension.

        EXAMPLES::

            sage: S = CuspForms(11,2)
            sage: S.q_integral_basis(5)
            [q - 2*q^2 - q^3 + 2*q^4 + O(q^5)]
        """
        if not self.base_ring() == QQ:
            raise TypeError("the base ring must be Q")
        prec = self.__normalize_prec(prec)
        R = PowerSeriesRing(ZZ, name=defaults.DEFAULT_VARIABLE)
        if prec == 0:
            z = R(0, prec)
            return Sequence([z] * int(self.dimension()), cr=True)
        try:
            current_prec, B = self.__q_integral_basis
        except AttributeError:
            current_prec, B = -1, Sequence([], cr=True, immutable=True)

        if current_prec == prec:
            return B
        if current_prec > prec:
            return Sequence([f.add_bigoh(prec) for f in B], cr=True)

        B = self.q_expansion_basis(prec)

        # It's over Q; we just need to intersect it with ZZ^n.
        A = ZZ**prec
        gens = [f.padded_list(prec) for f in B]
        C = A.span(gens)
        D = C.saturation()
        S = [R(f.list(), prec) for f in D.basis()]
        for _ in range(self.dimension() - len(S)):
            S.append(R(0, prec))
        S = Sequence(S, immutable=True, cr=True)
        self.__q_integral_basis = (prec, S)
        return S

    @cached_method
    def _q_expansion_ring(self):
        """
        Return the parent for `q`-expansions of modular forms in ``self``.

        EXAMPLES::

            sage: M = ModularForms(11,2)
            sage: M._q_expansion_ring()
            Power Series Ring in q over Rational Field
        """
        return PowerSeriesRing(self.base_ring(), name=defaults.DEFAULT_VARIABLE)

    @cached_method
    def _q_expansion_zero(self):
        """
        Return the `q`-expansion of the modular form 0.

        EXAMPLES::

            sage: M = ModularForms(11,2)
            sage: M._q_expansion_zero()
            0
            sage: M._q_expansion_zero() == M._q_expansion_ring()(0)
            True
        """
        return self._q_expansion_ring()(0)

    def _q_expansion(self, element, prec):
        """
        Take an element of ``self`` (specified as a list, tuple, or vector),
        and return the corresponding `q`-expansion.

        EXAMPLES::

            sage: m = ModularForms(Gamma0(23),2); m
            Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(23) of weight 2 over Rational Field
            sage: m.basis()
            [q - q^3 - q^4 + O(q^6),
             q^2 - 2*q^3 - q^4 + 2*q^5 + O(q^6),
             1 + 12/11*q + 36/11*q^2 + 48/11*q^3 + 84/11*q^4 + 72/11*q^5 + O(q^6)]
            sage: m._q_expansion([1,2,0], 5)
            q + 2*q^2 - 5*q^3 - 3*q^4 + O(q^5)
        """
        return self.ambient_module()._q_expansion(element, prec)

    def __add__(self, right):
        """
        If ``self`` and ``right`` live inside the same ambient module, return the
        sum of the two spaces (as modules).

        EXAMPLES::

            sage: N = CuspForms(44,2) ; ls = [N.submodule([N(u) for u in x.q_expansion_basis(20)]) for x in N.modular_symbols().decomposition()]; ls
            [Modular Forms subspace of dimension 1 of Modular Forms space of dimension 9 for Congruence Subgroup Gamma0(44) of weight 2 over Rational Field,
            Modular Forms subspace of dimension 3 of Modular Forms space of dimension 9 for Congruence Subgroup Gamma0(44) of weight 2 over Rational Field]

        ::

            sage: N1 = ls[0] ; N2 = ls[1]
            sage: N1 + N2 # indirect doctest
            Modular Forms subspace of dimension 4 of Modular Forms space of dimension 9 for Congruence Subgroup Gamma0(44) of weight 2 over Rational Field
        """
        from sage.modular.modform.submodule import ModularFormsSubmodule
        if self.ambient_module() != right.ambient_module():
            raise ArithmeticError(("Sum of %s and %s not defined because " +
                                    "they do not lie in a common ambient space.") %
                                   (self, right))
        if self.is_ambient():
            return self
        if right.is_ambient():
            return right
        V = self.free_module() + right.free_module()
        return ModularFormsSubmodule(self.ambient_module(), V)

    def _has_natural_inclusion_map_to(self, right):
        """
        Return true if there is a natural inclusion map from modular forms
        in ``self`` to modular forms in right.

        INPUT:

        - ``self``, ``right`` -- spaces of modular forms

        OUTPUT: ``True`` if ``self`` embeds in ``right``, ``False`` otherwise

        TODO: Barring a few trivial cases, this only works in the case that
        right.is_ambient() returns True.

        EXAMPLES::

            sage: N = ModularForms(6,4) ; S = N.cuspidal_subspace()

        ::

            sage: N._has_natural_inclusion_map_to(S)
            Traceback (most recent call last):
            ...
            NotImplementedError

        ::

            sage: S._has_natural_inclusion_map_to(N)
            True

        ::

            sage: M = ModularForms(11,2)
            sage: N._has_natural_inclusion_map_to(M)
            False
        """
        if not right.group().is_subgroup(self.group()):
            return False
        if right.character() is None:
            # It's the full Gamma_1(N).
            return True
        if right.is_ambient():
            e = self.character()
            f = right.character()
            return f.parent()(e) == f
        raise NotImplementedError

    def _coerce_map_from_(self, from_par):
        """
        Code to make ModularFormsSpace work well with coercion framework.

        EXAMPLES::

            sage: M = ModularForms(22,2)
            sage: M.has_coerce_map_from(M.cuspidal_subspace())
            True
            sage: M.has_coerce_map_from(ModularForms(22,4))
            False
        """
        if isinstance(from_par, ModularFormsSpace):
            if from_par.ambient() == self:
                return True
            if self.is_ambient() and self.group().is_subgroup(from_par.group()) and self.weight() == from_par.weight():
                return True

        return False

    def _element_constructor_(self, x, check=True):
        """
        Try to coerce ``x`` into ``self``. If ``x`` is a vector of length
        ``self.dimension()``, interpret it as a list of coefficients for
        ``self.basis()`` and return that linear combination. If ``x`` is a power
        series, it tries to determine whether or not ``x`` lives in ``self``. If
        so, it returns ``x`` as an element of M, and throws an error if not.

        EXAMPLES::

            sage: M = ModularForms(13,4)
            sage: M.dimension()
            5

        ::

            sage: M([1,2,3,4,5])
            4 + 6*q + 47*q^2 + 143*q^3 + 358*q^4 + 630*q^5 + O(q^6)

        ::

            sage: M([1,3])
            Traceback (most recent call last):
            ...
            TypeError: entries must be a list of length 5

        ::

            sage: R = M._q_expansion_ring()
            sage: M(R([0,1,0,0,0,-2,-4,-2,-12]).add_bigoh(9))
            q - 2*q^5 + O(q^6)

        ::

            sage: M.set_precision(9)
            sage: M(R([0,1,0,0,0,-2,-4,-2,-12]).add_bigoh(9))
            q - 2*q^5 - 4*q^6 - 2*q^7 - 12*q^8 + O(q^9)

        Note that one only needs coefficients up to self.sturm_bound() to
        determine the form::

            sage: M(R([0,1,0,0,0,-2,-4,-2,-12]).add_bigoh(8))
            q - 2*q^5 - 4*q^6 - 2*q^7 - 12*q^8 + O(q^9)

        ::

            sage: M(R([0,1,1,0,0,0,-4,-2,-12]).add_bigoh(9))
            Traceback (most recent call last):
            ...
            ValueError: q-expansion does not correspond to a form in self

        ::

            sage: S = CuspForms(1,12) ; R = PowerSeriesRing(QQ,'q') ; q = R.0
            sage: f = q+O(q^2) ; S(f)
            q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6)
            sage: f = q+2*q^2+O(q^3) ; S(f)
            Traceback (most recent call last):
            ...
            ValueError: q-expansion does not correspond to a form in self
            sage: f = q-24*q^2+O(q^3) ; S(f)
            q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6)

        Test that :issue:`13156` is fixed::

            sage: R.<q> = QQ[[]]
            sage: ModularForms(1, 12)(R(0))
            0
            sage: ModularForms(1, 12)(R(1))
            Traceback (most recent call last):
            ...
            TypeError: unable to create modular form from exact nonzero polynomial

            sage: E = ModularForms(3,12).cuspidal_subspace()
            sage: f = E.gens()[0]
            sage: g = f - f
            sage: g.is_old()
            True

        Test that :issue:`32168` is fixed::

            sage: M0 = ModularForms(Gamma0(8), 10)
            sage: M1 = ModularForms(Gamma1(8), 10)
            sage: f = M0.0; g = M1.0
            sage: f + g
            2*q + O(q^6)
            sage: M1(f)
            q + O(q^6)

        ::

            sage: M = ModularForms(22,2) ; S = CuspForms(22,2)
            sage: sum(S.basis())
            q + q^2 - q^3 - 4*q^4 + q^5 + O(q^6)
            sage: sum(S.basis() + M.basis())
            1 + 3*q + 3*q^2 + 2*q^3 - 7*q^4 + 8*q^5 + O(q^6)
            sage: M.coerce(S.basis()[0])
            q - q^3 - 2*q^4 + q^5 + O(q^6)

        ::

            sage: M = ModularForms(Gamma0(22)) ; N = ModularForms(Gamma0(44))
            sage: M.basis()[0]
            q - q^3 - 2*q^4 + q^5 + O(q^6)
            sage: N(M.basis()[0])
            q - q^3 - 2*q^4 + q^5 + O(q^6)

        TESTS::

            sage: M = ModularForms(13, 4)
            sage: M(M([1, 2, 3, 4, 5]), check=True)
            4 + 6*q + 47*q^2 + 143*q^3 + 358*q^4 + 630*q^5 + O(q^6)
        """
        if isinstance(x, ModularFormElement):

            if not check:
                from copy import copy
                f = copy(x)
                f._set_parent(self)
                return f

            if x.parent().ambient() == self:
                return self(x.element())

            return self(x.q_expansion(self._q_expansion_module().degree()))

        if isinstance(x, PowerSeries):
            if x.prec() == PlusInfinity():
                if x == 0:
                    return self.element_class(self, self.free_module().zero())
                raise TypeError("unable to create modular form from exact nonzero polynomial")
            W = self._q_expansion_module()
            if W.degree() <= x.prec():
                try:
                    x_potential = W.coordinates(x.padded_list(W.degree()))
                except ArithmeticError:
                    raise ValueError("q-expansion does not correspond to a form in self")
                x_potential = self.free_module().linear_combination_of_basis(x_potential)
                x_potential = self.element_class(self, x_potential)
                for i in range(int(W.degree()), x.prec()):
                    if x_potential[i] != x[i]:
                        raise ValueError("q-expansion does not correspond to a form in self")
                return x_potential
            raise TypeError("q-expansion needed to at least precision %s" % W.degree())

        return self.element_class(self, self.free_module()(x, check))

    def _pushout_(self, other):
        r"""
        Implement the pushout of ``self`` and ``other``.

        INPUT:

        - ``other`` -- ``ModularFormSpace`` or a ``ModularFormRing``

        OUTPUT: if ``self`` and ``other`` have the same groups and base rings, then this method returns
        ``self`` if the weights of the two spaces are equal, otherwise it returns a ``ModularFormsRing``.


        TESTS::

            sage: e4 = ModularForms(1,4).0; e6 = ModularForms(1,6).0;
            sage: M = ModularFormsRing(1)
            sage: e4 + e6
            2 - 264*q - 14472*q^2 - 116256*q^3 - 515208*q^4 - 1545264*q^5 + O(q^6)
            sage: (e4 + e6).parent()
            Ring of Modular Forms for Modular Group SL(2,Z) over Rational Field
            sage: (M(e4)*e6).parent()
            Ring of Modular Forms for Modular Group SL(2,Z) over Rational Field
            sage: f = ModularForms(5,12).0
            sage: f+e4
            Traceback (most recent call last):
            ...
            TypeError: unsupported operand parent(s) for +: 'Modular Forms space of dimension 7 for Congruence Subgroup Gamma0(5) of weight 12 over Rational Field' and 'Modular Forms space of dimension 1 for Modular Group SL(2,Z) of weight 4 over Rational Field'
        """
        from .ring import ModularFormsRing
        if isinstance(other, ModularFormsSpace):
            if self.group() == other.group() and self.base_ring() == other.base_ring():
                if self.weight() == other.weight():
                    return self
                return ModularFormsRing(self.group(), base_ring=self.base_ring())
        if isinstance(other, ModularFormsRing) and other.has_coerce_map_from(self):
            return other

    def __richcmp__(self, x, op):
        """
        Compare ``self`` and ``x``.

        For spaces of modular forms, we order first by signature, then by
        dimension, and then by the ordering on the underlying free
        modules.

        EXAMPLES::

            sage: N = ModularForms(6,4) ; S = N.cuspidal_subspace()
            sage: S < N
            True
            sage: N > S
            True
            sage: N == N
            True
            sage: M = ModularForms(11,2)
            sage: N < M
            True
            sage: M > N
            True
        """
        from sage.modular.modform.constructor import canonical_parameters as params

        if self is x:
            return rich_to_bool(op, 0)
        if not isinstance(x, ModularFormsSpace):
            return NotImplemented

        left_ambient = self.ambient()
        right_ambient = x.ambient()
        lx = params(left_ambient.character(), left_ambient.level(),
                    left_ambient.weight(), left_ambient.base_ring())
        rx = params(right_ambient.character(), right_ambient.level(),
                    right_ambient.weight(), right_ambient.base_ring())
        if lx != rx:
            return richcmp_not_equal(lx, rx, op)
        if self.is_ambient() or x.is_ambient():
            return richcmp(self.dimension(), x.dimension(), op)
        return self.free_module()._echelon_matrix_richcmp(x.free_module(), op)

    def span_of_basis(self, B):
        """
        Take a set B of forms, and return the subspace of ``self`` with B as a
        basis.

        EXAMPLES::

            sage: N = ModularForms(6,4) ; N
            Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field

        ::

            sage: N.span_of_basis([N.basis()[0]])
            Modular Forms subspace of dimension 1 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field

        ::

            sage: N.span_of_basis([N.basis()[0], N.basis()[1]])
            Modular Forms subspace of dimension 2 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field

        ::

            sage: N.span_of_basis( N.basis() )
            Modular Forms subspace of dimension 5 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field
        """
        from .submodule import ModularFormsSubmoduleWithBasis
        W = self._q_expansion_module()
        F = self.free_module()
        prec = W.degree()
        C = [F.linear_combination_of_basis(W.coordinates(f.padded_list(prec))) for f in B]
        S = F.span_of_basis(C)
        return ModularFormsSubmoduleWithBasis(self.ambient(), S)

    span = span_of_basis

    def __submodule_from_subset_of_basis(self, x):
        """
        Return the submodule of ``self`` generated by the elements of x.

        EXAMPLES::

            sage: N = ModularForms(6,4)
            sage: N._ModularFormsSpace__submodule_from_subset_of_basis( [0,2] )
            Vector space of degree 5 and dimension 2 over Rational Field
            Basis matrix:
            [1 0 0 0 0]
            [0 0 1 0 0]
        """
        V = self.free_module()
        return V.submodule([V.gen(i) for i in x], check=False)

    def _compute_hecke_matrix_prime(self, p, prec=None):
        """
        Compute the matrix of the Hecke operator `T_p` acting on ``self``.

        EXAMPLES::

            sage: M = ModularForms(11,2)
            sage: M._compute_hecke_matrix_prime(2)
            [-2  0]
            [ 0  3]

        ::

            sage: M = ModularForms(11,2)
            sage: M2 = M.span([M.0 + M.1])
            sage: M2.hecke_matrix(2)
            Traceback (most recent call last):
            ...
            ArithmeticError: vector is not in free module
        """
        if prec is None:
            # Initial guess -- will increase if need be.
            # We add on a few dimensions, so we are likely to
            # detect non-invariant subspaces (if they accidentally occur).
            prec = p*self.dimension() + 8
        try:
            cur, _ = self.__q_expansion_basis
        except AttributeError:
            pass
        else:
            prec = max(prec, cur)
        B = self.q_expansion_basis(prec)
        eps = self.character()
        if eps is None:
            raise NotImplementedError
        try:
            return hecke_operator_on_qexp.hecke_operator_on_basis(B, p,
                       self.weight(), eps, already_echelonized=False)
        except ValueError:
            # Double the precision.
            return self._compute_hecke_matrix_prime(p, prec=2 * prec + 1)

    def _compute_hecke_matrix(self, n):
        """
        Compute the matrix of the Hecke operator `T_n` acting on ``self``.

        EXAMPLES::

            sage: M = ModularForms(11,2)
            sage: M._compute_hecke_matrix(6)
            [ 2  0]
            [ 0 12]

        ::

            sage: M = ModularForms(11,2)
            sage: M2 = M.span([M.0 + M.1])
            sage: M2.hecke_matrix(2)
            Traceback (most recent call last):
            ...
            ArithmeticError: vector is not in free module

        We check that :issue:`10450` is fixed::

            sage: M = CuspForms(Gamma1(22), 2).new_submodule()  # long time (3s on sage.math, 2011)
            sage: M.hecke_matrix(3)  # long time
            [ 0 -2  3  0]
            [ 0 -3  5 -1]
            [ 1 -1  0 -1]
            [ 0 -2  3 -1]
            sage: M.hecke_matrix(9)  # long time
            [ 3  3 -4 -4]
            [ 2  6 -9 -4]
            [ 0  3 -2 -1]
            [ 3  2 -7  0]
        """
        # For spaces with character, we calculate a basis of q-expansions and
        # use that. For Gamma1 and GammaH spaces, we would need to compute
        # diamond operators, which is quite slow; so we just compute on the
        # whole space and restrict.

        # TODO: If we know the subspace of the modular *symbols* space to which
        # this modular forms space corresponds, then that might give a quicker
        # way of doing this step.

        if hasattr(self, '_compute_q_expansion_basis') and self.character() is not None:
            return hecke.HeckeModule_generic._compute_hecke_matrix(self, n)

        # Try to avoid doing unnecessary computations where possible.
        if self.is_cuspidal():
            M = self.ambient().cuspidal_submodule().hecke_matrix(n).block_sum(zero_matrix(self.base_ring(), self.ambient().eisenstein_submodule().rank()))
        elif self.is_eisenstein():
            M = zero_matrix(self.base_ring(), self.ambient().cuspidal_submodule().rank()).block_sum(self.ambient().eisenstein_submodule().hecke_matrix(n))
        else:
            M = self.ambient().hecke_matrix(n)
        return M.restrict(self.free_module(), check=(gcd(n, self.level()) > 1))

    @cached_method
    def basis(self):
        """
        Return a basis for ``self``.

        EXAMPLES::

            sage: MM = ModularForms(11,2)
            sage: MM.basis()
            [q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6),
             1 + 12/5*q + 36/5*q^2 + 48/5*q^3 + 84/5*q^4 + 72/5*q^5 + O(q^6)]
        """
        return Sequence([self.element_class(self, x)
                         for x in self.free_module().basis()],
                        immutable=True, cr=True)

    def gen(self, n):
        """
        Return the `n`-th generator of ``self``.

        EXAMPLES::

            sage: N = ModularForms(6,4)
            sage: N.basis()
            [q - 2*q^2 - 3*q^3 + 4*q^4 + 6*q^5 + O(q^6),
             1 + O(q^6),
             q - 8*q^4 + 126*q^5 + O(q^6),
             q^2 + 9*q^4 + O(q^6),
             q^3 + O(q^6)]

        ::

            sage: N.gen(0)
            q - 2*q^2 - 3*q^3 + 4*q^4 + 6*q^5 + O(q^6)

        ::

            sage: N.gen(4)
            q^3 + O(q^6)

        ::

            sage: N.gen(5)
            Traceback (most recent call last):
            ...
            ValueError: Generator 5 not defined
        """
        try:
            return self.basis()[int(n)]
        except IndexError:
            raise ValueError("Generator %s not defined" % n)

    def gens(self) -> tuple:
        """
        Return a complete set of generators for ``self``.

        EXAMPLES::

            sage: N = ModularForms(6,4)
            sage: N.gens()
            (q - 2*q^2 - 3*q^3 + 4*q^4 + 6*q^5 + O(q^6),
             1 + O(q^6),
             q - 8*q^4 + 126*q^5 + O(q^6),
             q^2 + 9*q^4 + O(q^6),
             q^3 + O(q^6))
        """
        return tuple(self.basis())

    def sturm_bound(self, M=None):
        r"""
        For a space M of modular forms, this function returns an integer B
        such that two modular forms in either ``self`` or M are equal if and
        only if their `q`-expansions are equal to precision B (note that this
        is 1+ the usual Sturm bound, since `O(q^\mathrm{prec})` has
        precision ``prec``). If M is none, then M is set equal to ``self``.

        EXAMPLES::

            sage: S37=CuspForms(37,2)
            sage: S37.sturm_bound()
            8
            sage: M = ModularForms(11,2)
            sage: M.sturm_bound()
            3
            sage: ModularForms(Gamma1(15),2).sturm_bound()
            33

            sage: CuspForms(Gamma1(144), 3).sturm_bound()
            3457
            sage: CuspForms(DirichletGroup(144).1^2, 3).sturm_bound()
            73
            sage: CuspForms(Gamma0(144), 3).sturm_bound()
            73

        REFERENCES:

        - [Stu1987]_

        NOTE:

        Kevin Buzzard pointed out to me (William Stein) in Fall 2002 that
        the above bound is fine for Gamma1 with character, as one sees by
        taking a power of `f`. More precisely, if
        `f\cong 0\pmod{p}` for first `s` coefficients, then
        `f^r = 0 \pmod{p}` for first `s r` coefficients.
        Since the weight of `f^r` is
        `r \text{weight}(f)`, it follows that if
        `s \geq` the Sturm bound for `\Gamma_0` at
        weight(f), then `f^r` has valuation large enough to be
        forced to be `0` at `r\cdot` weight(f) by Sturm
        bound (which is valid if we choose `r` right). Thus
        `f \cong 0 \pmod{p}`. Conclusion: For `\Gamma_1`
        with fixed character, the Sturm bound is *exactly* the same as for
        `\Gamma_0`. A key point is that we are finding
        `\ZZ[\varepsilon]` generators for the Hecke algebra
        here, not `\ZZ`-generators. So if one wants
        generators for the Hecke algebra over `\ZZ`, this
        bound is wrong.

        This bound works over any base, even a finite field. There might be
        much better bounds over `\QQ`, or for comparing two
        eigenforms.
        """
        if M is not None:
            raise NotImplementedError
        if self.__sturm_bound is None:
            G = self.group()
            from sage.modular.arithgroup.congroup_gamma1 import Gamma1_class
            if isinstance(G, Gamma1_class) and self.character() is not None:
                from sage.modular.arithgroup.congroup_gamma0 import (
                    Gamma0_constructor as Gamma0,
                )
                G = Gamma0(self.level())
            # the +1 below is because O(q^prec) has precision prec.
            self.__sturm_bound = G.sturm_bound(self.weight())+1
        return self.__sturm_bound

    def cuspidal_submodule(self):
        """
        Return the cuspidal submodule of ``self``.

        EXAMPLES::

            sage: N = ModularForms(6,4) ; N
            Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field
            sage: N.eisenstein_subspace().dimension()
            4

        ::

            sage: N.cuspidal_submodule()
            Cuspidal subspace of dimension 1 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field

        ::

            sage: N.cuspidal_submodule().dimension()
            1

        We check that a bug noticed on :issue:`10450` is fixed::

            sage: M = ModularForms(6, 10)
            sage: W = M.span_of_basis(M.basis()[0:2])
            sage: W.cuspidal_submodule()
            Modular Forms subspace of dimension 2 of Modular Forms space of dimension 11 for Congruence Subgroup Gamma0(6) of weight 10 over Rational Field
        """
        try:
            if self.__is_cuspidal:
                return self
        except AttributeError:
            pass
        if self.is_ambient():
            raise NotImplementedError("ambient modular forms spaces must override cuspidal_submodule")
        C = self.ambient_module().cuspidal_submodule()
        S = self.intersection(C)
        if S.dimension() < self.dimension():
            self.__is_cuspidal = False
        else:
            assert S.dimension() == self.dimension()
            self.__is_cuspidal = True
        S.is_eisenstein.set_cache(S.dimension() == 0)
        S.__is_cuspidal = True
        return S

    def cuspidal_subspace(self):
        """
        Synonym for cuspidal_submodule.

        EXAMPLES::

            sage: N = ModularForms(6,4) ; N
            Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field
            sage: N.eisenstein_subspace().dimension()
            4

        ::

            sage: N.cuspidal_subspace()
            Cuspidal subspace of dimension 1 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field

        ::

            sage: N.cuspidal_submodule().dimension()
            1
        """
        return self.cuspidal_submodule()

    def is_cuspidal(self) -> bool:
        r"""
        Return ``True`` if this space is cuspidal.

        EXAMPLES::

            sage: M = ModularForms(Gamma0(11), 2).new_submodule()
            sage: M.is_cuspidal()
            False
            sage: M.cuspidal_submodule().is_cuspidal()
            True
        """
        return (self.cuspidal_submodule() == self)

    @cached_method
    def is_eisenstein(self) -> bool:
        r"""
        Return ``True`` if this space is Eisenstein.

        EXAMPLES::

            sage: M = ModularForms(Gamma0(11), 2).new_submodule()
            sage: M.is_eisenstein()
            False
            sage: M.eisenstein_submodule().is_eisenstein()
            True
        """
        return (self.eisenstein_submodule() == self)

    def new_submodule(self, p=None):
        """
        Return the new submodule of ``self``.

        If `p` is specified, return the `p`-new submodule of ``self``.

        .. NOTE::

            This function should be overridden by all derived classes.

        EXAMPLES::

            sage: # needs sage.rings.number_field
            sage: M = sage.modular.modform.space.ModularFormsSpace(Gamma0(11), 2, DirichletGroup(1)[0], base_ring=QQ); M.new_submodule()
            Traceback (most recent call last):
            ...
            NotImplementedError: computation of new submodule not yet implemented
        """
        raise NotImplementedError("computation of new submodule not yet implemented")

    def new_subspace(self, p=None):
        """
        Synonym for new_submodule.

        EXAMPLES::

            sage: # needs sage.rings.number_field
            sage: M = sage.modular.modform.space.ModularFormsSpace(Gamma0(11), 2, DirichletGroup(1)[0], base_ring=QQ); M.new_subspace()
            Traceback (most recent call last):
            ...
            NotImplementedError: computation of new submodule not yet implemented
        """
        return self.new_submodule(p)

    def eisenstein_series(self):
        """
        Compute the Eisenstein series associated to this space.

        .. NOTE::

           This function should be overridden by all derived classes.

        EXAMPLES::

            sage: # needs sage.rings.number_field
            sage: M = sage.modular.modform.space.ModularFormsSpace(Gamma0(11), 2, DirichletGroup(1)[0], base_ring=QQ); M.eisenstein_series()
            Traceback (most recent call last):
            ...
            NotImplementedError: computation of Eisenstein series in this space not yet implemented
        """
        raise NotImplementedError("computation of Eisenstein series in this space not yet implemented")

    def decomposition(self):
        """
        This function returns a list of submodules `V(f_i,t)`
        corresponding to newforms `f_i` of some level dividing the
        level of self, such that the direct sum of the submodules equals
        self, if possible. The space `V(f_i,t)` is the image under
        `g(q)` maps to `g(q^t)` of the intersection with
        `R[[q]]` of the space spanned by the conjugates of
        `f_i`, where `R` is the base ring of ``self``.

        TODO: Implement this function.

        EXAMPLES::

            sage: M = ModularForms(11,2); M.decomposition()
            Traceback (most recent call last):
            ...
            NotImplementedError
        """
        raise NotImplementedError

    def newforms(self, names=None):
        """
        Return all newforms in the cuspidal subspace of ``self``.

        EXAMPLES::

            sage: CuspForms(18,4).newforms()
            [q + 2*q^2 + 4*q^4 - 6*q^5 + O(q^6)]
            sage: CuspForms(32,4).newforms()
            [q - 8*q^3 - 10*q^5 + O(q^6), q + 22*q^5 + O(q^6), q + 8*q^3 - 10*q^5 + O(q^6)]
            sage: CuspForms(23).newforms('b')
            [q + b0*q^2 + (-2*b0 - 1)*q^3 + (-b0 - 1)*q^4 + 2*b0*q^5 + O(q^6)]
            sage: CuspForms(23).newforms()
            Traceback (most recent call last):
            ...
            ValueError: Please specify a name to be used when generating names for generators of Hecke eigenvalue fields corresponding to the newforms.
        """
        M = self.modular_symbols(sign=1)
        factors = M.cuspidal_subspace().new_subspace().decomposition()
        large_dims = [X.dimension() for X in factors if X.dimension() != 1]
        if large_dims and names is None:
            raise ValueError("Please specify a name to be used when generating names for generators of Hecke eigenvalue fields corresponding to the newforms.")
        elif names is None:
            # In this case, we don't need a variable name, so insert
            # something to get passed along below
            names = 'a'
        return [Newform(self, factors[i], names=names + str(i))
                for i in range(len(factors))]

    @cached_method
    def eisenstein_submodule(self):
        """
        Return the Eisenstein submodule for this space of modular forms.

        EXAMPLES::

            sage: M = ModularForms(11,2)
            sage: M.eisenstein_submodule()
            Eisenstein subspace of dimension 1 of Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field

        We check that a bug noticed on :issue:`10450` is fixed::

            sage: M = ModularForms(6, 10)
            sage: W = M.span_of_basis(M.basis()[0:2])
            sage: W.eisenstein_submodule()
            Modular Forms subspace of dimension 0 of Modular Forms space of dimension 11 for Congruence Subgroup Gamma0(6) of weight 10 over Rational Field
        """
        if self.is_eisenstein.cache is True:
            return self

        if self.is_ambient():
            raise NotImplementedError("ambient modular forms spaces must override eisenstein_submodule")
        A = self.ambient_module().eisenstein_submodule()
        E = self.intersection(A)
        if E.dimension() < self.dimension():
            self.is_eisenstein.set_cache(False)
        else:
            assert E.dimension() == self.dimension()
            self.is_eisenstein.set_cache(True)
        E.__is_cuspidal = (E.dimension() == 0)
        E.is_eisenstein.set_cache(True)
        return E

    def eisenstein_subspace(self):
        """
        Synonym for :meth:`eisenstein_submodule`.

        EXAMPLES::

            sage: M = ModularForms(11,2)
            sage: M.eisenstein_subspace()
            Eisenstein subspace of dimension 1 of Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field
        """
        return self.eisenstein_submodule()

    def embedded_submodule(self):
        """
        Return the underlying module of ``self``.

        EXAMPLES::

            sage: N = ModularForms(6,4)
            sage: N.dimension()
            5

        ::

            sage: N.embedded_submodule()
            Vector space of dimension 5 over Rational Field
        """
        return self.free_module()

# intersect method commented out since it is a duplicate of the intersection method in sage.modular.hecke.submodule
# -- David Loeffler, 2009-04-30
#
#    def intersect(self, right):
#        """
#        If self and right live in the same ambient module, return the
#        intersection of self and right (as submodules).
#
#        EXAMPLES::
#
#            sage: N = ModularForms(6,4); S = N.cuspidal_subspace()
#
#        ::
#
#            sage: N.intersect(S)
#            Modular Forms subspace of dimension 1 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field
#
#        ::
#
#            sage: S.intersect(N)
#            Modular Forms subspace of dimension 1 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field
#
#        ::
#
#            sage: S.intersect(N.eisenstein_subspace())
#            Modular Forms subspace of dimension 0 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field
#        """
#        from sage.modular.modform.all import ModularForms
#        if self.ambient_module() != right.ambient_module():
#            raise ArithmeticError("Intersection of %s and %s not defined." %
#                                  (self, right))
#        V = self.embedded_submodule().intersection(right.embedded_submodule())
#        return ModularForms(self.ambient_module(),V)
#        return self.span([ self(b) for b in V.basis() ])

#    def _key(self):
#        if self.is_ambient():
#            return self.__key
#        return self.__ambient

    def level(self):
        """
        Return the level of ``self``.

        EXAMPLES::

            sage: M = ModularForms(47,3)
            sage: M.level()
            47
        """
        return self.group().level()

    def modular_symbols(self, sign=0):
        """
        Return the space of modular symbols corresponding to ``self`` with the
        given sign.

        .. NOTE::

            This function should be overridden by all derived classes.

        EXAMPLES::

            sage: # needs sage.rings.number_field
            sage: M = sage.modular.modform.space.ModularFormsSpace(Gamma0(11), 2, DirichletGroup(1)[0], base_ring=QQ); M.modular_symbols()
            Traceback (most recent call last):
            ...
            NotImplementedError: computation of associated modular symbols space not yet implemented
        """
        raise NotImplementedError("computation of associated modular symbols space not yet implemented")

    def find_in_space(self, f, forms=None, prec=None, indep=True):
        """
        INPUT:

        - ``f`` -- a modular form or power series

        - ``forms`` -- (default: ``None``) a specific list of
          modular forms or `q`-expansions

        - ``prec`` -- if forms are given, compute with them to
          the given precision

        - ``indep`` -- boolean (default: ``True``); whether the given list
          of forms are assumed to form a basis

        OUTPUT: list of numbers that give f as a linear combination of
        the basis for this space or of the given forms if
        independent=True.

        .. NOTE::

           If the list of forms is given, they do *not* have to be in
           ``self``.

        EXAMPLES::

            sage: M = ModularForms(11,2)
            sage: N = ModularForms(10,2)
            sage: M.find_in_space( M.basis()[0] )
            [1, 0]

        ::

            sage: M.find_in_space( N.basis()[0], forms=N.basis() )
            [1, 0, 0]

        ::

            sage: M.find_in_space( N.basis()[0] )
            Traceback (most recent call last):
            ...
            ArithmeticError: vector is not in free module
        """
        if forms is None or (forms == []):
            B = self._q_expansion_module()
            V = B.ambient_module()
            n = B.degree()
        else:
            if not isinstance(forms, (list, tuple)):
                raise TypeError("forms must be a list or tuple")
            if prec is None:
                n = forms[0].parent().prec()
            else:
                n = prec
            V = self.base_ring()**n
            w = [V(g.padded_list(n)) for g in forms]
            if indep:
                B = V.span_of_basis(w)
            else:
                B = V.span(w)
        if isinstance(f, PowerSeries) and f.prec() < n:
            raise ValueError("you need at least %s terms of precision" % n)
        x = V(f.padded_list(n))
        return B.coordinates(x)


def contains_each(V, B):
    """
    Determine whether or not V contains every element of B. Used here
    for linear algebra, but works very generally.

    EXAMPLES::

        sage: contains_each = sage.modular.modform.space.contains_each
        sage: contains_each( range(20), prime_range(20) )
        True
        sage: contains_each( range(20), range(30) )
        False
    """
    return all(b in V for b in B)
