def _test__jacobi_torsion_point(phi, weight, torsion_point): r""" Given a list of power series, which are the corrected Taylor coefficients of a Jacobi form, return the specialization to ``torsion_point``. INPUT: - ``phi`` -- A Fourier expansion of a Jacobi form. - ``weight`` -- An integer. - ``torsion_point`` -- A rational. OUPUT: - A power series. TESTS: See jacobi_form_by_taylor_expansion. sage: from psage.modform.jacobiforms.jacobiformd1nn_fegenerators import * sage: from psage.modform.jacobiforms.jacobiformd1nn_types import * sage: precision = 50 sage: weight = 10; index = 7 sage: phis = [jacobi_form_by_taylor_expansion(i, JacobiFormD1NNFilter(precision, index), weight) for i in range(JacobiFormD1NN_Gamma(weight, index)._rank(QQ))] sage: fs = [JacobiFormD1NNFactory_class._test__jacobi_torsion_point(phi, weight, 2/3) for phi in phis] sage: fs_vec = [vector(f.padded_list(precision)) for f in fs] sage: mf_span = span([vector(b.qexp(precision).padded_list(precision)) for b in ModularForms(GammaH(9, [4]), weight).basis()]) sage: all(f_vec in mf_span for f_vec in fs_vec) True FIXME: The case of torsion points of order 5, which should lead to forms for Gamma1(25) fails even in the simplest case. """ from sage.rings.all import CyclotomicField K = CyclotomicField(QQ(torsion_point).denominator()) zeta = K.gen() R = PowerSeriesRing(K, 'q') q = R.gen(0) ch = JacobiFormD1WeightCharacter(weight) coeffs = dict((n, QQ(0)) for n in range(phi.precision().index())) for (n, r) in phi.precision().monoid_filter(): coeffs[n] += zeta**r * phi[(ch, (n, r))] return PowerSeriesRing(K, 'q')(coeffs)
def _test__jacobi_corrected_taylor_expansions(nu, phi, weight): r""" Return the ``2 nu``-th corrected Taylor coefficient. INPUT: - ``nu`` -- An integer. - ``phi`` -- A Fourier expansion of a Jacobi form. - ``weight`` -- An integer. OUTPUT: - A power series in `q`. ..TODO: Implement this for all Taylor coefficients. TESTS:: sage: from psage.modform.jacobiforms.jacobiformd1nn_fegenerators import * sage: from psage.modform.jacobiforms.jacobiformd1nn_types import * sage: nu_bound = 10 sage: precision = 100 sage: weight = 10; index = 7 sage: phis = [jacobi_form_by_taylor_expansion(i, JacobiFormD1NNFilter(precision, index), weight) for i in range(JacobiFormD1NN_Gamma(weight, index)._rank(QQ))] sage: fss = [ [JacobiFormD1NNFactory_class._test__jacobi_corrected_taylor_expansions(nu, phi, weight) for phi in phis] for nu in range(nu_bound) ] sage: fss_vec = [ [vector(f.padded_list(precision)) for f in fs] for fs in fss ] sage: mf_spans = [ span([vector(b.qexp(precision).padded_list(precision)) for b in ModularForms(1, weight + 2 * nu).basis()]) for nu in range(nu_bound) ] sage: all(f_vec in mf_span for (fs_vec, mf_span) in zip(fss_vec, mf_spans) for f_vec in fs_vec) True """ ## We use EZ85, p.29 (3), the factorial in one of the factors is missing factors = [(-1)**mu * factorial(2 * nu) * factorial(weight + 2 * nu - mu - 2) / ZZ( factorial(mu) * factorial(2 * nu - 2 * mu) * factorial(weight + nu - 2)) for mu in range(nu + 1)] gegenbauer = lambda n, r: sum(f * r**(2 * nu - 2 * mu) * n**mu for (mu, f) in enumerate(factors)) ch = JacobiFormD1WeightCharacter(weight) jacobi_index = phi.precision().jacobi_index() coeffs = dict((n, QQ(0)) for n in range(phi.precision().index())) for (n, r) in phi.precision().monoid_filter(): coeffs[n] += gegenbauer(jacobi_index * n, r) * phi[(ch, (n, r))] return PowerSeriesRing(QQ, 'q')(coeffs)
def _weak_jacbi_form_by_taylor_expansion(precision, fs, weight, factory=None): r""" The lazy Fourier expansion of a Jacobi form of index ``len(fs) - 1``, whose first corrected Taylor coefficients are the ``fs``. INPUT: - ``precision`` -- A filter for the Fourier expansion of Jacobi forms of scalar index. - ``fs`` - A list of functions of one argument `p` that return a power series of precision `p`. The coefficients must be integral. - ``weight`` -- An integer. - ``factory`` -- Either ``None``, or a factory class for Jacobi forms of degree 1 with scalar index. OUTPUT: - A lazy Fourier expansion of a Jacobi form. TESTS:: sage: from sage.rings import big_oh sage: from psage.modform.jacobiforms.jacobiformd1nn_fegenerators import _weak_jacbi_form_by_taylor_expansion sage: R = PowerSeriesRing(ZZ, 'q'); q = R.gen(0) sage: _weak_jacbi_form_by_taylor_expansion(10, 3 * [lambda p: big_oh.O(q**p)], 10).precision().jacobi_index() 2 sage: _weak_jacbi_form_by_taylor_expansion(10, 2 * [lambda p: big_oh.O(q**p)], 9).precision().jacobi_index() 3 """ if factory is None: factory = JacobiFormD1NNFactory(precision, len(fs) - 1) if weight is None: raise ValueError( "Either one element of fs must be a modular form or " + \ "the weight must be passed." ) expansion_ring = JacobiFormD1NNFourierExpansionModule( ZZ, len(fs) - 1 if weight % 2 == 0 else len(fs) + 1, True) return EquivariantMonoidPowerSeries_lazy( expansion_ring, expansion_ring.monoid().filter(precision), DelayedFactory_JacobiFormD1NN_taylor_expansion_weak( weight, fs, factory).getcoeff, [JacobiFormD1WeightCharacter(weight)])
def __init__(self, precision, k, i): r""" INPUT: - ``precision`` -- A filter for Fourier expansions of Jacobi forms. - `k` -- An integer; The weight of the Jacobi forms. - `i` -- A nonnegative integer less the dimension of the considered space of Jacobi forms. """ self.__precision = precision self.__weight = k self.__i = i self.__ch = JacobiFormD1WeightCharacter( k, precision.jacobi_index().matrix().nrows())
def __init__(self, weight, fs, factory): r""" INPUT: - ``weight`` -- An integer. - ``fs`` -- A list of functions of one argument `p` that return a power series of precision `p`. The coefficients must be integral. - ``factory`` -- Either ``None``, or a factory class for Jacobi forms of degree 1 with scalar index. """ self.__weight = weight self.__fs = fs self.__factory = factory self.__series = None self.__ch = JacobiFormD1WeightCharacter(weight)
def __init__(self, i, precision, weight, index): r""" INPUT: - ``precision`` -- A non-negative integer that corresponds to a precision of the q-expansion. - ``weight`` -- An integer. - ``index`` -- A non-negative integer. """ self.__i = i self.__precision = precision self.__weight = weight self.__index = index self.__series = None self.__ch = JacobiFormD1WeightCharacter(weight)
def jacobi_form_by_taylor_expansion(i, precision, weight): r""" Lazy Fourier expansion of the i-th Jacobi form in a certain basis; see _jacobi_forms_by_taylor_expansion_coordinates. INPUT: - `i` -- A non-negative integer. - ``precision`` -- A filter for the Fourier indices of Jacobi forms. - ``weight`` -- An integer. OUTPUT: - A lazy element of the Fourier expansion module for Jacobi forms. TESTS: See also ``JacobiFormD1NNFactory_class._test__jacobi_corrected_taylor_expansions`` and ``JacobiFormD1NNFactory_class._test__jacobi_torsion_point`` :: sage: from psage.modform.jacobiforms.jacobiformd1nn_fegenerators import * sage: JacobiFormD1NNFactory_class._test__jacobi_taylor_coefficients( jacobi_form_by_taylor_expansion(1, JacobiFormD1NNFilter(20, 1), 10), 10 ) [O(q^20), q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + 84480*q^8 - 113643*q^9 - 115920*q^10 + 534612*q^11 - 370944*q^12 - 577738*q^13 + 401856*q^14 + 1217160*q^15 + 987136*q^16 - 6905934*q^17 + 2727432*q^18 + 10661420*q^19 + O(q^20)] sage: JacobiFormD1NNFactory_class._test__jacobi_taylor_coefficients( jacobi_form_by_taylor_expansion(1, JacobiFormD1NNFilter(20, 2), 10), 10 ) [O(q^20), q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + 84480*q^8 - 113643*q^9 - 115920*q^10 + 534612*q^11 - 370944*q^12 - 577738*q^13 + 401856*q^14 + 1217160*q^15 + 987136*q^16 - 6905934*q^17 + 2727432*q^18 + 10661420*q^19 + O(q^20), q - 48*q^2 + 756*q^3 - 5888*q^4 + 24150*q^5 - 36288*q^6 - 117208*q^7 + 675840*q^8 - 1022787*q^9 - 1159200*q^10 + 5880732*q^11 - 4451328*q^12 - 7510594*q^13 + 5625984*q^14 + 18257400*q^15 + 15794176*q^16 - 117400878*q^17 + 49093776*q^18 + 202566980*q^19 + O(q^20)] sage: JacobiFormD1NNFactory_class._test__jacobi_taylor_coefficients( jacobi_form_by_taylor_expansion(0, JacobiFormD1NNFilter(20, 3), 9), 9 ) [O(q^20), q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + 84480*q^8 - 113643*q^9 - 115920*q^10 + 534612*q^11 - 370944*q^12 - 577738*q^13 + 401856*q^14 + 1217160*q^15 + 987136*q^16 - 6905934*q^17 + 2727432*q^18 + 10661420*q^19 + O(q^20)] """ jacobi_index = precision.jacobi_index() return EquivariantMonoidPowerSeries_lazy( JacobiFormD1NNFourierExpansionModule(ZZ, jacobi_index), precision, DelayedFactory_JacobiFormD1NN_by_taylor_expansion( i, precision.index(), weight, jacobi_index).getcoeff, [JacobiFormD1WeightCharacter(weight)])
def _test__coefficient_by_restriction(precision, k, relation_precision=None, additional_lengths=1): r""" TESTS:: sage: from psage.modform.jacobiforms.jacobiformd1_fourierexpansion import * sage: from psage.modform.jacobiforms.jacobiformd1_fegenerators import _test__coefficient_by_restriction :: sage: indices = JacobiFormD1Indices(QuadraticForm(matrix(2, [2,1,1,2]))) sage: precision = indices.filter(10) sage: _test__coefficient_by_restriction(precision, 10, additional_lengths = 10) :: sage: indices = JacobiFormD1Indices(QuadraticForm(matrix(2, [4,1,1,2]))) sage: precision = JacobiFormD1Filter(5, indices.jacobi_index()) sage: _test__coefficient_by_restriction(precision, 40, additional_lengths = 4) # long test We use different precisions for relations and restrictions:: sage: indices = JacobiFormD1Indices(QuadraticForm(matrix(2, [2,1,1,2]))) sage: precision = indices.filter(20) sage: relation_precision = indices.filter(2) sage: _test__coefficient_by_restriction(precision, 10, relation_precision, additional_lengths = 4) """ from sage.misc.misc import verbose L = precision.jacobi_index() if relation_precision is not None and not relation_precision <= precision: raise ValueError( "Relation precision must be less than or equal to precision.") expansions = _coefficient_by_restriction(precision, k, relation_precision) verbose( "Start testing restrictions of {2} Jacobi forms of weight {0} and index {1}" .format(k, L, len(expansions))) ch1 = JacobiFormD1WeightCharacter(k) chL = JacobiFormD1WeightCharacter(k, L.matrix().nrows()) R = precision.monoid()._r_representatives S_extended = _find_complete_set_of_restriction_vectors(L, R) S = list() for (s, _) in S_extended: if s not in S: S.append(s) max_S_length = max([L(s) for s in S]) S = L.short_vector_list_up_to_length(max_S_length + 1 + additional_lengths, True)[1:] Sold = flatten(S[:max_S_length + 1], max_level=1) Snew = flatten(S[max_S_length + 1:], max_level=1) S = flatten(S, max_level=1) verbose("Will use the following restriction vectors: {0}".format(S)) jacobi_forms_dict = dict() non_zero_expansions = list() for s in S: m = L(s) verbose("Restriction to index {0} via {1}".format(m, s)) try: jacobi_forms = jacobi_forms_dict[m] except KeyError: jacobi_forms = JacobiFormsD1NN( QQ, JacobiFormD1NNGamma(k, m), JacobiFormD1NNFilter(precision.index(), m)) jacobi_forms_dict[m] = jacobi_forms jacobi_forms_module = span([ vector(b[(ch1, k)] for k in jacobi_forms.fourier_expansion_precision()) for b in map(lambda b: b.fourier_expansion(), jacobi_forms.graded_submodule(None).basis()) ]) fourier_expansion_module = jacobi_forms.fourier_expansion_ambient() for (i, expansion) in enumerate(expansions): verbose("Testing restriction of {0}-th form".format(i)) restricted_expansion_dict = dict() for (n, r) in precision.monoid_filter(): rres = s.dot_product(vector(r)) try: restricted_expansion_dict[(n, rres)] += expansion[(chL, (n, r))] except KeyError: restricted_expansion_dict[(n, rres)] = expansion[(chL, (n, r))] restricted_expansion = vector( restricted_expansion_dict.get(k, 0) for k in jacobi_forms.fourier_expansion_precision()) if restricted_expansion not in jacobi_forms_module: raise RuntimeError( "{0}-th restricted via {1} is not a Jacobi form".format( i, s)) if restricted_expansion != 0: non_zero_expansions.append(i) assert Set(non_zero_expansions) == Set(range(len(expansions)))
global_restriction_matrix = global_restriction_matrix__big.matrix_from_rows_and_columns( row_indices__small, [column_labels.index(l) for l in column_labels_relations]) else: global_restriction_matrix = global_restriction_matrix__big jacobi_indices = [m for (_, m, _, _) in row_groups] index_filters = dict((m, JacobiFormD1NNFilter(precision.index(), m)) for m in Set(jacobi_indices)) jacobi_forms = dict( (m, JacobiFormsD1NN(QQ, JacobiFormD1NNGamma(k, m), prec)) for (m, prec) in index_filters.iteritems()) forms = list() nmb_forms_coords = row_groups[-1][2] + row_groups[-1][3] ch1 = JacobiFormD1WeightCharacter(k) for (s, m, start, length) in row_groups: row_labels_dict = row_labels[m] for f in jacobi_forms[m].graded_submodule(None).basis(): f = f.fourier_expansion() v = vector(ZZ, len(row_labels_dict)) for (l, i) in row_labels_dict.iteritems(): v[i] = f[(ch1, l)] forms.append( vector(start * [0] + v.list() + (nmb_forms_coords - start - length) * [0])) if relation_precision == precision: restriction_expansion = FreeModule(QQ, nmb_forms_coords).span(forms) else: