| 1 | """ |
|---|
| 2 | Jacobian ``morphism'' as a class in the Picard group |
|---|
| 3 | """ |
|---|
| 4 | |
|---|
| 5 | #***************************************************************************** |
|---|
| 6 | # Copyright (C) 2005 David Kohel <kohel@maths.usyd.edu.au> |
|---|
| 7 | # Distributed under the terms of the GNU General Public License (GPL) |
|---|
| 8 | # http://www.gnu.org/licenses/ |
|---|
| 9 | #***************************************************************************** |
|---|
| 10 | |
|---|
| 11 | from sage.rings.all import PolynomialRing, ZZ |
|---|
| 12 | from sage.structure.element import AdditiveGroupElement |
|---|
| 13 | from sage.schemes.generic.morphism import SchemeMorphism |
|---|
| 14 | |
|---|
| 15 | def cantor_reduction_simple(a1,b1,f,genus): |
|---|
| 16 | # Divisor reduction. |
|---|
| 17 | a2 = (f - b1**2).div(a1) |
|---|
| 18 | a2 *= 1/a2.leading_coefficient() |
|---|
| 19 | b2 = -b1.mod(a2); |
|---|
| 20 | if a2.degree() == a1.degree(): |
|---|
| 21 | assert a2.degree() == genus+1 |
|---|
| 22 | print "Returning ambiguous form of degree genus+1." |
|---|
| 23 | return (a2, b2) |
|---|
| 24 | elif a2.degree() > genus: |
|---|
| 25 | return cantor_reduction_simple(a2,b2,f) |
|---|
| 26 | return (a2, b2) |
|---|
| 27 | |
|---|
| 28 | def cantor_reduction(a,b,f,h,genus): |
|---|
| 29 | assert a.degree() < 2*genus+1 |
|---|
| 30 | assert b.degree() < a.degree() |
|---|
| 31 | k = f - h*b - b**2 |
|---|
| 32 | if 2*a.degree() == k.degree(): |
|---|
| 33 | # must adjust b to include the point at infinity |
|---|
| 34 | g1 = a.degree() |
|---|
| 35 | x = a.parent().gen() |
|---|
| 36 | r = (x**2 + h[g1]*x - f[2*g1]).roots()[0][0] |
|---|
| 37 | b = b + r*(x**g1 - (x**g1).mod(a)) |
|---|
| 38 | k = f - h*b - b**2 |
|---|
| 39 | assert k.mod(a) == 0 |
|---|
| 40 | a = k.div(a) |
|---|
| 41 | a /= a.leading_coefficient() |
|---|
| 42 | b = -(b+h).mod(a) |
|---|
| 43 | if a.degree() > genus: |
|---|
| 44 | return cantor_reduction(a,b,f,h,genus) |
|---|
| 45 | return (a, b) |
|---|
| 46 | |
|---|
| 47 | def cantor_composition_simple(D1,D2,f,genus): |
|---|
| 48 | a1, b1 = D1 |
|---|
| 49 | a2, b2 = D2 |
|---|
| 50 | if a1 == a2 and b1 == b2: |
|---|
| 51 | # Duplication law: |
|---|
| 52 | d, h1, h3 = a1.xgcd(2*b1) |
|---|
| 53 | a = (a1.div(d))**2 |
|---|
| 54 | b = (b1 + h3*((f - b1**2).div(d))).mod(a) |
|---|
| 55 | else: |
|---|
| 56 | d0, _, h2 = a1.xgcd(a2) |
|---|
| 57 | if d0 == 1: |
|---|
| 58 | a = a1*a2 |
|---|
| 59 | b = (b2 + h2*a2*(b1-b2)).mod(a) |
|---|
| 60 | else: |
|---|
| 61 | d, l, h3 = d0.xgcd(b1 + b2) |
|---|
| 62 | a = (a1*a2).div(d**2) |
|---|
| 63 | b = (b2 + l*h2*(b1-b2)*a2.div(d)) + h3*((f - b2**2).div(d)).mod(a) |
|---|
| 64 | if a.degree() > genus: |
|---|
| 65 | return cantor_reduction_simple(a,b,f,genus) |
|---|
| 66 | return (a,b) |
|---|
| 67 | |
|---|
| 68 | def cantor_composition(D1,D2,f,h,genus): |
|---|
| 69 | a1, b1 = D1 |
|---|
| 70 | a2, b2 = D2 |
|---|
| 71 | if a1 == a2 and b1 == b2: |
|---|
| 72 | # Duplication law: |
|---|
| 73 | d, h1, h3 = a1.xgcd(2*b1 + h) |
|---|
| 74 | # NOTE THAT d is not normalised, but this gives a crash: |
|---|
| 75 | # d *= 1/d.leading_coefficient() |
|---|
| 76 | # print "d =", d |
|---|
| 77 | a = (a1.div(d))**2; |
|---|
| 78 | b = (b1 + h3*((f-h*b1-b1**2).div(d))).mod(a) |
|---|
| 79 | else: |
|---|
| 80 | d0, _, h2 = a1.xgcd(a2) |
|---|
| 81 | if d0 == 1: |
|---|
| 82 | a = a1*a2; |
|---|
| 83 | b = (b2 + h2*a2*(b1-b2)).mod(a) |
|---|
| 84 | else: |
|---|
| 85 | e0 = b1+b2+h |
|---|
| 86 | if e0 == 0: |
|---|
| 87 | a = (a1*a2).div(d0**2); |
|---|
| 88 | b = (b2 + h2*(b1-b2)*(a2.div(d0))).mod(a) |
|---|
| 89 | else: |
|---|
| 90 | d, l, h3 = d0.xgcd(e0) |
|---|
| 91 | a = (a1*a2).div(d**2); |
|---|
| 92 | b = (b2 + l*h2*(b1-b2)*(a2.div(d)) + h3*((f-h*b2-b2**2).div(d))).mod(a) |
|---|
| 93 | a *= 1/a.leading_coefficient() |
|---|
| 94 | if a.degree() > genus: |
|---|
| 95 | return cantor_reduction(a,b,f,h,genus) |
|---|
| 96 | return (a,b) |
|---|
| 97 | |
|---|
| 98 | class JacobianMorphism_divisor_class_field(AdditiveGroupElement, SchemeMorphism): |
|---|
| 99 | r""" |
|---|
| 100 | An element of a $J(K) = \Pic^0_K(C)$. |
|---|
| 101 | """ |
|---|
| 102 | def __init__(self, parent, polys, reduce=True, check=False): |
|---|
| 103 | SchemeMorphism.__init__(self, parent) |
|---|
| 104 | if polys == 0: |
|---|
| 105 | P = PolynomialRing(self.parent(), 'x') |
|---|
| 106 | self.__polys = (P(1),P(0)) |
|---|
| 107 | if check: |
|---|
| 108 | C = parent.curve() |
|---|
| 109 | K = parent.value_ring() |
|---|
| 110 | f, h = C.hyperelliptic_polynomials(K) |
|---|
| 111 | a, b = polys |
|---|
| 112 | if not (b**2 + h*b - f)%a == 0: |
|---|
| 113 | raise ValueError, \ |
|---|
| 114 | "Argument polys (= %s) must be reduced divisor on curve %s."%( |
|---|
| 115 | polys, C) |
|---|
| 116 | self.__polys = polys |
|---|
| 117 | |
|---|
| 118 | def __repr__(self): |
|---|
| 119 | a, b = self.__polys |
|---|
| 120 | if a == 1: |
|---|
| 121 | return "(1)" |
|---|
| 122 | P = self.parent()._printing_ring |
|---|
| 123 | y = P.gen() |
|---|
| 124 | x = P.base_ring().gen() |
|---|
| 125 | return "(%s, %s)"%(a(x), y - b(x)) |
|---|
| 126 | |
|---|
| 127 | def list(self): |
|---|
| 128 | return self.__polys |
|---|
| 129 | |
|---|
| 130 | def __add__(self,other): |
|---|
| 131 | X = self.parent() |
|---|
| 132 | C = X.curve() |
|---|
| 133 | K = X.value_ring() |
|---|
| 134 | f, h = C.hyperelliptic_polynomials(K) |
|---|
| 135 | if h == 0: |
|---|
| 136 | D = cantor_composition_simple(self.__polys,other.__polys,f,C.genus()) |
|---|
| 137 | else: |
|---|
| 138 | D = cantor_composition(self.__polys,other.__polys,f,h,C.genus()) |
|---|
| 139 | return JacobianMorphism_divisor_class_field(X, D, reduce=False, check=False) |
|---|
| 140 | |
|---|
| 141 | def __sub__(self, other): |
|---|
| 142 | return self + (-other) |
|---|
| 143 | |
|---|
| 144 | def __neg__(self): |
|---|
| 145 | if self.is_zero(): |
|---|
| 146 | return self |
|---|
| 147 | polys = self.__polys |
|---|
| 148 | X = self.parent() |
|---|
| 149 | K = X.value_ring() |
|---|
| 150 | f, h = X.curve().hyperelliptic_polynomials(K) |
|---|
| 151 | if h == 0: |
|---|
| 152 | D = (polys[0],-polys[1]) |
|---|
| 153 | else: |
|---|
| 154 | D = (polys[0],-polys[1]-h.mod(polys[0])) |
|---|
| 155 | return JacobianMorphism_divisor_class_field(X, D, reduce=False, check=False) |
|---|
| 156 | |
|---|
| 157 | def __mul__(self, n): |
|---|
| 158 | try: |
|---|
| 159 | n = ZZ(n) |
|---|
| 160 | except TypeError: |
|---|
| 161 | raise TypeError, "Argument n (= %s) must be an integer." |
|---|
| 162 | X = self.parent() |
|---|
| 163 | if n < 0: |
|---|
| 164 | return self * (-n) |
|---|
| 165 | elif n == 0: |
|---|
| 166 | return self.parent()(0) |
|---|
| 167 | elif n == 1: |
|---|
| 168 | return self |
|---|
| 169 | D = self.__mul__(n//2) |
|---|
| 170 | if n % 2 == 0: |
|---|
| 171 | return D + D |
|---|
| 172 | else: |
|---|
| 173 | return D + D + self |
|---|
| 174 | |
|---|
| 175 | def __nonzero__(self): |
|---|
| 176 | return self.__polys[0] != 1 |
|---|
| 177 | |
|---|
| 178 | def scheme(self): |
|---|
| 179 | return self.codomain() |
|---|