Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

convert gens method in modular to return tuple #39474

Merged
merged 2 commits into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/sage/modular/abvar/finite_subgroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -579,11 +579,13 @@ def order(self):
self.__order = o
return o

def gens(self):
def gens(self) -> Sequence:
"""
Return generators for this finite subgroup.

EXAMPLES: We list generators for several cuspidal subgroups::
EXAMPLES:

We list generators for several cuspidal subgroups::

sage: J0(11).cuspidal_subgroup().gens()
[[(0, 1/5)]]
Expand Down
2 changes: 1 addition & 1 deletion src/sage/modular/abvar/homspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ def ngens(self):
self.calculate_generators()
return len(self._gens)

def gens(self):
def gens(self) -> tuple:
"""
Return tuple of generators for this endomorphism ring.

Expand Down
4 changes: 2 additions & 2 deletions src/sage/modular/dirichlet.py
Original file line number Diff line number Diff line change
Expand Up @@ -3104,7 +3104,7 @@ def gen(self, n=0):
return g[n]

@cached_method
def gens(self):
def gens(self) -> tuple:
"""
Return generators of ``self``.

Expand All @@ -3117,7 +3117,7 @@ def gens(self):
g = []
ord = self.zeta_order()
M = self._module
zero = M(0)
zero = M.zero()
orders = self.integers_mod().unit_group().gens_orders()
for i in range(len(self.unit_gens())):
z = zero.__copy__()
Expand Down
20 changes: 10 additions & 10 deletions src/sage/modular/drinfeld_modform/ring.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ class DrinfeldModularForms(Parent, UniqueRepresentation):
Use the :meth:`gens` method to obtain the generators of the ring::

sage: M.gens()
[g1, g2, g3]
(g1, g2, g3)
sage: M.inject_variables() # assign the variable g1, g2, g3
Defining g1, g2, g3
sage: T*g1*g2 + g3
Expand All @@ -130,23 +130,23 @@ class DrinfeldModularForms(Parent, UniqueRepresentation):

sage: M.<F, G, H> = DrinfeldModularForms(K)
sage: M.gens()
[F, G, H]
(F, G, H)
sage: M = DrinfeldModularForms(K, 5, names='f') # must specify the rank
sage: M.gens()
[f1, f2, f3, f4, f5]
(f1, f2, f3, f4, f5)
sage: M = DrinfeldModularForms(K, names='u, v, w, x')
sage: M.gens()
[u, v, w, x]
(u, v, w, x)
sage: M = DrinfeldModularForms(K, names=['F', 'G', 'H'])
sage: M.gens()
[F, G, H]
(F, G, H)

Set the keyword parameter ``has_type`` to ``True`` in order to create
the ring of Drinfeld modular forms of arbitrary type::

sage: M = DrinfeldModularForms(K, 4, has_type=True)
sage: M.gens()
[g1, g2, g3, h4]
(g1, g2, g3, h4)
sage: h4 = M.3
sage: h4.type()
1
Expand Down Expand Up @@ -618,18 +618,18 @@ def gen(self, n):
"""
return self(self._poly_ring.gen(n))

def gens(self):
def gens(self) -> tuple:
r"""
Return a list of generators of this ring.
Return a tuple of generators of this ring.

EXAMPLES::

sage: A = GF(3)['T']; K = Frac(A); T = K.gen()
sage: M = DrinfeldModularForms(K, 5)
sage: M.gens()
[g1, g2, g3, g4, g5]
(g1, g2, g3, g4, g5)
"""
return [self(g) for g in self._poly_ring.gens()]
return tuple(self(g) for g in self._poly_ring.gens())

