def graded_dimension(self, k):
        r"""
        Return the dimension of the ``k``-th graded piece of ``self``.

        The `k`-th graded part of a free Lie algebra on `n` generators
        has dimension

        .. MATH::

            \frac{1}{k} \sum_{d \mid k} \mu(d) n^{k/d},

        where `\mu` is the Mobius function.

        REFERENCES:

        [MKO1998]_

        EXAMPLES::

            sage: L = LieAlgebra(QQ, 'x', 3)
            sage: H = L.Hall()
            sage: [H.graded_dimension(i) for i in range(1, 11)]
            [3, 3, 8, 18, 48, 116, 312, 810, 2184, 5880]
            sage: H.graded_dimension(0)
            0
        """
        if k == 0:
            return 0
        from sage.arith.all import moebius
        s = len(self.lie_algebra_generators())
        k = ZZ(k)  # Make sure we have something that is in ZZ
        return sum(moebius(d) * s**(k // d) for d in k.divisors()) // k
    def graded_dimension(self, k):
        r"""
        Return the dimension of the ``k``-th graded piece of ``self``.

        The `k`-th graded part of a free Lie algebra on `n` generators
        has dimension

        .. MATH::

            \frac{1}{k} \sum_{d \mid k} \mu(d) n^{k/d},

        where `\mu` is the Mobius function.

        REFERENCES:

        [MKO1998]_

        EXAMPLES::

            sage: L = LieAlgebra(QQ, 'x', 3)
            sage: H = L.Hall()
            sage: [H.graded_dimension(i) for i in range(1, 11)]
            [3, 3, 8, 18, 48, 116, 312, 810, 2184, 5880]
            sage: H.graded_dimension(0)
            0
        """
        if k == 0:
            return 0
        from sage.arith.all import moebius
        s = len(self.lie_algebra_generators())
        k = ZZ(k) # Make sure we have something that is in ZZ
        return sum(moebius(d) * s**(k // d) for d in k.divisors()) // k
Exemple #3
0
    def _b_power_k(self, k):
        r"""
        An expression involving Moebius inversion in the powersum generators.

        For a positive value of ``k``, this expression is

        .. MATH::

            \frac{1}{k} \sum_{d|k} \mu(d/k) p_d.

        INPUT:

        - ``k`` -- a positive integer

        OUTPUT:

        - an expression in the powersum basis of the symmetric functions

        EXAMPLES::

            sage: st = SymmetricFunctions(QQ).st()
            sage: st._b_power_k(1)
            p[1]
            sage: st._b_power_k(2)
            -1/2*p[1] + 1/2*p[2]
            sage: st._b_power_k(6)
            1/6*p[1] - 1/6*p[2] - 1/6*p[3] + 1/6*p[6]

        """
        if k == 1:
            return self._p([1])
        if k > 0:
            return ~k * self._p.linear_combination(
                (self._p([d]), moebius(k // d)) for d in divisors(k))
Exemple #4
0
    def cardinality(self):
        """
        Returns the number of Lyndon words with the evaluation e.

        EXAMPLES::

            sage: LyndonWords([]).cardinality()
            0
            sage: LyndonWords([2,2]).cardinality()
            1
            sage: LyndonWords([2,3,2]).cardinality()
            30

        Check to make sure that the count matches up with the number of
        Lyndon words generated.

        ::

            sage: comps = [[],[2,2],[3,2,7],[4,2]] + Compositions(4).list()
            sage: lws = [LyndonWords(comp) for comp in comps]
            sage: all(lw.cardinality() == len(lw.list()) for lw in lws)
            True
        """
        evaluation = self._e
        le = builtins.list(evaluation)
        if len(evaluation) == 0:
            return 0

        n = sum(evaluation)

        return sum([
            moebius(j) * factorial(n / j) /
            prod([factorial(ni / j) for ni in evaluation])
            for j in divisors(gcd(le))
        ]) / n
Exemple #5
0
    def _b_power_k(self, k):
        r"""
        An expression involving Moebius inversion in the powersum generators.

        For a positive value of ``k``, this expression is

        .. MATH::

            \frac{1}{k} \sum_{d|k} \mu(d/k) p_d.

        INPUT:

        - ``k`` -- a positive integer

        OUTPUT:

        - an expression in the powersum basis of the symmetric functions

        EXAMPLES::

            sage: st = SymmetricFunctions(QQ).st()
            sage: st._b_power_k(1)
            p[1]
            sage: st._b_power_k(2)
            -1/2*p[1] + 1/2*p[2]
            sage: st._b_power_k(6)
            1/6*p[1] - 1/6*p[2] - 1/6*p[3] + 1/6*p[6]

        """
        if k == 1:
            return self._p([1])
        if k > 0:
            return ~k * self._p.linear_combination((self._p([d]),moebius(k//d))
                                    for d in divisors(k))
Exemple #6
0
    def _cycle_type(self, s):
        """
        EXAMPLES::

            sage: cis = species.PartitionSpecies().cycle_index_series()
            sage: [cis._cycle_type(p) for p in Partitions(3)]
            [[3, 1, 1], [2, 1, 1, 1], [1, 1, 1, 1, 1]]
            sage: cis = species.PermutationSpecies().cycle_index_series()
            sage: [cis._cycle_type(p) for p in Partitions(3)]
            [[3, 1, 1, 1], [2, 2, 1, 1], [1, 1, 1, 1, 1, 1]]
            sage: cis = species.SetSpecies().cycle_index_series()
            sage: [cis._cycle_type(p) for p in Partitions(3)]
            [[1], [1], [1]]
        """
        if s == []:
            return self._card(0)
        res = []
        for k in range(1, self._upper_bound_for_longest_cycle(s)+1):
            e = 0
            for d in divisors(k):
                m = moebius(d)
                if m == 0:
                    continue
                u = s.power(k/d)
                e += m*self.count(u)
            res.extend([k]*int(e/k))
        res.reverse()
        return Partition(res)
Exemple #7
0
    def _cycle_type(self, s):
        """
        EXAMPLES::

            sage: cis = species.PartitionSpecies().cycle_index_series()
            sage: [cis._cycle_type(p) for p in Partitions(3)]
            [[3, 1, 1], [2, 1, 1, 1], [1, 1, 1, 1, 1]]
            sage: cis = species.PermutationSpecies().cycle_index_series()
            sage: [cis._cycle_type(p) for p in Partitions(3)]
            [[3, 1, 1, 1], [2, 2, 1, 1], [1, 1, 1, 1, 1, 1]]
            sage: cis = species.SetSpecies().cycle_index_series()
            sage: [cis._cycle_type(p) for p in Partitions(3)]
            [[1], [1], [1]]
        """
        if s == []:
            return self._card(0)
        res = []
        for k in range(1, self._upper_bound_for_longest_cycle(s)+1):
            e = 0
            for d in divisors(k):
                m = moebius(d)
                if m == 0:
                    continue
                u = s.power(k/d)
                e += m*self.count(u)
            res.extend([k]*int(e/k))
        res.reverse()
        return Partition(res)
Exemple #8
0
    def cardinality(self):
        """
        Returns the number of Lyndon words with the evaluation e.

        EXAMPLES::

            sage: LyndonWords([]).cardinality()
            0
            sage: LyndonWords([2,2]).cardinality()
            1
            sage: LyndonWords([2,3,2]).cardinality()
            30

        Check to make sure that the count matches up with the number of
        Lyndon words generated.

        ::

            sage: comps = [[],[2,2],[3,2,7],[4,2]] + Compositions(4).list()
            sage: lws = [LyndonWords(comp) for comp in comps]
            sage: all(lw.cardinality() == len(lw.list()) for lw in lws)
            True
        """
        evaluation = self._e
        le = builtins.list(evaluation)
        if len(evaluation) == 0:
            return 0

        n = sum(evaluation)

        return sum([moebius(j)*factorial(n/j) / prod([factorial(ni/j) for ni in evaluation]) for j in divisors(gcd(le))])/n
Exemple #9
0
    def cardinality(self):
        """
        Return the number of Lyndon words with the evaluation e.

        EXAMPLES::

            sage: LyndonWords([]).cardinality()
            0
            sage: LyndonWords([2,2]).cardinality()
            1
            sage: LyndonWords([2,3,2]).cardinality()
            30

        Check to make sure that the count matches up with the number of
        Lyndon words generated::

            sage: comps = [[],[2,2],[3,2,7],[4,2]] + Compositions(4).list()
            sage: lws = [LyndonWords(comp) for comp in comps]
            sage: all(lw.cardinality() == len(lw.list()) for lw in lws)
            True
        """
        evaluation = self._e
        le = list(evaluation)
        if not evaluation:
            return Integer(0)
        n = sum(evaluation)
        return sum(
            moebius(j) * multinomial([ni // j for ni in evaluation])
            for j in divisors(gcd(le))) // n
Exemple #10
0
    def cardinality(self):
        """
        TESTS::

            sage: [ LyndonWords(3,i).cardinality() for i in range(1, 11) ]
            [3, 3, 8, 18, 48, 116, 312, 810, 2184, 5880]
        """
        if self._k == 0:
            return Integer(1)
        else:
            s = Integer(0)
            for d in divisors(self._k):
                s += moebius(d)*(self._n**(self._k/d))
        return s/self._k
Exemple #11
0
    def cardinality(self):
        """
        TESTS::

            sage: [ LyndonWords(3,i).cardinality() for i in range(1, 11) ]
            [3, 3, 8, 18, 48, 116, 312, 810, 2184, 5880]
        """
        if self._k == 0:
            return Integer(1)
        else:
            s = Integer(0)
            for d in divisors(self._k):
                s += moebius(d) * (self._n**(self._k / d))
        return s / self._k
    def dimension_new_cusp_forms(self, k=2, p=0):
        r"""
        Return the dimension of the space of new (or `p`-new)
        weight `k` cusp forms for this congruence subgroup.

        INPUT:

        - `k` -- an integer (default: 2), the weight. Not fully
          implemented for `k = 1`.
        - `p` -- integer (default: 0); if nonzero, compute the
          `p`-new subspace.

        OUTPUT: Integer

        ALGORITHM:

        This comes from the formula given in Theorem 1 of
        http://www.math.ubc.ca/~gerg/papers/downloads/DSCFN.pdf

        EXAMPLES::

            sage: Gamma0(11000).dimension_new_cusp_forms()
            240
            sage: Gamma0(11000).dimension_new_cusp_forms(k=1)
            0
            sage: Gamma0(22).dimension_new_cusp_forms(k=4)
            3
            sage: Gamma0(389).dimension_new_cusp_forms(k=2,p=17)
            32

        TESTS::

             sage: L = [1213, 1331, 2169, 2583, 2662, 2745, 3208,
             ....:      3232, 3465, 3608, 4040, 4302, 4338]
             sage: all(Gamma0(N).dimension_new_cusp_forms(2)==100 for N in L)
             True
        """
        from sage.arith.all import moebius
        from sage.functions.other import floor

        N = self.level()
        k = ZZ(k)

        if not (p == 0 or N % p):
            return (self.dimension_cusp_forms(k) -
                    2 * self.restrict(N // p).dimension_new_cusp_forms(k))

        if k < 2 or k % 2:
            return ZZ.zero()

        factors = list(N.factor())

        def s0(q, a):
            # function s_0^#
            if a == 1:
                return 1 - 1 / q
            elif a == 2:
                return 1 - 1 / q - 1 / q**2
            else:
                return (1 - 1 / q) * (1 - 1 / q**2)

        def vinf(q, a):
            # function v_oo^#
            if a % 2:
                return 0
            elif a == 2:
                return q - 2
            else:
                return q**(a / 2 - 2) * (q - 1)**2

        def v2(q, a):
            # function v_2^#
            if q % 4 == 1:
                if a == 2:
                    return -1
                else:
                    return 0
            elif q % 4 == 3:
                if a == 1:
                    return -2
                elif a == 2:
                    return 1
                else:
                    return 0
            elif a in (1, 2):
                return -1
            elif a == 3:
                return 1
            else:
                return 0

        def v3(q, a):
            # function v_3^#
            if q % 3 == 1:
                if a == 2:
                    return -1
                else:
                    return 0
            elif q % 3 == 2:
                if a == 1:
                    return -2
                elif a == 2:
                    return 1
                else:
                    return 0
            elif a in (1, 2):
                return -1
            elif a == 3:
                return 1
            else:
                return 0

        res = (k - 1) / 12 * N * prod(s0(q, a) for q, a in factors)
        res -= prod(vinf(q, a) for q, a in factors) / ZZ(2)
        res += (
            (1 - k) / 4 + floor(k / 4)) * prod(v2(q, a) for q, a in factors)
        res += (
            (1 - k) / 3 + floor(k / 3)) * prod(v3(q, a) for q, a in factors)
        if k == 2:
            res += moebius(N)
        return res
Exemple #13
0
    def dimension_eis(self, k=2, eps=None, algorithm="CohenOesterle"):
        r"""
        Return the dimension of the space of Eisenstein series forms for self,
        or the dimension of the subspace corresponding to the given character
        if one is supplied.

        INPUT:

        - ``k`` - an integer (default: 2), the weight.

        - ``eps`` - either None or a Dirichlet character modulo N, where N is
          the level of this group. If this is None, then the dimension of the
          whole space is returned; otherwise, the dimension of the subspace of
          Eisenstein series of character eps.

        - ``algorithm`` -- either "CohenOesterle" (the default) or "Quer". This
          specifies the method to use in the case of nontrivial character:
          either the Cohen--Oesterle formula as described in Stein's book, or
          by Möbius inversion using the subgroups GammaH (a method due to
          Jordi Quer).

        AUTHORS:

        - William Stein - Cohen--Oesterle algorithm

        - Jordi Quer - algorithm based on GammaH subgroups

        - David Loeffler (2009) - code refactoring

        EXAMPLES:

        The following two computations use different algorithms: ::

            sage: [Gamma1(36).dimension_eis(1,eps) for eps in DirichletGroup(36)]
            [0, 4, 3, 0, 0, 2, 6, 0, 0, 2, 3, 0]
            sage: [Gamma1(36).dimension_eis(1,eps,algorithm="Quer") for eps in DirichletGroup(36)]
            [0, 4, 3, 0, 0, 2, 6, 0, 0, 2, 3, 0]

        So do these: ::

            sage: [Gamma1(48).dimension_eis(3,eps) for eps in DirichletGroup(48)]
            [0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0]
            sage: [Gamma1(48).dimension_eis(3,eps,algorithm="Quer") for eps in DirichletGroup(48)]
            [0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0]
        """
        from all import Gamma0

        # first deal with special cases

        if eps is None:
            return GammaH_class.dimension_eis(self, k)

        N = self.level()
        K = eps.base_ring()
        eps = DirichletGroup(N, K)(eps)

        if eps.is_trivial():
            return Gamma0(N).dimension_eis(k)

        # Note case of k = 0 and trivial character already dealt with separately, so k <= 0 here is valid:
        if (k <= 0) or ((k % 2) == 1 and eps.is_even()) or ((k%2) == 0 and eps.is_odd()):
            return ZZ(0)

        if algorithm == "Quer":
            n = eps.order()
            dim = ZZ(0)
            for d in n.divisors():
                G = GammaH_constructor(N,(eps**d).kernel())
                dim = dim + moebius(d)*G.dimension_eis(k)
            return dim//phi(n)

        elif algorithm == "CohenOesterle":
            from sage.modular.dims import CohenOesterle
            j = 2-k
            # We use the Cohen-Oesterle formula in a subtle way to
            # compute dim M_k(N,eps) (see Ch. 6 of William Stein's book on
            # computing with modular forms).
            alpha = -ZZ( K(Gamma0(N).index()*(j-1)/ZZ(12)) + CohenOesterle(eps,j) )
            if k == 1:
                return alpha
            else:
                return alpha - self.dimension_cusp_forms(k, eps)

        else: #algorithm not in ["CohenOesterle", "Quer"]:
            raise ValueError("Unrecognised algorithm in dimension_eis")
Exemple #14
0
    def dimension_cusp_forms(self, k=2, eps=None, algorithm="CohenOesterle"):
        r"""
        Return the dimension of the space of cusp forms for self, or the
        dimension of the subspace corresponding to the given character if one
        is supplied.

        INPUT:

        - ``k`` - an integer (default: 2), the weight.

        - ``eps`` - either None or a Dirichlet character modulo N, where N is
          the level of this group. If this is None, then the dimension of the
          whole space is returned; otherwise, the dimension of the subspace of
          forms of character eps.

        - ``algorithm`` -- either "CohenOesterle" (the default) or "Quer". This
          specifies the method to use in the case of nontrivial character:
          either the Cohen--Oesterle formula as described in Stein's book, or
          by Möbius inversion using the subgroups GammaH (a method due to
          Jordi Quer).

        EXAMPLES:

        We compute the same dimension in two different ways ::

            sage: K = CyclotomicField(3)
            sage: eps = DirichletGroup(7*43,K).0^2
            sage: G = Gamma1(7*43)

        Via Cohen--Oesterle: ::

            sage: Gamma1(7*43).dimension_cusp_forms(2, eps)
            28

        Via Quer's method: ::

            sage: Gamma1(7*43).dimension_cusp_forms(2, eps, algorithm="Quer")
            28

        Some more examples: ::

            sage: G.<eps> = DirichletGroup(9)
            sage: [Gamma1(9).dimension_cusp_forms(k, eps) for k in [1..10]]
            [0, 0, 1, 0, 3, 0, 5, 0, 7, 0]
            sage: [Gamma1(9).dimension_cusp_forms(k, eps^2) for k in [1..10]]
            [0, 0, 0, 2, 0, 4, 0, 6, 0, 8]
        """
        from all import Gamma0

        # first deal with special cases

        if eps is None:
            return GammaH_class.dimension_cusp_forms(self, k)

        N = self.level()
        K = eps.base_ring()
        eps = DirichletGroup(N, K)(eps)

        if K.characteristic() != 0:
            raise NotImplementedError('dimension_cusp_forms() is only implemented for rings of characteristic 0')

        if eps.is_trivial():
            return Gamma0(N).dimension_cusp_forms(k)

        if (k <= 0) or ((k % 2) == 1 and eps.is_even()) or ((k%2) == 0 and eps.is_odd()):
            return ZZ(0)

        if k == 1:
            try:
                n = self.dimension_cusp_forms(1)
                if n == 0:
                    return ZZ(0)
                else: # never happens at present
                    raise NotImplementedError("Computations of dimensions of spaces of weight 1 cusp forms not implemented at present")
            except NotImplementedError:
                raise

        # now the main part

        if algorithm == "Quer":
            n = eps.order()
            dim = ZZ(0)
            for d in n.divisors():
                G = GammaH_constructor(N,(eps**d).kernel())
                dim = dim + moebius(d)*G.dimension_cusp_forms(k)
            return dim//phi(n)

        elif algorithm == "CohenOesterle":
            from sage.modular.dims import CohenOesterle
            return ZZ( K(Gamma0(N).index() * (k-1)/ZZ(12)) + CohenOesterle(eps,k) )

        else: #algorithm not in ["CohenOesterle", "Quer"]:
            raise ValueError("Unrecognised algorithm in dimension_cusp_forms")
Exemple #15
0
    def dimension_cusp_forms(self, k=2, eps=None, algorithm="CohenOesterle"):
        r"""
        Return the dimension of the space of cusp forms for self, or the
        dimension of the subspace corresponding to the given character if one
        is supplied.

        INPUT:

        - ``k`` - an integer (default: 2), the weight.

        - ``eps`` - either None or a Dirichlet character modulo N, where N is
          the level of this group. If this is None, then the dimension of the
          whole space is returned; otherwise, the dimension of the subspace of
          forms of character eps.

        - ``algorithm`` -- either "CohenOesterle" (the default) or "Quer". This
          specifies the method to use in the case of nontrivial character:
          either the Cohen--Oesterle formula as described in Stein's book, or
          by Möbius inversion using the subgroups GammaH (a method due to Jordi
          Quer). Ignored for weight 1.

        EXAMPLES:

        We compute the same dimension in two different ways ::

            sage: K = CyclotomicField(3)
            sage: eps = DirichletGroup(7*43,K).0^2
            sage: G = Gamma1(7*43)

        Via Cohen--Oesterle::

            sage: Gamma1(7*43).dimension_cusp_forms(2, eps)
            28

        Via Quer's method::

            sage: Gamma1(7*43).dimension_cusp_forms(2, eps, algorithm="Quer")
            28

        Some more examples::

            sage: G.<eps> = DirichletGroup(9)
            sage: [Gamma1(9).dimension_cusp_forms(k, eps) for k in [1..10]]
            [0, 0, 1, 0, 3, 0, 5, 0, 7, 0]
            sage: [Gamma1(9).dimension_cusp_forms(k, eps^2) for k in [1..10]]
            [0, 0, 0, 2, 0, 4, 0, 6, 0, 8]

        In weight 1, we can sometimes rule out cusp forms existing via
        Riemann-Roch, but if this does not work, we trigger computation of the
        cusp forms space via Schaeffer's algorithm::

            sage: chi = [u for u in DirichletGroup(40) if u(-1) == -1 and u(21) == 1][0]
            sage: Gamma1(40).dimension_cusp_forms(1, chi)
            0
            sage: G = DirichletGroup(57); chi = (G.0) * (G.1)^6
            sage: Gamma1(57).dimension_cusp_forms(1, chi)
            1
        """
        from .all import Gamma0

        # first deal with special cases

        if eps is None:
            return GammaH_class.dimension_cusp_forms(self, k)

        N = self.level()
        K = eps.base_ring()
        eps = DirichletGroup(N, K)(eps)

        if K.characteristic() != 0:
            raise NotImplementedError(
                'dimension_cusp_forms() is only implemented for rings of characteristic 0'
            )

        if eps.is_trivial():
            return Gamma0(N).dimension_cusp_forms(k)

        if (k <= 0) or ((k % 2) == 1 and eps.is_even()) or ((k % 2) == 0
                                                            and eps.is_odd()):
            return ZZ(0)

        if k == 1:
            from sage.modular.modform.weight1 import dimension_wt1_cusp_forms
            return dimension_wt1_cusp_forms(eps)

        # now the main part

        if algorithm == "Quer":
            n = eps.order()
            dim = ZZ(0)
            for d in n.divisors():
                G = GammaH_constructor(N, (eps**d).kernel())
                dim = dim + moebius(d) * G.dimension_cusp_forms(k)
            return dim // phi(n)

        elif algorithm == "CohenOesterle":
            from sage.modular.dims import CohenOesterle
            return ZZ(
                K(Gamma0(N).index() * (k - 1) / ZZ(12)) +
                CohenOesterle(eps, k))

        else:  #algorithm not in ["CohenOesterle", "Quer"]:
            raise ValueError("Unrecognised algorithm in dimension_cusp_forms")
Exemple #16
0
    def dimension_eis(self, k=2, eps=None, algorithm="CohenOesterle"):
        r"""
        Return the dimension of the space of Eisenstein series forms for self,
        or the dimension of the subspace corresponding to the given character
        if one is supplied.

        INPUT:

        - ``k`` - an integer (default: 2), the weight.

        - ``eps`` - either None or a Dirichlet character modulo N, where N is
          the level of this group. If this is None, then the dimension of the
          whole space is returned; otherwise, the dimension of the subspace of
          Eisenstein series of character eps.

        - ``algorithm`` -- either "CohenOesterle" (the default) or "Quer". This
          specifies the method to use in the case of nontrivial character:
          either the Cohen--Oesterle formula as described in Stein's book, or
          by Möbius inversion using the subgroups GammaH (a method due to
          Jordi Quer).

        AUTHORS:

        - William Stein - Cohen--Oesterle algorithm

        - Jordi Quer - algorithm based on GammaH subgroups

        - David Loeffler (2009) - code refactoring

        EXAMPLES:

        The following two computations use different algorithms::

            sage: [Gamma1(36).dimension_eis(1,eps) for eps in DirichletGroup(36)]
            [0, 4, 3, 0, 0, 2, 6, 0, 0, 2, 3, 0]
            sage: [Gamma1(36).dimension_eis(1,eps,algorithm="Quer") for eps in DirichletGroup(36)]
            [0, 4, 3, 0, 0, 2, 6, 0, 0, 2, 3, 0]

        So do these::

            sage: [Gamma1(48).dimension_eis(3,eps) for eps in DirichletGroup(48)]
            [0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0]
            sage: [Gamma1(48).dimension_eis(3,eps,algorithm="Quer") for eps in DirichletGroup(48)]
            [0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0]
        """
        from .all import Gamma0

        # first deal with special cases

        if eps is None:
            return GammaH_class.dimension_eis(self, k)

        N = self.level()
        K = eps.base_ring()
        eps = DirichletGroup(N, K)(eps)

        if eps.is_trivial():
            return Gamma0(N).dimension_eis(k)

        # Note case of k = 0 and trivial character already dealt with separately, so k <= 0 here is valid:
        if (k <= 0) or ((k % 2) == 1 and eps.is_even()) or ((k % 2) == 0
                                                            and eps.is_odd()):
            return ZZ(0)

        if algorithm == "Quer":
            n = eps.order()
            dim = ZZ(0)
            for d in n.divisors():
                G = GammaH_constructor(N, (eps**d).kernel())
                dim = dim + moebius(d) * G.dimension_eis(k)
            return dim // phi(n)

        elif algorithm == "CohenOesterle":
            from sage.modular.dims import CohenOesterle
            j = 2 - k
            # We use the Cohen-Oesterle formula in a subtle way to
            # compute dim M_k(N,eps) (see Ch. 6 of William Stein's book on
            # computing with modular forms).
            alpha = -ZZ(
                K(Gamma0(N).index() *
                  (j - 1) / ZZ(12)) + CohenOesterle(eps, j))
            if k == 1:
                return alpha
            else:
                return alpha - self.dimension_cusp_forms(k, eps)

        else:  #algorithm not in ["CohenOesterle", "Quer"]:
            raise ValueError("Unrecognised algorithm in dimension_eis")
    def dimension_new_cusp_forms(self, k=2, p=0):
        r"""
        Return the dimension of the space of new (or `p`-new)
        weight `k` cusp forms for this congruence subgroup.

        INPUT:

        - `k` -- an integer (default: 2), the weight. Not fully
          implemented for `k = 1`.
        - `p` -- integer (default: 0); if nonzero, compute the
          `p`-new subspace.

        OUTPUT: Integer

        ALGORITHM:

        This comes from the formula given in Theorem 1 of
        http://www.math.ubc.ca/~gerg/papers/downloads/DSCFN.pdf

        EXAMPLES::

            sage: Gamma0(11000).dimension_new_cusp_forms()
            240
            sage: Gamma0(11000).dimension_new_cusp_forms(k=1)
            0
            sage: Gamma0(22).dimension_new_cusp_forms(k=4)
            3
            sage: Gamma0(389).dimension_new_cusp_forms(k=2,p=17)
            32

        TESTS::

             sage: L = [1213, 1331, 2169, 2583, 2662, 2745, 3208,
             ....:      3232, 3465, 3608, 4040, 4302, 4338]
             sage: all(Gamma0(N).dimension_new_cusp_forms(2)==100 for N in L)
             True
        """
        from sage.arith.all import moebius
        from sage.functions.other import floor

        N = self.level()
        k = ZZ(k)

        if not(p == 0 or N % p):
            return (self.dimension_cusp_forms(k) -
                    2 * self.restrict(N // p).dimension_new_cusp_forms(k))

        if k < 2 or k % 2:
            return ZZ.zero()

        factors = list(N.factor())

        def s0(q, a):
            # function s_0^#
            if a == 1:
                return 1 - 1/q
            elif a == 2:
                return 1 - 1/q - 1/q**2
            else:
                return (1 - 1/q) * (1 - 1/q**2)

        def vinf(q, a):
            # function v_oo^#
            if a % 2:
                return 0
            elif a == 2:
                return q - 2
            else:
                return q**(a/2 - 2) * (q - 1)**2

        def v2(q, a):
            # function v_2^#
            if q % 4 == 1:
                if a == 2:
                    return -1
                else:
                    return 0
            elif q % 4 == 3:
                if a == 1:
                    return -2
                elif a == 2:
                    return 1
                else:
                    return 0
            elif a in (1, 2):
                return -1
            elif a == 3:
                return 1
            else:
                return 0

        def v3(q, a):
            # function v_3^#
            if q % 3 == 1:
                if a == 2:
                    return -1
                else:
                    return 0
            elif q % 3 == 2:
                if a == 1:
                    return -2
                elif a == 2:
                    return 1
                else:
                    return 0
            elif a in (1, 2):
                return -1
            elif a == 3:
                return 1
            else:
                return 0

        res = (k - 1) / 12 * N * prod(s0(q, a) for q, a in factors)
        res -= prod(vinf(q, a) for q, a in factors) / ZZ(2)
        res += ((1 - k)/4 + floor(k/4)) * prod(v2(q, a) for q, a in factors)
        res += ((1 - k)/3 + floor(k/3)) * prod(v3(q, a) for q, a in factors)
        if k == 2:
            res += moebius(N)
        return res