/usr/share/axiom-20170501/src/algebra/HELLFDIV.spad is in axiom-source 20170501-3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | )abbrev domain HELLFDIV HyperellipticFiniteDivisor
++ Author: Manuel Bronstein
++ Date Created: 19 May 1993
++ Date Last Updated: 20 July 1998
++ Description:
++ This domains implements finite rational divisors on an hyperelliptic curve,
++ that is finite formal sums SUM(n * P) where the n's are integers and the
++ P's are finite rational points on the curve.
++ The equation of the curve must be y^2 = f(x) and f must have odd degree.
HyperellipticFiniteDivisor(F, UP, UPUP, R) : SIG == CODE where
F : Field
UP : UnivariatePolynomialCategory F
UPUP : UnivariatePolynomialCategory Fraction UP
R : FunctionFieldCategory(F, UP, UPUP)
O ==> OutputForm
Z ==> Integer
RF ==> Fraction UP
ID ==> FractionalIdeal(UP, RF, UPUP, R)
ERR ==> error "divisor: incomplete implementation for hyperelliptic curves"
SIG ==> FiniteDivisorCategory(F, UP, UPUP, R)
CODE ==> add
if (uhyper:Union(UP, "failed") := hyperelliptic()$R) case "failed" then
error "HyperellipticFiniteDivisor: curve must be hyperelliptic"
-- we use the semi-reduced representation from D.Cantor, "Computing in the
-- Jacobian of a HyperellipticCurve", Mathematics of Computation, vol 48,
-- no.177, January 1987, 95-101.
-- The representation [a,b,f] for D means D = [a,b] + div(f)
-- and [a,b] is a semi-reduced representative on the Jacobian
Rep := Record(center:UP, polyPart:UP, principalPart:R, reduced?:Boolean)
hyper:UP := uhyper::UP
gen:Z := ((degree(hyper)::Z - 1) exquo 2)::Z -- genus of the curve
dvd:O := "div"::Symbol::O
zer:O := 0::Z::O
makeDivisor : (UP, UP, R) -> %
intReduc : (R, UP) -> R
princ? : % -> Boolean
polyIfCan : R -> Union(UP, "failed")
redpolyIfCan : (R, UP) -> Union(UP, "failed")
intReduce : (R, UP) -> R
mkIdeal : (UP, UP) -> ID
reducedTimes : (Z, UP, UP) -> %
reducedDouble: (UP, UP) -> %
0 == divisor(1$R)
divisor(g:R) == [1, 0, g, true]
makeDivisor(a, b, g) == [a, b, g, false]
princ? d == (d.center = 1) and zero?(d.polyPart)
ideal d == ideal([d.principalPart]) * mkIdeal(d.center, d.polyPart)
decompose d == [ideal makeDivisor(d.center, d.polyPart, 1),d.principalPart]
mkIdeal(a, b) == ideal [a::RF::R, reduce(monomial(1, 1)$UPUP-b::RF::UPUP)]
-- keep the sum reduced if d1 and d2 are both reduced at the start
d1 + d2 ==
a1 := d1.center; a2 := d2.center
b1 := d1.polyPart; b2 := d2.polyPart
rec := principalIdeal [a1, a2, b1 + b2]
d := rec.generator
h := rec.coef -- d = h1 a1 + h2 a2 + h3(b1 + b2)
a := ((a1 * a2) exquo d**2)::UP
b:UP:= first(h) * a1 * b2
b := b + second(h) * a2 * b1
b := b + third(h) * (b1*b2 + hyper)
b := (b exquo d)::UP rem a
dd := makeDivisor(a, b, d::RF * d1.principalPart * d2.principalPart)
d1.reduced? and d2.reduced? => reduce dd
dd
-- if is cheaper to keep on reducing as we exponentiate
-- if d is already reduced
n:Z * d:% ==
zero? n => 0
n < 0 => (-n) * (-d)
divisor(d.principalPart ** n) + divisor(mkIdeal(d.center,d.polyPart)**n)
divisor(i:ID) ==
(n := #(v := basis minimize i)) = 1 => divisor v minIndex v
n ^= 2 => ERR
a := v minIndex v
h := v maxIndex v
(u := polyIfCan a) case UP =>
(w := redpolyIfCan(h, u::UP)) case UP => makeDivisor(u::UP, w::UP, 1)
ERR
(u := polyIfCan h) case UP =>
(w := redpolyIfCan(a, u::UP)) case UP => makeDivisor(u::UP, w::UP, 1)
ERR
ERR
polyIfCan a ==
(u := retractIfCan(a)@Union(RF, "failed")) case "failed" => "failed"
(v := retractIfCan(u::RF)@Union(UP, "failed")) case "failed" => "failed"
v::UP
redpolyIfCan(h, a) ==
degree(p := lift h) ^= 1 => "failed"
q := - coefficient(p, 0) / coefficient(p, 1)
rec := extendedEuclidean(denom q, a)
not ground?(rec.generator) => "failed"
((numer(q) * rec.coef1) exquo rec.generator)::UP rem a
coerce(d:%):O ==
r := bracket [d.center::O, d.polyPart::O]
g := prefix(dvd, [d.principalPart::O])
z := (d.principalPart = 1)
princ? d => (z => zer; g)
z => r
r + g
reduce d ==
d.reduced? => d
degree(a := d.center) <= gen => (d.reduced? := true; d)
b := d.polyPart
a0 := ((hyper - b**2) exquo a)::UP
b0 := (-b) rem a0
g := d.principalPart * reduce(b::RF::UPUP-monomial(1,1)$UPUP)/a0::RF::R
reduce makeDivisor(a0, b0, g)
generator d ==
d := reduce d
princ? d => d.principalPart
"failed"
- d ==
a := d.center
makeDivisor(a, - d.polyPart, inv(a::RF * d.principalPart))
d1 = d2 ==
d1 := reduce d1
d2 := reduce d2
d1.center = d2.center and d1.polyPart = d2.polyPart
and d1.principalPart = d2.principalPart
divisor(a, b) ==
x := monomial(1, 1)$UP
not ground? gcd(d := x - a::UP, retract(discriminant())@UP) =>
error "divisor: point is singular"
makeDivisor(d, b::UP, 1)
intReduce(h, b) ==
v := integralCoordinates(h).num
integralRepresents(
[qelt(v, i) rem b for i in minIndex v .. maxIndex v], 1)
-- with hyperelliptic curves, cheaper to keep divisors in reduced form
divisor(h, a, dp, g, r) ==
h := h - (r * dp)::RF::R
a := gcd(a, retract(norm h)@UP)
h := intReduce(h, a)
if not ground? gcd(g, a) then h := intReduce(h ** rank(), a)
hh := lift h
b := - coefficient(hh, 0) / coefficient(hh, 1)
rec := extendedEuclidean(denom b, a)
not ground?(rec.generator) => ERR
bb := ((numer(b) * rec.coef1) exquo rec.generator)::UP rem a
reduce makeDivisor(a, bb, 1)
|