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

add basic doc... #1377

Merged
merged 8 commits into from
Jun 9, 2022
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
7 changes: 7 additions & 0 deletions docs/src/Experimental/galois.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,10 @@ minpoly(C::Oscar.GaloisGrp.GaloisCtx, I, extra::Int = 5)
Oscar.GaloisGrp.cauchy_ideal(f::PolyElem{<:FieldElem})
Oscar.GaloisGrp.galois_ideal(C::Oscar.GaloisGrp.GaloisCtx, extra::Int = 5)
```

Over the integers, if the Galois group is solvable, the roots can be expressed
as radicals:
```@docs
solve(f::fmpz_poly)
fixed_field(C::Oscar.GaloisGrp.GaloisCtx, s::Vector{PermGroup})
```
113 changes: 104 additions & 9 deletions experimental/GaloisGrp/Solve.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module SolveRadical

using Oscar
using Oscar, Markdown
import Oscar: AbstractAlgebra, Hecke, GaloisGrp.GaloisCtx

function __init__()
Expand Down Expand Up @@ -46,7 +46,7 @@ function Oscar.number_field(S::SubField)
end

#let G, C = galois_group(..)
#starting with QQ:
#startig with QQ:
# QQ = fixed_field(C, G)
# pe = 1 (constant)
# conj = [()]
Expand Down Expand Up @@ -158,6 +158,14 @@ function rationals_as_subfield(C::GaloisCtx)
return S
end

"""
The subfield fixed by U as an extension of S

The invar will yield the primitive element under evaluation at the
original roots

max_prec can be given to limit the internal precision
"""
function _fixed_field(C::GaloisCtx, S::SubField, U::PermGroup; invar=nothing, max_prec::Int = typemax(Int))
@hassert :SolveRadical 1 is_subgroup(S.grp, U)[1]
t = right_transversal(S.grp, U)
Expand Down Expand Up @@ -228,6 +236,14 @@ function refined_derived_series(G::PermGroup)
return Oscar._as_subgroups(G,s)
end

"""
The tower of subfields corresponding to the subgroup chain.

invar is an array that will be used to get the primitive elements.
invar can be shorter than s - it will be used from the bottom up

max_prec is an upper limit on the internal precision
"""
function _fixed_field(C::GaloisCtx, s::Vector{PermGroup}; invar=nothing, max_prec::Int = typemax(Int))
k = rationals_as_subfield(C)
if order(s[1]) != order(C.G)
Expand All @@ -248,23 +264,50 @@ function _fixed_field(C::GaloisCtx, s::Vector{PermGroup}; invar=nothing, max_pre
return k
end

function fixed_field(C::GaloisCtx, s::Vector{PermGroup}; invar=nothing, max_prec::Int = typemax(Int))
return number_field(_fixed_field(C, s, invar = invar, max_prec = max_prec))
@doc Markdown.doc"""
fixed_field(C::GaloisCtx, s::Vector{PermGroup})

Given a descending chain of subgroups, each being maximal in the previous
one, compute the corresponding subfields as a tower.

# Examples
```julia
julia> Qx, x = QQ["x"];

julia> G, C = galois_group(x^3-3*x+17)
(Sym( [ 1 .. 3 ] ), Galois Context for x^3 - 3*x + 17 and prime 7)

julia> d = derived_series(G)
3-element Vector{PermGroup}:
Sym( [ 1 .. 3 ] )
Alt( [ 1 .. 3 ] )
Group(())

julia> fixed_field(C, d)
(Relative number field over with defining polynomial x^3 - 3*x + 17
over Number field over Rational Field with defining polynomial x^2 + 7695, a2)

