Skip to content

Commit

Permalink
first draft at generic tate
Browse files Browse the repository at this point in the history
  • Loading branch information
thofma committed Jul 27, 2023
1 parent 7b06fea commit 71a69d7
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 38 deletions.
105 changes: 69 additions & 36 deletions src/EllCrv/LocalData.jl
Original file line number Diff line number Diff line change
Expand Up @@ -55,37 +55,71 @@ $f$ is the conductor valuation at $p$, $c$ is the local Tamagawa number
at $p$ and s is false if and only if $E$ has non-split
multiplicative reduction.
"""
function tates_algorithm_local(E::EllCrv{nf_elem}, pIdeal::NfOrdIdl)
return _tates_algorithm(E, pIdeal)
function tates_algorithm_local(E::EllCrv{nf_elem}, P::NfOrdIdl)
return _tates_algorithm(E, P)
end

# internal version
# extend this for global fields
function _tates_algorithm(E, P)
K = base_field(E)
OK = maximal_order(K)
F, _mF = residue_field(OK, P)
mF = extend(_mF, K)

p = minimum(P)
pis2 = p == 2
pis3 = p == 3
pi = uniformizer(P)

# valuation
function _tates_algorithm(E::EllCrv{nf_elem}, P::NfOrdIdl)
OK = order(P)
F, _mF = residue_field(OK, P)
mF = extend(_mF, nf(OK))
_val(x) = iszero(x) ? inf : valuation(x, P)

# reduction and lift
_lift(y) = mF\y
_red(x) = mF(x)
# reduction
_redmod(x) = mF\(mF(x))
# inverse mod
_invmod(x) = mF\(inv(mF(x)))
# divisibility check
_pdiv(x) = iszero(x) || valuation(x, P) > 0
pi = uniformizer(P)
return __tates_algorithm_generic(E, OK, _val, _redmod, _red, _lift, _invmod, pi)
end

function _tates_algorithm(E::EllCrv{<:AbstractAlgebra.Generic.RationalFunctionFieldElem}, f::PolyRingElem)
@req is_irreducible(f) "Polynomial must be irreducible"
R = parent(f)
K = base_field(E)
@assert R === base_ring(K.fraction_field)
F, _mF = residue_field(R, f)
mF = x -> _mF(numerator(x))/_mF(denominator(x))
_val = x -> iszero(x) ? inf : valuation(numerator(x), f) - valuation(denominator(x), f)
_res = mF
_mod = x -> K(preimage(_mF, (_res(x))))
_invmod = x -> K(preimage(_mF, inv(_res(x))))
_uni = K(f)
_lift = x -> K(preimage(_mF, x))
return __tates_algorithm_generic(E, R, _val, _mod, _res, _lift, _invmod, _uni)
end

function _tates_algorithm(E::EllCrv{<:AbstractAlgebra.Generic.RationalFunctionFieldElem}, x)
K = base_field(E)
@assert is_one(denominator(x))
return _tates_algorithm(E, numerator(x))
end

function _tates_algorithm(E::EllCrv{QQFieldElem}, _p::IntegerUnion)
p = ZZ(_p)
F = GF(p, cached = false)
_invmod = x -> QQ(lift(inv(F(x))))
_uni = p
return __tates_algorithm_generic(E, ZZ, x -> is_zero(x) ? inf : valuation(x, p), x -> smod(x, p), x -> F(x), x -> QQ(lift(x)), _invmod, p)
end

function __tates_algorithm_generic(E, R, _val, _redmod, _red, _lift, _invmod, pi)
#K = base_field(E)
#OK = maximal_order(K)
#F, _mF = residue_field(OK, P)
#mF = extend(_mF, K)

K = base_field(E)
F = parent(_red(one(K)))
p = characteristic(F)
pis2 = p == 2
pis3 = p == 3
## divisibility check
_pdiv(x) = _val(x) > 0
# p/2
onehalfmodp = pis2 ? ZZ(0) : invmod(ZZ(2), p)
onehalfmodp = p == 0 ? QQ(1//2) : (pis2 ? ZZ(0) : invmod(ZZ(2), ZZ(p)))
# root mod P
_rootmod(x, e) = begin
fl, y = is_power(_red(x), e)
Expand All @@ -107,19 +141,19 @@ function _tates_algorithm(E, P)
# Non-integral at P, lets make integral
e = 0
if !iszero(a1)
e = max(e, -val(a1))
e = max(e, -_val(a1))
end
if !iszero(a2)
e = max(e, ceil(Int, -val(a2)//2))
e = max(e, ceil(Int, -_val(a2)//2))
end
if !iszero(a3)
e = max(e, ceil(Int, -val(a2)//3))
e = max(e, ceil(Int, -_val(a3)//3))
end
if !iszero(a4)
e = max(e, ceil(Int, -val(a2)//4))
e = max(e, ceil(Int, -_val(a4)//4))
end
if !iszero(a6)
e = max(e, ceil(Int, -val(a2)//6))
e = max(e, ceil(Int, -_val(a6)//6))
end

pie = pi^e
Expand All @@ -139,7 +173,7 @@ function _tates_algorithm(E, P)
delta = discriminant(E)
vD = _val(delta)
if vD == 0 # Good reduction
return (E, KodairaSymbol("I0"), FlintZZ(0), FlintZZ(1), true)::Tuple{EllCrv{nf_elem}, KodairaSymbol, ZZRingElem, ZZRingElem, Bool}
return (E, KodairaSymbol("I0"), FlintZZ(0), FlintZZ(1), true)::Tuple{typeof(E), KodairaSymbol, ZZRingElem, ZZRingElem, Bool}
end

# change coords so that p|a3,a4,a6
Expand Down Expand Up @@ -191,28 +225,28 @@ function _tates_algorithm(E, P)
end
Kp = KodairaSymbol("I$(vD)")
fp = FlintZZ(1)
return (E, Kp, fp, cp, split)::Tuple{EllCrv{nf_elem}, KodairaSymbol, ZZRingElem, ZZRingElem, Bool}
return (E, Kp, fp, cp, split)::Tuple{typeof(E), KodairaSymbol, ZZRingElem, ZZRingElem, Bool}
end

if _val(a6) < 2 # Type II
Kp = KodairaSymbol("II")
fp = FlintZZ(vD)
cp = FlintZZ(1)
return (E, Kp, fp, cp, true)::Tuple{EllCrv{nf_elem}, KodairaSymbol, ZZRingElem, ZZRingElem, Bool}
return (E, Kp, fp, cp, true)::Tuple{typeof(E), KodairaSymbol, ZZRingElem, ZZRingElem, Bool}
end

if _val(b8) < 3 # Type III
Kp = KodairaSymbol("III")
fp = FlintZZ(vD - 1)
cp = FlintZZ(2)
return (E, Kp, fp, cp, true)::Tuple{EllCrv{nf_elem}, KodairaSymbol, ZZRingElem, ZZRingElem, Bool}
return (E, Kp, fp, cp, true)::Tuple{typeof(E), KodairaSymbol, ZZRingElem, ZZRingElem, Bool}
end

if _val(b6) < 3 # Type IV
cp = _hasroot(one(K), a3//pi, -a6//pi^2) ? ZZ(3) : ZZ(1)
Kp = KodairaSymbol("IV")
fp = FlintZZ(vD - 2)
return (E, Kp, fp, cp, true)::Tuple{EllCrv{nf_elem}, KodairaSymbol, ZZRingElem, ZZRingElem, Bool}
return (E, Kp, fp, cp, true)::Tuple{typeof(E), KodairaSymbol, ZZRingElem, ZZRingElem, Bool}
end

# Change coords so that p|a1,a2, p^2|a3,a4, p^3|a6
Expand Down Expand Up @@ -259,7 +293,7 @@ function _tates_algorithm(E, P)
Kp = KodairaSymbol("I0*")
fp = FlintZZ(vD - 4)
cp = ZZ(1 + _nrootscubic(b, c, d))
return (E, Kp, fp, cp, true)::Tuple{EllCrv{nf_elem}, KodairaSymbol, ZZRingElem, ZZRingElem, Bool}
return (E, Kp, fp, cp, true)::Tuple{typeof(E), KodairaSymbol, ZZRingElem, ZZRingElem, Bool}
elseif sw == 2
# One double root, so type I*m for some m
# Change coords so that the double root is T = 0 mod p
Expand Down Expand Up @@ -329,7 +363,7 @@ function _tates_algorithm(E, P)
m = ix + iy - 5
fp = vD - m - 4
Kp = KodairaSymbol("I$(m)*")
return (E, Kp, FlintZZ(fp), FlintZZ(cp), true)::Tuple{EllCrv{nf_elem}, KodairaSymbol, ZZRingElem, ZZRingElem, Bool}
return (E, Kp, FlintZZ(fp), FlintZZ(cp), true)::Tuple{typeof(E), KodairaSymbol, ZZRingElem, ZZRingElem, Bool}
elseif sw == 3
# Triple root
# Change coordinates so that T = 0 mod p
Expand Down Expand Up @@ -358,7 +392,7 @@ function _tates_algorithm(E, P)
cp = _hasroot(one(K), a3t, -a6t) ? 3 : 1
Kp = KodairaSymbol("IV*")
fp = FlintZZ(vD - 6)
return (E, Kp, fp, FlintZZ(cp), true)::Tuple{EllCrv{nf_elem}, KodairaSymbol, ZZRingElem, ZZRingElem, Bool}
return (E, Kp, fp, FlintZZ(cp), true)::Tuple{typeof(E), KodairaSymbol, ZZRingElem, ZZRingElem, Bool}
end

# Change coordinates so that p^3|a3, p^5|a6
Expand All @@ -377,14 +411,14 @@ function _tates_algorithm(E, P)
Kp = KodairaSymbol("III*")
fp = FlintZZ(vD - 7)
cp = FlintZZ(2)
return (E, Kp, fp, FlintZZ(cp), true)::Tuple{EllCrv{nf_elem}, KodairaSymbol, ZZRingElem, ZZRingElem, Bool}
return (E, Kp, fp, FlintZZ(cp), true)::Tuple{typeof(E), KodairaSymbol, ZZRingElem, ZZRingElem, Bool}
end

if _val(a6) < 6 # Type II*
Kp = KodairaSymbol("II*")
fp = FlintZZ(vD - 8)
cp = FlintZZ(1)
return (E, Kp, fp, FlintZZ(cp), true)::Tuple{EllCrv{nf_elem}, KodairaSymbol, ZZRingElem, ZZRingElem, Bool}
return (E, Kp, fp, FlintZZ(cp), true)::Tuple{typeof(E), KodairaSymbol, ZZRingElem, ZZRingElem, Bool}
end

# Non-minimal equation, dividing out
Expand All @@ -397,7 +431,6 @@ function _tates_algorithm(E, P)
end
end


@doc raw"""
tates_algorithm_local(E::EllCrv{QQFieldElem}, p:: Int)
-> EllipticCurve{QQFieldElem}, String, ZZRingElem, ZZRingElem, Bool
Expand Down
27 changes: 27 additions & 0 deletions src/EllCrv/Misc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,33 @@ function quadroots(a, b, c, p)
end
end