def ngens(self):
r"""
Expand Down
2 changes: 1 addition & 1 deletion src/sage/modular/drinfeld_modform/tutorial.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@

sage: M = DrinfeldModularForms(K, 4, has_type=True)
sage: M.gens()
[g1, g2, g3, h4]
(g1, g2, g3, h4)
sage: h4 = M.3
sage: h4.weight()
40
Expand Down
8 changes: 5 additions & 3 deletions src/sage/modular/hecke/algebra.py
Original file line number Diff line number Diff line change
Expand Up @@ -518,10 +518,12 @@ def discriminant(self):
trace_matrix[i, j] = trace_matrix[j, i] = basis[i].matrix().trace_of_product(basis[j].matrix())
return trace_matrix.det()

def gens(self):
def gens(self) -> Iterator:
r"""
Return a generator over all Hecke operator `T_n` for
`n = 1, 2, 3, \ldots`. This is infinite.
Return a generator over all Hecke operator `T_n`
for `n = 1, 2, 3, \ldots`.

This is infinite.

EXAMPLES::

Expand Down
2 changes: 1 addition & 1 deletion src/sage/modular/hecke/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -1341,7 +1341,7 @@ def factor_number(self):
except AttributeError:
return -1

def gens(self):
def gens(self) -> tuple:
"""
Return a tuple of basis elements of ``self``.

Expand Down
2 changes: 1 addition & 1 deletion src/sage/modular/modform/space.py
Original file line number Diff line number Diff line change
Expand Up @@ -1358,7 +1358,7 @@ def gen(self, n):
except IndexError:
raise ValueError("Generator %s not defined" % n)

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

Expand Down
89 changes: 44 additions & 45 deletions src/sage/modular/modform_hecketriangle/abstract_space.py
Original file line number Diff line number Diff line change
Expand Up @@ -1352,7 +1352,7 @@

return (min_exp, order_1)

def quasi_part_gens(self, r=None, min_exp=0, max_exp=infinity, order_1=ZZ.zero()):
def quasi_part_gens(self, r=None, min_exp=0, max_exp=infinity, order_1=ZZ.zero()) -> tuple:
r"""
Return a basis in ``self`` of the subspace of (quasi) weakly
holomorphic forms which satisfy the specified properties on
Expand Down Expand Up @@ -1391,35 +1391,38 @@
sage: QF = QuasiWeakModularForms(n=8, k=10/3, ep=-1)
sage: QF.default_prec(1)
sage: QF.quasi_part_gens(min_exp=-1)
[q^-1 + O(q), 1 + O(q), q^-1 - 9/(128*d) + O(q), 1 + O(q), q^-1 - 19/(64*d) + O(q), q^-1 + 1/(64*d) + O(q)]
(q^-1 + O(q), 1 + O(q), q^-1 - 9/(128*d) + O(q),
1 + O(q), q^-1 - 19/(64*d) + O(q), q^-1 + 1/(64*d) + O(q))

sage: QF.quasi_part_gens(min_exp=-1, max_exp=-1)
[q^-1 + O(q), q^-1 - 9/(128*d) + O(q), q^-1 - 19/(64*d) + O(q), q^-1 + 1/(64*d) + O(q)]
(q^-1 + O(q), q^-1 - 9/(128*d) + O(q),
q^-1 - 19/(64*d) + O(q), q^-1 + 1/(64*d) + O(q))
sage: QF.quasi_part_gens(min_exp=-2, r=1)
[q^-2 - 9/(128*d)*q^-1 - 261/(131072*d^2) + O(q), q^-1 - 9/(128*d) + O(q), 1 + O(q)]
(q^-2 - 9/(128*d)*q^-1 - 261/(131072*d^2) + O(q),
q^-1 - 9/(128*d) + O(q), 1 + O(q))

sage: from sage.modular.modform_hecketriangle.space import ModularForms
sage: MF = ModularForms(k=36)
sage: MF.quasi_part_gens(min_exp=2)
[q^2 + 194184*q^4 + O(q^5), q^3 - 72*q^4 + O(q^5)]
(q^2 + 194184*q^4 + O(q^5), q^3 - 72*q^4 + O(q^5))

