CoCalc -- Collaborative Calculation in the Cloud
Sharedsupport / 2015-05-29-105121-billeray.sagewsOpen in CoCalc

Examples for support purposes...


9731d058-825e-44de-a8db-0ef502f79df8i
%md
## Author of this worksheet: William Stein

### Question in email on May 28, 2015 from Nicolas Billerey

> Hi William,
> I suspect that there exists a CM form of weight 12, level $23^2$ and trivial Nebentypus character which is congruent to $\Delta$ mod 23. Similarly, I suspect that there also exists a CM form of weight 16, level $31^2$ and trivial Nebentypus congruent mod 31 to the unique newform of wt 16, level 1 and rational integer coefficients.


Author of this worksheet: William Stein

Question in email on May 28, 2015 from Nicolas Billerey

Hi William, I suspect that there exists a CM form of weight 12, level 23223^2 and trivial Nebentypus character which is congruent to Δ\Delta mod 23. Similarly, I suspect that there also exists a CM form of weight 16, level 31231^2 and trivial Nebentypus congruent mod 31 to the unique newform of wt 16, level 1 and rational integer coefficients.

First want to check there is nothing at level 23, so what we find below is at level 23223^2...

%time M = ModularSymbols(23, base_ring=GF(23), weight=12, sign=1)
CPU time: 0.14 s, Wall time: 0.15 s
d = delta_qexp(20); show(d)
q24q2+252q31472q4+4830q56048q616744q7+84480q8113643q9115920q10+534612q11370944q12577738q13+401856q14+1217160q15+987136q166905934q17+2727432q18+10661420q19+O(q20)\displaystyle q - 24q^{2} + 252q^{3} - 1472q^{4} + 4830q^{5} - 6048q^{6} - 16744q^{7} + 84480q^{8} - 113643q^{9} - 115920q^{10} + 534612q^{11} - 370944q^{12} - 577738q^{13} + 401856q^{14} + 1217160q^{15} + 987136q^{16} - 6905934q^{17} + 2727432q^{18} + 10661420q^{19} + O(q^{20})
%time T2 = M.hecke_operator(2)
CPU time: 0.01 s, Wall time: 0.01 s
%time V2 = (T2 - d[2]).kernel()
CPU time: 0.01 s, Wall time: 0.01 s

The following dimension shows that we have only the two images of delta under degen map, namely delta(q) and delta(q^23). Nothing else is possible.

V2.dimension()
2

OK, time to look into level 23223^2. We know a priori that we will have Δ(q)\Delta(q), Δ(q23)\Delta(q^{23}), and Δ(q232)\Delta(q^{23^2}), the images under the degeneracy maps corresponding to the divisors of 23223^2. So the question is whether or not there is a fourth form.

In the calculation below we will work modulo 2323 at level 23223^2 and deduce that there is such a fourth form (and no others). However, the mod 2323 calculation doesn't tell us anything else about that form -- just that it exists!

Incidentally, working mod a prime like below is fine as long as the prime isn't 22 or 33 -- if it is, then there are problems.

import sage_server; sage_server.MAX_OUTPUT_MESSAGES = 10000  # below may generate a lot of output
# this is a nontrivial sparse linear algebra computation over a small finite field, which should take 10s.
%time M = ModularSymbols(23^2, base_ring=GF(23), weight=12, sign=1)
M
CPU time: 10.20 s, Wall time: 10.66 s Modular Symbols space of dimension 507 for Gamma_0(529) of weight 12 with sign 1 over Finite Field of size 23
d = delta_qexp(600); show(d[:15])
q24q2+252q31472q4+4830q56048q616744q7+84480q8113643q9115920q10+534612q11370944q12577738q13+401856q14+O(q600)\displaystyle q - 24q^{2} + 252q^{3} - 1472q^{4} + 4830q^{5} - 6048q^{6} - 16744q^{7} + 84480q^{8} - 113643q^{9} - 115920q^{10} + 534612q^{11} - 370944q^{12} - 577738q^{13} + 401856q^{14} + O(q^{600})
%time T2 = M.hecke_operator(2)
CPU time: 0.02 s, Wall time: 0.02 s
%time V2 = (T2 - d[2]).kernel()
CPU time: 0.39 s, Wall time: 0.49 s
# positive evidence
V2.dimension()
4
%time V3 = (V2.hecke_operator(3) - d[3]).kernel()
CPU time: 0.33 s, Wall time: 0.33 s
# more positive evidence
V3.dimension()
4
%time V5 = (V3.hecke_operator(5) - d[5]).kernel()
CPU time: 0.37 s, Wall time: 0.37 s
# even more evidence
V5.dimension()
4

To prove we have a congruence with a newform we have to check up to the Sturm bound:

M.sturm_bound()
552

That's big and could be done in the following straightforward way, which would take a day. However, I'm too impatient and there is a trick that is massively faster (reducing an O(N) computation to O(1)).

%time  # so get overall time
d = delta_qexp(M.sturm_bound()+1)
V = M
p = 2
while p <= M.sturm_bound() and V.dimension()>1:
    print "working on p=%s"%p; sys.stdout.flush()
    if p != 23:
        %time V = (V.hecke_operator(p) - d[p]).kernel()
        print p, V.dimension()
    else:
        print "ignoring p=23 (for now)"
    p = next_prime(p)
    if p > 30:
        # THIS IS TOO SLOW FOR ME... but should work -- don't run.
        print "you should be morally convinced by now"
        break
working on p=2 CPU time: 0.10 s, Wall time: 0.10 s 2 4 working on p=3 CPU time: 0.00 s, Wall time: 0.01 s 3 4 working on p=5 CPU time: 0.00 s, Wall time: 0.00 s 5 4 working on p=7 CPU time: 0.43 s, Wall time: 0.43 s 7 4 working on p=11 CPU time: 0.59 s, Wall time: 0.61 s 11 4 working on p=13 CPU time: 0.68 s, Wall time: 0.69 s 13 4 working on p=17 CPU time: 0.79 s, Wall time: 0.80 s 17 4 working on p=19 CPU time: 0.82 s, Wall time: 0.83 s 19 4 working on p=23 ignoring p=23 (for now) working on p=29 CPU time: 1.10 s, Wall time: 1.17 s 29 4 you should be morally convinced by now CPU time: 4.52 s, Wall time: 4.66 s
d = delta_qexp(M.sturm_bound()+1)

What do the matrices look like on this 4-dimensional space?

V5
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 507 for Gamma_0(529) of weight 12 with sign 1 over Finite Field of size 23
show(V5.hecke_matrix(13))
(22000022000022000022)\displaystyle \left(\begin{array}{rrrr} 22 & 0 & 0 & 0 \\ 0 & 22 & 0 & 0 \\ 0 & 0 & 22 & 0 \\ 0 & 0 & 0 & 22 \end{array}\right)

I bet they are all diagonal except for T23T_{23}.

T23 = V5.hecke_matrix(23)
show(T23)
show(T23.fcp())

(6401432071630222021016)\displaystyle \left(\begin{array}{rrrr} 6 & 4 & 0 & 14 \\ 3 & 2 & 0 & 7 \\ 16 & 3 & 0 & 22 \\ 20 & 21 & 0 & 16 \end{array}\right)
(x+22)x3\displaystyle (x + 22) \cdot x^{3}

0a0dbc2c-db02-4948-893a-76551de23641
d[23] % 23
1

Use a trick to reduce complexity dramatically...

%time T2 = M.dual_hecke_matrix(2)
CPU time: 0.01 s, Wall time: 0.01 s
%time V2dual = (T2 - d[2]).kernel()
CPU time: 0.06 s, Wall time: 0.06 s
V2dual.dimension()
4
B = V2dual.free_module().basis()
# we need 4 easy-to-compute with basis elements that dot nonzero with our basis.
guess = [M.gen(i).element() for i in [0..3]]
A = matrix(4,4, [B[i].dot_product(guess[j]) for i in range(4) for j in range(4)])
show(A)

(1000010000100001)\displaystyle \left(\begin{array}{rrrr} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{array}\right)
# we got super lucky in this case.  The above means that computing
# the action of Tp on M.gen(0),..., M.gen(3) will give the same matrix
# as computing the action on our 4-dimensional subspace.
# But surprisingly it is massively easier...
# In general would have to invert a matrix and multiply by that.
# This should really be implemented in general in Sage, but evidently isn't...
Tp = M.hecke_operator(37)
%time x = Tp.apply_sparse(M.gen(0)) # fast even if "37" is large...
CPU time: 0.02 s, Wall time: 0.02 s
def fastT(p):
    Tp = M.hecke_operator(p)
    C = [Tp.apply_sparse(M.gen(i)).element() for i in range(4)]  # the real work
    return matrix(4,4,[b.dot_product(c) for b in B for c in C])
fastT(2).fcp()
(x + 1)^4
# compare with
V2.hecke_matrix(2).fcp()
(x + 1)^4
# try bigger
%time show(fastT(37))
(0000000000000000)\displaystyle \left(\begin{array}{rrrr} 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 \end{array}\right)
CPU time: 0.12 s, Wall time: 0.16 s
%time show(V2.hecke_matrix(37))
(0000000000000000)\displaystyle \left(\begin{array}{rrrr} 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 \end{array}\right)
CPU time: 1.25 s, Wall time: 1.32 s
show(fastT(23).fcp())
(x+22)x3\displaystyle (x + 22) \cdot x^{3}
show(V2.hecke_matrix(23).fcp())
(x+22)x3\displaystyle (x + 22) \cdot x^{3}

