{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's investigate the conjecture on elliptic periods.\n",
    "\n",
    "We want to find a counter-example, i.e., we want to find a curve over $\\mathbb{F}_p$ such that a subgroup of order $ℓ$ is defined over an extension of degree $r|(ℓ-1)$, and such that the periods of that subgroup fall in a field smaller than $\\mathbb{F}_{p^r}$.\n",
    "\n",
    "To avoid pitfalls, we prefer having $r>2$, $ℓ≠p$, and maybe even $r≠p$. Since we have to mod-out the automorphisms of the curve, the smallest possible $ℓ$ to exhibit a counter-example is $13$, so that $(ℤ/13ℤ)^*/\\{±1\\}=\\mathcal{C}_2\\times\\mathcal{C}_3$.\n",
    "\n",
    "So, let's set $ℓ=13$, $r=3$. The elliptic period is defined as $x(P)+x([5]P)$ for $P$ a point of order 13 in a well chosen subgroup.\n",
    "\n",
    "We look for a curve that has $13$-torsion points in an extension of degree $3$.\n",
    "\n",
    "Here's an idea to generate tons of examples: take a curve over $ℚ$ with this property, and reduce modulo many primes. We are lucky: there are infinitely many such curves (<http://arxiv.org/pdf/1211.2188.pdf>, prop 31), and one such example is curve `147b1` in Cremona's database."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Elliptic Curve defined by y^2 + y = x^3 + x^2 - 114*x + 473 over Rational Field"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "E = EllipticCurve('147b1')\n",
    "E"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The curve is singular at $3$ and $7$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-1 * 3 * 7^8"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "E.discriminant().factor()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And certainly supersingular at $2$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(-28672/3, -1 * 2^12 * 3^-1 * 7)"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "E.j_invariant(), E.j_invariant().factor()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It's $13$-division polynomial factors as expected"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[3, 3, 78]"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[f[0].degree() for f in E.division_polynomial(13).factor()]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[(x^3 - 48*x^2 + 425*x - 1009, 1), (x^3 + x^2 - 114*x - 127, 1)]"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "facts = E.division_polynomial(13).factor()[:2]\n",
    "facts"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's look at multiplication by $5$. It's action on the abscissa is given by a rational fraction in $x$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(x^25 + 11400*x^23 - 952440*x^22 + 21459390*x^21 - 109428732*x^20 - 4950010695*x^19 + 144784682400*x^18 - 181243777785*x^17 - 76264253249145*x^16 + 1852228009144500*x^15 - 17751704371327800*x^14 - 13405942951098075*x^13 + 2174244297003851940*x^12 - 23804139576831231690*x^11 + 121433153419916125074*x^10 - 449464862928041129205*x^9 + 5800247633495175127650*x^8 - 83614774727436641897175*x^7 + 721566408459768769400580*x^6 - 4069574415747167715056277*x^5 + 16123970604415307494932945*x^4 - 46252779384036854092437225*x^3 + 94273994056986749224110510*x^2 - 123535079543891692412564130*x + 77552624336221526363279505)/(25*x^24 + 200*x^23 - 70120*x^22 + 1425070*x^21 + 48308554*x^20 - 2610219360*x^19 + 43594684875*x^18 - 67903799190*x^17 - 9897608934825*x^16 + 202483959479556*x^15 - 2037974926602780*x^14 + 6054274701348300*x^13 + 169194401041110165*x^12 - 3540471811324712460*x^11 + 39604874743194363378*x^10 - 306463233082971903660*x^9 + 1678785952137330965175*x^8 - 5689479606125098303260*x^7 + 3210444480296511269595*x^6 + 76839986296881639452124*x^5 - 379972558692366773002065*x^4 + 584163989209171893761550*x^3 + 1091490755999416581874005*x^2 - 5298108546577918019618340*x + 5764429991723000943803364)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mul5 = E.multiplication_by_m(5, x_only=True)\n",
    "mul5"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As we expect, multiplication by $5$ sends the abscissas of one factor to the other. We can verify this with a resultant."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_.<x,y> = QQ[]\n",
    "facts[0][0].resultant(mul5.denominator()*y - mul5.numerator()).univariate_polynomial().monic() == facts[1][0](y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "facts[1][0].resultant(mul5.denominator()*y - mul5.numerator()).univariate_polynomial().monic() == facts[0][0](y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By the same resultant trick, we get the minimal polynomial of the elliptic period. Remember: the period is defined as $x(P)+x([5]P)$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1347137238494276547832006567721872890819326613454654477690085519113574118965817601*y^3 - 63315450209230997748104308682928025868508350832368760451434019398337983591393427247*y^2 + 375851289539903156845129832394402536538592125153848599275533859832687179191463110679*y + 5430310208370428764310818474486869622892705578835712199568734727546817273551210749631"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "period = facts[0][0].resultant(mul5.denominator()*(y - x) - mul5.numerator()).univariate_polynomial()\n",
    "period"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Quite big coefficients, but let's look at the leading one"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "7^96"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "period.leading_coefficient().factor()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ahah! Only the singular prime appears in it! Of course not a coincidence.\n",
    "\n",
    "Let's simplify"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "y^3 - 47*y^2 + 279*y + 4031"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "period = period.monic()\n",
    "period"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Surprisingly short!\n",
    "\n",
    "Just to be sure, let's check that this does not depend on the choice of the initial point."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "facts[1][0].resultant(mul5.denominator()*(y - x) - mul5.numerator()).univariate_polynomial().monic() == period"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "So, now we look for a prime $p≠2,3,7$ such that the $13$-torsion points live in $\\mathbb{F}_{p^3}$, but the period lives in $\\mathbb{F}_p$.\n",
    "\n",
    "We can read this directly on the polynomials."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[(2, ([], [], [(1, 3)])),\n",
       " (3, ([], [], [])),\n",
       " (5, ([], [], [])),\n",
       " (7, ([(2, 3)], [(2, 3)], [(4, 3)])),\n",
       " (11, ([], [], [])),\n",
       " (13,\n",
       "  ([(10, 1), (8, 1), (4, 1)],\n",
       "   [(12, 1), (7, 1), (6, 1)],\n",
       "   [(4, 1), (3, 1), (1, 1)])),\n",
       " (17, ([], [], [])),\n",
       " (19, ([], [], [])),\n",
       " (23, ([], [], [])),\n",
       " (29,\n",
       "  ([(27, 1), (15, 1), (6, 1)],\n",
       "   [(23, 1), (22, 1), (12, 1)],\n",
       "   [(0, 1), (27, 1), (20, 1)])),\n",
       " (31, ([], [], [])),\n",
       " (37, ([], [], [])),\n",
       " (41,\n",
       "  ([(24, 1), (19, 1), (5, 1)],\n",
       "   [(18, 1), (15, 1), (7, 1)],\n",
       "   [(26, 1), (20, 1), (1, 1)])),\n",
       " (43,\n",
       "  ([(31, 1), (10, 1), (7, 1)],\n",
       "   [(21, 1), (15, 1), (6, 1)],\n",
       "   [(28, 1), (16, 1), (3, 1)])),\n",
       " (47, ([], [], [])),\n",
       " (53, ([], [], [])),\n",
       " (59, ([], [], [])),\n",
       " (61, ([], [], [])),\n",
       " (67, ([], [], [])),\n",
       " (71,\n",
       "  ([(69, 1), (35, 1), (15, 1)],\n",
       "   [(30, 1), (29, 1), (11, 1)],\n",
       "   [(64, 1), (28, 1), (26, 1)])),\n",
       " (73, ([], [], [])),\n",
       " (79, ([], [], [])),\n",
       " (83,\n",
       "  ([(61, 1), (51, 1), (19, 1)],\n",
       "   [(72, 1), (69, 1), (24, 1)],\n",
       "   [(50, 1), (43, 1), (37, 1)])),\n",
       " (89, ([], [], [])),\n",
       " (97,\n",
       "  ([(78, 1), (36, 1), (31, 1)],\n",
       "   [(95, 1), (80, 1), (18, 1)],\n",
       "   [(76, 1), (49, 1), (19, 1)]))]"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def test(p):\n",
    "    R = PolynomialRing(GF(p), 'x')\n",
    "    return R(facts[0][0]).roots(), R(facts[1][0]).roots(), R(period).roots()\n",
    "\n",
    "[(p,test(p)) for p in primes(100)]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Bad luck! Or maybe not.\n",
    "\n",
    "One thing is obvious: if the first two split, the third splits as well. The opposite is less obvious. Let's work it out.\n",
    "\n",
    "Call $P_1$ and $P_2$ the two factors of $φ_{13}$ of degree $3$. We want to prove that if $P_1$ (and $P_2$) is irreducible, then the minimal polynomial of the period is irreducible too. Let's suppose this is not the case and see what happens.\n",
    "\n",
    "The first component of the multiplication-by-$5$ defines a rational mapping $I(x) = ψ_5(x)/φ_5^2(x)$. Since the only poles of $I(x)$ are in $E[5]$, its restriction to $V(P_1P_2)$ defines a polynomial mapping $i(x) = I(x) \\bmod P_1P_2$, sending the roots of $P_1$ onto the roots of $P_2$ and *vice-versa*. This is obvious from the properties of the resultant, but let's double check."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A = QQ['x'].quo(facts[0][0]*facts[1][0])\n",
    "facts[0][0].resultant(y - mul5(A.gen()).lift()) == facts[1][0](y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "facts[1][0].resultant(y - mul5(A.gen()).lift()) == facts[0][0](y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The mapping $x + i(x)$ sends the roots of $P_1$ and the roots of $P_2$ onto the ellptic periods. If we suppose that $\\mathrm{Res}_x(P_1(x), y - x - i(x)) = \\mathrm{Res}_x(P_2(x), y - x - i(x))$ splits over $\\mathbb{F}_p$, then by Galois invariance $x + i(x) = t \\bmod P_1$ for a constant $t∈\\mathbb{F}_p$, and since the periods do not depend on the initial choice of $P_1$ or $P_2$, we conclude that $i(x) = (t - x) \\bmod P_1P_2$.\n",
    "\n",
    "Hence, we can just compute $x + i(x) \\bmod P_1P_2$ and see for what primes it is a constant."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "12/16807*x^5 - 526/16807*x^4 + 1572/16807*x^3 + 58484/16807*x^2 - 308958/16807*x + 194559/16807"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x + mul5(A.gen()).lift()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "7^5"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "factor(16807)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "gcd([526, 1572, 58484, 308958])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "No suprise: $7$ is the only divisor in the denominators.\n",
    "\n",
    "And bad news: the only prime that divides all coefficients is $2$, but we had ruled this one out before. So no reduction of $E$ is ever going to yield a counter-example.\n",
    "\n",
    "Just for completeness, let's do the same check using norms instead of traces"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1347137238494276547832006567721872890819326613454654477690085519113574118965817601*y^3 + 21554195815908424765312105083549966253109225815274471643041368305817185903453081616*y^2 - 5583883853558776290763667223207163132446108812769542810025404476725764723113313956145*y - 172626207152372079668836817607583957848260970227919788734640628675770728326636764844943"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "period2 = facts[0][0].resultant(mul5.denominator()*y - x*mul5.numerator()).univariate_polynomial()\n",
    "period2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "7^96"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "period2.leading_coefficient().factor()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "y^3 + 16*y^2 - 4145*y - 128143"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "period2 = period2.monic()\n",
    "period2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "facts[1][0].resultant(mul5.denominator()*y - x*mul5.numerator()).univariate_polynomial().monic() == period2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "38/16807*x^5 - 1584/16807*x^4 + 1352/16807*x^3 + 194591/16807*x^2 - 538053/16807*x - 1537716/16807"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "((mul5)(A.gen()) * A.gen()).lift()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "gcd([1584, 1352, 194591, 538053])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "At least now we have a criterion to do a brute-force search relatively fast: look for a curve $E/\\mathbb{F}_p$ such that its $13$-division polynomial has two factors of degree $3$, and such that multiplication-by-$5$ modulo these two factors equals $t-x$ for some constant $t∈\\mathbb{F}_p$.\n",
    "\n",
    "This criterion easily extends to all primes $r,ℓ$ such that $4r=ℓ-1$ and where $i^2=-1\\bmod ℓ$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def test_p(ell, r, i, p):\n",
    "    count = 0\n",
    "    ex = []\n",
    "    for j in GF(p):\n",
    "        if j != 0 and j != 1728:\n",
    "            E = EllipticCurve(j=j)\n",
    "            phi = E.division_polynomial(ell)\n",
    "            x = phi.parent().gen()\n",
    "            f = gcd(phi, pow(x, p**r, phi) - x)\n",
    "            if f.degree() == 2*r:\n",
    "                count += 1\n",
    "                I = E.multiplication_by_m(i, x_only=True)\n",
    "                I = I.numerator().mod(f) * I.denominator().inverse_mod(f) % f\n",
    "                if (I + x).degree() <= 0:\n",
    "                    ex.append(E)\n",
    "    return count, ex"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def test_ell(ell, max_p=Infinity):\n",
    "    r = (ell - 1)//4\n",
    "    assert(is_prime(r))\n",
    "    i = Zmod(ell)(-1).sqrt()\n",
    "    i = min(i, -i).lift()\n",
    "    p = 3\n",
    "    ex = []\n",
    "    while p <= max_p:\n",
    "        t = test_p(ell, r, i, p)\n",
    "        print p, t, ex\n",
    "        if t[1]:\n",
    "            ex.append(t)\n",
    "        p = next_prime(p)\n",
    "    return ex"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3 (0, []) []\n",
      "5 (1, []) []\n",
      "7 (2, []) []\n",
      "11 (5, []) []\n",
      "13 (5, []) []\n",
      "17 (0, []) []\n",
      "19 (8, []) []\n",
      "23 (0, []) []\n",
      "29 (4, []) []\n",
      "31 (14, []) []\n",
      "37 (16, []) []\n",
      "41 (19, []) []\n",
      "43 (0, []) []\n",
      "47 (23, []) []\n",
      "53 (8, []) []\n",
      "59 (29, []) []\n",
      "61 (10, []) []\n",
      "67 (32, []) []\n",
      "71 (35, []) []\n",
      "73 (34, []) []\n",
      "79 (10, []) []\n",
      "83 (41, []) []\n",
      "89 (43, []) []\n",
      "97 (46, []) []\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[]"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test_ell(13, 100)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3 (0, []) []\n",
      "5 (0, []) []\n",
      "7 (0, []) []\n",
      "11 (4, []) []\n",
      "13 (0, []) []\n",
      "17 (9, []) []\n",
      "19 (3, []) []\n",
      "23 (0, []) []\n",
      "29 (15, []) []\n",
      "31 (12, []) []\n",
      "37 (21, []) []\n",
      "41 (15, []) []\n",
      "43 (16, []) []\n",
      "47 (22, []) []\n",
      "53 (4, []) []\n",
      "59 (2, []) []\n",
      "61 (31, []) []\n",
      "67 (0, []) []\n",
      "71 (0, []) []\n",
      "73 (31, []) []\n",
      "79 (40, []) []\n",
      "83 (2, []) []\n",
      "89 (47, []) []\n",
      "97 (51, []) []\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[]"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test_ell(29, 100)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "I'm testing $ℓ=13,29,53$. No luck so far (tested some thousands of primes).\n",
    "\n",
    "The test is quite slow, mainly due to the factorization step in `test_p`. Using modular polynomials à la SEA could speed it up a bit.\n",
    "\n",
    "It was suggested that we use `sage.schemes.elliptic_curves.isogeny_small_degree.isogenies_prime_degree_genus_0` for $ℓ=13,29$, but a quick profiling shows that this function is (significantly) slower than our naive factorization."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we can generalize the test we performed on `147b1` to other curves over $ℚ$ that have 13-torsion points in a cubic extension.\n",
    "\n",
    "Table 1 in <http://arxiv.org/pdf/1509.00528v2.pdf> parameterizes these curves by\n",
    "\n",
    "$$j(t) = \\frac{(t^4 - t^3 + 5t^2 + t + 1)(t^8 - 5t^7 + 7t^6 - 5t^5 + 5t^3 + 7t^2 + 5t + 1)^3}{t^{13} (t^2 - 3t - 1)}.$$\n",
    "\n",
    "Below is a very fast test that runs through all this curves, and looks for prime factors common to all coefficients of $x+i(x)\\bmod P_1P_2$, except the constant coefficient, and excluding singular primes and those that yield $j$-invariant $0$ and $1728$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def test_X0(T=QQ, period=None):\n",
    "    _.<t> = QQ[]\n",
    "    j = (t^4 - t^3 + 5*t^2 + t + 1)*(t^8 - 5*t^7 + 7*t^6 - 5*t^5 + 5*t^3 + 7*t^2 + 5*t + 1)^3/(t^13 * (t^2 - 3*t - 1))\n",
    "    ex = []\n",
    "    if period is None:\n",
    "        period = lambda I: I + I.parent().gen()\n",
    "    for t in T:\n",
    "        if t != 0:\n",
    "            E = EllipticCurve(j=j(t))    # this is the slowest computation\n",
    "            I = period(E.multiplication_by_m(5, x_only=True))\n",
    "            for phi in E.isogenies_prime_degree(13):\n",
    "                f = phi.kernel_polynomial().factor()[0][0]\n",
    "                m = I.numerator().mod(f) * I.denominator().inverse_mod(f) % f\n",
    "                J = E.j_invariant()\n",
    "                badp = E.discriminant() * J.numerator() * (J-1728).numerator()\n",
    "                goodp = filter(lambda (p,m): not p.divides(badp), gcd(m[1:]).factor())\n",
    "                if goodp:\n",
    "                    ex.append((t, J, goodp))\n",
    "                print t, J, ex"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can test the conjecture for traces and norms"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 -28672/3 []\n",
      "-1 -28672/3 []\n",
      "1/2 -140246460241/73728 []\n",
      "-1/2 152303/24576 []\n",
      "2 152303/24576 []\n",
      "-2 -140246460241/73728 []\n",
      "1/3 -2017252899377152/27103491 []\n",
      "-1/3 2072735744/1594323 []\n",
      "3 2072735744/1594323 []\n",
      "-3 -2017252899377152/27103491 []\n",
      "2/3 -55698160846329217/300395962368 []\n",
      "-2/3 -3924067587589/13060694016 []\n",
      "3/2 -3924067587589/13060694016 []\n",
      "-3/2 -55698160846329217/300395962368 []\n",
      "1/4 -2354926657441487617/1811939328 []\n",
      "-1/4 122607109504897/201326592 []\n",
      "4 122607109504897/201326592 []\n",
      "-4 -2354926657441487617/1811939328 []\n",
      "3/4 -349809498592264034737/4600707831300096 []\n"
     ]
    }
   ],
   "source": [
    "from itertools import islice\n",
    "test_X0(islice(QQ, 20))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 -28672/3 []\n",
      "-1 -28672/3 []\n",
      "1/2 -140246460241/73728 []\n",
      "-1/2 152303/24576 []\n",
      "2 152303/24576 []\n",
      "-2 -140246460241/73728 []\n",
      "1/3 -2017252899377152/27103491 []\n",
      "-1/3 2072735744/1594323 []\n",
      "3 2072735744/1594323 []\n",
      "-3 -2017252899377152/27103491 []\n",
      "2/3 -55698160846329217/300395962368 []\n",
      "-2/3 -3924067587589/13060694016 []\n",
      "3/2 -3924067587589/13060694016 []\n",
      "-3/2 -55698160846329217/300395962368 []\n",
      "1/4 -2354926657441487617/1811939328 []\n",
      "-1/4 122607109504897/201326592 []\n",
      "4 122607109504897/201326592 []\n",
      "-4 -2354926657441487617/1811939328 []\n",
      "3/4 -349809498592264034737/4600707831300096 []\n"
     ]
    }
   ],
   "source": [
    "test_X0(islice(QQ, 20), lambda I: I * I.parent().gen())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We're intensively testing the conjecture for many more $j$-invariants, and no counter-example has been found yet.\n",
    "\n",
    "On the other hand, to vaguely support the conjecture, perturbing the period function just slightly quickly yields common factors:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 -28672/3 []\n",
      "-1 -28672/3 []\n",
      "1/2 -140246460241/73728 []\n",
      "-1/2 152303/24576 []\n",
      "2 152303/24576 []\n",
      "-2 -140246460241/73728 []\n",
      "1/3 -2017252899377152/27103491 []\n",
      "-1/3 2072735744/1594323 [(-1/3, 2072735744/1594323, [(19, 1)])]\n",
      "3 2072735744/1594323 [(-1/3, 2072735744/1594323, [(19, 1)]), (3, 2072735744/1594323, [(19, 1)])]\n"
     ]
    }
   ],
   "source": [
    "test_X0(islice(QQ, 10), lambda I: I + I.parent().gen()^2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 -28672/3 []\n",
      "2 152303/24576 []\n",
      "3 2072735744/1594323 []\n",
      "4 122607109504897/201326592 []\n",
      "5 533792153118969856/10986328125 []\n",
      "6 233420288435867735377/222031798272 []\n",
      "7 31497655516265535188992/2616003280989 []\n",
      "8 152136674190176801141317/1649267441664 []\n",
      "9 71737321403335622493417472/134718888901437 []\n",
      "10 1715948050978542408916511761/690000000000000 [(10, 1715948050978542408916511761/690000000000000, [(29, 1)])]\n"
     ]
    }
   ],
   "source": [
    "test_X0(range(11), lambda I: I + I.parent().gen()^3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "48 84645560883547843260626938593288714317943248641/15502035539941028184195072 [(48, 84645560883547843260626938593288714317943248641/15502035539941028184195072, [(13, 1)])]\n",
      "80 158059455224004445519963223677801007293951562732263681/33859460577361920000000000000 [(48, 84645560883547843260626938593288714317943248641/15502035539941028184195072, [(13, 1)]), (80, 158059455224004445519963223677801007293951562732263681/33859460577361920000000000000, [(23, 1)])]\n"
     ]
    }
   ],
   "source": [
    "test_X0([48, 80], lambda I: I - I.parent().gen()^3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Sage 6.9.beta7",
   "language": "",
   "name": "sage_6_9_beta7"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}