sage: from sage.modular.modform_hecketriangle.space import QuasiModularForms
sage: MF = QuasiModularForms(n=5, k=6, ep=-1)
sage: MF.default_prec(2)
sage: MF.dimension()
3
sage: MF.quasi_part_gens(r=0)
[1 - 37/(200*d)*q + O(q^2)]
(1 - 37/(200*d)*q + O(q^2),)
sage: MF.quasi_part_gens(r=0)[0] == MF.E6()
True
sage: MF.quasi_part_gens(r=1)
[1 + 33/(200*d)*q + O(q^2)]
(1 + 33/(200*d)*q + O(q^2),)
sage: MF.quasi_part_gens(r=1)[0] == MF.E2()*MF.E4()
True
sage: MF.quasi_part_gens(r=2)
[]
()
sage: MF.quasi_part_gens(r=3)
[1 - 27/(200*d)*q + O(q^2)]
(1 - 27/(200*d)*q + O(q^2),)
sage: MF.quasi_part_gens(r=3)[0] == MF.E2()^3
True

Expand All @@ -1429,18 +1432,18 @@
sage: MF.dimension()
8
sage: MF.quasi_part_gens(r=0)
[q - 34743/(640000*d^2)*q^3 + O(q^4), q^2 - 69/(200*d)*q^3 + O(q^4)]
(q - 34743/(640000*d^2)*q^3 + O(q^4), q^2 - 69/(200*d)*q^3 + O(q^4))
sage: MF.quasi_part_gens(r=1)
[q - 9/(200*d)*q^2 + 37633/(640000*d^2)*q^3 + O(q^4),
q^2 + 1/(200*d)*q^3 + O(q^4)]
(q - 9/(200*d)*q^2 + 37633/(640000*d^2)*q^3 + O(q^4),
q^2 + 1/(200*d)*q^3 + O(q^4))
sage: MF.quasi_part_gens(r=2)
[q - 1/(4*d)*q^2 - 24903/(640000*d^2)*q^3 + O(q^4)]
(q - 1/(4*d)*q^2 - 24903/(640000*d^2)*q^3 + O(q^4),)
sage: MF.quasi_part_gens(r=3)
[q + 1/(10*d)*q^2 - 7263/(640000*d^2)*q^3 + O(q^4)]
(q + 1/(10*d)*q^2 - 7263/(640000*d^2)*q^3 + O(q^4),)
sage: MF.quasi_part_gens(r=4)
[q - 11/(20*d)*q^2 + 53577/(640000*d^2)*q^3 + O(q^4)]
(q - 11/(20*d)*q^2 + 53577/(640000*d^2)*q^3 + O(q^4),)
sage: MF.quasi_part_gens(r=5)
[q - 1/(5*d)*q^2 + 4017/(640000*d^2)*q^3 + O(q^4)]
(q - 1/(5*d)*q^2 + 4017/(640000*d^2)*q^3 + O(q^4),)

sage: MF.quasi_part_gens(r=1)[0] == MF.E2() * CuspForms(n=5, k=16, ep=1).gen(0)
True
Expand All @@ -1453,64 +1456,61 @@
sage: MF.quasi_part_gens(r=1, min_exp=-2) == MF.quasi_part_gens(r=1, min_exp=1)
True
sage: MF.quasi_part_gens(r=1)
[q - 8*q^2 - 8*q^3 + 5952*q^4 + O(q^5),
(q - 8*q^2 - 8*q^3 + 5952*q^4 + O(q^5),
q^2 - 8*q^3 + 208*q^4 + O(q^5),
q^3 - 16*q^4 + O(q^5)]
q^3 - 16*q^4 + O(q^5))

