{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## A tutorial on how to use AVIsogenies in SageMath\n",
"\n",
"With this notebook we introduce the main functionalities of the AVIsogenies package.\n",
"\n",
"### Table of contents\n",
"\n",
"1. [Introduction](#intro)\n",
"2. [Basic arithmetic](#arithmetic)\n",
"3. [Morphisms](#morphisms)\n",
" * [In level 4](#m-lvl4)\n",
" * [In level 2](#m-lvl2)\n",
" * [Change of coordinates](#m-change)\n",
"\n",
"\n",
"\n",
"### Introduction \n",
"\n",
"To import the functionalities of this package, start with the following line:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"from avisogenies_sage import *"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The following cell shows how to create an Abelian Variety with theta structure, by giving its Theta Null point."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"FF = GF(331); n = 2; g = 2\n",
"\n",
"pt = [328 , 213 , 75 , 1]\n",
"A = KummerVariety(FF, g, pt)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It is possible to check that the given point is a valid Theta Null point. It checks that the given data satisfies the Riemann Relations. This is not tested unless it is specified."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Abelian variety of dimension 1 with theta null point (26 : 191 : 70 : 130) defined over Finite Field of size 331"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"B = AbelianVariety(GF(331), 4, 1, [26, 191, 70, 130]); B"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"scrolled": true,
"tags": [
"raises-exception"
]
},
"outputs": [
{
"ename": "ValueError",
"evalue": "The given list does not define a valid thetanullpoint",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m/tmp/ipykernel_44692/81372161.py\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mB\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mAbelianVariety\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mGF\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m331\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m4\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m[\u001b[0m\u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m26\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m191\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m70\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m130\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcheck\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[1;32m~/anaconda3/envs/sage-cgf/lib/python3.10/site-packages/avisogenies_sage/constructor.py\u001b[0m in \u001b[0;36mAbelianVariety\u001b[1;34m(*data, **kwargs)\u001b[0m\n\u001b[0;32m 86\u001b[0m \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mdata\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0mdata\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 87\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mtheta_null_point\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mKummerVariety\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 88\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mtheta_null_point\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mAbelianVariety_ThetaStructure\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 89\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 90\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mModularAbelianVariety\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;32m~/anaconda3/envs/sage-cgf/lib/python3.10/site-packages/avisogenies_sage/theta_null_point.py\u001b[0m in \u001b[0;36m__init__\u001b[1;34m(self, R, n, g, T, check)\u001b[0m\n\u001b[0;32m 532\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 533\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0many\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mT\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0midx\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m-\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m!=\u001b[0m \u001b[0mval\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mi\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mval\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mzip\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mD\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mT\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 534\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'The given list does not define a valid thetanullpoint'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 535\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 536\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0midxi\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mi\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0midxj\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mj\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mproduct\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0menumerate\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mD\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mrepeat\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mValueError\u001b[0m: The given list does not define a valid thetanullpoint"
]
}
],
"source": [
"B = AbelianVariety(GF(331), 4, 1, [26, 191, 70, 130], check=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The following cell shows how to define a point in the constructed abelian variety."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"P0 = A(0)\n",
"P = A([255 , 89 , 30 , 1])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As with the theta null point, it is possible to check that the given data defines a valid point, but it is not tested unless it is specified. For that we need to use the AbelianVariety method `point`."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"Q = B([1 , 1 , 1 , 1])"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"tags": [
"raises-exception"
]
},
"outputs": [
{
"ename": "AttributeError",
"evalue": "'AbelianVarietyPoint' object has no attribute 'level'",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m/tmp/ipykernel_44692/3498440664.py\u001b[0m in \u001b[0;36m| \u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mQ\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mB\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpoint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m,\u001b[0m \u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m,\u001b[0m \u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m,\u001b[0m \u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcheck\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[1;32m~/anaconda3/envs/sage-cgf/lib/python3.10/site-packages/avisogenies_sage/theta_null_point.py\u001b[0m in \u001b[0;36mpoint\u001b[1;34m(self, P, **kwds)\u001b[0m\n\u001b[0;32m 235\u001b[0m \u001b[0mAP\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mA\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mP\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 236\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mAP\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mto_algebraic\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mA\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 237\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_point\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mP\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwds\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 238\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 239\u001b[0m \u001b[0m__call__\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpoint\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;32m~/anaconda3/envs/sage-cgf/lib/python3.10/site-packages/avisogenies_sage/theta_point.py\u001b[0m in \u001b[0;36m__init__\u001b[1;34m(self, X, v, check)\u001b[0m\n\u001b[0;32m 788\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mcheck\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 789\u001b[0m \u001b[0mO\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mX\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtheta_null_point\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 790\u001b[1;33m \u001b[0midx\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpartial\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtools\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0midx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mn\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mO\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlevel\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 791\u001b[0m \u001b[0mdual\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mX\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_dual\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 792\u001b[0m \u001b[0mD\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mX\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_D\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;32m~/anaconda3/envs/sage-cgf/lib/python3.10/site-packages/sage/structure/element.pyx\u001b[0m in \u001b[0;36msage.structure.element.Element.__getattr__ (build/cythonized/sage/structure/element.c:4826)\u001b[1;34m()\u001b[0m\n\u001b[0;32m 492\u001b[0m \u001b[0mAttributeError\u001b[0m\u001b[1;33m:\u001b[0m \u001b[1;34m'LeftZeroSemigroup_with_category.element_class'\u001b[0m \u001b[0mobject\u001b[0m \u001b[0mhas\u001b[0m \u001b[0mno\u001b[0m \u001b[0mattribute\u001b[0m \u001b[1;34m'blah_blah'\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 493\u001b[0m \"\"\"\n\u001b[1;32m--> 494\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mgetattr_from_category\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 495\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 496\u001b[0m \u001b[0mcdef\u001b[0m \u001b[0mgetattr_from_category\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mname\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;32m~/anaconda3/envs/sage-cgf/lib/python3.10/site-packages/sage/structure/element.pyx\u001b[0m in \u001b[0;36msage.structure.element.Element.getattr_from_category (build/cythonized/sage/structure/element.c:4938)\u001b[1;34m()\u001b[0m\n\u001b[0;32m 505\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 506\u001b[0m \u001b[0mcls\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mP\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_abstract_element_class\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 507\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mgetattr_from_other_class\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcls\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mname\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 508\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 509\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0m__dir__\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;32m~/anaconda3/envs/sage-cgf/lib/python3.10/site-packages/sage/cpython/getattr.pyx\u001b[0m in \u001b[0;36msage.cpython.getattr.getattr_from_other_class (build/cythonized/sage/cpython/getattr.c:2702)\u001b[1;34m()\u001b[0m\n\u001b[0;32m 359\u001b[0m \u001b[0mdummy_error_message\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcls\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtype\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 360\u001b[0m \u001b[0mdummy_error_message\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mname\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mname\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 361\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mAttributeError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdummy_error_message\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 362\u001b[0m \u001b[0mattribute\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m<\u001b[0m\u001b[0mobject\u001b[0m\u001b[1;33m>\u001b[0m\u001b[0mattr\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 363\u001b[0m \u001b[1;31m# Check for a descriptor (__get__ in Python)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mAttributeError\u001b[0m: 'AbelianVarietyPoint' object has no attribute 'level'"
]
}
],
"source": [
"Q = B.point([1 , 1 , 1 , 1], check=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can access a given coordinate using the corresponding element of $(\\mathbb{Z}/n\\mathbb{Z})^g$:"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"89"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"P[[1,0]]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Basic arithmetic \n",
"Follows the example in Section 6 of 'Efficient Pairing Computation with theta functions' by David Lubicz and Damien Robert."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"l = 1889\n",
"lP = l*P; lP\n",
"lP == A(0) #as projective points"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"((221*t^3 + 178*t^2 + 126*t + 27 : 32*t^3 + 17*t^2 + 175*t + 171 : 180*t^3 + 188*t^2 + 161*t + 119 : 261*t^3 + 107*t^2 + 37*t + 135),\n",
" (1 : 56*t^3 + 312*t^2 + 147*t + 287 : 277*t^3 + 295*t^2 + 7*t + 287 : 290*t^3 + 203*t^2 + 274*t + 10))"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"R. = PolynomialRing(FF)\n",
"poly = X^4 + 3*X^2 + 290*X + 3\n",
"FF2. = poly.splitting_field()\n",
"\n",
"Q_list = [158*t^3 + 67*t^2 + 9*t + 293, 290*t^3 + 25*t^2 + 235*t + 280,\n",
" 155*t^3 + 84*t^2 + 15*t + 170, 1]\n",
"A2 = A.change_ring(FF2)\n",
"P = A2(P)\n",
"Q = A2(Q_list)\n",
"\n",
"P + Q #returns P + Q and P - Q"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(261*t^3 + 107*t^2 + 37*t + 135 : 205*t^3 + 88*t^2 + 195*t + 125 : 88*t^3 + 99*t^2 + 164*t + 98 : 159*t^3 + 279*t^2 + 254*t + 276)"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"PmQ_list = (62*t^3 + 16*t^2 + 255*t + 129 , 172*t^3 + 157*t^2 + 43*t + 222 ,\n",
" 258*t^3 + 39*t^2 + 313*t + 150 , 1)\n",
"PmQ = A2.point(PmQ_list)\n",
"\n",
"PQ = Q.diff_add(P, PmQ); PQ"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"17*t^3 + 153*t^2 + 305*t + 187"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"P.weil_pairing(l, Q, PQ)"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"17*t^3 + 153*t^2 + 305*t + 187"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"lPQ, lP = P.diff_multadd(l, PQ, Q)\n",
"PlQ, lQ = Q.diff_multadd(l, PQ, P)\n",
"P._weil_pairing_from_points(Q, lP, lQ, lPQ, PlQ)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Computing points from other data \n",
"\n",
"This section focuses on the computation of morphisms between hyperelliptic curves and the corresponding abelian varieties (their jacobians) with theta functions of level 2 and 4.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can define a curve and its Jacobian"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Hyperelliptic Curve over Finite Field in z2 of size 83^2 defined by y^2 = x^5 + 44*x^4 + 28*x^3 + 23*x^2 + 70*x"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"F = GF(83^2); z, = F.gens(); Fx. = PolynomialRing(F)\n",
"\n",
"g = 2\n",
"a = [F(0), 1, 3, 15, 20]\n",
"rac = sqrt(a[1] - a[0])\n",
"\n",
"f = prod(x - al for al in a)\n",
"C = HyperellipticCurve(f); C"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The most natural way to construct the corresponding Abelian Variety is with the function `AbelianVariety.from_curve`:"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Abelian variety of dimension 2 with theta null point (68 : z2 + 33 : 46 : z2 + 33 : 2*z2 + 29 : 77*z2 + 58 : 81*z2 + 31 : 38*z2 + 16 : 8 : 67*z2 + 53 : 48 : 67*z2 + 53 : 2*z2 + 29 : 38*z2 + 16 : 81*z2 + 31 : 77*z2 + 58) defined over Finite Field in z2 of size 83^2"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A = AbelianVariety.from_curve(C); A"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Alternatively, if we have the classical theta constants associated to the Jacobian, we can also use `AbelianVariety.with_theta_basis('F(2,2)')`"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [],
"source": [
"thc = [0]*(2**(2*g))\n",
"idx = lambda x : ZZ(x, 2)\n",
"thc[idx([0,0,0,0])]=F(1)\n",
"thc[idx([0,0,1,1])]=z^1491\n",
"thc[idx([0,0,1,0])]=z^777\n",
"thc[idx([0,0,0,1])]=F(30)\n",
"thc[idx([1,0,0,0])]=F(37)\n",
"thc[idx([1,0,0,1])]=z^2058\n",
"thc[idx([0,1,0,0])]=F(56)\n",
"thc[idx([1,1,0,0])]=F(57)\n",
"thc[idx([0,1,1,0])]=z^609\n",
"thc[idx([1,1,1,1])]=z^1533\n",
"thc[idx([0,1,0,1])]=F(0)\n",
"thc[idx([0,1,1,1])]=F(0)\n",
"thc[idx([1,0,1,0])]=F(0)\n",
"thc[idx([1,1,1,0])]=F(0)\n",
"thc[idx([1,0,1,1])]=F(0)\n",
"thc[idx([1,1,0,1])]=F(0)\n",
"thc = AbelianVariety.with_theta_basis('F(2,2)', F, 4, g, thc, curve=C, wp=a, rac=rac)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we can map some points between Mumford and Theta representation.\n",
"\n",
"We define the jacobian of C and consider the Mumford divisor defined by:"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(x^2 + 30*x + 15, y + (21*z2 + 71)*x + 10*z2 + 10)"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"J = Jacobian(C)\n",
"u = (x-43)*(x-10); v = z^954*x + z^2518;\n",
"D = J([u,v]); D"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then we can simply create a point of the abelian variety with this data:"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [],
"source": [
"thD = thc(D);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that, even if internally we use the classical basis for these computations, the result is always given with basis $\\mathcal{F}(4)$:"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/plain": [
"Abelian variety of dimension 2 with theta null point (68 : z2 + 33 : 46 : z2 + 33 : 2*z2 + 29 : 77*z2 + 58 : 81*z2 + 31 : 38*z2 + 16 : 8 : 67*z2 + 53 : 48 : 67*z2 + 53 : 2*z2 + 29 : 38*z2 + 16 : 81*z2 + 31 : 77*z2 + 58) defined over Finite Field in z2 of size 83^2"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"thD.abelian_variety()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"But one can always recover the point in terms of the basis $\\mathcal{F}(2,2)$ as follows:"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(78*z2 + 13 : 77*z2 + 26 : 43*z2 + 3 : 54*z2 + 67 : 77*z2 + 61 : 35*z2 + 2 : 31*z2 + 8 : 19*z2 + 38 : 25*z2 + 9 : z2 + 65 : 17*z2 + 75 : 18*z2 + 38 : 50*z2 + 17 : 41*z2 + 6 : 18*z2 + 48 : 39*z2 + 73)"
]
},
"execution_count": 39,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"thD.with_theta_basis('F(2,2)')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Conversely, if we define the theta point"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [],
"source": [
"th = [0]*(2**(2*g))\n",
"th[idx([0,0,0,0])] = z^1755\n",
"th[idx([0,0,1,1])] = z^1179\n",
"th[idx([0,0,1,0])] = z^977\n",
"th[idx([0,0,0,1])] = z^1105\n",
"th[idx([1,0,0,0])] = z^352\n",
"th[idx([1,0,0,1])] = z^1674\n",
"th[idx([0,1,0,0])] = z^2523\n",
"th[idx([1,1,0,0])] = z^5890\n",
"th[idx([0,1,1,0])] = z^5051\n",
"th[idx([1,1,1,1])] = z^5243\n",
"th[idx([0,1,0,1])] = z^4021\n",
"th[idx([0,1,1,1])] = z^4716\n",
"th[idx([1,0,1,0])] = z^139\n",
"th[idx([1,1,1,0])] = z^507\n",
"th[idx([1,0,1,1])] = z^2832\n",
"th[idx([1,1,0,1])] = z^3382\n",
"th = thc(th, basis='F(2,2)')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The function `Level4ThetaPointToMumford` returns the corresponding Mumford polynomials"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from avisogenies_sage.morphisms_level4 import Level4ThetaPointToMumford\n",
"u,v = Level4ThetaPointToMumford(a, rac, th.with_theta_basis('F(2,2)'))\n",
"D == J([u, v])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### In level 2 \n",
"\n",
"First we define the curve and its Kummer surface\n",
"\n",
"A curve y² = f(x) is defined by a list `a` containing the roots of f(x); it is important that f be of odd degree and `a` be ordered (the Theta constants depend on this ordering).\n",
"\n",
"First defined the curve and the Kummer Surface"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Hyperelliptic Curve over Finite Field in z2 of size 83^2 defined by y^2 = x^5 + 44*x^4 + 28*x^3 + 23*x^2 + 70*x"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"F = GF(83^2); z, = F.gens(); Fx. = PolynomialRing(F)\n",
"\n",
"g = 2;\n",
"a = [F(el) for el in [0,1,3,15,20]]\n",
"f = prod(x - al for al in a)\n",
"C = HyperellipticCurve(f); C"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The Theta constants of the Kummer surface."
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [],
"source": [
"thc2 = [0]*(2**(2*g))\n",
"idx = lambda x : ZZ(x, 2)\n",
"thc2[idx([0,0,0,0])] = F(1)\n",
"thc2[idx([0,0,1,1])] = z^2982\n",
"thc2[idx([0,0,1,0])] = z^1554\n",
"thc2[idx([0,0,0,1])] = F(70)\n",
"thc2[idx([1,0,0,0])] = F(41)\n",
"thc2[idx([1,0,0,1])] = F(76)\n",
"thc2[idx([0,1,0,0])] = F(65)\n",
"thc2[idx([1,1,0,0])] = F(12)\n",
"thc2[idx([0,1,1,0])] = z^1218\n",
"thc2[idx([1,1,1,1])] = z^3066\n",
"thc2[idx([0,1,0,1])] = F(0)\n",
"thc2[idx([0,1,1,1])] = F(0)\n",
"thc2[idx([1,0,1,0])] = F(0)\n",
"thc2[idx([1,1,1,0])] = F(0)\n",
"thc2[idx([1,0,1,1])] = F(0)\n",
"thc2[idx([1,1,0,1])] = F(0)\n",
"thc2 = KummerVariety.with_theta_basis('F(2,2)^2', F, 2, g, thc2, curve=C, wp=a)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we can map points between Mumford and Theta representations.\n",
"Consider the Mumford divisor defined by:"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(x^2 + 30*x + 15, y + (21*z2 + 71)*x + 10*z2 + 10)"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"J = Jacobian(C)\n",
"u = (x-43)*(x-10); v2 = (z^954*x + z^2518)^2; \n",
"D = J([u,v]); D"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And as we did for level 4, we compute the corresponding point."
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [],
"source": [
"th2D = thc2(D)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Conversely, define the Theta functions"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [],
"source": [
"th2 = [0]*(2**(2*g))\n",
"th2[idx([0,0,0,0])] = z^3608\n",
"th2[idx([0,0,1,1])] = z^5026\n",
"th2[idx([0,0,1,0])] = z^1654\n",
"th2[idx([0,0,0,1])] = z^6408\n",
"th2[idx([1,0,0,0])] = z^5576\n",
"th2[idx([1,0,0,1])] = z^3952\n",
"th2[idx([0,1,0,0])] = z^734\n",
"th2[idx([1,1,0,0])] = z^2674\n",
"th2[idx([0,1,1,0])] = z^3262\n",
"th2[idx([1,1,1,1])] = z^5436\n",
"th2[idx([0,1,0,1])] = F(82)\n",
"th2[idx([0,1,1,1])] = z^6258\n",
"th2[idx([1,0,1,0])] = z^4746\n",
"th2[idx([1,1,1,0])] = z^798\n",
"th2[idx([1,0,1,1])] = z^5082\n",
"th2[idx([1,1,0,1])] = F(2)\n",
"th2 = thc2(th2, basis='F(2,2)^2')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The function `Level2ThetaPointToMumford` returns the corresponding Mumford polynomials (u, v²)"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from avisogenies_sage.morphisms_level2 import Level2ThetaPointToMumford\n",
"uth,v2th = Level2ThetaPointToMumford(a, th2.with_theta_basis('F(2,2)^2'))\n",
"D == J([uth, sqrt(v2th)])"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "SageMath 9.5",
"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.10.2"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
| |