def cyclotomic_to_gamma(cyclo_up, cyclo_down): """ Convert a quotient of products of cyclotomic polynomials to a quotient of products of polynomials `x^n - 1`. INPUT: - ``cyclo_up`` -- list of indices of cyclotomic polynomials in the numerator - ``cyclo_down`` -- list of indices of cyclotomic polynomials in the denominator OUTPUT: a dictionary mapping an integer `n` to the power of `x^n - 1` that appears in the given product EXAMPLES:: sage: from sage.modular.hypergeometric_motive import cyclotomic_to_gamma sage: cyclotomic_to_gamma([6], [1]) {2: -1, 3: -1, 6: 1} """ dico = defaultdict(int) for d in cyclo_up: dico[d] += 1 for d in cyclo_down: dico[d] -= 1 resu = defaultdict(int) for n in dico: for d in divisors(n): resu[d] += moebius(n / d) * dico[n] return {d: resu[d] for d in resu if resu[d]}
def AllCusps(N): r""" Return a list of CuspFamily objects corresponding to the cusps of `X_0(N)`. INPUT: - ``N`` -- (integer): the level EXAMPLES:: sage: AllCusps(18) [(Inf), (c_{2}), (c_{3,1}), (c_{3,2}), (c_{6,1}), (c_{6,2}), (c_{9}), (0)] sage: AllCusps(0) Traceback (most recent call last): ... ValueError: N must be positive """ N = ZZ(N) if N <= 0: raise ValueError("N must be positive") c = [] for d in divisors(N): n = num_cusps_of_width(N, d) if n == 1: c.append(CuspFamily(N, d)) elif n > 1: for i in range(n): c.append(CuspFamily(N, d, label=str(i + 1))) return c
def origami_H2_2cyl_iterator(n, reducible=False, output="coordinates"): r""" INPUT: - ``n`` - positive integer - the number of squares - ``reducible`` - bool (default: False) - if True returns also the reducible origamis. - ``output`` - either "coordinates" or "origami" or "standard origami" """ for n1,n2 in OrderedPartitions(n,k=2): for w1 in divisors(n1): h1 = n1//w1 for w2 in filter(lambda x: x < w1, divisors(n2)): h2 = n2//w2 if reducible or gcd(h1,h2) == 1: d = gcd(w1,w2) if d == 1: for t1 in xrange(w1): for t2 in xrange(w2): if output == "coordinates": yield w1,h1,t1,w2,h2,t2 elif output == "origami": yield origami_H2_2cyl(w1,h1,t1,w2,h2,t2) elif output == "standard_origami": yield origami_H2_2cyl(w1,h1,t1,w2,h2,t2).standard_form() else: for t1 in xrange(w1): for t2 in xrange(w2): if reducible or gcd(d,h2*t1-h1*t2) == 1: if output == "coordinates": yield w1,h1,t1,w2,h2,t2 elif output == "origami": yield origami_H2_2cyl(w1,h1,t1,w2,h2,t2) elif output == "standard_origami": yield origami_H2_2cyl(w1,h1,t1,w2,h2,t2).standard_form()
def reduce_basis(self, long_etas): r""" Produce a more manageable basis via LLL-reduction. INPUT: - ``long_etas`` - a list of EtaGroupElement objects (which should all be of the same level) OUTPUT: - a new list of EtaGroupElement objects having hopefully smaller norm ALGORITHM: We define the norm of an eta-product to be the `L^2` norm of its divisor (as an element of the free `\ZZ`-module with the cusps as basis and the standard inner product). Applying LLL-reduction to this gives a basis of hopefully more tractable elements. Of course we'd like to use the `L^1` norm as this is just twice the degree, which is a much more natural invariant, but `L^2` norm is easier to work with! EXAMPLES:: sage: EtaGroup(4).reduce_basis([ EtaProduct(4, {1:8,2:24,4:-32}), EtaProduct(4, {1:8, 4:-8})]) [Eta product of level 4 : (eta_1)^8 (eta_4)^-8, Eta product of level 4 : (eta_1)^-8 (eta_2)^24 (eta_4)^-16] """ N = self.level() cusps = AllCusps(N) r = matrix(ZZ, [[et.order_at_cusp(c) for c in cusps] for et in long_etas]) V = FreeModule(ZZ, r.ncols()) A = V.submodule_with_basis([V(rw) for rw in r.rows()]) rred = r.LLL() short_etas = [] for shortvect in rred.rows(): bv = A.coordinates(shortvect) dic = { d: sum(bv[i] * long_etas[i].r(d) for i in range(r.nrows())) for d in divisors(N) } short_etas.append(self(dic)) return short_etas
def _hermite_normal_forms(r, det): """ Generate all r x r integer matrices in (left) Hermite normal form with the given determinant. """ if r == 0: if det == 1: yield matrix(ZZ, 0, []) else: for d in divisors(det): for A in _hermite_normal_forms(r - 1, det // d): for column in itertools.product(range(d), repeat=r - 1): yield matrix( ZZ, r, r, lambda i, j: A[i, j] if i < r - 1 and j < r - 1 else d if i == r - 1 and j == r - 1 else column[i] if j == r - 1 else 0)
def capital_M(n): """ Auxiliary function, used to describe the canonical scheme. INPUT: - ``n`` -- an integer OUTPUT: a rational EXAMPLES:: sage: from sage.modular.hypergeometric_motive import capital_M sage: [capital_M(i) for i in range(1,8)] [1, 4, 27, 64, 3125, 432, 823543] """ n = ZZ(n) return QQ.prod(d ** (d * moebius(n / d)) for d in divisors(n))
def DivisorLattice(n, facade=None): """ Return the divisor lattice of an integer. Elements of the lattice are divisors of `n` and `x < y` in the lattice if `x` divides `y`. INPUT: - ``n`` -- an integer - ``facade`` (boolean) -- whether to make the returned poset a facade poset (see :mod:`sage.categories.facade_sets`); the default behaviour is the same as the default behaviour of the :func:`~sage.combinat.posets.posets.Poset` constructor EXAMPLES:: sage: P = Posets.DivisorLattice(12) sage: sorted(P.cover_relations()) [[1, 2], [1, 3], [2, 4], [2, 6], [3, 6], [4, 12], [6, 12]] sage: P = Posets.DivisorLattice(10, facade=False) sage: P(2) < P(5) False TESTS:: sage: Posets.DivisorLattice(1) Finite lattice containing 1 elements """ from sage.arith.misc import divisors try: n = Integer(n) except TypeError: raise TypeError( "number of elements must be an integer, not {0}".format(n)) if n <= 0: raise ValueError("n must be a positive integer") return LatticePoset((divisors(n), lambda x, y: y % x == 0), facade=facade, linear_extension=True)
def DivisorLattice(n, facade=None): """ Return the divisor lattice of an integer. Elements of the lattice are divisors of `n` and `x < y` in the lattice if `x` divides `y`. INPUT: - ``n`` -- an integer - ``facade`` (boolean) -- whether to make the returned poset a facade poset (see :mod:`sage.categories.facade_sets`); the default behaviour is the same as the default behaviour of the :func:`~sage.combinat.posets.posets.Poset` constructor EXAMPLES:: sage: P = Posets.DivisorLattice(12) sage: sorted(P.cover_relations()) [[1, 2], [1, 3], [2, 4], [2, 6], [3, 6], [4, 12], [6, 12]] sage: P = Posets.DivisorLattice(10, facade=False) sage: P(2) < P(5) False TESTS:: sage: Posets.DivisorLattice(1) Finite lattice containing 1 elements """ from sage.arith.misc import divisors try: n = Integer(n) except TypeError: raise TypeError("number of elements must be an integer, not {0}".format(n)) if n <= 0: raise ValueError("n must be a positive integer") return LatticePoset( (divisors(n), lambda x, y: y % x == 0), facade=facade, linear_extension=True)
def gamma_list_to_cyclotomic(galist): r""" Convert a quotient of products of polynomials `x^n - 1` to a quotient of products of cyclotomic polynomials. INPUT: - ``galist`` -- a list of integers, where an integer `n` represents the power `(x^{|n|} - 1)^{\operatorname{sgn}(n)}` OUTPUT: a pair of list of integers, where `k` represents the cyclotomic polynomial `\Phi_k` EXAMPLES:: sage: from sage.modular.hypergeometric_motive import gamma_list_to_cyclotomic sage: gamma_list_to_cyclotomic([-1, -1, 2]) ([2], [1]) sage: gamma_list_to_cyclotomic([-1, -1, -1, -3, 6]) ([2, 6], [1, 1, 1]) sage: gamma_list_to_cyclotomic([-1, 2, 3, -4]) ([3], [4]) sage: gamma_list_to_cyclotomic([8,2,2,2,-6,-4,-3,-1]) ([2, 2, 8], [3, 3, 6]) """ resu = defaultdict(int) for n in galist: eps = sgn(n) for d in divisors(abs(n)): resu[d] += eps return (sorted(d for d in resu for k in range(resu[d])), sorted(d for d in resu for k in range(-resu[d])))
def origami_H2_1cyl_iterator(n, reducible=False, output='coordinates'): r""" INPUT: - ``n`` - positive integer - the number of squares - ``reducible`` - bool (default: False) - if True returns also the reducible origamis. - ``output`` - either "coordinates" or "origami" or "standard origami" """ if reducible: hlist = divisors(n) else: hlist = [1] for h in hlist: for p in Partitions(Integer(n/h),length=3): for l in CyclicPermutationsOfPartition([p]): l1,l2,l3 = l[0] if l1 == l2 and l2 == l3: if reducible or l1 == 1: for t in xrange(l1): if output == "coordinates": yield l1,l2,l3,h,t elif output == "origami": yield origami_H2_1cyl(l1,l2,l3,h,t) elif output == "standard_origami": yield origami_H2_1cyl(l1,l2,l3,h,t).standard_form() elif reducible or gcd([l1,l2,l3]) == 1: for t in xrange(n): if output == "coordinates": yield l1,l2,l3,h,t elif output == "origami": yield origami_H2_1cyl(l1,l2,l3,h,t) elif output == "standard_origami": yield origami_H2_1cyl(l1,l2,l3,h,t).standard_form()
def basis(self, reduce=True): r""" Produce a basis for the free abelian group of eta-products of level N (under multiplication), attempting to find basis vectors of the smallest possible degree. INPUT: - ``reduce`` - a boolean (default True) indicating whether or not to apply LLL-reduction to the calculated basis EXAMPLES:: sage: EtaGroup(5).basis() [Eta product of level 5 : (eta_1)^6 (eta_5)^-6] sage: EtaGroup(12).basis() [Eta product of level 12 : (eta_1)^-3 (eta_2)^2 (eta_3)^1 (eta_4)^-1 (eta_6)^-2 (eta_12)^3, Eta product of level 12 : (eta_1)^-4 (eta_2)^2 (eta_3)^4 (eta_6)^-2, Eta product of level 12 : (eta_1)^6 (eta_2)^-9 (eta_3)^-2 (eta_4)^3 (eta_6)^3 (eta_12)^-1, Eta product of level 12 : (eta_1)^-1 (eta_2)^3 (eta_3)^3 (eta_4)^-2 (eta_6)^-9 (eta_12)^6, Eta product of level 12 : (eta_1)^3 (eta_3)^-1 (eta_4)^-3 (eta_12)^1] sage: EtaGroup(12).basis(reduce=False) # much bigger coefficients [Eta product of level 12 : (eta_1)^384 (eta_2)^-576 (eta_3)^-696 (eta_4)^216 (eta_6)^576 (eta_12)^96, Eta product of level 12 : (eta_2)^24 (eta_12)^-24, Eta product of level 12 : (eta_1)^-40 (eta_2)^116 (eta_3)^96 (eta_4)^-30 (eta_6)^-80 (eta_12)^-62, Eta product of level 12 : (eta_1)^-4 (eta_2)^-33 (eta_3)^-4 (eta_4)^1 (eta_6)^3 (eta_12)^37, Eta product of level 12 : (eta_1)^15 (eta_2)^-24 (eta_3)^-29 (eta_4)^9 (eta_6)^24 (eta_12)^5] ALGORITHM: An eta product of level `N` is uniquely determined by the integers `r_d` for `d | N` with `d < N`, since `\sum_{d | N} r_d = 0`. The valid `r_d` are those that satisfy two congruences modulo 24, and one congruence modulo 2 for every prime divisor of N. We beef up the congruences modulo 2 to congruences modulo 24 by multiplying by 12. To calculate the kernel of the ensuing map `\ZZ^m \to (\ZZ/24\ZZ)^n` we lift it arbitrarily to an integer matrix and calculate its Smith normal form. This gives a basis for the lattice. This lattice typically contains "large" elements, so by default we pass it to the reduce_basis() function which performs LLL-reduction to give a more manageable basis. """ N = self.level() divs = divisors(N)[:-1] s = len(divs) primedivs = prime_divisors(N) rows = [] for di in divs: # generate a row of relation matrix row = [Mod(di, 24) - Mod(N, 24), Mod(N // di, 24) - Mod(1, 24)] for p in primedivs: row.append(Mod(12 * (N // di).valuation(p), 24)) rows.append(row) M = matrix(IntegerModRing(24), rows) Mlift = M.change_ring(ZZ) # now we compute elementary factors of Mlift S, U, V = Mlift.smith_form() good_vects = [] for i in range(U.nrows()): vect = U.row(i) nf = (i < S.ncols() and S[i, i]) or 0 # ? good_vects.append((vect * 24 / gcd(nf, 24)).list()) for v in good_vects: v.append(-sum([r for r in v])) dicts = [] for v in good_vects: dicts.append({}) for i in range(s): dicts[-1][divs[i]] = v[i] dicts[-1][N] = v[-1] if reduce: return self.reduce_basis([self(d) for d in dicts]) else: return [self(d) for d in dicts]
def weight_two_basis_from_theta_blocks(N, prec, dim, jacobiforms=None, verbose=False): r""" Look for theta blocks of weight two and given index among the infinite families of weight two theta blocks associated to the root systems A_4, B_2+G_2, A_1+B_3, A_1+C_3 This is not meant to be called directly. Use JacobiForms(N).basis(2) with the optional parameter try_theta_blocks = True. INPUT: - ``N`` -- the index - ``prec`` -- precision - ``dim`` -- the dimension of the space of Jacobi forms. - ``jacobiforms`` -- a JacobiForms instance for this index. (If none is provided then we construct one now.) - ``verbose`` -- boolean (default False); if True then we comment on the computations. OUTPUT: a list of JacobiForm's """ if not jacobiforms: jacobiforms = JacobiForms(N) rank = 0 #the four families of weight two theta blocks from root lattices thetablockQ_1 = QuadraticForm( matrix([[4, 3, 2, 1], [3, 6, 4, 2], [2, 4, 6, 3], [1, 2, 3, 4]])) thetablockQ_2 = QuadraticForm( matrix([[24, 12, 0, 0], [12, 8, 0, 0], [0, 0, 12, 6], [0, 0, 6, 6]])) thetablockQ_3 = QuadraticForm( matrix([[4, 0, 0, 0], [0, 20, 10, 20], [0, 10, 10, 20], [0, 20, 20, 60]])) thetablockQ_4 = QuadraticForm( matrix([[4, 0, 0, 0], [0, 8, 8, 4], [0, 8, 16, 8], [0, 4, 8, 6]])) thetablock_tuple = thetablockQ_1, thetablockQ_2, thetablockQ_3, thetablockQ_4 from .jacobi_forms_class import theta_block thetablock_1 = lambda a, b, c, d, prec: theta_block( [a, a + b, a + b + c, a + b + c + d, b, b + c, b + c + d, c, c + d, d], -6, prec, jacobiforms=jacobiforms) thetablock_2 = lambda a, b, c, d, prec: theta_block([ a, 3 * a + b, 3 * a + b + b, a + a + b, a + b, b, c + c, c + c + d, 2 * (c + d), d ], -6, prec, jacobiforms=jacobiforms ) thetablock_3 = lambda a, b, c, d, prec: theta_block([ a + a, b + b, b + b + c, 2 * (b + c + d + d), b + b + c + d + d, b + b + c + 4 * d, c, c + d + d, c + 4 * d, d + d ], -6, prec, jacobiforms=jacobiforms ) thetablock_4 = lambda a, b, c, d, prec: theta_block([ a + a, b, b + b + c + c + d, b + c, b + c + c + d, b + c + d, c, c + c + d, c + d, d ], -6, prec, jacobiforms=jacobiforms ) thetablocks = thetablock_1, thetablock_2, thetablock_3, thetablock_4 basis = [] basis_vectors = [] pivots = [] div_N = divisors(N) div_N.reverse() for i, Q in enumerate(thetablock_tuple): v_list = Q.short_vector_list_up_to_length(N + 1, up_to_sign_flag=True) if verbose: print( 'I am looking through the theta block family of the root system %s.' % ['A_4', 'B_2+G_2', 'A_1+B_3', 'A_1+C_3'][i]) for _d in div_N: prec_d = prec * (N // _d) for v in v_list[_d]: a, b, c, d = v try: j = thetablocks[i](a, b, c, d, prec_d).hecke_V(N // _d) old_rank = 0 + rank basis, basis_vectors, pivots, rank = update_echelon_form_with( j, basis, basis_vectors, pivots, rank, sage_one_eighth) if verbose and old_rank < rank: if i == 0: L = [ abs(x) for x in (a, a + b, a + b + c, a + b + c + d, b, b + c, b + c + d, c, c + d, d) ] elif i == 1: L = [ abs(x) for x in (a, 3 * a + b, 3 * a + b + b, a + a + b, a + b, b, c + c, c + c + d, 2 * (c + d), d) ] elif i == 2: L = [ abs(x) for x in (a + a, b + b, b + b + c, 2 * (b + c + d + d), b + b + c + d + d, b + b + c + 4 * d, c, c + d + d, c + 4 * d, d + d) ] else: L = [ abs(x) for x in (a + a, b, b + b + c + c + d, b + c, b + c + c + d, b + c + d, c, c + c + d, c + d, d) ] L.sort() print('I found the theta block Th_' + str(L) + ' / eta^6.') if rank == dim: return basis except ValueError: pass if verbose: print( 'I did not find enough theta blocks. Time to try something else.') return jacobiforms.basis(2, prec, try_theta_blocks=False, verbose=verbose)
def weight_three_basis_from_theta_blocks(N, prec, dim, jacobiforms=None, verbose=False): r""" Look for theta blocks of weight three and given index among the infinite families of weight three theta blocks associated to the root systems B_3, C_3, A_2+A_3, 3A_2, 2A_1 + A_2 + B_2, 3A_1 + A_3, A_6, A_1+D_5. This is not meant to be called directly. Use JacobiForms(N).basis(3) with the optional parameter try_theta_blocks = True. INPUT: - ``N`` -- the index - ``prec`` -- precision - ``dim`` -- the dimension of the space of Jacobi forms. - ``jacobiforms`` -- a JacobiForms instance for this index. (If none is provided then we construct one now.) - ``verbose`` -- boolean (default False); if True then we comment on the computations. OUTPUT: a list of JacobiForm's """ if not jacobiforms: jacobiforms = JacobiForms(N) rank = 0 thetablockQ_1 = QuadraticForm( matrix([[20, 10, 20], [10, 10, 20], [20, 20, 60]])) #B3 thetablockQ_2 = QuadraticForm(matrix([[8, 8, 4], [8, 16, 8], [4, 8, 6]])) #C3 thetablockQ_3 = QuadraticForm( matrix([[2, 1, 0, 0, 0], [1, 2, 0, 0, 0], [0, 0, 12, 4, 4], [0, 0, 4, 4, 4], [0, 0, 4, 4, 12]])) #A2 + A3 thetablockQ_4 = QuadraticForm( matrix([[2, 1, 0, 0, 0, 0], [1, 2, 0, 0, 0, 0], [0, 0, 2, 1, 0, 0], [0, 0, 1, 2, 0, 0], [0, 0, 0, 0, 2, 1], [0, 0, 0, 0, 1, 2]])) #3 A2 thetablockQ_5 = QuadraticForm( matrix([[4, 0, 0, 0, 0, 0], [0, 4, 0, 0, 0, 0], [0, 0, 2, 1, 0, 0], [0, 0, 1, 2, 0, 0], [0, 0, 0, 0, 6, 6], [0, 0, 0, 0, 6, 12]])) #2A1 + A2 + B2 thetablockQ_6 = QuadraticForm( matrix([[4, 0, 0, 0, 0, 0], [0, 4, 0, 0, 0, 0], [0, 0, 4, 0, 0, 0], [0, 0, 0, 12, 4, 4], [0, 0, 0, 4, 4, 4], [0, 0, 0, 4, 4, 12]])) #3A1 + A3 thetablockQ_7 = QuadraticForm( matrix([[6, 5, 4, 3, 2, 1], [5, 10, 8, 6, 4, 2], [4, 8, 12, 9, 6, 3], [3, 6, 9, 12, 8, 4], [2, 4, 6, 8, 10, 5], [1, 2, 3, 4, 5, 6]])) #A6 thetablockQ_8 = QuadraticForm( matrix([[4, 0, 0, 0, 0, 0], [0, 10, 6, 12, 8, 4], [0, 6, 10, 12, 8, 4], [0, 12, 12, 24, 16, 8], [0, 8, 8, 16, 16, 8], [0, 4, 4, 8, 8, 8]])) #A1 + D5 thetablock_tuple = thetablockQ_1, thetablockQ_2, thetablockQ_3, thetablockQ_4, thetablockQ_5, thetablockQ_6, thetablockQ_7, thetablockQ_8 args1 = lambda b, c, d: [ b + b, b + b + c, 2 * (b + c + d + d), b + b + c + d + d, b + b + c + 4 * d, c, c + d + d, c + 4 * d, d + d ] args2 = lambda b, c, d: [ b, b + b + c + c + d, b + c, b + c + c + d, b + c + d, c, c + c + d, c + d, d ] args3 = lambda a, b, d, e, f: [ a, a + b, b, d + d, e, d + d + e, f + f, e + f + f, d + d + e + f + f ] args4 = lambda a, b, c, d, e, f: [a, a + b, b, c, c + d, d, e, e + f, f] args5 = lambda a, b, c, d, e, f: [ a + a, b + b, c, c + d, d, e, f + f, e + f + f, e + e + f + f ] args6 = lambda a, b, c, d, e, f: [ a + a, b + b, c + c, d + d, e, d + d + e, f + f, e + f + f, d + d + e + f + f ] args7 = lambda a, b, c, d, e, f: [ a, a + b, a + b + c, a + b + c + d, a + b + c + d + e, a + b + c + d + e + f, b, b + c, b + c + d, b + c + d + e, b + c + d + e + f, c, c + d, c + d + e, c + d + e + f, d, d + e, d + e + f, e, e + f, f ] args8 = lambda a, b, c, d, e, f: [ a + a, b, c, d, b + d, c + d, b + c + d, e, d + e, b + d + e, c + d + e, b + c + d + e, b + c + 2 * d + e, f, e + f, d + e + f, b + d + e + f, c + d + e + f, b + c + d + e + f, b + c + 2 * d + e + f, b + c + 2 * d + 2 * e + f ] args_tuple = args1, args2, args3, args4, args5, args6, args7, args8 from .jacobi_forms_class import theta_block thetablock_1 = lambda b, c, d, prec: theta_block( args1(b, c, d), -3, prec, jacobiforms=jacobiforms) thetablock_2 = lambda b, c, d, prec: theta_block( args2(b, c, d), -3, prec, jacobiforms=jacobiforms) thetablock_3 = lambda a, b, d, e, f, prec: theta_block( args3(a, b, d, e, f), -3, prec, jacobiforms=jacobiforms) thetablock_4 = lambda a, b, c, d, e, f, prec: theta_block( args4(a, b, c, d, e, f), -3, prec, jacobiforms=jacobiforms) thetablock_5 = lambda a, b, c, d, e, f, prec: theta_block( args5(a, b, c, d, e, f), -3, prec, jacobiforms=jacobiforms) thetablock_6 = lambda a, b, c, d, e, f, prec: theta_block( args6(a, b, c, d, e, f), -3, prec, jacobiforms=jacobiforms) thetablock_7 = lambda a, b, c, d, e, f, prec: theta_block( args7(a, b, c, d, e, f), -15, prec, jacobiforms=jacobiforms) thetablock_8 = lambda a, b, c, d, e, f, prec: theta_block( args8(a, b, c, d, e, f), -15, prec, jacobiforms=jacobiforms) thetablocks = thetablock_1, thetablock_2, thetablock_3, thetablock_4, thetablock_5, thetablock_6, thetablock_7, thetablock_8 basis = [] basis_vectors = [] pivots = [] div_N = divisors(N) div_N.reverse() for i, Q in enumerate(thetablock_tuple): v_list = Q.short_vector_list_up_to_length(N + 1, up_to_sign_flag=True) if verbose: print( 'I am looking through the theta block family of the root system %s.' % [ 'B_3', 'C_3', 'A_2+A_3', '3A_2', '2A_1+A_2+B_2', '3A_1 + A_3', 'A_6', 'A_1+D_5' ][i]) for _d in div_N: prec_d = prec * (N // _d) for v in v_list[_d]: if all(a for a in args_tuple[i](*v)): try: j = thetablocks[i](*(list(v) + [prec])).hecke_V(N // _d) old_rank = 0 + rank basis, basis_vectors, pivots, rank = update_echelon_form_with( j, basis, basis_vectors, pivots, rank, sage_one_eighth) if verbose and old_rank < rank: L = [abs(x) for x in args_tuple[i](*v)] L.sort() if _d == N: print('I found the theta block Th_' + str(L) + [' / eta^3.', ' / eta^15.'][i >= 6]) else: print( 'I applied the Hecke operator V_%d to the theta block Th_' % (N // _d) + str(L) + [' / eta^3.', ' / eta^15.'][i >= 6]) if rank == dim: return basis except ValueError: pass if verbose: print( 'I did not find enough theta blocks. Time to try something else.') return jacobiforms.basis(2, prec, try_theta_blocks=False, verbose=verbose)