sage: MF = QuasiWeakModularForms(n=infinity, k=4, ep=1)
sage: MF.quasi_part_gens(r=2, min_exp=2, order_1=-2)[0] == MF.E2()^2 * MF.E4()^(-2) * MF.f_inf()^2
True
sage: [v.order_at(-1) for v in MF.quasi_part_gens(r=0, min_exp=2, order_1=-2)]
[-2, -2]
"""

if (not self.is_weakly_holomorphic()):
if not self.is_weakly_holomorphic():
from warnings import warn
warn("This function only determines generators of (quasi) weakly modular forms!")

(min_exp, order_1) = self._canonical_min_exp(min_exp, order_1)
min_exp, order_1 = self._canonical_min_exp(min_exp, order_1)

# For modular forms spaces the quasi parts are all zero except for r=0
if (self.is_modular()):
if self.is_modular():
r = ZZ(r)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember you saying in another PR that Integer is faster than ZZ. Fine to leave it since the PR is addressing typing annotations. Perhaps a find/replace ZZ with Integer is something worth doing in another PR.

if (r != 0):
return []
if r:
return ()

Check warning on line 1479 in src/sage/modular/modform_hecketriangle/abstract_space.py

View check run for this annotation

Codecov / codecov/patch

src/sage/modular/modform_hecketriangle/abstract_space.py#L1479

Added line #L1479 was not covered by tests

# The lower bounds on the powers of f_inf and E4 determine
# how large powers of E2 we can fit in...
n = self.hecke_n()
if (n == infinity):
if n == infinity:
max_numerator_weight = self._weight - 4*min_exp - 4*order_1 + 4
else:
max_numerator_weight = self._weight - 4*n/(n-2)*min_exp + 4

# If r is not specified we gather all generators for all possible r's
if r is None:
gens = []
for rnew in range(QQ(max_numerator_weight/ZZ(2)).floor() + 1):
gens += self.quasi_part_gens(r=rnew, min_exp=min_exp, max_exp=max_exp, order_1=order_1)
return gens
for rnew in range(QQ(max_numerator_weight / ZZ(2)).floor() + 1):
gens.extend(self.quasi_part_gens(r=rnew, min_exp=min_exp, max_exp=max_exp, order_1=order_1))
return tuple(gens)

r = ZZ(r)
if r < 0 or 2*r > max_numerator_weight:
return []
return ()

E2 = self.E2()
ambient_weak_space = self.graded_ring().reduce_type("weak", degree=(self._weight-QQ(2*r), self._ep*(-1)**r))
ambient_weak_space = self.graded_ring().reduce_type("weak",
degree=(self._weight-QQ(2*r), self._ep*(-1)**r))
order_inf = ambient_weak_space._l1 - order_1

if (max_exp == infinity):
if max_exp == infinity:
max_exp = order_inf
elif (max_exp < min_exp):
return []
elif max_exp < min_exp:
return ()

Check warning on line 1508 in src/sage/modular/modform_hecketriangle/abstract_space.py

View check run for this annotation

Codecov / codecov/patch

src/sage/modular/modform_hecketriangle/abstract_space.py#L1508

Added line #L1508 was not covered by tests
else:
max_exp = min(ZZ(max_exp), order_inf)

gens = []
for m in range(min_exp, max_exp + 1):
gens += [ self(ambient_weak_space.F_basis(m, order_1=order_1)*E2**r) ]

return gens
return tuple(self(ambient_weak_space.F_basis(m, order_1=order_1) * E2**r)
for m in range(min_exp, max_exp + 1))

def quasi_part_dimension(self, r=None, min_exp=0, max_exp=infinity, order_1=ZZ.zero()):
r"""
Expand Down Expand Up @@ -2096,7 +2096,7 @@
q^-1 + O(q^5)

sage: MF = ModularForms(k=36)
sage: MF.q_basis() == MF.gens()
sage: MF.q_basis() == list(MF.gens())
True

sage: QF = QuasiModularForms(k=6)
Expand Down Expand Up @@ -2490,11 +2490,11 @@

return self.module()(self.ambient_space().coordinate_vector(v))

