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

extend iso_oscar_gap(FO::AnticNumberField) #2511

Merged
merged 3 commits into from
Jul 4, 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
70 changes: 66 additions & 4 deletions src/GAP/iso_oscar_gap.jl
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,8 @@ function _iso_oscar_gap_field_quadratic_functions(FO::AnticNumberField, FG::GAP.
return (f, finv)
end

function _iso_oscar_gap(FO::AnticNumberField)
# Deal with simple extensions of Q.
function _iso_oscar_gap(FO::SimpleNumField{QQFieldElem})
flag1, N1 = Hecke.is_cyclotomic_type(FO)
flag2, N2 = Hecke.is_quadratic_type(FO)
if flag1
Expand All @@ -285,16 +286,15 @@ function _iso_oscar_gap(FO::AnticNumberField)
FG = GAPWrap.Field(GAPWrap.Sqrt(GAP.Obj(N2)))
f, finv = _iso_oscar_gap_field_quadratic_functions(FO, FG)
else
polFO = FO.pol
N = degree(polFO)
polFO = defining_polynomial(FO)
coeffs_polFO = collect(coefficients(polFO))
fam = GAP.Globals.CyclotomicsFamily::GapObj
cfs = GAP.GapObj(coeffs_polFO, recursive = true)::GapObj
polFG = GAPWrap.UnivariatePolynomialByCoefficients(fam, cfs, 1)
FG = GAPWrap.AlgebraicExtension(GAP.Globals.Rationals::GapObj, polFG)
fam = GAPWrap.ElementsFamily(GAPWrap.FamilyObj(FG))

f = function(x::Nemo.nf_elem)
f = function(x::SimpleNumFieldElem{QQFieldElem})
coeffs = GAP.GapObj(coefficients(x), recursive = true)::GapObj
return GAPWrap.AlgExtElm(fam, coeffs)
end
Expand All @@ -308,6 +308,68 @@ function _iso_oscar_gap(FO::AnticNumberField)
return MapFromFunc(f, finv, FO, FG)
end

# Deal with simple extensions of proper extensions of Q.
function _iso_oscar_gap(FO::SimpleNumField{nf_elem})
B = base_field(FO)
isoB = iso_oscar_gap(B)
BG = codomain(isoB)::GapObj

polFO = defining_polynomial(FO)
coeffs_polFO = collect(coefficients(polFO))
fam = GAPWrap.ElementsFamily(GAPWrap.FamilyObj(BG))
cfs = GAP.GapObj([isoB(x) for x in coeffs_polFO])::GapObj
polFG = GAPWrap.UnivariatePolynomialByCoefficients(fam, cfs, 1)
FG = GAPWrap.AlgebraicExtension(BG, polFG)
fam = GAPWrap.ElementsFamily(GAPWrap.FamilyObj(FG))

f = function(x::SimpleNumFieldElem{nf_elem})
coeffs = GAP.GapObj([isoB(x) for x in coefficients(x)])::GapObj
return GAPWrap.AlgExtElm(fam, coeffs)
end

finv = function(x::GapObj)
coeffs = [preimage(isoB, x) for x in GapObj(GAPWrap.ExtRepOfObj(x))]
return FO(coeffs)
end

return MapFromFunc(f, finv, FO, FG)
end

# Deal with non-simple extensions of Q or of extensions of Q.
function _iso_oscar_gap(FO::NumField)
@assert ! is_simple(FO)
if is_absolute(FO)
F, emb = absolute_simple_field(FO)
else
F, emb = simple_extension(FO)
end
iso = iso_oscar_gap(F)
FG = codomain(iso)
fam = GAPWrap.ElementsFamily(GAPWrap.FamilyObj(FG))
B = base_field(F)
isoB = iso_oscar_gap(B)

f = function(x::NumFieldElem)
coeffs = GAP.GapObj([isoB(x) for x in coefficients(preimage(emb, x))])::GapObj
return GAPWrap.AlgExtElm(fam, coeffs)
end

if is_absolute(FO)
finv = function(x::GapObj)
coeffs = Vector{QQFieldElem}(GAPWrap.ExtRepOfObj(x))
return emb(F(coeffs))
end
else
finv = function(x::GapObj)
coeffs = [preimage(isoB, y) for y in GAPWrap.ExtRepOfObj(x)]
return emb(F(coeffs))
end
end

return MapFromFunc(f, finv, FO, FG)
end


# Assume that `FO` is a `QQAbField` and `FG` is `GAP.Globals.Cyclotomics`.
function _iso_oscar_gap_abelian_closure_functions(FO::QQAbField, FG::GAP.GapObj)
return (GAP.julia_to_gap, QQAbElem)
Expand Down
27 changes: 24 additions & 3 deletions test/GAP/iso_oscar_gap.jl
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ end
b = my_rand_bits(F, 5)
@test f(a*b) == f(a)*f(b)
@test f(a - b) == f(a) - f(b)
@test preimage(f, f(a)) == a
end
end
@test_throws ErrorException f(cyclotomic_field(2)[2])
Expand Down Expand Up @@ -210,6 +211,7 @@ end
b = my_rand_bits(F, 5)
@test f(a*b) == f(a)*f(b)
@test f(a - b) == f(a) - f(b)
@test preimage(f, f(a)) == a
end
end

Expand All @@ -221,11 +223,21 @@ end
@testset "number fields" begin
# for computing random elements of the fields in question
my_rand_bits(F::QQField, b::Int) = rand_bits(F, b)
my_rand_bits(F::AnticNumberField, b::Int) = F([rand_bits(QQ, b) for i in 1:degree(F)])
my_rand_bits(F::NumField, b::Int) = F([my_rand_bits(base_field(F), b) for i in 1:degree(F)])

# absolute number fields
R, x = polynomial_ring(QQ, "x")
@testset for pol in [ x^2 - 5, x^2 + 3, x^3 - 2 ]
F, z = number_field(pol)
pols = [ x^2 - 5, x^2 + 3, x^3 - 2, # simple
[x^2 - 2, x^2 + 1] ] # non-simple
fields = Any[number_field(pol)[1] for pol in pols]

# non-absolute number fields
F1, _ = number_field(x^2-2)
R1, x1 = polynomial_ring(F1, "x")
push!(fields, number_field(x1^2-3)[1]) # simple
push!(fields, number_field([x1^2-3, x1^2+1])[1]) # non-simple

@testset for F in fields
f = Oscar.iso_oscar_gap(F)
@test f === Oscar.iso_oscar_gap(F) # test that everything gets cached
for i in 1:10
Expand All @@ -234,9 +246,18 @@ end
b = my_rand_bits(F, 5)
@test f(a*b) == f(a)*f(b)
@test f(a - b) == f(a) - f(b)
@test preimage(f, f(a)) == a
end
end
end

# an application
K = fields[4]
a, b = gens(K)
M1 = 1/a*matrix(K, [1 1; 1 -1])
M2 = matrix(K, [1 0 ; 0 b])
G = matrix_group(M1, M2)
@test small_group_identification(G) == (192, 963)
end

@testset "abelian closure" begin
Expand Down
Loading