︠78211bb9-e2f0-43d7-b602-fd76e3fd4789︠ ### How to experiment with modular forms in Sage ### ︡a09c357f-2fc8-485e-9bcd-c02364019367︡︡{"done":true} ︠5be6b2e6-3efd-4b98-b2c8-58e451a10b84︠ ## Before starting with modular forms commands, we briefly look at some basic Python/SageMath syntax ## ︡776be0dd-42cb-4c6a-bccc-c13135adf8ab︡︡{"done":true} ︠dc5d17e9-4043-46d5-a056-92a1170ec594︠ # Variables are pretty standard, we get some output using the print command # To evaluate a code block, press shift-enter a = 7 b = 8 print a + b mystring = "Variables can handle anything, " mystring_number_two = "and are allowed pretty long names." print mystring + mystring_number_two ︡40a836ae-d439-4d3b-802b-7a0893bd5d4f︡︡{"stdout":"15\n"}︡{"stdout":"Variables can handle anything, and are allowed pretty long names.\n"}︡{"done":true} ︠4b3d16d8-fb93-4bcd-8875-cc08b9f0189b︠ # The if-statement shows how indentation works. The Sage notebook tries to help you by indenting the cursor with 4 spaces when indentation is needed. Also, this examples shows that you can use variables from other code blocks (provided they are evaluated earlier). if a == b: print "We aren't working in the zero ring, are we?" else: if true: print "If-statements can be nested." ︡f6eca592-6f4b-4ce4-849c-8eb4a5e986d2︡︡{"stdout":"If-statements can be nested.\n"}︡{"done":true} ︠4d988825-b170-488c-82c7-a1a8b6ba7fb6︠ # A typical while-loop c=5 while c < 10: print c c = c + 2 ︡67d51a05-063f-4509-b4fd-fd0dbaff8707︡︡{"stdout":"5\n7\n9\n"}︡{"done":true} ︠256e83e8-6912-4276-aa74-6439a0e2c1ae︠ # Lists R=[1,2,4]; print R S=[1..5]; print S T=[x^2 for x in S]; print T print prime_range(17) print prime_range(7,18) ︡6b9ce68e-8f47-4360-a307-77cc5465cea1︡︡{"stdout":"[1, 2, 4]\n"}︡{"stdout":"[1, 2, 3, 4, 5]\n"}︡{"stdout":"[1, 4, 9, 16, 25]\n"}︡{"stdout":"[2, 3, 5, 7, 11, 13]\n"}︡{"stdout":"[7, 11, 13, 17]\n"}︡{"done":true} ︠9b7d7135-b6e4-4499-9437-de996699dd95︠ # A typical for-loop S = [3..7] for x in S: print 2*x ︡f1b3c5e9-ad22-4477-81b4-ff63fdfb6f0e︡︡{"stdout":"6\n8\n10\n12\n14\n"}︡{"done":true} ︠8dcb1786-4a3d-4478-87df-9ae3e972413a︠ ## Now we start with modular forms commands ## ︡e62ee350-6a47-460b-b37b-486acef70686︡︡{"done":true} ︠af3555a7-6ea0-4d65-bd94-6730c12ac9e2︠ # Create some congruence subgroups G = SL2Z G02 = Gamma0(2) G15 = Gamma1(5) G16 = Gamma1(6) G7 = Gamma(7) ︡7dcd56fb-025b-44f1-baf1-3200301f0371︡︡{"done":true} ︠b3f3bb3c-71a1-47a1-9e0f-31b727249bad︠ # Print a description of two of the objects we have defined print G print G02 ︡43e43f2d-962d-4e4b-ba6c-0cb8cd93f14d︡︡{"stdout":"Modular Group SL(2,Z)\n"}︡{"stdout":"Congruence Subgroup Gamma0(2)\n"}︡{"done":true} ︠5473473b-2d9e-4983-be48-b9d9de1feb2b︠ # Sage knows about relations between different groups print G16.is_subgroup(G02) print G16.index()/G02.index() ︡8f470b66-6b19-44a3-a131-3cf7603d7342︡︡{"stdout":"True\n"}︡{"stdout":"8\n"}︡{"done":true} ︠90775032-cf4a-4f68-a64e-8573a37305db︠ # Representatives for the cusps print G.cusps() print G15.cusps() ︡a56735ce-258c-4c53-82ac-ab64d49672e3︡︡{"stdout":"[Infinity]\n"}︡{"stdout":"[0, 2/5, 1/2, Infinity]\n"}︡{"done":true} ︠73fa2271-0128-49b8-9e6a-c94a685ab96a︠ # Generators print "Generators for SL2Z:" for g in G.gens(): print g print "" print "Generators for Gamma0(2):" for g in G02.gens(): print g print "" ︡3473644a-6587-4e6c-804b-b0901f8d7dd4︡︡{"stdout":"Generators for SL2Z:\n"}︡{"stdout":"[ 0 -1]\n[ 1 0]\n\n[1 1]\n[0 1]\n\n"}︡{"stdout":"Generators for Gamma0(2):\n"}︡{"stdout":"[1 1]\n[0 1]\n\n[ 1 -1]\n[ 2 -1]\n\n"}︡{"done":true} ︠be948e43-712d-4ab9-8e81-1f904aa4013d︠ #Coset representatives print "Coset representatives of Gamma0(2) in SL2Z:" for g in G02.coset_reps(): print g print "" ︡3f15152f-de5b-436b-a796-d911700a9d8d︡︡{"stdout":"Coset representatives of Gamma0(2) in SL2Z:\n"}︡{"stdout":"[1 0]\n[0 1]\n\n[ 0 -1]\n[ 1 0]\n\n[1 0]\n[1 1]\n\n"}︡{"done":true} ︠34a834d9-25ad-4df9-8f39-47b8bdb834e9︠ #Fundamental domains (the FareySymbol can be considered as a black box) FareySymbol(G02).fundamental_domain(show_pairing=true) FareySymbol(G15).fundamental_domain(show_pairing=true) ︡99b6231e-bbe0-4af8-ae92-ffa64285acff︡︡{"file":{"filename":"/projects/0d171da5-84c5-42cd-b702-55b21bf8f103/.sage/temp/compute1-us/16669/tmp_0cY5Hd.svg","show":true,"text":null,"uuid":"d6c883a4-922d-4501-8e66-db3ee9115e8b"},"once":false}︡{"html":"
"}︡{"file":{"filename":"/projects/0d171da5-84c5-42cd-b702-55b21bf8f103/.sage/temp/compute1-us/16669/tmp_ryf2CB.svg","show":true,"text":null,"uuid":"08061017-5177-408a-af95-7663d6397b9b"},"once":false}︡{"html":""}︡{"done":true} ︠e3545d41-c3cf-429f-a9ce-73f3245bc18c︠ # Construct a space of modular forms M = ModularForms(SL2Z, 12) print M ︡8bca1ef3-6f73-4696-9c1e-f886c719945b︡︡{"stdout":"Modular Forms space of dimension 2 for Modular Group SL(2,Z) of weight 12 over Rational Field\n"}︡{"done":true} ︠527dc95b-fd45-4e81-ac04-79080e83fd3b︠ # Compute a basis and give the q-expansions print M.basis() ︡da35de18-6664-496d-84fa-d6d014dc45df︡︡{"stdout":"[\nq - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6),\n1 + 65520/691*q + 134250480/691*q^2 + 11606736960/691*q^3 + 274945048560/691*q^4 + 3199218815520/691*q^5 + O(q^6)\n]\n"}︡{"done":true} ︠8e34cf13-22a1-474e-a693-978075096903︠ # Getting more terms is no problem. print M.q_expansion_basis(20) ︡3c518064-70bc-4e0b-9b34-b4892b45f3aa︡︡{"stdout":"[\nq - 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),\n1 + 65520/691*q + 134250480/691*q^2 + 11606736960/691*q^3 + 274945048560/691*q^4 + 3199218815520/691*q^5 + 23782204031040/691*q^6 + 129554448266880/691*q^7 + 563087459516400/691*q^8 + 2056098632318640/691*q^9 + 6555199353000480/691*q^10 + 18693620658498240/691*q^11 + 48705965462306880/691*q^12 + 117422349017369760/691*q^13 + 265457064498837120/691*q^14 + 566735214731736960/691*q^15 + 1153203117089652720/691*q^16 + 2245494646076179680/691*q^17 + 4212946097620893360/691*q^18 + 7632441763011374400/691*q^19 + O(q^20)\n]\n"}︡{"done":true} ︠8607451a-7770-4505-96d6-2c3582b27e82︠ # picking out a modular form from the basis # showing q_expansion and picking out coefficients of q^p with p prime delta=M.basis()[0] print delta.q_expansion() print delta.q_expansion(12) print [delta[p] for p in prime_range(2,12)] ︡acd1528a-91ef-4d06-b12a-93763037fe2f︡︡{"stdout":"q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6)\n"}︡{"stdout":"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 + O(q^12)\n"}︡{"stdout":"[-24, 252, 4830, -16744, 534612]\n"}︡{"done":true} ︠56a73384-5e84-49ec-adf9-184e632d98f3︠ # Construct a space of cusp forms S = CuspForms(SL2Z,24) print S ︡ea3ba8a4-7645-4170-9b22-ad75c2321211︡︡{"stdout":"Cuspidal subspace of dimension 2 of Modular Forms space of dimension 3 for Modular Group SL(2,Z) of weight 24 over Rational Field\n"}︡{"done":true} ︠0e554da6-0f89-4d31-b504-8f7c27ab7d99︠ # Hecke operators # Matrix with respect to computed basis, here: S.basis() # characteristic polynomial of the operator/matrix T2=S.T(2) print T2 print T2.matrix() print T2.charpoly() ︡efbbef96-8bfa-492d-bc25-376fb5ac0a93︡︡{"stdout":"Hecke operator T_2 on Cuspidal subspace of dimension 2 of Modular Forms space of dimension 3 for Modular Group SL(2,Z) of weight 24 over Rational Field\n"}︡{"stdout":"[ 0 20468736]\n[ 1 1080]\n"}︡{"stdout":"x^2 - 1080*x - 20468736\n"}︡{"done":true} ︠c59a3548-322b-4d38-b1e5-70e8ac8a1ce1︠ # Hecke operator on modular form print T2(delta*delta) print T2(delta*delta) == S.basis()[0]+1080*S.basis()[1] ︡bdcfaddb-9177-4ce9-ad1e-b07a720daf1e︡︡{"stdout":"q + 1080*q^2 + 143820*q^3 + 13246528*q^4 + 28412910*q^5 + O(q^6)\n"}︡{"stdout":"True\n"}︡{"done":true} ︠a97f317e-1a66-4a2c-9eac-6e8c7e6211df︠ # The diamond operator MM=ModularForms(Gamma1(7),2) print MM d5=MM.diamond_bracket_operator(5) print d5 print d5.matrix() ︡185202e0-96f5-4c61-8872-1b9a662a6d40︡︡{"stdout":"Modular Forms space of dimension 5 for Congruence Subgroup Gamma1(7) of weight 2 over Rational Field\n"}︡{"stdout":"Diamond bracket operator <5> on Modular Forms space of dimension 5 for Congruence Subgroup Gamma1(7) of weight 2 over Rational Field\n"}︡{"stdout":"[ -47 -84 -420 -420 -1260]\n[ -13 -24 -120 -115 -355]\n[ 2 4 19 18 57]\n[ 3 5 27 25 81]\n[ 1 2 9 10 26]\n"}︡{"done":true} ︠bff60c17-ebdf-4ac0-8937-fc9bf1ee27cds︠ ︡1d569614-a782-4e09-9967-7efdbe57e687︡︡{"done":true} ︠9e2b03ae-5d52-43ee-8a98-d7c2ae435ed4︠ %md 26 April -------- _The Petersson inner product; old and new subspaces_ ︡4c7a1ab7-d142-44db-a107-4cb422fb672f︡︡{"done":true,"md":"26 April\n--------\n\n_The Petersson inner product; old and new subspaces_"} ︠6eda7fd5-d418-4d2b-b842-9c4d70de3b60s︠ # Eisenstein subspace and cuspidal subspace M = ModularForms(Gamma1(14), 4) E = M.eisenstein_submodule() S = CuspForms(Gamma1(14), 4) S == M.cuspidal_submodule() M.dimension() (E.dimension(), S.dimension()) ︡36764c47-4826-4a52-8675-89511de0790d︡︡{"stdout":"True\n"}︡{"stdout":"24\n"}︡{"stdout":"(12, 12)\n"}︡{"done":true} ︠f4899a49-419f-4a12-a8d6-f5d42914b34bs︠ # Old and new subspaces Sold = S.old_submodule() Snew = S.new_submodule() (Sold.dimension(), Snew.dimension()) ︡30eee5a0-dab6-45b7-b748-930c9e11167a︡︡{"stdout":"(6, 6)\n"}︡{"done":true} ︠607306a7-4d14-4e1e-bff7-4e5c899fafa2︠ # Check consistency with dimensions of spaces of lower level CuspForms(Gamma1(2), 4).dimension() CuspForms(Gamma1(7), 4).dimension()s ︡ec9c8c77-eadf-4bf5-8169-e4962254a047︡︡{"stdout":"0\n"}︡{"stdout":"3\n"}︡{"done":true} ︠729e5964-b241-454d-9216-e7fed01a7016s︠ S.old_submodule(2) ︡f9ada2e9-fe77-4c46-919e-cc4c9277a7b6︡︡{"stdout":"Modular Forms subspace of dimension 6 of Modular Forms space of dimension 24 for Congruence Subgroup Gamma1(14) of weight 4 over Rational Field\n"}︡{"done":true} ︠f8452ca6-7682-4b65-a60f-4da63146413fs︠ # An example of a non-diagonalisable Hecke operator. This shows that the result # stated in the lecture on simultaneous eigenvectors for the T_m with m coprime to # the level N cannot be generalised directly to the T_m with m not coprime to N. S = CuspForms(Gamma0(16), 4) T2 = S.hecke_matrix(2) T2.jordan_form() ︡1b4b2880-76e6-4c6b-b1d8-956f21037929︡︡{"stdout":"[0 1|0]\n[0 0|0]\n[---+-]\n[0 0|0]\n"}︡{"done":true} ︠243d06fe-9dce-430f-9c84-cfeca000871e︠ ︡2718672f-c4e2-4b63-ad0b-6459d108c934︡ ︠e041d564-b8d8-49af-a2ba-1278a9281c68i︠ %md 3 May ----- _Newforms_ ︡25766dee-2e50-4c3d-9e35-77b2884ce98f︡︡{"done":true,"md":"3 May\n-----\n\n_Newforms_"} ︠e93f12dd-1633-4f41-a12a-c2b4335889fcs︠ # We can compute the set of newforms (primitive forms) of a given level and weight. S = CuspForms(Gamma1(15), 2) N = S.newforms() N Newforms(Gamma1(15), 2) == N ︡947bfd04-a241-4225-b980-52ab27f8f124︡︡{"stdout":"[q - q^2 - q^3 - q^4 + q^5 + O(q^6)]\n"}︡{"stdout":"True"}︡{"stdout":"\n"}︡{"done":true} ︠870e0a04-5d86-4c88-b60b-8bad84cc4ceds︠ # An example with multiple newforms Newforms(Gamma0(26), 2) ︡e0fefd8a-d5f2-4029-8874-7f4ef8d8f53d︡︡{"stdout":"[q - q^2 + q^3 + q^4 - 3*q^5 + O(q^6), q + q^2 - 3*q^3 + q^4 - q^5 + O(q^6)]"}︡{"stdout":"\n"}︡{"done":true} ︠f77b6c48-9ad3-4a35-8c3b-4a8bc5bcd0b1s︠ # We have to be careful when the newforms don't have rational coefficients Newforms(Gamma1(26), 2) ︡caf29572-4e52-4357-80c5-0e1ff5c402fe︡︡{"stderr":"Error in lines 2-2\n"}︡{"stderr":"Traceback (most recent call last):\n File \"/projects/sage/sage-6.10/local/lib/python2.7/site-packages/smc_sagews/sage_server.py\", line 905, in execute\n exec compile(block+'\\n', '', 'single') in namespace, locals\n File \"\", line 1, in