def gens(self):
def gens(self) -> tuple:
r"""
This method should be overloaded by subclasses.

Return a basis of ``self``.
Return a basis of ``self`` as a tuple.

Note that the coordinate vector of elements of ``self``
are with respect to this basis.
Expand All @@ -2503,11 +2503,10 @@

sage: from sage.modular.modform_hecketriangle.space import ModularForms
sage: ModularForms(k=12).gens() # defined in space.py
[1 + 196560*q^2 + 16773120*q^3 + 398034000*q^4 + O(q^5),
q - 24*q^2 + 252*q^3 - 1472*q^4 + O(q^5)]
(1 + 196560*q^2 + 16773120*q^3 + 398034000*q^4 + O(q^5),
q - 24*q^2 + 252*q^3 - 1472*q^4 + O(q^5))
"""

raise NotImplementedError("No generators are implemented yet for {}!".format(self))
raise NotImplementedError(f"No generators are implemented yet for {self}!")

Check warning on line 2509 in src/sage/modular/modform_hecketriangle/abstract_space.py

View check run for this annotation

Codecov / codecov/patch

src/sage/modular/modform_hecketriangle/abstract_space.py#L2509

Added line #L2509 was not covered by tests

def gen(self, k=0):
r"""
Expand Down
14 changes: 7 additions & 7 deletions src/sage/modular/modform_hecketriangle/readme.py
Original file line number Diff line number Diff line change
Expand Up @@ -1015,12 +1015,12 @@
sage: QF = QuasiWeakModularForms(n=8, k=10/3, ep=-1)
sage: QF.default_prec(1)
sage: QF.quasi_part_gens(min_exp=-1)
[q^-1 + O(q),
(q^-1 + O(q),
1 + O(q),
q^-1 - 9/(128*d) + O(q),
1 + O(q),
q^-1 - 19/(64*d) + O(q),
q^-1 + 1/(64*d) + O(q)]
q^-1 + 1/(64*d) + O(q))
sage: QF.default_prec(QF.required_laurent_prec(min_exp=-1))
sage: QF.q_basis(min_exp=-1) # long time
[q^-1 + O(q^5),
Expand All @@ -1042,9 +1042,9 @@
3
sage: MF.default_prec(2)
sage: MF.gens()
[1 - 37/(200*d)*q + O(q^2),
(1 - 37/(200*d)*q + O(q^2),
1 + 33/(200*d)*q + O(q^2),
1 - 27/(200*d)*q + O(q^2)]
1 - 27/(200*d)*q + O(q^2))


- **Coordinate vectors for (quasi) holomorphic modular forms and (quasi) cusp forms:**
Expand Down Expand Up @@ -1135,16 +1135,16 @@
sage: MF.dimension()
2
sage: MF.gens()
[1 + 240*q^2 + 2160*q^4 + O(q^5), q - 8*q^2 + 28*q^3 - 64*q^4 + O(q^5)]
(1 + 240*q^2 + 2160*q^4 + O(q^5), q - 8*q^2 + 28*q^3 - 64*q^4 + O(q^5))
sage: E4(i)
1.941017189...
sage: E4.order_at(-1)
1

sage: MF = (E2/E4).reduced_parent()
sage: MF.quasi_part_gens(order_1=-1)
[1 - 40*q + 552*q^2 - 4896*q^3 + 33320*q^4 + O(q^5),
1 - 24*q + 264*q^2 - 2016*q^3 + 12264*q^4 + O(q^5)]
(1 - 40*q + 552*q^2 - 4896*q^3 + 33320*q^4 + O(q^5),
1 - 24*q + 264*q^2 - 2016*q^3 + 12264*q^4 + O(q^5))
sage: prec = MF.required_laurent_prec(order_1=-1)
sage: qexp = (E2/E4).q_expansion(prec=prec)
sage: qexp
Expand Down
Loading
Loading