```
"""
function Oscar.fixed_field(C::GaloisCtx, s::Vector{PermGroup})
return number_field(_fixed_field(C, s))
end

#a bound on the largest conjugate of an absolute dual basis (product basis)
function dual_basis_bound(S::SubField)
if S.fld == QQ
return fmpz(1)
end
return upper_bound(fmpz, maximum(x->maximum(abs, Oscar.conjugates(x)), S.dual_basis))*dual_basis_bound(S.coeff_field)
end

function Hecke.length(x::NumFieldElem, abs_tol::Int = 32, T = arb)
function Hecke.length(x::NumFieldElem, abs_tol::Int = 32, T = arb)
return sum(x^2 for x = Oscar.conjugates(x, abs_tol, T))
end

function conjugates(C::GaloisCtx, S::SubField, a::fmpq, pr::Int = 10)
rt = roots(C, pr)
@assert S.fld == QQ
return [parent(rt[1])(a)]
end

Expand Down Expand Up @@ -297,7 +340,14 @@ function recognise(C::GaloisCtx, S::SubField, J::Vector{<:SLPoly})
return D
end

"""
For a cyclic extension K/k with Automorphism group generated by aut and
a corresponding primitive n-th root of 1, find an isomorphic radical extension
using Lagrange resolvents.
"""
function as_radical_extension(K::NumField, aut::Map, zeta::NumFieldElem)
CHECK = get_assert_level(:SolveRadical) > 0

g = gen(K)
d = degree(K)
#assumes K is cyclic, aut generates K/ceoff(K), zeta has order d
Expand All @@ -316,16 +366,60 @@ function as_radical_extension(K::NumField, aut::Map, zeta::NumFieldElem)
end
s = coeff(r^d, 0)
@hassert :SolveRadical 1 s == r^d
L, b = number_field(gen(parent(defining_polynomial(K)))^d-s, cached = false, check = false)
L, b = number_field(gen(parent(defining_polynomial(K)))^d-s, cached = false, check = CHECK)
@assert base_field(L) == base_field(K)
return L, hom(L, K, r)
global last_b = (L, K, r)
return L, hom(L, K, r, check = CHECK)
end

function Oscar.solve(f::fmpq_poly; max_prec::Int=typemax(Int))
return solve(numerator(f), max_prec = max_prec)
end

@doc Markdown.doc"""
Oscar.solve(f::fmpz_poly; max_prec::Int=typemax(Int))
Oscar.solve(f::fmpq_poly; max_prec::Int=typemax(Int))
Comment on lines +380 to +381
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this exported?

Suggested change
Oscar.solve(f::fmpz_poly; max_prec::Int=typemax(Int))
Oscar.solve(f::fmpq_poly; max_prec::Int=typemax(Int))
solve(f::fmpz_poly; max_prec::Int=typemax(Int))
solve(f::fmpq_poly; max_prec::Int=typemax(Int))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no can do: solve is not imported...


Compute a presentation of the roots of `f` in a radical tower.
The necessary roots of unity are not themselves computed as radicals.

See also [`galois_group`](@ref).

# VERBOSE
Supports `set_verbose_level(:SolveRadical, i)` to obtain information.


# Examples
```julia
julia> Qx,x = QQ["x"];

julia> K, r = solve(x^3+3*x+5)
(Relative number field over with defining polynomial x^3 + (3*z_3 + 3//2)*a2 + 135//2
over Relative number field over with defining polynomial x^2 + 783
over Number field over Rational Field with defining polynomial x^2 + x + 1, Any[((1//81*z_3 + 1//162)*a2 - 5//18)*a3^2 + 1//3*a3, ((-1//162*z_3 + 1//162)*a2 + 5//18*z_3 + 5//18)*a3^2 + 1//3*z_3*a3, ((-1//162*z_3 - 1//81)*a2 - 5//18*z_3)*a3^2 + (-1//3*z_3 - 1//3)*a3])

julia> #z_3 indicates the 3-rd root-of-1 used

julia> map(x^3+3*x+5, r)
3-element Vector{Hecke.NfRelElem{Hecke.NfRelElem{nf_elem}}}:
0
0
0

julia> solve(cyclotomic(12, x)) #zeta_12 as radical
(Relative number field over with defining polynomial x^2 - 3//4
over Number field over Rational Field with defining polynomial x^2 + 1, Any[a2 + 1//2*a1, a2 - 1//2*a1, -a2 - 1//2*a1, -a2 + 1//2*a1])

```
"""
function Oscar.solve(f::fmpz_poly; max_prec::Int=typemax(Int))
#if poly is not monic, the roots are scaled (by default) to
#make them algebraically integral. This has to be compensated
#in a couple of places...

scale = leading_coefficient(f)

#switches check = true in hom and number_field on
CHECK = get_assert_level(:SolveRadical) > 0
@vprint :SolveRadical 1 "computing initial galois group...\n"
@vtime :SolveRadical 1 G, C = galois_group(f)
Expand All @@ -334,7 +428,7 @@ function Oscar.solve(f::fmpz_poly; max_prec::Int=typemax(Int))
@vprint :SolveRadical 1 "need to add roots-of-one: $lp\n"
@vtime :SolveRadical 1 G, C = galois_group(f*prod(cyclotomic(Int(p), gen(parent(f))) for p = lp))
end
r = roots(C, 2)
r = roots(C, 2, raw = true)
#the indices of zeta
pp = [findfirst(isone, [x^p for x = r]) for p = lp]
#and the indices of the roots of f
Expand Down Expand Up @@ -364,7 +458,7 @@ function Oscar.solve(f::fmpz_poly; max_prec::Int=typemax(Int))

cyclo = fld_arr[length(pp)+1]
@vprint :SolveRadical 1 "finding roots-of-1...\n"
@vtime :SolveRadical 1 zeta = [recognise(C, cyclo, gens(parent(cyclo.pe))[i]) for i=pp]
@vtime :SolveRadical 1 zeta = [recognise(C, cyclo, gens(parent(cyclo.pe))[i])//scale for i=pp]
@hassert :SolveRadical 1 all(i->isone(zeta[i]^lp[i]), 1:length(pp))
aut = []
@vprint :SolveRadical 1 "finding automorphisms...\n"
Expand All @@ -378,6 +472,7 @@ function Oscar.solve(f::fmpz_poly; max_prec::Int=typemax(Int))
end
@vprint :SolveRadical 1 "find roots...\n"
@vtime :SolveRadical 1 R = recognise(C, All, gens(S)[rt])
R = R .// scale
#now, rewrite as radicals..
#the cyclos are fine:
K = number_field(fld_arr[length(pp)+1])[1]
Expand Down