So now we do the hard computation above for primes up to the Sturm bound, but using our fastT:

%time  # so get overall time
d = delta_qexp(M.sturm_bound()+1)
V = M
p = 2
while p <= M.sturm_bound():
    print "doing p=%s"%p; sys.stdout.flush()
    if p != 23:
        %time Tp = fastT(p)
        if Tp != d[p]:  # the right scalar matrix
            print "FAIL at p=%s"%p
    else:
        print "ignoring p=23"
    p = next_prime(p)
doing p=2 CPU time: 0.09 s, Wall time: 0.09 s doing p=3 CPU time: 0.08 s, Wall time: 0.11 s doing p=5 CPU time: 0.09 s, Wall time: 0.10 s doing p=7 CPU time: 0.09 s, Wall time: 0.09 s doing p=11 CPU time: 0.08 s, Wall time: 0.08 s doing p=13 CPU time: 0.08 s, Wall time: 0.09 s doing p=17 CPU time: 0.08 s, Wall time: 0.08 s doing p=19 CPU time: 0.10 s, Wall time: 0.10 s doing p=23 ignoring p=23 doing p=29 CPU time: 0.08 s, Wall time: 0.09 s doing p=31 CPU time: 0.09 s, Wall time: 0.09 s doing p=37 CPU time: 0.10 s, Wall time: 0.10 s doing p=41 CPU time: 0.10 s, Wall time: 0.10 s doing p=43 CPU time: 0.10 s, Wall time: 0.10 s doing p=47 CPU time: 0.10 s, Wall time: 0.10 s doing p=53 CPU time: 0.10 s, Wall time: 0.10 s doing p=59 CPU time: 0.10 s, Wall time: 0.11 s doing p=61 CPU time: 0.12 s, Wall time: 0.12 s doing p=67 CPU time: 0.11 s, Wall time: 0.11 s doing p=71 CPU time: 0.11 s, Wall time: 0.12 s doing p=73 CPU time: 0.12 s, Wall time: 0.12 s doing p=79 CPU time: 0.12 s, Wall time: 0.13 s doing p=83 CPU time: 0.13 s, Wall time: 0.14 s doing p=89 CPU time: 0.12 s, Wall time: 0.13 s doing p=97 CPU time: 0.19 s, Wall time: 0.20 s doing p=101 CPU time: 0.13 s, Wall time: 0.13 s doing p=103 CPU time: 0.13 s, Wall time: 0.14 s doing p=107 CPU time: 0.16 s, Wall time: 0.17 s doing p=109 CPU time: 0.14 s, Wall time: 0.14 s doing p=113 CPU time: 0.19 s, Wall time: 0.20 s doing p=127 CPU time: 0.23 s, Wall time: 0.25 s doing p=131 CPU time: 0.14 s, Wall time: 0.14 s doing p=137 CPU time: 0.14 s, Wall time: 0.15 s doing p=139 CPU time: 0.15 s, Wall time: 0.15 s doing p=149 CPU time: 0.21 s, Wall time: 0.22 s doing p=151 CPU time: 0.16 s, Wall time: 0.16 s doing p=157 CPU time: 0.15 s, Wall time: 0.15 s doing p=163 CPU time: 0.16 s, Wall time: 0.16 s doing p=167 CPU time: 0.16 s, Wall time: 0.16 s doing p=173 CPU time: 0.16 s, Wall time: 0.16 s doing p=179 CPU time: 0.16 s, Wall time: 0.16 s doing p=181 CPU time: 0.16 s, Wall time: 0.17 s doing p=191 CPU time: 0.16 s, Wall time: 0.17 s doing p=193 CPU time: 0.17 s, Wall time: 0.17 s doing p=197 CPU time: 0.17 s, Wall time: 0.17 s doing p=199 CPU time: 0.17 s, Wall time: 0.18 s doing p=211 CPU time: 0.18 s, Wall time: 0.18 s doing p=223 CPU time: 0.18 s, Wall time: 0.19 s doing p=227 CPU time: 0.18 s, Wall time: 0.19 s doing p=229 CPU time: 0.24 s, Wall time: 0.24 s doing p=233 CPU time: 0.24 s, Wall time: 0.25 s doing p=239 CPU time: 0.20 s, Wall time: 0.20 s doing p=241 CPU time: 0.20 s, Wall time: 0.20 s doing p=251 CPU time: 0.19 s, Wall time: 0.20 s doing p=257 CPU time: 0.20 s, Wall time: 0.21 s doing p=263 CPU time: 0.21 s, Wall time: 0.22 s doing p=269 CPU time: 0.25 s, Wall time: 0.26 s doing p=271 CPU time: 0.20 s, Wall time: 0.21 s doing p=277 CPU time: 0.23 s, Wall time: 0.23 s doing p=281 CPU time: 0.29 s, Wall time: 0.30 s doing p=283 CPU time: 0.22 s, Wall time: 0.23 s doing p=293 CPU time: 0.21 s, Wall time: 0.23 s doing p=307 CPU time: 0.22 s, Wall time: 0.23 s doing p=311 CPU time: 0.22 s, Wall time: 0.22 s doing p=313 CPU time: 0.22 s, Wall time: 0.23 s doing p=317 CPU time: 0.29 s, Wall time: 0.30 s doing p=331 CPU time: 0.24 s, Wall time: 0.25 s doing p=337 CPU time: 0.26 s, Wall time: 0.26 s doing p=347 CPU time: 0.24 s, Wall time: 0.24 s doing p=349 CPU time: 0.26 s, Wall time: 0.27 s doing p=353 CPU time: 0.25 s, Wall time: 0.26 s doing p=359 CPU time: 0.25 s, Wall time: 0.30 s doing p=367 CPU time: 0.26 s, Wall time: 0.33 s doing p=373 CPU time: 0.25 s, Wall time: 0.26 s doing p=379 CPU time: 0.26 s, Wall time: 0.26 s doing p=383 CPU time: 0.37 s, Wall time: 0.38 s doing p=389 CPU time: 0.46 s, Wall time: 0.49 s doing p=397 CPU time: 0.37 s, Wall time: 0.45 s doing p=401 CPU time: 0.31 s, Wall time: 0.31 s doing p=409 CPU time: 0.33 s, Wall time: 0.34 s doing p=419 CPU time: 0.30 s, Wall time: 0.30 s doing p=421 CPU time: 0.37 s, Wall time: 0.38 s doing p=431 CPU time: 0.28 s, Wall time: 0.29 s doing p=433 CPU time: 0.28 s, Wall time: 0.28 s doing p=439 CPU time: 0.28 s, Wall time: 0.29 s doing p=443 CPU time: 0.30 s, Wall time: 0.31 s doing p=449 CPU time: 0.30 s, Wall time: 0.31 s doing p=457 CPU time: 0.30 s, Wall time: 0.31 s doing p=461 CPU time: 0.29 s, Wall time: 0.30 s doing p=463 CPU time: 0.29 s, Wall time: 0.30 s doing p=467 CPU time: 0.29 s, Wall time: 0.31 s doing p=479 CPU time: 0.30 s, Wall time: 0.31 s doing p=487 CPU time: 0.30 s, Wall time: 0.31 s doing p=491 CPU time: 0.38 s, Wall time: 0.39 s doing p=499 CPU time: 0.33 s, Wall time: 0.34 s doing p=503 CPU time: 0.36 s, Wall time: 0.37 s doing p=509 CPU time: 0.32 s, Wall time: 0.33 s doing p=521 CPU time: 0.39 s, Wall time: 0.40 s doing p=523 CPU time: 0.40 s, Wall time: 0.41 s doing p=541 CPU time: 0.31 s, Wall time: 0.32 s doing p=547 CPU time: 0.50 s, Wall time: 0.60 s CPU time: 21.27 s, Wall time: 22.28 s

