{ "cells": [ { "cell_type": "markdown", "id": "685ed40a", "metadata": {}, "source": [ "# Algebraic Number Theory, Lecture 15\n", "This notebook was created for the course on Algebraic Number Theory at Nagoya University in the Fall semester 2021/2022.\n", "\n", "See https://www.henrikbachmann.com/algnt_2021.html for the lecture notes and infos on this course." ] }, { "cell_type": "markdown", "id": "9ee06e9c", "metadata": {}, "source": [ "### Basics\n", "Create the number field $K=\\mathbb{Q}(i)$ and its ring of integers $\\mathcal{O}_K=\\mathbb{Z}[i]$ by using the minimal polynomial $x^2+1$ of $i$:" ] }, { "cell_type": "code", "execution_count": 55, "id": "8650ae3a", "metadata": {}, "outputs": [], "source": [ "K. = NumberField(x^2+1)\n", "O = K.ring_of_integers()" ] }, { "cell_type": "markdown", "id": "39788b31", "metadata": {}, "source": [ "Factor the ideal $(13)$ in $\\mathbb{Z}[i]$:" ] }, { "cell_type": "code", "execution_count": 6, "id": "b7900bbf", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Fractional ideal (-3*y - 2)) * (Fractional ideal (2*y + 3))" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "I=O.ideal(13);\n", "I.factor()" ] }, { "cell_type": "code", "execution_count": 245, "id": "4ec82c47", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4001 = 49 ^2 + 40 ^2\n" ] } ], "source": [ "# Naive way of finding the representation of p as a sum of two squares\n", "p=4001\n", "for a in range(p):\n", " for b in range(1,a+1):\n", " if a^2+b^2==p:\n", " print(p,\" = \", a,\"^2 + \",b,\"^2\")" ] }, { "cell_type": "markdown", "id": "ecdb4e1b", "metadata": {}, "source": [ "----\n", "Factorizing $6$ in $\\mathbb{Z}[\\sqrt{-5}]$." ] }, { "cell_type": "code", "execution_count": 54, "id": "d0b8fea6", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Fractional ideal (2, y + 1))^2 * (Fractional ideal (3, y + 1)) * (Fractional ideal (3, y + 2))" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "K. = NumberField(x^2+5); O = K.ring_of_integers();\n", "I=O.ideal(6)\n", "I.factor()" ] }, { "cell_type": "code", "execution_count": 57, "id": "1a25317d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "p1^2 = Fractional ideal (2)\n", "p2*p3 = Fractional ideal (1)\n", "p1*p2 = Fractional ideal (y + 1)\n", "p1*p3 = Fractional ideal (y + 1)\n" ] } ], "source": [ "p1=O.ideal(2,y+1); p2=O.ideal(3,y+1); p3=O.ideal(3,y+2);\n", "print(\"p1^2 = \",p1^2)\n", "print(\"p2*p3 = \",p2*p3)\n", "print(\"p1*p2 = \",p1*p2)\n", "print(\"p1*p3 = \",p1*p3)" ] }, { "cell_type": "markdown", "id": "a1373470", "metadata": {}, "source": [ "---\n", "### Trace and Norm\n" ] }, { "cell_type": "code", "execution_count": 59, "id": "14cfa5d1", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The element 4*y + 5 has norm 41 and trace 10\n" ] } ], "source": [ "K. = NumberField(x^2+1)\n", "m=5+4*y\n", "print(\"The element \", m , \" has norm \", m.norm() ,\" and trace \", m.trace() )" ] }, { "cell_type": "markdown", "id": "22bf9710", "metadata": {}, "source": [ "Consider the polynomial $f(x)=x^4-2x^2+x+1$. This has two real roots and one pair of complex conjugates. We can plot the graph of it by using the following code:" ] }, { "cell_type": "code", "execution_count": 92, "id": "16b742cf", "metadata": {}, "outputs": [ { "data": { "image/png": "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SUnRkiVLNHv2bOXm5qpnz546cuRIke/x273hOE5pD58988wzTmJiYpF/np+f78THxztPP/104XM///yz4/V6nVdffbU4p3Kt8ePHO16v16fXDh061OnX7wbnxhsdp1w5x/nvfwNbW7D5ei1s3Rc5OY6Tmuo4NWo4TnS04zzwgONkZPjv8zds2OBIcpYsWVL43OLFix1JzsaNG4t839ChQ53+/fv7rxCXyszMdCQ5mZmZtksJuLZt2zr33HPPac81adLEGTly5DlfP3fuXEeS89NPPwWhOnskOVOnTj3va/785z87TZo0Oe25u+++22nfvn0AKws+X65FpNwXjuM4+/btcyQ58+fPL/I1PtwbPuWcoA7mzszMVNWqVYv8823btikjI0M9e/YsfK58+fLq2rWrFi1aFIwSXWfBgi+1YEFtRUd/ob59c/X665G3B3Gw74v8fLP33uWXS/ffbwZsb94s/d//STVq+O88ixcvltfrVbt27Qqfa9++vbxe7wW/r3nz5ikuLk6XXXaZ7rrrLu3bt89/hSGojh8/rhUrVpx2f0tSz549L3gftGzZUjVr1lSPHj00d+7cQJbpWosXLz7r2vXq1UvLly/XiRMnLFVlVyTcF5mZ5mfh+TKFv+6NoAWlLVu26MUXX9Q999xT5GsyMjIkSTXO+GlUo0aNwj+LJNddd53effddzZ07S++887NiYz/XXXdV1iuvRNZf/mDdF44jzZhhpvrfcot0xRVmZttbb5nVtf0tIyNDcXFxZz0fFxd33u+r4L748ssv9fzzzystLU3du3c/bUPZUJaamqqkpCQlJyfbLiUoDhw4oLy8vGLd3zVr1tS4ceM0efJkTZkyRY0bN1aPHj20YMGCYJTsKhkZGee8drm5uTpw4IClquyIlPvCcRyNGDFCnTt3VrNmzYp8nb/ujWLPevN4PI9Leux8r0lLS1ObNm0Kv/7hhx/Uu3dvDRw4UHfeeacv5zjta8dxznrODR5//HE98cQT533NmdeiOH79618X/nezZs3Utu0e1a37mu677x5lZpqBxW65LIG+FlLg7gvHkWbOlJ54Qlq+3KyFtGiR1KFDyT7P12shnf09mXrO/32deV+0adNG9erV08yZM3XjjTeWrGgXSUlJUUpKSuGCk5GiOPd348aN1bhx48KvO3TooJ07d+q5555Tly5dAlqnG53r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\n", "text/plain": [ "Graphics object consisting of 1 graphics primitive" ] }, "execution_count": 92, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f(x)=x^4-2*x^2+x+1\n", "plot(f(x),(x,-2,2))" ] }, { "cell_type": "markdown", "id": "8b82ff2b", "metadata": {}, "source": [ "The roots of $f$ can be calculated by f.roots():" ] }, { "cell_type": "code", "execution_count": 119, "id": "07ba192f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-1.49021612009995\n", "-0.524888598656405\n", "1.00755235937818 - 0.513115795597015*I\n", "1.00755235937818 + 0.513115795597015*I\n" ] } ], "source": [ "f(x)=x^4-2*x^2+x+1\n", "for r in f.roots():\n", " print(r[0].n())" ] }, { "cell_type": "markdown", "id": "7344ea16", "metadata": {}, "source": [ "Now consider the number field obtained by adjoining a root of $f$:" ] }, { "cell_type": "code", "execution_count": 189, "id": "49a0f5c8", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "K is a Number Field in y with defining polynomial x^4 - 2*x^2 + x + 1 \n", "The degree is 4\n", "K has 2 real embeddings and 1 pair of complex embeddings\n" ] } ], "source": [ "K. = NumberField(f(x))\n", "print(\"K is a\",K,\"\\nThe degree is \", K.degree())\n", "[r,s]=K.signature()\n", "print(\"K has\",r,\" real embeddings and \",s, \"pair of complex embeddings\")" ] }, { "cell_type": "code", "execution_count": 104, "id": "b601e739", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "y^2 - 3 has norm 13 and trace -8\n" ] } ], "source": [ "# Using the built-in functions for norm and trace\n", "a=y^2-3\n", "print(a, \" has norm \", a.norm(), \" and trace \", a.trace())" ] }, { "cell_type": "markdown", "id": "b92b74b9", "metadata": {}, "source": [ "The trace and norm can be calculated by \n", "\\begin{align*}\n", " \\operatorname{Tr}_{L/K}(x) &= \\sum_{i=1}^n \\sigma_i(x)\\,,\\\\\n", " \\operatorname{N}_{L/K}(x) &= \\prod_{i=1}^n \\sigma_i(x)\\,.\n", "\\end{align*}\n", "where $\\sigma_i : K \\rightarrow \\mathbb{C}$ runs through all embeddings of $K$. If $\\theta_1,\\dots,\\theta_4$ are the roots of $f$, then $\\sigma_i$ for an element $a=\\sum_{j=0}^3 a_j y^j$ is given for $i=1,\\dots,4$ by\n", "\\begin{align*}\n", "\\sigma_i: \\sum_{j=0}^3 a_j y^j \\mapsto \\sum_{j=0}^3 a_j \\theta_i^j\n", "\\end{align*}" ] }, { "cell_type": "code", "execution_count": 188, "id": "338bc384", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "y^2 - 3 has norm 13.0000000000000 and trace -8.00000000000000\n" ] } ], "source": [ "# Calculating the norm&trace of y^2-3 by using the roots of the polynomial f\n", "p(x)=x^2-3\n", "norm=1\n", "trace=0\n", "for r in f.roots():\n", " norm*=p(r[0])\n", " trace+=p(r[0])\n", "print(a, \" has norm \", norm.n(), \" and trace \", trace.n())" ] }, { "cell_type": "markdown", "id": "203ba69d", "metadata": {}, "source": [ "Sage can also create all the $\\mathbb{C}-$embeddings of K:" ] }, { "cell_type": "code", "execution_count": 186, "id": "b6b2f66f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[\n", "Ring morphism:\n", " From: Number Field in y with defining polynomial x^3 - x^2 - 2*x - 8\n", " To: Complex Field with 53 bits of precision\n", " Defn: y |--> -0.883672870430983 - 1.45257666464430*I,\n", "Ring morphism:\n", " From: Number Field in y with defining polynomial x^3 - x^2 - 2*x - 8\n", " To: Complex Field with 53 bits of precision\n", " Defn: y |--> -0.883672870430983 + 1.45257666464430*I,\n", "Ring morphism:\n", " From: Number Field in y with defining polynomial x^3 - x^2 - 2*x - 8\n", " To: Complex Field with 53 bits of precision\n", " Defn: y |--> 2.76734574086197\n", "]" ] }, "execution_count": 186, "metadata": {}, "output_type": "execute_result" } ], "source": [ "K.embeddings(CC)" ] }, { "cell_type": "markdown", "id": "278551ec", "metadata": {}, "source": [ "With this we can compute the norm and trace as follows:" ] }, { "cell_type": "code", "execution_count": 193, "id": "9fada5ff", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "y^2 - 3 has norm 13.0000000000000 + 8.88178419700125e-16*I and trace -8.00000000000000\n" ] } ], "source": [ "# Calculating the norm&trace of y^2-3 by using the C-embeddings \n", "embeddings=K.embeddings(CC);\n", "a=y^2-3\n", "norm=1\n", "trace=0\n", "for e in embeddings:\n", " norm*=e(a)\n", " trace+=e(a)\n", "print(a, \" has norm \", norm.n(), \" and trace \", trace.n())" ] }, { "cell_type": "markdown", "id": "c6e81c49", "metadata": {}, "source": [ "---\n", "### Discriminant\n", "\n", "Let $\\omega_1,\\dots,\\omega_w$ be an integral basis of $K$. Then the discriminant of $K$ is given by \n", "\\begin{align*}\n", " d_K = d(\\omega_1,\\dots,\\omega_n) = \\det( \\sigma_i(\\omega_j) )^2,\n", "\\end{align*}\n", "where $\\sigma_i$ run again through all embeddings of $K$. " ] }, { "cell_type": "code", "execution_count": 206, "id": "86021342", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "K is a Number Field in y with defining polynomial x^3 - x^2 - 2*x - 8 \n", "The degree is 3\n", "K has 1 real embeddings and 1 pair of complex embeddings\n", "discriminant: -503\n", "integral basis: [1, 1/2*y^2 + 1/2*y, y^2]\n" ] } ], "source": [ "g(x)=x^3-x^2-2*x-8\n", "K. = NumberField(g(x))\n", "\n", "print(\"K is a\",K,\"\\nThe degree is \", K.degree())\n", "[r,s]=K.signature()\n", "print(\"K has\",r,\" real embeddings and \",s, \"pair of complex embeddings\")\n", "\n", "# Using the built in function for the discriminant & integral basis\n", "print(\"discriminant: \", K.discriminant())\n", "print(\"integral basis: \",K.integral_basis())" ] }, { "cell_type": "markdown", "id": "20cd34ed", "metadata": {}, "source": [ "Calculating the discriminant by using the integral basis" ] }, { "cell_type": "code", "execution_count": 244, "id": "858ad9ed", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-503.000000000000\n" ] } ], "source": [ "# Calculating the discriminant by using an integral basis\n", "B=K.integral_basis()\n", "embeddings=K.embeddings(CC)\n", "n=K.degree();\n", "mat=matrix.zero(CC,n,n)\n", "\n", "for i in range(n):\n", " for j in range(n):\n", " mat[i,j]=embeddings[i](B[j])\n", " \n", "print(det(mat)^2)" ] }, { "cell_type": "markdown", "id": "275f773b", "metadata": {}, "source": [ "---\n", "### Class number & Analytic class number formula" ] }, { "cell_type": "markdown", "id": "054deed6", "metadata": {}, "source": [ "Let $K=\\mathbb{Q}(\\sqrt{-5})$ then $\\mathcal{O}_K=\\mathbb{Z}[\\sqrt{-5}]$. The class number is $h_K=2$ and we can compute the classes as follows:" ] }, { "cell_type": "code", "execution_count": 255, "id": "d41db3eb", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Class group of order 2 with structure C2 of Number Field in y with defining polynomial x^2 + 5\n", "generators: Fractional ideal class (2, y + 1)\n", "class number: 2\n" ] } ], "source": [ "K. = NumberField(x^2+5)\n", "CK = K.class_group();\n", "print(CK)\n", "print(\"generators: \",CK.gen())\n", "print(\"class number: \",K.class_number())" ] }, { "cell_type": "code", "execution_count": 299, "id": "c34e637b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "RHS: 1.40496294620815\n", "LHS: 1.40496290972109\n" ] } ], "source": [ "# Analytic class number formula\n", "K. = NumberField(x^2+5)\n", "DZ = K.zeta_function()\n", "[r,s]=K.signature()\n", "RK=K.regulator()\n", "wK=K.zeta_order()\n", "dK=K.discriminant()\n", "hK=K.class_number()\n", "print(\"RHS:\", 2^r*(2*pi.n())^s*hK*RK/(wK*sqrt(abs(dK.n()))))\n", "print(\"LHS: \",(0.9999999-1)*DZ(0.9999999))" ] }, { "cell_type": "markdown", "id": "1c7f7dbd", "metadata": {}, "source": [ "---\n", "### Cyclotomic fields & regular primes\n", "\n", "\n", "A prime $p$ is called regular if $p$ does not divide $h_{\\mathbb{Q}(\\zeta_p)}$\n", "\n", "Recall the criteria of Kummer: A prime $p$ is regular if and only if it does not divide the numerator of the Bernoulli numbers $B_k$ for $k=2,4,\\dots,p-3$." ] }, { "cell_type": "code", "execution_count": 204, "id": "48902ef0", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cyclotomic Field of order 13 and degree 12\n" ] } ], "source": [ "# Cyclotomic field \n", "p=13\n", "K.

= CyclotomicField(p);\n", "print(K)" ] }, { "cell_type": "code", "execution_count": 110, "id": "ca71fd2a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", "-1/2\n", "1/6\n", "0\n", "-1/30\n", "0\n", "1/42\n", "0\n", "-1/30\n", "0\n" ] } ], "source": [ "# List of Bernoulli numbers B_0,....,B_9\n", "for k in range(10):\n", " print(bernoulli(k))" ] }, { "cell_type": "code", "execution_count": 200, "id": "fdd86153", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CPU times: user 9 µs, sys: 1 µs, total: 10 µs\n", "Wall time: 10 µs\n", "\n", "class number: 3\n", "23 is regular\n" ] } ], "source": [ "# Check if a prime is regular by using the definition\n", " \n", "p=23\n", "K. = CyclotomicField(p)\n", "# the command %time measures the time it takes for a command to be executed\n", "%time classnumber = K.class_number()\n", "\n", "print(\"\")\n", "print(\"class number: \", classnumber)\n", "\n", "if classnumber % p != 0:\n", " print(p, \" is regular\")\n", "else:\n", " print(p, \" is not regular\")" ] }, { "cell_type": "code", "execution_count": 68, "id": "6aa0ebba", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "37 is not regular\n" ] } ], "source": [ "# Using Kummer's criteria to check if a prime is regular \n", "p=37\n", "regular=True\n", "for k in range(2,p-2):\n", " if k % 2 ==0 and bernoulli(k).numerator() % p == 0:\n", " regular=False\n", " break\n", "\n", "if regular:\n", " print(p, \" is regular\")\n", "else:\n", " print(p, \" is not regular\")" ] }, { "cell_type": "code", "execution_count": 52, "id": "85fa00b5", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "37 is not regular\n", "59 is not regular\n", "67 is not regular\n", "101 is not regular\n", "103 is not regular\n" ] } ], "source": [ "# Give all irregular primes up to a given bound\n", "\n", "P = Primes()\n", "\n", "for n in range(30):\n", " p = P.unrank(n)\n", " regular=True\n", " for k in range(2,p-2):\n", " if k % 2 ==0 and bernoulli(k).numerator() % p == 0:\n", " regular=False\n", " break\n", "\n", " if not regular:\n", " print(p, \" is not regular\")" ] }, { "cell_type": "markdown", "id": "2ab6e6e4", "metadata": {}, "source": [ "---\n", "### Units " ] }, { "cell_type": "code", "execution_count": 331, "id": "8b052d63", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Unit group with structure C2 x Z of Number Field in y with defining polynomial x^2 - 7\n", "generators: [-1, 3*y - 8]\n" ] } ], "source": [ "K. = NumberField(x^2-7)\n", "UK = UnitGroup(K); \n", "print(UK);\n", "print(\"generators: \", UK.gens_values())\n", "zeta=UK.gens()[0]\n", "eps1=UK.gens()[1]" ] }, { "cell_type": "code", "execution_count": 330, "id": "afa40367", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Unit group with structure C2 x Z x Z of Number Field in y with defining polynomial x^5 - 8*x^2 + 36\n", "generators: [-1, 1/6*y^3 + 1/3*y^2 + 2/3*y + 1, 431/6*y^4 + 165/2*y^3 + 35*y^2 - 2384/3*y - 1525]\n" ] } ], "source": [ "K. = NumberField(x^5-8*x^2+36)\n", "UK = UnitGroup(K); \n", "print(UK);\n", "print(\"generators: \", UK.gens_values())\n", "zeta=UK.gens()[0]\n", "eps1=UK.gens()[1]\n", "eps2=UK.gens()[2]" ] }, { "cell_type": "markdown", "id": "8dd8856d", "metadata": {}, "source": [ "### Ramification " ] }, { "cell_type": "code", "execution_count": 358, "id": "105259cc", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The ideals over Fractional ideal (53) are:\n", "Fractional ideal (-2*y + 7) with ramification index e = 1 and inertia degree f = 1\n", "Fractional ideal (2*y + 7) with ramification index e = 1 and inertia degree f = 1\n" ] } ], "source": [ "# Calculate the ramification indices and inertia degrees\n", "K. = NumberField(x^2+1)\n", "p=K.ideal(53)\n", "fac=K.factor(p)\n", "print(\"The ideals over \", p, \" are:\")\n", "for P in fac:\n", " print(P[0], \"with ramification index e =\", P[1], \" and inertia degree f =\", P[0].residue_class_degree())" ] } ], "metadata": { "kernelspec": { "display_name": "SageMath 9.2", "language": "sage", "name": "sagemath" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.0" } }, "nbformat": 4, "nbformat_minor": 5 }