From 6185e8caed47a2958f8713ea2e7338ef8200268e Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Tue, 7 Feb 2023 11:06:36 +0100 Subject: [PATCH 1/5] first implementation --- src/sage/modular/quasimodform/ring.py | 33 +++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/sage/modular/quasimodform/ring.py b/src/sage/modular/quasimodform/ring.py index 5579aa621d6..4302150eafe 100644 --- a/src/sage/modular/quasimodform/ring.py +++ b/src/sage/modular/quasimodform/ring.py @@ -778,3 +778,36 @@ def from_polynomial(self, polynomial): raise ValueError("the number of variables (%s) of the given polynomial cannot exceed the number of generators (%s) of the quasimodular forms ring" % (nb_var, self.ngens())) gens_dict = {poly_parent.gen(i):self.gen(i) for i in range(0, nb_var)} return self(polynomial.subs(gens_dict)) + + def basis_of_weight(self, weight): + r""" + Return a basis of elements generating the subspace of the given weight. + + EXAMPLES:: + + sage: QM = QuasiModularForms(1) + sage: QM.basis_of_weight(12) + [q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6), + 1 + 65520/691*q + 134250480/691*q^2 + 11606736960/691*q^3 + 274945048560/691*q^4 + 3199218815520/691*q^5 + O(q^6), + 1 - 288*q - 129168*q^2 - 1927296*q^3 + 65152656*q^4 + 1535768640*q^5 + O(q^6), + 1 + 432*q + 39312*q^2 - 1711296*q^3 - 14159664*q^4 + 317412000*q^5 + O(q^6), + 1 - 576*q + 21168*q^2 + 308736*q^3 - 15034608*q^4 - 39208320*q^5 + O(q^6), + 1 + 144*q - 17712*q^2 + 524736*q^3 - 2279088*q^4 - 79760160*q^5 + O(q^6), + 1 - 144*q + 8208*q^2 - 225216*q^3 + 2634192*q^4 + 1488672*q^5 + O(q^6)] + sage: QM = QuasiModularForms(Gamma1(3)) + sage: QM.basis_of_weight(3) + [1 + 54*q^2 + 72*q^3 + 432*q^5 + O(q^6), + q + 3*q^2 + 9*q^3 + 13*q^4 + 24*q^5 + O(q^6)] + sage: QM.basis_of_weight(5) + [1 - 90*q^2 - 240*q^3 - 3744*q^5 + O(q^6), + q + 15*q^2 + 81*q^3 + 241*q^4 + 624*q^5 + O(q^6), + 1 - 24*q - 18*q^2 - 1320*q^3 - 5784*q^4 - 10080*q^5 + O(q^6), + q - 21*q^2 - 135*q^3 - 515*q^4 - 1392*q^5 + O(q^6)] + """ + basis = [] + E2 = self.weight_2_eisenstein_series() + for j in range(weight//2): + basis += [f*E2**j for f in self.__modular_forms_subring.modular_forms_of_weight(weight - 2*j).basis()] + if not weight%2: + basis.append(E2**(Integer(weight/2))) + return basis From ef73ceb0d84af46d83e8a507a7e2826056d0f0c5 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Thu, 16 Mar 2023 12:08:18 -0400 Subject: [PATCH 2/5] some details --- src/sage/modular/quasimodform/ring.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/sage/modular/quasimodform/ring.py b/src/sage/modular/quasimodform/ring.py index 4302150eafe..76b2b632dff 100644 --- a/src/sage/modular/quasimodform/ring.py +++ b/src/sage/modular/quasimodform/ring.py @@ -781,7 +781,16 @@ def from_polynomial(self, polynomial): def basis_of_weight(self, weight): r""" - Return a basis of elements generating the subspace of the given weight. + Return a basis of elements generating the subspace of the given + weight. + + INPUT: + + - ``weight`` (integer) -- the weight of the subspace + + OUTPUT: + + A list of quasimodular forms of the given weight. EXAMPLES:: @@ -806,8 +815,10 @@ def basis_of_weight(self, weight): """ basis = [] E2 = self.weight_2_eisenstein_series() + M = self.__modular_forms_subring for j in range(weight//2): - basis += [f*E2**j for f in self.__modular_forms_subring.modular_forms_of_weight(weight - 2*j).basis()] + basis += [f*E2**j for f + in M.modular_forms_of_weight(weight - 2*j).basis()] if not weight%2: basis.append(E2**(Integer(weight/2))) return basis From 563b666b8df755dfe741c0692e40c5b81145d128 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Sat, 15 Apr 2023 09:42:25 -0400 Subject: [PATCH 3/5] initial implementation --- src/sage/modular/quasimodform/element.py | 39 ++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/sage/modular/quasimodform/element.py b/src/sage/modular/quasimodform/element.py index b92c31722ac..07873379e33 100644 --- a/src/sage/modular/quasimodform/element.py +++ b/src/sage/modular/quasimodform/element.py @@ -294,6 +294,45 @@ def __bool__(self): """ return bool(self._polynomial) + def depth(self): + r""" + Return the depth of the given quasimodular form. + + Note that the quasimodular form must be homogeneous of weight + `k`. Recall that the *depth* is the integer `p` such that + + .. MATH:: + + f = f_0 + f_1 E_2 + \cdots + f_p E_2^p, + + where `f_i` is a modular form of weight `k - 2i` and `f_p` is + nonzero. + + EXAMPLES:: + + sage: QM = QuasiModularForms(1) + sage: E2, E4, E6 = QM.gens() + sage: E2.depth() + 1 + sage: F = E4^2 + E6*E2 + E4*E2^2 + E2^4 + sage: F.depth() + 4 + sage: QM(7/11).depth() + 0 + + TESTS:: + + sage: QM = QuasiModularForms(1) + sage: (QM.0 + QM.1).depth() + Traceback (most recent call last): + ... + ValueError: the given graded quasiform is not an homogeneous element + """ + if not self.is_homogeneous(): + raise ValueError("the given graded quasiform is not an " + "homogeneous element") + return self._polynomial.degree() + def is_zero(self): r""" Return whether the given quasimodular form is zero. From 0f486e3bfb8bb03f76adbec2696cc21805302ca6 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Sat, 15 Apr 2023 09:45:05 -0400 Subject: [PATCH 4/5] Revert "initial implementation" This reverts commit 563b666b8df755dfe741c0692e40c5b81145d128. --- src/sage/modular/quasimodform/element.py | 39 ------------------------ 1 file changed, 39 deletions(-) diff --git a/src/sage/modular/quasimodform/element.py b/src/sage/modular/quasimodform/element.py index 07873379e33..b92c31722ac 100644 --- a/src/sage/modular/quasimodform/element.py +++ b/src/sage/modular/quasimodform/element.py @@ -294,45 +294,6 @@ def __bool__(self): """ return bool(self._polynomial) - def depth(self): - r""" - Return the depth of the given quasimodular form. - - Note that the quasimodular form must be homogeneous of weight - `k`. Recall that the *depth* is the integer `p` such that - - .. MATH:: - - f = f_0 + f_1 E_2 + \cdots + f_p E_2^p, - - where `f_i` is a modular form of weight `k - 2i` and `f_p` is - nonzero. - - EXAMPLES:: - - sage: QM = QuasiModularForms(1) - sage: E2, E4, E6 = QM.gens() - sage: E2.depth() - 1 - sage: F = E4^2 + E6*E2 + E4*E2^2 + E2^4 - sage: F.depth() - 4 - sage: QM(7/11).depth() - 0 - - TESTS:: - - sage: QM = QuasiModularForms(1) - sage: (QM.0 + QM.1).depth() - Traceback (most recent call last): - ... - ValueError: the given graded quasiform is not an homogeneous element - """ - if not self.is_homogeneous(): - raise ValueError("the given graded quasiform is not an " - "homogeneous element") - return self._polynomial.degree() - def is_zero(self): r""" Return whether the given quasimodular form is zero. From 4df388b037f4a2590d31f5235af4af16944c6293 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Sat, 24 Feb 2024 11:34:59 -0500 Subject: [PATCH 5/5] src/sage/modular/quasimodform/ring.py: use incremental powers of E2 --- src/sage/modular/quasimodform/ring.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/modular/quasimodform/ring.py b/src/sage/modular/quasimodform/ring.py index d5cf90c429e..53fcea616bd 100644 --- a/src/sage/modular/quasimodform/ring.py +++ b/src/sage/modular/quasimodform/ring.py @@ -817,9 +817,11 @@ def basis_of_weight(self, weight): basis = [] E2 = self.weight_2_eisenstein_series() M = self.__modular_forms_subring + E2_pow = self.one() for j in range(weight//2): - basis += [f*E2**j for f + basis += [f*E2_pow for f in M.modular_forms_of_weight(weight - 2*j).basis()] + E2_pow *= E2 if not weight%2: - basis.append(E2**(Integer(weight/2))) + basis.append(E2_pow) return basis