From bc105af33e785d02fb7769f25c9933b2d5b1576e Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 19 Sep 2023 08:38:34 +0200 Subject: [PATCH 1/9] Change 'nonnegative' to 'non-negative' for consistency (#1215) --- src/NumFieldOrd/NfOrd/Ideal/Ideal.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NumFieldOrd/NfOrd/Ideal/Ideal.jl b/src/NumFieldOrd/NfOrd/Ideal/Ideal.jl index e82b097092..a5ef0c427a 100644 --- a/src/NumFieldOrd/NfOrd/Ideal/Ideal.jl +++ b/src/NumFieldOrd/NfOrd/Ideal/Ideal.jl @@ -596,7 +596,7 @@ end @doc raw""" minimum(A::NfAbsOrdIdl) -> ZZRingElem -Returns the smallest nonnegative element in $A \cap \mathbf Z$. +Returns the smallest non-negative element in $A \cap \mathbf Z$. """ function minimum(A::NfAbsOrdIdl; copy::Bool = true) assure_has_minimum(A) From c5f65d5925e291d6032d73fa83e39908c0f72b60 Mon Sep 17 00:00:00 2001 From: Stevell Muller <78619134+StevellM@users.noreply.github.com> Date: Tue, 19 Sep 2023 08:43:41 +0200 Subject: [PATCH 2/9] Fix trace equivalence for infinite isometries (#1212) * fix trace equivalence for infinite isometries * forgot a argument check --- src/QuadForm/Lattices.jl | 9 ++++----- test/QuadForm/Lattices.jl | 7 +++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/QuadForm/Lattices.jl b/src/QuadForm/Lattices.jl index b77036d1cc..da5a7d08de 100644 --- a/src/QuadForm/Lattices.jl +++ b/src/QuadForm/Lattices.jl @@ -1135,7 +1135,7 @@ function trace_lattice_with_isometry_and_transfer_data(H::AbstractLat{T}; alpha: return H, f, AbstractSpaceRes(V, V, identity_matrix(E, n), identity_matrix(E, n)) end - @req (degree(E) == 2) && (is_totally_complex(E)) && (is_totally_real(base_field(E))) "The base field of H must be CM" + @req H isa HermLat "H must be hermitian or defined over the integers" @req maximal_order(E) == equation_order(E) "Equation order and maximal order must coincide" # This function perform the trace construction on the level of the @@ -1178,7 +1178,6 @@ function trace_lattice_with_isometry(H::HermLat, res::AbstractSpaceRes; beta::Fi @req parent(beta) === E "beta must be an element of the base algebra of H" @req (beta == QQ(1) || norm(beta) == 1) "beta must be of norm 1" - @req (degree(E) == 2) && (is_totally_complex(E)) && (is_totally_real(base_field(E))) "The base field of H must be CM" @req maximal_order(E) == equation_order(E) "Equation order and maximal order must coincide" Lres = restrict_scalars(H, res) @@ -1342,7 +1341,7 @@ function hermitian_structure_with_transfer_data(_L::ZZLat, f::QQMatrix; check::B end else @req E isa NfRel "E must be a relative number field" - @req (degree(E) == 2) && (is_totally_complex(E)) && (is_totally_real(base_field(E))) "E must be a CM-field" + @req degree(E) == 2 "E must be a degree 2 extension of a number field" b = gen(E) chi = absolute_minpoly(b) R = parent(chi) @@ -1390,9 +1389,9 @@ function hermitian_structure_with_transfer_data(_L::ZZLat, f::QQMatrix; check::B for i=1:m for j=1:m vi = deepcopy(v) - vi[1,1+(i-1)*euler_phi(n)] = one(QQ) + vi[1,1+(i-1)*n2] = one(QQ) vj = deepcopy(v) - vj[1,1+(j-1)*euler_phi(n)] = one(QQ) + vj[1,1+(j-1)*n2] = one(QQ) a = matrix(QQ, 1, n2, [(vi*mb^k*G*transpose(vj))[1] for k in 0:n2-1]) co = solve_left(trace_mat, a) gram[i,j] = (co*bs)[1] diff --git a/test/QuadForm/Lattices.jl b/test/QuadForm/Lattices.jl index cb9e7c0de3..3e0145eb0c 100644 --- a/test/QuadForm/Lattices.jl +++ b/test/QuadForm/Lattices.jl @@ -359,6 +359,13 @@ end @test_throws ArgumentError trace_lattice_with_isometry(E8, order = 3) end +@testset "Fix #1210: trace equivalence for infinite isometries" begin + L = integer_lattice(; gram=QQ[1 2; 2 1]) + f = QQ[4 -1; 1 0] + H, res = @inferred hermitian_structure_with_transfer_data(L, f) + @test trace_lattice_with_isometry(H, res) == (L, f) +end + @testset "Hashes" begin E, b = cyclotomic_field_as_cm_extension(14) V = hermitian_space(E, 2) From 3827bb49cb87f0508cc2a04cff3475e66c9af5e9 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Tue, 19 Sep 2023 08:55:34 +0200 Subject: [PATCH 3/9] pretty printing for HeckeMap (#1213) --- src/Map/MapType.jl | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/Map/MapType.jl b/src/Map/MapType.jl index 59680f5e44..04cc275888 100644 --- a/src/Map/MapType.jl +++ b/src/Map/MapType.jl @@ -148,18 +148,27 @@ object `f`. If `g` is provided, it is assumed to satisfy julia> F = GF(2); julia> f = MapFromFunc(QQ, F, x -> F(numerator(x)) * inv(F(denominator(x)))) -Map from -Rational field to Finite field of characteristic 2 defined by a julia-function +Map defined by a julia-function + from rational field + to finite field of characteristic 2 julia> f(QQ(1//3)) 1 +julia> println(f) +Map: QQ -> GF(2) + julia> f = MapFromFunc(QQ, F, x -> F(numerator(x)) * inv(F(denominator(x))), y -> QQ(lift(y)),) -Map from -Rational field to Finite field of characteristic 2 defined by a julia-function with inverse +Map defined by a julia-function with inverse + from rational field + to finite field of characteristic 2 julia> preimage(f, F(1)) 1 + +julia> println(f) +Map: QQ -> GF(2) + ``` """ mutable struct MapFromFunc{R, T} <: Map{R, T, HeckeMap, MapFromFunc} @@ -197,20 +206,16 @@ function preimage(f::MapFromFunc, y) return x end -function Base.show(io::IO, M::MapFromFunc) +function Base.show(io::IO, ::MIME"text/plain", M::MapFromFunc) @show_name(io, M) - - io = IOContext(io, :compact => true) -# println(io, "Map from the $(M.f) julia-function") - println(io, "Map from") - show(io, domain(M)) - print(io, " to ") - show(io, codomain(M)) - print(io, " defined by a julia-function") + io = pretty(io) + print(io, "Map defined by a julia-function") if isdefined(M, :g) -# println(io, "with inverse by $(M.g)") print(io, " with inverse") end + println(io) + println(io, Indent(),"from ", Lowercase(), domain(M)) + print(io, "to ", Lowercase(), codomain(M), Dedent()) end function MapFromFunc(D, C, f) From 30faeb2e73fbf33676c8e1d62b15d1f14b3e4722 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 21 Sep 2023 05:29:02 +0200 Subject: [PATCH 4/9] Fix rational_normal_form example (#1211) --- examples/Jordan.jl | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/examples/Jordan.jl b/examples/Jordan.jl index ef447a02dc..ace874d8e3 100644 --- a/examples/Jordan.jl +++ b/examples/Jordan.jl @@ -13,15 +13,15 @@ function rref_with_trans(M::T) where {T <: MatElem{S} where {S <: FieldElem}} end function quo_gens(A, B) - n, B = rref(B') - B = sub(B, 1:n, 1:ncols(B))' + n, B = rref(transpose(B)) + B = transpose(sub(B, 1:n, 1:ncols(B))) fl, T = can_solve_with_solution(A, B) # A T = B - d, r = rref(T') + d, r = rref(transpose(T)) t = sub(r, 1:d, 1:ncols(r)) t = Hecke.reduce_mod(identity_matrix(base_ring(t), ncols(t)), t) d = rref!(t) t = t[1:d, :] - return A*t' + return A*transpose(t) end function rational_normal_form(M::T) where {T <: MatElem{S} where {S <: FieldElem}} @@ -43,10 +43,10 @@ function rational_normal_form(M::T) where {T <: MatElem{S} where {S <: FieldElem if ncols(b) > 0 break end - @show ex -= 1 + ex -= 1 km = g(M)*km - d, km = rref(km') - km = km[1:d, :]' + d, km = rref(transpose(km)) + km = transpose(km[1:d, :]) end b = b[:, 1] #any 0 ne b in km/g(M)km will generate a sigma cyclic subspace @@ -55,11 +55,10 @@ function rational_normal_form(M::T) where {T <: MatElem{S} where {S <: FieldElem b = zero_matrix(base_ring(M), nrows(M), 0) for k = 1:ex for j = 1:degree(g) - @show k, j b = hcat(b, (M^(j-1))*((g^(k-1))(M))*ve) end end - @show this_g = hcat(this_g, b) + this_g = hcat(this_g, b) end all_b = hcat(all_b, this_g) end From 008325818c66d194ad0d0b6a0cee0c351584905e Mon Sep 17 00:00:00 2001 From: Tommy Hofmann Date: Thu, 21 Sep 2023 06:31:48 +0200 Subject: [PATCH 5/9] Change copy to deepcopy (#1216) --- src/NumFieldOrd/NfOrd/NfOrd.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NumFieldOrd/NfOrd/NfOrd.jl b/src/NumFieldOrd/NfOrd/NfOrd.jl index 02211f2191..6b08093e6c 100644 --- a/src/NumFieldOrd/NfOrd/NfOrd.jl +++ b/src/NumFieldOrd/NfOrd/NfOrd.jl @@ -1059,7 +1059,7 @@ function _order(K::S, elt::Vector{T}; cached::Bool = true, check::Bool = true, e end if phase == 1 # [1] -> [1, e] -> [1, e, e, e^2] -> ... otherwise - push!(bas, copy(f)) + push!(bas, deepcopy(f)) else b = elem_type(K)[e*x for x in bas] append!(bas, b) From 779deda4c9669cdf5f5a0a517b7031e2bbf09c2e Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 21 Sep 2023 08:10:12 +0200 Subject: [PATCH 6/9] Add some tweaks for type stability etc. (#1214) Several changes deal with JET warnings about "captured variables" resulting in disabled optimizations resp. type unstable code. E.g. `mFF` was assigned different values in two places which then are referenced inside closures. Likewise, `NN` was used in lambdas, which we now avoid. --- src/Map/MapType.jl | 4 ++-- src/Map/NfRelOrd.jl | 10 +++++----- src/QuadForm/Herm/LocallyIsometricSublattice.jl | 4 ++-- src/QuadForm/Lattices.jl | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Map/MapType.jl b/src/Map/MapType.jl index 04cc275888..a734dbd190 100644 --- a/src/Map/MapType.jl +++ b/src/Map/MapType.jl @@ -196,14 +196,14 @@ function image(f::MapFromFunc, x) @req parent(x) === domain(f) "Element not in the domain" y = f.f(x) @req parent(y) === codomain(f) "Image not in the codomain" - return y + return y::elem_type(codomain(f)) end function preimage(f::MapFromFunc, y) @req parent(y) === codomain(f) "Element not in the codomain" x = f.g(y) @req parent(x) === domain(f) "Preimage not in the domain" - return x + return x::elem_type(domain(f)) end function Base.show(io::IO, ::MIME"text/plain", M::MapFromFunc) diff --git a/src/Map/NfRelOrd.jl b/src/Map/NfRelOrd.jl index adc4044b3f..275cc09ff3 100644 --- a/src/Map/NfRelOrd.jl +++ b/src/Map/NfRelOrd.jl @@ -72,7 +72,7 @@ function NfRelOrdToFqMor(O::NfRelOrd{T, S, U}, P::NfRelOrdIdl{T, S, U}) where {T ccall((:fq_default_poly_set, libflint), Nothing, (Ref{FqPolyRingElem}, Ref{FqPolyRingElem}, Ref{FqField}), hh, h, F) z.poly_of_the_field = hh d = degree(hh) - FF, mFF = Nemo._residue_field(hh; absolute = true) + FF, mFF2 = Nemo._residue_field(hh; absolute = true) function _image(x::NfRelOrdElem) f = parent(nf(O).pol)(elem_in_nf(x)) @@ -81,11 +81,11 @@ function NfRelOrdToFqMor(O::NfRelOrd{T, S, U}, P::NfRelOrdIdl{T, S, U}) where {T else ff = Fx([ mmF(coeff(f, i)) for i = 0:degree(f) ]) end - return mFF(ff) + return mFF2(ff) end function _preimage(x::FqFieldElem) - f = preimage(mFF, x) + f = preimage(mFF2, x) immF = pseudo_inv(mmF) #xp = Nemo._as_poly(x) y = nf(O)([ immF(coeff(f, i)) for i = 0:(d - 1) ]) @@ -173,7 +173,7 @@ mutable struct NfRelOrdToFqFieldRelMor{S} <: Map{S, FqField, HeckeMap, NfRelOrdT poly_of_the_field P map_subfield::Union{NfOrdToFqFieldMor, NfRelOrdToFqFieldRelMor} - + function NfRelOrdToFqFieldRelMor{S}(O::S, P, mapsub) where {S} z = new{S}() z.P = P @@ -194,7 +194,7 @@ mutable struct NfRelOrdToFqFieldRelMor{S} <: Map{S, FqField, HeckeMap, NfRelOrdT hh = FKx() ccall((:fq_default_poly_set, libflint), Nothing, (Ref{FqPolyRingElem}, Ref{FqPolyRingElem}, Ref{FqField}), hh, h, FK) z.poly_of_the_field = hh - + FE, mE = Nemo._residue_field(hh) # # FE = RelFinField(hh, :v) diff --git a/src/QuadForm/Herm/LocallyIsometricSublattice.jl b/src/QuadForm/Herm/LocallyIsometricSublattice.jl index 5a6e0d9ab4..df62bb6bc3 100644 --- a/src/QuadForm/Herm/LocallyIsometricSublattice.jl +++ b/src/QuadForm/Herm/LocallyIsometricSublattice.jl @@ -203,7 +203,7 @@ function _locally_isometric_sublattice_odd_ramified(M, L, p, P, absolute_map) end _Y0 = vcat(B[1:r-1], mtype[B[n - 1] + s * B[n]]) else - SS = Int[ i for i in 1:n if !(i in NN)] + SS = setdiff(1:n, NN) if det(c, 1) == 1 Y0 = Int[] else @@ -222,7 +222,7 @@ function _locally_isometric_sublattice_odd_ramified(M, L, p, P, absolute_map) v = B[n - 1] B[n - 1] = B[n - 1] + E(s) * B[n] B[n] = B[n] - s * _G[n, n]//_G[n - 1, n - 1] * v - NN = Int[i for i in NN if i < n - 1] + filter!(i -> i < n - 1, NN) SS = Int[n - 1, n] end push!(Y0, SS[1]) diff --git a/src/QuadForm/Lattices.jl b/src/QuadForm/Lattices.jl index da5a7d08de..1eb6444ed4 100644 --- a/src/QuadForm/Lattices.jl +++ b/src/QuadForm/Lattices.jl @@ -1320,9 +1320,9 @@ function hermitian_structure_with_transfer_data(_L::ZZLat, f::QQMatrix; check::B @req !is_finite(n) || n > 2 "Isometry must have infinite order or order bigger than 2" if check - G = gram_matrix(ambient_space(L)) + gram = gram_matrix(ambient_space(L)) @req is_irreducible(minpoly(f)) "The minimal polynomial of f must be irreducible" - @req f*G*transpose(f) == G "f does not define an isometry of the space of L" + @req f*gram*transpose(f) == gram "f does not define an isometry of the space of L" @req divides(rank(L), n2)[1] "The degree of the minimal polynomial of f must divide the rank of L" end From bdd2d250b10c59f4960fcb1b56dea9c359bc6139 Mon Sep 17 00:00:00 2001 From: Tommy Hofmann Date: Thu, 21 Sep 2023 08:10:43 +0200 Subject: [PATCH 7/9] Fix automorphism group of non-simple field (#1218) --- src/Map/automorphisms.jl | 4 ++-- test/NumField/NfAbs/NfAbs.jl | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Map/automorphisms.jl b/src/Map/automorphisms.jl index 07bd180f77..d8d550fba7 100644 --- a/src/Map/automorphisms.jl +++ b/src/Map/automorphisms.jl @@ -10,7 +10,7 @@ export absolute_automorphism_list, absolute_automorphism_group function _automorphisms(K::NfAbsNS; is_abelian::Bool = false) - pols = QQPolyRingElem[is_univariate(x)[2] for x in K.pol] + pols = QQPolyRingElem[to_univariate(Globals.Qx, x) for x in K.pol] rt = Vector{Vector{NfAbsNSElem}}(undef, length(pols)) for i = 1:length(pols) rt[i] = roots(K, pols[i]) @@ -19,7 +19,7 @@ function _automorphisms(K::NfAbsNS; is_abelian::Bool = false) ind = 1 I = cartesian_product_iterator([1:length(x) for x in rt], inplace = true) for i in I - auts[ind] = hom(K, K, elem_type(K)[rt[i[j]] for j = 1:length(pols)]) + auts[ind] = hom(K, K, elem_type(K)[rt[j][i[j]] for j = 1:length(pols)]) ind += 1 end return auts diff --git a/test/NumField/NfAbs/NfAbs.jl b/test/NumField/NfAbs/NfAbs.jl index d4cc4a8af3..7d6248e073 100644 --- a/test/NumField/NfAbs/NfAbs.jl +++ b/test/NumField/NfAbs/NfAbs.jl @@ -66,3 +66,13 @@ end K, a = number_field(f) @test length(factor(K, f).fac) == 4 end + +@testset "automorphisms" begin + Qx, x = QQ["x"] + K, a = number_field([x^2 - 2, x^2 - 3], "a", cached = false) + @test is_normal(K) + @test length(automorphism_list(K)) == 4 + K, a = number_field([x^2 - 2, x^3 - 2], "a", cached = false) + @test !is_normal(K) + @test length(automorphism_list(K)) == 2 +end From 0b550bd137d2ca3fc6f0d9e871b71ae3af080c79 Mon Sep 17 00:00:00 2001 From: Tommy Hofmann Date: Thu, 21 Sep 2023 08:10:56 +0200 Subject: [PATCH 8/9] Relax some signatures (#1217) --- src/NumFieldOrd/NfOrd/Ideal/Prime.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NumFieldOrd/NfOrd/Ideal/Prime.jl b/src/NumFieldOrd/NfOrd/Ideal/Prime.jl index 3c8e0d98cc..660b34e0cf 100644 --- a/src/NumFieldOrd/NfOrd/Ideal/Prime.jl +++ b/src/NumFieldOrd/NfOrd/Ideal/Prime.jl @@ -227,7 +227,7 @@ $\mathfrak p$ with $l \leq \deg(\mathfrak p)$ will be returned. Note that in this case it may happen that $p\mathcal O$ is not the product of the $\mathfrak p_i^{e_i}$. """ -function prime_decomposition(O::NfAbsOrd{NfAbsNS, NfAbsNSElem}, p::IntegerUnion, degree_limit::Int = degree(O), lower_limit::Int = 0; cached::Bool = true) +function prime_decomposition(O::NfAbsOrd{<:NumField{QQFieldElem}, <:Any}, p::IntegerUnion, degree_limit::Int = degree(O), lower_limit::Int = 0; cached::Bool = true) if typeof(p) != Int && fits(Int, p) return prime_decomposition(O, Int(p), degree_limit, lower_limit, cached = cached) end @@ -235,7 +235,7 @@ function prime_decomposition(O::NfAbsOrd{NfAbsNS, NfAbsNSElem}, p::IntegerUnion, return prime_decomposition(O, ZZRingElem(p), degree_limit, lower_limit, cached = cached) end - if !divisible(numerator(discriminant(nf(O))), p) + if (nf(O) isa NfAbsNS || nf(O) isa AnticNumberField) && !divisible(numerator(discriminant(nf(O))), p) return prime_dec_nonindex(O, p, degree_limit, lower_limit) else return prime_dec_gen(O, p, degree_limit, lower_limit) From 1c2c0ab653fa2b2db422e6619a1f553fc84ddac3 Mon Sep 17 00:00:00 2001 From: Tommy Hofmann Date: Thu, 21 Sep 2023 09:07:19 +0200 Subject: [PATCH 9/9] Update Project.toml --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 4bce7989c5..9d0d4ec3e9 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "Hecke" uuid = "3e1990a7-5d81-5526-99ce-9ba3ff248f21" -version = "0.21.0" +version = "0.22.0" [deps] AbstractAlgebra = "c3fe647b-3220-5bb0-a1ea-a7954cac585d"