Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

first draft at generic tate #1144

Merged
merged 1 commit into from
Jul 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 96 additions & 43 deletions src/EllCrv/LocalData.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,46 +46,100 @@

# Tate's algorithm over number fields, see Cremona, p. 66, Silverman p. 366
@doc raw"""
tates_algorithm_local(E::EllCrv{nf_elem}, pIdeal:: NfOrdIdl)
-> elliptic_curve{nf_elem}, String, ZZRingElem, ZZRingElem, Bool
tates_algorithm_local(E::EllCrv{nf_elem}, p:: NfOrdIdl)
-> EllipticCurve{nf_elem}, String, ZZRingElem, ZZRingElem, Bool

Returns a tuple $(\tilde E, K, m, f, c, s)$, where $\tilde E$ is a
minimal model for $E$ at the prime ideal $p$, $K$ is the Kodaira symbol,
$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.
Returns a tuple $(\tilde E, K, m, f, c, s)$, where $\tilde E$ is a minimal
model for $E$ at the prime ideal $p$, $K$ is the Kodaira symbol, $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, P)
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}, ::typeof(degree))
K = base_field(E)
R = base_ring(K.fraction_field)
Kl = localization(K, degree)
F, _mF = residue_field(Kl, Kl(1//gen(K)))
mF = x -> _mF(Kl(x))
_val = x -> iszero(x) ? inf : degree(denominator(x)) - degree(numerator(x))
_res = mF
_mod = x -> K(preimage(_mF, (_res(x))))
_invmod = x -> K(preimage(_mF, inv(_res(x))))
_uni = 1//gen(K)
_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}, 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 parent(x) === K
t = gen(K)
if is_one(denominator(x))
return _tates_algorithm(E, numerator(x))
else
@assert x == 1//t
return _tates_algorithm(E, degree)
end
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 +161,19 @@
# 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))

Check warning on line 167 in src/EllCrv/LocalData.jl

View check run for this annotation

Codecov / codecov/patch

src/EllCrv/LocalData.jl#L167

Added line #L167 was not covered by tests
end
if !iszero(a3)
e = max(e, ceil(Int, -val(a2)//3))
e = max(e, ceil(Int, -_val(a3)//3))

Check warning on line 170 in src/EllCrv/LocalData.jl

View check run for this annotation

Codecov / codecov/patch

src/EllCrv/LocalData.jl#L170

Added line #L170 was not covered by tests
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 +193,7 @@
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 +245,28 @@
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 +313,7 @@
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 +383,7 @@
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 +412,7 @@
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 +431,14 @@
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 +451,6 @@
end
end


@doc raw"""
tates_algorithm_local(E::EllCrv{QQFieldElem}, p:: Int)
-> elliptic_curve{QQFieldElem}, String, ZZRingElem, ZZRingElem, Bool
Expand Down
46 changes: 45 additions & 1 deletion src/EllCrv/MinimalModels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@
Returns a model of $E$, which is minimal at $p$. It is assumed that $p$
is a prime ideal.
"""
function minimal_model(E::EllCrv{nf_elem}, p::NfOrdIdl)
function minimal_model(E::EllCrv, p)
Ep = tates_algorithm_local(E, p)
Ep = Ep[1]
phi = isomorphism(E, Ep)
Expand Down Expand Up @@ -617,3 +617,47 @@
return false, zero(OK)
end

function reduce_model(E::EllCrv{<: AbstractAlgebra.Generic.RationalFunctionFieldElem})
Kt = base_field(E)
Rt = base_ring(Kt.fraction_field)
d = discriminant(E)
E, = minimal_model(E, degree)
for (g, e) in factor(d, Rt)
g = AbstractAlgebra.MPolyFactor.make_monic(g)
E, = minimal_model(E, g)
end
return E

Check warning on line 629 in src/EllCrv/MinimalModels.jl

View check run for this annotation

Codecov / codecov/patch

src/EllCrv/MinimalModels.jl#L620-L629

Added lines #L620 - L629 were not covered by tests
end

function _minimize(E::EllCrv{<: AbstractAlgebra.Generic.RationalFunctionFieldElem})
Kt = base_field(E)
Rt = base_ring(Kt.fraction_field)
d = discriminant(E)
for (g, e) in factor(d, Rt)
g = AbstractAlgebra.MPolyFactor.make_monic(g)
E = _minimize(E, Kt(g), e)
end
return E

Check warning on line 640 in src/EllCrv/MinimalModels.jl

View check run for this annotation

Codecov / codecov/patch

src/EllCrv/MinimalModels.jl#L632-L640

Added lines #L632 - L640 were not covered by tests
end

function _minimize(E::EllCrv, u, e)
v = one(u)
if abs(e) > 11
v = u^(fdiv(ZZ(e), 12))

Check warning on line 646 in src/EllCrv/MinimalModels.jl

View check run for this annotation

Codecov / codecov/patch

src/EllCrv/MinimalModels.jl#L643-L646

Added lines #L643 - L646 were not covered by tests
end
if -12 < e < 0
v *= inv(u)

Check warning on line 649 in src/EllCrv/MinimalModels.jl

View check run for this annotation

Codecov / codecov/patch

src/EllCrv/MinimalModels.jl#L648-L649

Added lines #L648 - L649 were not covered by tests
end
E, = transform_rstu(E, [0, 0, 0, v])
return E

Check warning on line 652 in src/EllCrv/MinimalModels.jl

View check run for this annotation

Codecov / codecov/patch

src/EllCrv/MinimalModels.jl#L651-L652

Added lines #L651 - L652 were not covered by tests
end

#def minimize(E,factored_disc=None):
# if factored_disc is None:
# factored_disc = E.discriminant().factor()
# u = [e for e in factored_disc if abs(e[1])>11]
# u = prod(e[0]^(e[1]//12) for e in u)
# u *= prod(e[0]^-1 for e in factored_disc if -12<e[1]<0)
# E1 = E.change_weierstrass_model((u,0,0,0))
# return E1,u

27 changes: 27 additions & 0 deletions src/EllCrv/Misc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,33 @@
end
end

function quadroots(a, b, c, _res::Union{Function, MapFromFunc})

Check warning on line 91 in src/EllCrv/Misc.jl

View check run for this annotation

Codecov / codecov/patch

src/EllCrv/Misc.jl#L91

Added line #L91 was not covered by tests
#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)

Check warning on line 96 in src/EllCrv/Misc.jl

View check run for this annotation

Codecov / codecov/patch

src/EllCrv/Misc.jl#L93-L96

Added lines #L93 - L96 were not covered by tests

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

Check warning on line 103 in src/EllCrv/Misc.jl

View check run for this annotation

Codecov / codecov/patch

src/EllCrv/Misc.jl#L98-L103

Added lines #L98 - L103 were not covered by tests
end

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

Check warning on line 107 in src/EllCrv/Misc.jl

View check run for this annotation

Codecov / codecov/patch

src/EllCrv/Misc.jl#L106-L107

Added lines #L106 - L107 were not covered by tests

if fac[p] == 2 # f has a double zero
return true
elseif length(fac) == 2 # f splits into two different linear factors
return true

Check warning on line 112 in src/EllCrv/Misc.jl

View check run for this annotation

Codecov / codecov/patch

src/EllCrv/Misc.jl#L109-L112

Added lines #L109 - L112 were not covered by tests
else # f does not have a root
return false

Check warning on line 114 in src/EllCrv/Misc.jl

View check run for this annotation

Codecov / codecov/patch

src/EllCrv/Misc.jl#L114

Added line #L114 was not covered by tests
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
Loading
Loading