So in less than minute total CPU time we've verified your first claim using exactly the right algorithms...
















1cceb312-cf04-49ba-86ac-13c4d8dd9925





468254dc-750c-4c4d-93f7-a6d2e5a6f980is
%md
Some stuff involving new subspaces I left around...
New subspaces with modular symbols behave funny in characteristic $p$.

Some stuff involving new subspaces I left around... New subspaces with modular symbols behave funny in characteristic pp.

set_verbose(2)
%time Mn = M.new_subspace()
3f663140-919f-497d-8ff3-410c88a1fce1
%time V2new = V2.new_subspace()
7807ea9f-fadd-4047-95ce-8b972d5e7833
V2new
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 507 for Gamma_0(529) of weight 12 with sign 1 over Finite Field of size 23
V2new.hecke_operator(23).fcp()
verbose 1 (6534: free_module.py, echelon_coordinates) mod-p multiply of 1 x 2 matrix by 2 x 507 matrix modulo 23 verbose 1 (6534: free_module.py, echelon_coordinates) mod-p multiply of 1 x 2 matrix by 2 x 507 matrix modulo 23 verbose 1 (579: matrix_morphism.py, characteristic_polynomial) _charpoly_linbox... x^2
%time D = V2new.dual_free_module(bound=5)
7e4ff758-7af1-4b0b-ab25-39ced6736065