function quadroots(a, b, c, _res::Union{Function, MapFromFunc})
#F_p = GF(p, cached = false)
aa = _res(a)
F = parent(aa)
R, x = polynomial_ring(F, "x", cached = false)
f = aa*x^2 + _res(b)*x + _res(c)

if degree(f) == -1
return true
elseif degree(f) == 0
return false
elseif degree(f) == 1
return true
end

fac = factor(f)
p = first(keys(fac.fac))

if fac[p] == 2 # f has a double zero
return true
elseif length(fac) == 2 # f splits into two different linear factors
return true
else # f does not have a root
return false
end
end

function quadroots(a::nf_elem, b::nf_elem, c::nf_elem, pIdeal:: NfOrdIdl)
R = order(pIdeal)
F, phi = residue_field(R, pIdeal)
Expand Down
2 changes: 1 addition & 1 deletion src/Misc/Poly.jl
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@ function roots(f::FpPolyRingElem, K::FqPolyRepField)
return roots(ff)
end

function is_power(a::Union{fqPolyRepFieldElem, FqPolyRepFieldElem, FqFieldElem}, m::Int)
function is_power(a::Union{FpFieldElem, fqPolyRepFieldElem, FqPolyRepFieldElem, FqFieldElem}, m::Int)
if iszero(a)
return true, a
end
Expand Down
17 changes: 16 additions & 1 deletion test/EllCrv/LocalData.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
@test f == 1
@test c == 1

_, K, f, c = Hecke._tates_algorithm(E, 2)
@test K == "I1"
@test f == 1
@test c == 1

@test reduction_type(E, 2) == "Nonsplit multiplicative"

Ep, K, f, c = tates_algorithm_local(E, 3)
Expand All @@ -25,13 +30,23 @@
@test f == 1
@test c == 2

_, K, f, c = Hecke._tates_algorithm(E, 3)
@test K == "I2"
@test f == 1
@test c == 2

Ep, K, f, c = tates_algorithm_local(E, 5)
@test a_invars(tidy_model(Ep)) == a_invars(E)
@test K == "III*"
@test f == 2
@test c == 2

@test reduction_type(E, 5) == "Additive"
_, K, f, c = Hecke._tates_algorithm(E, 5)
@test K == "III*"
@test f == 2
@test c == 2

@test reduction_type(E, 5) == "Additive"

Ep, K, f, c = tates_algorithm_local(E, 13)
@test a_invars(tidy_model(Ep)) == a_invars(E)
Expand Down

0 comments on commit 71a69d7

Please sign in to comment.