From 9a65c160385da40280e026a81fca9acb9763e71c Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Wed, 15 Oct 2025 21:31:31 +0200 Subject: [PATCH 01/13] Allow lists of characteristic or minimal polynomials in enumerate_classes_of_lattices_with_isometry --- .../QuadFormAndIsom/enumeration.jl | 161 ++++++++++++++---- 1 file changed, 132 insertions(+), 29 deletions(-) diff --git a/src/NumberTheory/QuadFormAndIsom/enumeration.jl b/src/NumberTheory/QuadFormAndIsom/enumeration.jl index 2a8e10d2a873..87aac3b8e9ba 100644 --- a/src/NumberTheory/QuadFormAndIsom/enumeration.jl +++ b/src/NumberTheory/QuadFormAndIsom/enumeration.jl @@ -1029,7 +1029,7 @@ function representatives_of_hermitian_type( gene = representative.(orbits(omega)) end - allow_info && println("All possible hermitian genera: $(length(gene))") + allow_info && println("All possible hermitian genera $G $min_poly: $(length(gene))") for g in gene if is_integral(G) && !is_integral(DE*scale(g)) continue @@ -1345,7 +1345,7 @@ end Lf::ZZLatWithIsom, p::IntegerUnion, b::Int = 0; - eiglat_cond::Dict{Int, Vector{Int}}=Dict{Int, Vector{Int}}(), + eiglat_cond::Union{Dict{Int, Vector{Int}}, Vector{Dict{Int,Vector{Int}}}}=[Dict{Int, Vector{Int}}()], fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, @@ -1419,11 +1419,17 @@ julia> is_of_same_type(Lf, reps[2]^2) true ``` """ +splitting_of_hermitian_type( + args...; + eiglat_cond::Dict{Int, Vector{Int}}, + kwargs... + ) = splitting_of_hermitian_type(args...;eiglat_cond=[eiglat_cond], kwargs...) + function splitting_of_hermitian_type( Lf::ZZLatWithIsom, p::IntegerUnion, b::Int = 0; - eiglat_cond::Dict{Int, Vector{Int}}=Dict{Int, Vector{Int}}(), + eiglat_cond::Vector{Dict{Int, Vector{Int}}}=[Dict{Int, Vector{Int}}()], fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, @@ -1451,10 +1457,56 @@ function splitting_of_hermitian_type( # If p divides n, then any output is still of hermitian type since taking pth # power decreases the order of the isometry if iszero(mod(n, p)) - reps = representatives_of_hermitian_type(Lf, p, fix_root; cond=get(eiglat_cond, k, Int[-1, -1, -1]), genusDB, root_test, info_depth, discriminant_annihilator) + cond = unique!([get(i, k, Int[-1, -1, -1]) for i in eiglat_cond]) + reps = representatives_of_hermitian_type(Lf, p, fix_root; cond, genusDB, root_test, info_depth, discriminant_annihilator) return reps end + reps = ZZLatWithIsom[] + V = _from_cyclotomic_polynomial_to_dict(characteristic_polynomial(Lf)) + for i in keys(V) + V[i] = euler_phi(i)*V[i] + end + + # avoid overcounting + eiglat_cond_trimmed = Vector{Dict{Int, Vector{Int}}}() + for cond in eiglat_cond + T = Dict{Int64,Vector{Int64}}() + T[n] = get(cond, n, Int[-1, -1, -1]) + T[k] = get(cond, k, Int[-1, -1, -1]) + push!(eiglat_cond_trimmed, T) + end + unique!(eiglat_cond_trimmed) + + + for cond in eiglat_cond_trimmed + condp = _conditions_after_power(cond, p) + if !all(V[i]==get(condp,i,[-1])[1]||-1==get(condp,i,[-1])[1] for i in keys(V)) + continue + end + tmp = __splitting_of_hermitian_type(Lf, p, b; eiglat_cond=cond, fix_root, genusDB, root_test, check, info_depth, discriminant_annihilator, _local) + append!(reps, tmp) + end + return reps +end + +function __splitting_of_hermitian_type( + Lf::ZZLatWithIsom, + p::IntegerUnion, + b::Int = 0; + eiglat_cond::Dict{Int, Vector{Int}}=Dict{Int, Vector{Int}}(), + fix_root::Int=-1, + genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, + root_test::Bool=false, + check::Bool=true, + info_depth::Int=1, + discriminant_annihilator::Union{ZZPolyRingElem, ZZMPolyRingElem, MPolyIdeal{ZZMPolyRingElem}}=_default_discriminant_annihilator(Lf), + _local::Bool=false, + ) + n = order_of_isometry(Lf) + k = p*n + + @req b == 0 || b == 1 "b must be an integer equal to 0 or 1" if fix_root == k Sk = Int[i for i in 1:k if isone(gcd(i, k))] end @@ -1470,6 +1522,7 @@ function splitting_of_hermitian_type( phi_n = euler_phi(n) phi_k = euler_phi(k) rL = rank(Lf) + rA, pA, nA = get(eiglat_cond, n, Int[-1, -1, -1]) intrA::AbstractVector{Int} = rA >= 0 ? Int[rA] : 0:phi_n:rL rB, pB, nB = get(eiglat_cond, k, Int[-1, -1, -1]) @@ -1560,7 +1613,7 @@ end Lf::ZZLatWithIsom, p::Int, b::Int = 0; - eiglat_cond::Dict{Int, Vector{Int}}=Dict{Int, Vector{Int}}(), + eiglat_cond=[Dict{Int, Vector{Int}}()], fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, @@ -1627,7 +1680,7 @@ function splitting_of_prime_power( Lf::ZZLatWithIsom, p::Int, b::Int = 0; - eiglat_cond::Dict{Int, Vector{Int}}=Dict{Int, Vector{Int}}(), + eiglat_cond=[Dict{Int, Vector{Int}}()], fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, @@ -1735,10 +1788,12 @@ negative signature. generator as input. """ +splitting_of_pure_mixed_prime_power(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_of_pure_mixed_prime_power(args;eiglat_cond=[eiglat_cond], kwargs...) + function splitting_of_pure_mixed_prime_power( Lf::ZZLatWithIsom, p::Int; - eiglat_cond::Dict{Int, Vector{Int}} = Dict{Int, Vector{Int}}(), + eiglat_cond::Vector{Dict{Int, Vector{Int}}}=[Dict{Int, Vector{Int}}()], fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, @@ -1756,11 +1811,15 @@ function splitting_of_pure_mixed_prime_power( pd = prime_divisors(n) + reps = ZZLatWithIsom[] @req length(pd) <= 2 && p in pd "Order must be divisible by p and have at most 2 prime divisors" # In that case (L, f) is of hermitian type, so we can call the appropriate # function if length(pd) == 1 - return representatives_of_hermitian_type(Lf, p, fix_root; cond=get(eiglat_cond, p*n, Int[-1, -1, -1]), genusDB, root_test, info_depth, discriminant_annihilator, _local) + for cond in unique!([get(i, p*n, Int[-1, -1, -1]) for i in eiglat_cond]) + append!(reps, representatives_of_hermitian_type(Lf, p, fix_root; cond, genusDB, root_test, info_depth, discriminant_annihilator, _local)) + end + return reps end q = pd[1] == p ? pd[2] : pd[1] @@ -1772,8 +1831,6 @@ function splitting_of_pure_mixed_prime_power( @req is_divisible_by(chi, phi) "Minimal polynomial is not of the correct form" - reps = ZZLatWithIsom[] - bool, r = divides(phi, cyclotomic_polynomial(n, parent(phi))) @hassert :ZZLatWithIsom 1 bool @@ -1783,7 +1840,11 @@ function splitting_of_pure_mixed_prime_power( A0 = kernel_lattice(Lf, r) B0 = kernel_lattice(Lf, n) # Compute this one first because it is faster to decide whether it is empty - RB = representatives_of_hermitian_type(B0, p, fix_root; cond=get(eiglat_cond, p*n, Int[-1, -1, -1]), genusDB, root_test, info_depth, discriminant_annihilator=q*discriminant_annihilator, _local) + condB = unique!([get(i, p*n, Int[-1, -1, -1]) for i in eiglat_cond]) + RB = ZZLatWithIsom[] + for cond in condB + append!(RB, representatives_of_hermitian_type(B0, p, fix_root; cond=cond, genusDB, root_test, info_depth, discriminant_annihilator=q*discriminant_annihilator, _local)) + end is_empty(RB) && return reps RA = splitting_of_pure_mixed_prime_power(A0, p; eiglat_cond, genusDB, root_test, info_depth=info_depth+1, discriminant_annihilator=q*discriminant_annihilator, _local) is_empty(RA) && return reps @@ -1800,7 +1861,7 @@ end Lf::ZZLatWithIsom, p::IntegerUnion, b::Int = 1; - eiglat_cond::Dict{Int, Vector{Int}}=Dict{Int, Vector{Int}}(), + eiglat_cond::Vector{Dict{Int, Vector{Int}}}=[Dict{Int, Vector{Int}}()], fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, @@ -1878,11 +1939,13 @@ julia> all(LL -> is_of_same_type(Lf, LL^2), reps) true ``` """ +splitting_of_mixed_prime_power(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_of_mixed_prime_power(args;eiglat_cond=[eiglat_cond], kwargs...) + function splitting_of_mixed_prime_power( Lf::ZZLatWithIsom, p::Int, b::Int = 1; - eiglat_cond::Dict{Int, Vector{Int}} = Dict{Int, Vector{Int}}(), + eiglat_cond::Vector{Dict{Int, Vector{Int}}} = [Dict{Int, Vector{Int}}()], fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, @@ -1951,6 +2014,8 @@ end b::Int = 0; char_poly::Union{ZZPolyRingElem, QQPolyRingElem, Nothing}=nothing, min_poly::Union{ZZPolyRingElem, QQPolyRingElem, Nothing}=nothing, + char_polys::Vector=[nothing], + min_polys::Vector=[nothing], rks::Vector{Tuple{Int, Int}}=Tuple{Int, Int}[], pos_sigs::Vector{Tuple{Int, Int}}=Tuple{Int, Int}[], neg_sigs::Vector{Tuple{Int, Int}}=Tuple{Int, Int}[], @@ -1972,8 +2037,9 @@ would enforce every $(M, g)$ in output to satisfy that $g$ has order $p*m$. For every $(M, g)$ in output, one may decide on the minimal polynomial (resp. the characteristic polynomial) of $g$ by setting the keyword argument `min_poly` -(resp. `char_poly`) to the desired value. Moreover, one can also decide on the -rank, positive signature and negative signature of the eigenlattices of $(M, g)$ +(resp. `char_poly`) to the desired value (or `char_polys` resp. `min_poly` +to a list of possibilities). Moreover, one can also decide on the rank, +positive signature and negative signature of the eigenlattices of $(M, g)$ using the keyword arguments `rks`, `pos_sigs` and `neg_sigs` respectively. Each list should consist of tuples $(k, i)$ where $k$ is a divisor of $p*m$ and $i$ is the value to be assigned for the given property (rank, positive/negative @@ -2021,10 +2087,12 @@ function splitting( b::Int = 0; char_poly::Union{ZZPolyRingElem, QQPolyRingElem, Nothing}=nothing, min_poly::Union{ZZPolyRingElem, QQPolyRingElem, Nothing}=nothing, + char_polys::Vector=[nothing], + min_polys::Vector=[nothing], rks::Vector{Tuple{Int, Int}}=Tuple{Int, Int}[], pos_sigs::Vector{Tuple{Int, Int}}=Tuple{Int, Int}[], neg_sigs::Vector{Tuple{Int, Int}}=Tuple{Int, Int}[], - eiglat_cond::Dict{Int64, Vector{Int64}}=Dict{Int64, Vector{Int64}}(), + eiglat_cond::Vector{Dict{Int64, Vector{Int64}}}= Dict{Int64, Vector{Int64}}[], fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, @@ -2050,13 +2118,20 @@ function splitting( min_poly = _radical(char_poly) end end + # If the user does not already input a dictionary of conditions on the # eigenlattices, we create one based on the conditions imposed on the # characteristic/minimal polynomials, on the ranks and on the signatures + if char_poly !== nothing + char_polys = [char_poly] + end + if min_poly !==nothing + min_polys=[min_poly] + end if isempty(eiglat_cond) - eiglat_cond = _conditions_from_input(p*n, char_poly, min_poly, rks, pos_sigs, neg_sigs) + eiglat_cond = [_conditions_from_input(p*n, char_p, min_p, rks, pos_sigs, neg_sigs) for char_p in char_polys for min_p in min_polys] end - + pds = prime_divisors(n) # If the order of the isometry f is a prime power, or a power of p times # another prime power, then we can call the machinery from [BH23]. @@ -2210,10 +2285,12 @@ function enumerate_classes_of_lattices_with_isometry( m::Int; char_poly::Union{ZZPolyRingElem, QQPolyRingElem, Nothing}=nothing, min_poly::Union{ZZPolyRingElem, QQPolyRingElem, Nothing}=nothing, + char_polys::Vector=[nothing], + min_polys::Vector=[nothing], rks::Vector{Tuple{Int, Int}}=Tuple{Int, Int}[], pos_sigs::Vector{Tuple{Int, Int}}=Tuple{Int, Int}[], neg_sigs::Vector{Tuple{Int, Int}}=Tuple{Int, Int}[], - eiglat_cond::Dict{Int64, Vector{Int64}}=Dict{Int64, Vector{Int64}}(), + eiglat_cond::Vector{Dict{Int64, Vector{Int64}}} = Dict{Int64, Vector{Int64}}[], fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, @@ -2228,13 +2305,23 @@ function enumerate_classes_of_lattices_with_isometry( # If the user does not already input a dictionary of conditions on the # eigenlattices, we create one based on the conditions imposed on the # characteristic/minimal polynomials, on the ranks and on the signatures - if isempty(eiglat_cond) - eiglat_cond = _conditions_from_input(m, char_poly, min_poly, rks, pos_sigs, neg_sigs) + if char_poly !== nothing + char_polys = [char_poly] + end + if min_poly !==nothing + min_polys=[min_poly] end + if length(eiglat_cond) == 0 + eiglat_cond = [_conditions_from_input(m, char_p, min_p, rks, pos_sigs, neg_sigs) for char_p in char_polys for min_p in min_polys] + end + allow_info && println("Conditions computed") if m == 1 - reps = representatives_of_hermitian_type(L, 1, fix_root; cond=get(eiglat_cond, 1, Int[-1, -1, -1]), genusDB, root_test, info_depth, discriminant_annihilator, _local) + reps = ZZLatWithIsom[] + for cond in unique!([get(i, 1, Int[-1, -1, -1]) for i in eiglat_cond]) + append!(reps, representatives_of_hermitian_type(L, 1, fix_root; cond, genusDB, root_test, info_depth, discriminant_annihilator, _local)) + end return reps end @@ -2324,7 +2411,7 @@ function splitting_by_prime_power!( Np::Vector{ZZLatWithIsom}, p::Int, v::Int; - eiglat_cond::Dict{Int, Vector{Int}}=Dict{Int, Vector{Int}}(), + eiglat_cond=Dict{Int, Vector{Int}}(), fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, @@ -2514,6 +2601,13 @@ function _conditions_after_power( return V end +function _conditions_after_power( + eiglat_cond::Vector{Dict{Int, Vector{Int}}}, + p::Int, + ) + return unique!([_conditions_after_power(i, p) for i in eiglat_cond]) +end + ############################################################################### # # Enhanced genus enumeration @@ -2922,6 +3016,16 @@ function _annihilator( return ideal(P, [P(d)]) end +raw""" + _annihilator( + f::AutomorphismGroupElem{TorQuadModule}; parent=polynomial_ring(ZZ, [:x]; cached=false)[1]) + +Return some ideal ``I \subseteq \ZZ[x]`` such that +``g(f)=0`` for all ``g \in I``. + +!warning + ``I`` is merely contained in the annihilator but may not be equal to it. +""" function _annihilator( f::AutomorphismGroupElem{TorQuadModule}; parent=polynomial_ring(ZZ, [:x]; cached=false)[1], @@ -2929,13 +3033,12 @@ function _annihilator( D = domain(f) J = _annihilator(D; parent) P = base_ring(J) + c = exponent(D) m = minpoly(Hecke.Globals.Zx, matrix(f)) - m = m(gen(P, 1)) - for d in _divisors(m) - if is_annihilated(f, d) - J = J + ideal(P, [d]) - end - end + x = gen(parent,1) + m = m(x) + J = J + ideal(parent, m) + ideal(parent, x^order(f) - 1) + # a bound for the discriminant annihilator .... but I don't think that it is everything. return J end From 6dc71e4767f248d100505507215fe6b9a386e357 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Wed, 15 Oct 2025 21:34:15 +0200 Subject: [PATCH 02/13] disable expensive check --- src/NumberTheory/QuadFormAndIsom/lattices_with_isometry.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NumberTheory/QuadFormAndIsom/lattices_with_isometry.jl b/src/NumberTheory/QuadFormAndIsom/lattices_with_isometry.jl index 0baf68e5f3c4..10f58c4eaeb3 100644 --- a/src/NumberTheory/QuadFormAndIsom/lattices_with_isometry.jl +++ b/src/NumberTheory/QuadFormAndIsom/lattices_with_isometry.jl @@ -1843,7 +1843,7 @@ function special_subgroup( end mu = matrix_group(QQMatrix[QQ[-1;]]) j = one(mu) - d = hom(G, mu, [Int(det(m))*j for m in gens(G)]) + d = hom(G, mu, [Int(det(m))*j for m in gens(G)]; check=false) return kernel(d) end From 3195269a42804b92299467ac53e2bbba84ecf776 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Wed, 15 Oct 2025 21:45:03 +0200 Subject: [PATCH 03/13] reattach docstring --- .../QuadFormAndIsom/enumeration.jl | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/NumberTheory/QuadFormAndIsom/enumeration.jl b/src/NumberTheory/QuadFormAndIsom/enumeration.jl index 87aac3b8e9ba..2b724f196464 100644 --- a/src/NumberTheory/QuadFormAndIsom/enumeration.jl +++ b/src/NumberTheory/QuadFormAndIsom/enumeration.jl @@ -1418,13 +1418,7 @@ true julia> is_of_same_type(Lf, reps[2]^2) true ``` -""" -splitting_of_hermitian_type( - args...; - eiglat_cond::Dict{Int, Vector{Int}}, - kwargs... - ) = splitting_of_hermitian_type(args...;eiglat_cond=[eiglat_cond], kwargs...) - +""" function splitting_of_hermitian_type( Lf::ZZLatWithIsom, p::IntegerUnion, @@ -1488,7 +1482,13 @@ function splitting_of_hermitian_type( append!(reps, tmp) end return reps -end +end + +splitting_of_hermitian_type( + args...; + eiglat_cond::Dict{Int, Vector{Int}}, + kwargs... + ) = splitting_of_hermitian_type(args...;eiglat_cond=[eiglat_cond], kwargs...) function __splitting_of_hermitian_type( Lf::ZZLatWithIsom, @@ -1788,8 +1788,6 @@ negative signature. generator as input. """ -splitting_of_pure_mixed_prime_power(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_of_pure_mixed_prime_power(args;eiglat_cond=[eiglat_cond], kwargs...) - function splitting_of_pure_mixed_prime_power( Lf::ZZLatWithIsom, p::Int; @@ -1855,6 +1853,9 @@ function splitting_of_pure_mixed_prime_power( end return reps end + +splitting_of_pure_mixed_prime_power(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_of_pure_mixed_prime_power(args;eiglat_cond=[eiglat_cond], kwargs...) + @doc raw""" splitting_of_mixed_prime_power( @@ -1939,8 +1940,6 @@ julia> all(LL -> is_of_same_type(Lf, LL^2), reps) true ``` """ -splitting_of_mixed_prime_power(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_of_mixed_prime_power(args;eiglat_cond=[eiglat_cond], kwargs...) - function splitting_of_mixed_prime_power( Lf::ZZLatWithIsom, p::Int, @@ -2001,6 +2000,9 @@ function splitting_of_mixed_prime_power( return reps end +splitting_of_mixed_prime_power(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_of_mixed_prime_power(args;eiglat_cond=[eiglat_cond], kwargs...) + + ############################################################################### # # Generic functions From 5332aa241c2de33d8d57e8f167335d05e04a747d Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Thu, 16 Oct 2025 11:17:46 +0200 Subject: [PATCH 04/13] Apply suggestion from @StevellM Co-authored-by: Stevell Muller <78619134+StevellM@users.noreply.github.com> --- src/NumberTheory/QuadFormAndIsom/enumeration.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NumberTheory/QuadFormAndIsom/enumeration.jl b/src/NumberTheory/QuadFormAndIsom/enumeration.jl index 2b724f196464..abf055996a9d 100644 --- a/src/NumberTheory/QuadFormAndIsom/enumeration.jl +++ b/src/NumberTheory/QuadFormAndIsom/enumeration.jl @@ -1418,7 +1418,7 @@ true julia> is_of_same_type(Lf, reps[2]^2) true ``` -""" +""" function splitting_of_hermitian_type( Lf::ZZLatWithIsom, p::IntegerUnion, From bd1aad4385a442aea64c095e34368eec9d5e1ad7 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Thu, 16 Oct 2025 11:20:31 +0200 Subject: [PATCH 05/13] Apply suggestion from @StevellM Co-authored-by: Stevell Muller <78619134+StevellM@users.noreply.github.com> --- src/NumberTheory/QuadFormAndIsom/enumeration.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NumberTheory/QuadFormAndIsom/enumeration.jl b/src/NumberTheory/QuadFormAndIsom/enumeration.jl index abf055996a9d..d923d6f16b27 100644 --- a/src/NumberTheory/QuadFormAndIsom/enumeration.jl +++ b/src/NumberTheory/QuadFormAndIsom/enumeration.jl @@ -1475,7 +1475,7 @@ function splitting_of_hermitian_type( for cond in eiglat_cond_trimmed condp = _conditions_after_power(cond, p) - if !all(V[i]==get(condp,i,[-1])[1]||-1==get(condp,i,[-1])[1] for i in keys(V)) + if !all(get(condp, i, [-1])[1] == V[i] || get(condp, i, [-1])[1] == -1 for i in keys(V)) continue end tmp = __splitting_of_hermitian_type(Lf, p, b; eiglat_cond=cond, fix_root, genusDB, root_test, check, info_depth, discriminant_annihilator, _local) From d3b5dcf2fa74874bb96ca6fe90416883417a4326 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Thu, 16 Oct 2025 11:22:01 +0200 Subject: [PATCH 06/13] Apply suggestion from @StevellM Co-authored-by: Stevell Muller <78619134+StevellM@users.noreply.github.com> --- src/NumberTheory/QuadFormAndIsom/enumeration.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NumberTheory/QuadFormAndIsom/enumeration.jl b/src/NumberTheory/QuadFormAndIsom/enumeration.jl index d923d6f16b27..bbc4730dd96f 100644 --- a/src/NumberTheory/QuadFormAndIsom/enumeration.jl +++ b/src/NumberTheory/QuadFormAndIsom/enumeration.jl @@ -1613,7 +1613,7 @@ end Lf::ZZLatWithIsom, p::Int, b::Int = 0; - eiglat_cond=[Dict{Int, Vector{Int}}()], + eiglat_cond::Union{Dict{Int, Vector{Int}}, Vector{Dict{Int,Vector{Int}}}}=[Dict{Int, Vector{Int}}()], fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, From da4c96906b942c8ba9dc011ee17250d28796d235 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Thu, 16 Oct 2025 11:22:14 +0200 Subject: [PATCH 07/13] Apply suggestion from @StevellM Co-authored-by: Stevell Muller <78619134+StevellM@users.noreply.github.com> --- src/NumberTheory/QuadFormAndIsom/enumeration.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NumberTheory/QuadFormAndIsom/enumeration.jl b/src/NumberTheory/QuadFormAndIsom/enumeration.jl index bbc4730dd96f..bdd2a1c74f6c 100644 --- a/src/NumberTheory/QuadFormAndIsom/enumeration.jl +++ b/src/NumberTheory/QuadFormAndIsom/enumeration.jl @@ -1680,7 +1680,7 @@ function splitting_of_prime_power( Lf::ZZLatWithIsom, p::Int, b::Int = 0; - eiglat_cond=[Dict{Int, Vector{Int}}()], + eiglat_cond::Vector{Dict{Int, Vector{Int}}}=[Dict{Int, Vector{Int}}()], fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, From e147c79032210c10559aa84e62c4d8b33ddfa158 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Thu, 16 Oct 2025 11:23:13 +0200 Subject: [PATCH 08/13] Apply suggestion from @StevellM Co-authored-by: Stevell Muller <78619134+StevellM@users.noreply.github.com> --- src/NumberTheory/QuadFormAndIsom/enumeration.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/NumberTheory/QuadFormAndIsom/enumeration.jl b/src/NumberTheory/QuadFormAndIsom/enumeration.jl index bdd2a1c74f6c..ac6ae3281bea 100644 --- a/src/NumberTheory/QuadFormAndIsom/enumeration.jl +++ b/src/NumberTheory/QuadFormAndIsom/enumeration.jl @@ -2002,7 +2002,6 @@ end splitting_of_mixed_prime_power(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_of_mixed_prime_power(args;eiglat_cond=[eiglat_cond], kwargs...) - ############################################################################### # # Generic functions From 18f84a0770339740d8dc315d6580c72fd2489b9c Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Thu, 16 Oct 2025 11:24:06 +0200 Subject: [PATCH 09/13] Apply suggestion from @StevellM Co-authored-by: Stevell Muller <78619134+StevellM@users.noreply.github.com> --- src/NumberTheory/QuadFormAndIsom/enumeration.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NumberTheory/QuadFormAndIsom/enumeration.jl b/src/NumberTheory/QuadFormAndIsom/enumeration.jl index ac6ae3281bea..743dbc03a4c5 100644 --- a/src/NumberTheory/QuadFormAndIsom/enumeration.jl +++ b/src/NumberTheory/QuadFormAndIsom/enumeration.jl @@ -1862,7 +1862,7 @@ splitting_of_pure_mixed_prime_power(args;eiglat_cond::Dict{Int,Vector{Int}}, kwa Lf::ZZLatWithIsom, p::IntegerUnion, b::Int = 1; - eiglat_cond::Vector{Dict{Int, Vector{Int}}}=[Dict{Int, Vector{Int}}()], + eiglat_cond::Union{Dict{Int, Vector{Int}}, Vector{Dict{Int,Vector{Int}}}}=[Dict{Int, Vector{Int}}()], fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, From 6f5307864f5db2b152aaba20841548a84dc91ca6 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Thu, 16 Oct 2025 11:36:26 +0200 Subject: [PATCH 10/13] Apply suggestion from @simonbrandhorst --- src/NumberTheory/QuadFormAndIsom/enumeration.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/NumberTheory/QuadFormAndIsom/enumeration.jl b/src/NumberTheory/QuadFormAndIsom/enumeration.jl index 743dbc03a4c5..dd6eb16f1f54 100644 --- a/src/NumberTheory/QuadFormAndIsom/enumeration.jl +++ b/src/NumberTheory/QuadFormAndIsom/enumeration.jl @@ -3034,7 +3034,6 @@ function _annihilator( D = domain(f) J = _annihilator(D; parent) P = base_ring(J) - c = exponent(D) m = minpoly(Hecke.Globals.Zx, matrix(f)) x = gen(parent,1) m = m(x) From 6c6634a2ee6d1b50e224383956429d9897e5354d Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Sun, 19 Oct 2025 15:47:48 +0200 Subject: [PATCH 11/13] Address Stevell's comments --- .../QuadFormAndIsom/enumeration.jl | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/NumberTheory/QuadFormAndIsom/enumeration.jl b/src/NumberTheory/QuadFormAndIsom/enumeration.jl index dd6eb16f1f54..9e722313bc15 100644 --- a/src/NumberTheory/QuadFormAndIsom/enumeration.jl +++ b/src/NumberTheory/QuadFormAndIsom/enumeration.jl @@ -1447,16 +1447,17 @@ function splitting_of_hermitian_type( @req is_of_hermitian_type(Lf) "Lattice with isometry must be of hermitian type" end + reps = ZZLatWithIsom[] k = p*n # If p divides n, then any output is still of hermitian type since taking pth # power decreases the order of the isometry if iszero(mod(n, p)) - cond = unique!([get(i, k, Int[-1, -1, -1]) for i in eiglat_cond]) - reps = representatives_of_hermitian_type(Lf, p, fix_root; cond, genusDB, root_test, info_depth, discriminant_annihilator) + for cond in unique!([get(i, k, Int[-1, -1, -1]) for i in eiglat_cond]) + append!(reps,representatives_of_hermitian_type(Lf, p, fix_root; cond, genusDB, root_test, info_depth, discriminant_annihilator)) + end return reps end - reps = ZZLatWithIsom[] V = _from_cyclotomic_polynomial_to_dict(characteristic_polynomial(Lf)) for i in keys(V) V[i] = euler_phi(i)*V[i] @@ -1484,12 +1485,7 @@ function splitting_of_hermitian_type( return reps end -splitting_of_hermitian_type( - args...; - eiglat_cond::Dict{Int, Vector{Int}}, - kwargs... - ) = splitting_of_hermitian_type(args...;eiglat_cond=[eiglat_cond], kwargs...) - + function __splitting_of_hermitian_type( Lf::ZZLatWithIsom, p::IntegerUnion, @@ -1854,8 +1850,6 @@ function splitting_of_pure_mixed_prime_power( return reps end -splitting_of_pure_mixed_prime_power(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_of_pure_mixed_prime_power(args;eiglat_cond=[eiglat_cond], kwargs...) - @doc raw""" splitting_of_mixed_prime_power( @@ -2000,8 +1994,6 @@ function splitting_of_mixed_prime_power( return reps end -splitting_of_mixed_prime_power(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_of_mixed_prime_power(args;eiglat_cond=[eiglat_cond], kwargs...) - ############################################################################### # # Generic functions @@ -2412,7 +2404,7 @@ function splitting_by_prime_power!( Np::Vector{ZZLatWithIsom}, p::Int, v::Int; - eiglat_cond=Dict{Int, Vector{Int}}(), + eiglat_cond::Union{Dict{Int,Vector{Int}}, Vector{Dict{Int,Vector{Int}}}}=Dict{Int, Vector{Int}}(), fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, @@ -3059,3 +3051,16 @@ function *(x::Hecke.IntegerUnion, I::MPolyIdeal{ZZMPolyRingElem}) return ideal(base_ring(I), [x*i for i in gens(I)]) end +###################################################################################### +# +# Legacy interface ... to be deprecated at some point +# +###################################################################################### + +splitting_of_hermitian_type(args...; eiglat_cond::Dict{Int, Vector{Int}}, kwargs...) = splitting_of_hermitian_type(args...;eiglat_cond=[eiglat_cond], kwargs...) + +splitting_of_prime_power(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_of_prime_power(args;eiglat_cond=[eiglat_cond], kwargs...) + +splitting_of_pure_mixed_prime_power(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_of_pure_mixed_prime_power(args;eiglat_cond=[eiglat_cond], kwargs...) + +splitting_of_mixed_prime_power(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_of_mixed_prime_power(args;eiglat_cond=[eiglat_cond], kwargs...) From 363bc2cd381013eacf5b2b71d9d085c6b34811db Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Sun, 19 Oct 2025 16:33:20 +0200 Subject: [PATCH 12/13] remove the old interface from documentation --- .../QuadFormAndIsom/enumeration.jl | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/NumberTheory/QuadFormAndIsom/enumeration.jl b/src/NumberTheory/QuadFormAndIsom/enumeration.jl index 9e722313bc15..3f618fae4e89 100644 --- a/src/NumberTheory/QuadFormAndIsom/enumeration.jl +++ b/src/NumberTheory/QuadFormAndIsom/enumeration.jl @@ -1345,7 +1345,7 @@ end Lf::ZZLatWithIsom, p::IntegerUnion, b::Int = 0; - eiglat_cond::Union{Dict{Int, Vector{Int}}, Vector{Dict{Int,Vector{Int}}}}=[Dict{Int, Vector{Int}}()], + eiglat_cond::Vector{Dict{Int,Vector{Int}}}=[Dict{Int, Vector{Int}}()], fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, @@ -1609,7 +1609,7 @@ end Lf::ZZLatWithIsom, p::Int, b::Int = 0; - eiglat_cond::Union{Dict{Int, Vector{Int}}, Vector{Dict{Int,Vector{Int}}}}=[Dict{Int, Vector{Int}}()], + eiglat_cond::Vector{Dict{Int,Vector{Int}}}=[Dict{Int, Vector{Int}}()], fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, @@ -1740,7 +1740,7 @@ end splitting_of_pure_mixed_prime_power( Lf::ZZLatWithIsom, p::Int; - eiglat_cond::Dict{Int, Vector{Int}}=Dict{Int, Vector{Int}}(), + eiglat_cond::Vector{Dict{Int, Vector{Int}}}=[Dict{Int, Vector{Int}}()], fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, @@ -1856,7 +1856,7 @@ end Lf::ZZLatWithIsom, p::IntegerUnion, b::Int = 1; - eiglat_cond::Union{Dict{Int, Vector{Int}}, Vector{Dict{Int,Vector{Int}}}}=[Dict{Int, Vector{Int}}()], + eiglat_cond::Vector{Dict{Int,Vector{Int}}}=[Dict{Int, Vector{Int}}()], fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, @@ -1938,7 +1938,7 @@ function splitting_of_mixed_prime_power( Lf::ZZLatWithIsom, p::Int, b::Int = 1; - eiglat_cond::Vector{Dict{Int, Vector{Int}}} = [Dict{Int, Vector{Int}}()], + eiglat_cond::Vector{Dict{Int, Vector{Int}}} = [Dict{Int, Vector{Int}}[]], fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, @@ -2012,7 +2012,7 @@ end rks::Vector{Tuple{Int, Int}}=Tuple{Int, Int}[], pos_sigs::Vector{Tuple{Int, Int}}=Tuple{Int, Int}[], neg_sigs::Vector{Tuple{Int, Int}}=Tuple{Int, Int}[], - eiglat_cond::Dict{Int64, Vector{Int64}}=Dict{Int64, Vector{Int64}}(), + eiglat_cond::Vector{Dict{Int64, Vector{Int64}}}=Dict{Int64, Vector{Int64}}[], fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, @@ -2204,7 +2204,7 @@ end rks::Vector{Tuple{Int, Int}}=Tuple{Int, Int}[], pos_sigs::Vector{Tuple{Int, Int}}=Tuple{Int, Int}[], neg_sigs::Vector{Tuple{Int, Int}}=Tuple{Int, Int}[], - eiglat_cond::Dict{Int64, Vector{Int64}}=Dict{Int64, Vector{Int64}}(), + eiglat_cond::Vector{Dict{Int64, Vector{Int64}}}=Dict{Int64, Vector{Int64}}[], fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, @@ -2355,7 +2355,7 @@ end Np::Vector{ZZLatWithIsom}, p::Int, v::Int; - eiglat_cond::Dict{Int, Vector{Int}}=Dict{Int, Vector{Int}}(), + eiglat_cond::Vector{Dict{Int, Vector{Int}}}=Dict{Int, Vector{Int}}(), fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, @@ -2404,7 +2404,7 @@ function splitting_by_prime_power!( Np::Vector{ZZLatWithIsom}, p::Int, v::Int; - eiglat_cond::Union{Dict{Int,Vector{Int}}, Vector{Dict{Int,Vector{Int}}}}=Dict{Int, Vector{Int}}(), + eiglat_cond::Vector{Dict{Int,Vector{Int}}}=Dict{Int, Vector{Int}}[], fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, @@ -3056,7 +3056,8 @@ end # Legacy interface ... to be deprecated at some point # ###################################################################################### - +splitting_by_prime_power!(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_by_prime_power!(args;eiglat_cond=[eiglat_cond], kwargs...) + splitting_of_hermitian_type(args...; eiglat_cond::Dict{Int, Vector{Int}}, kwargs...) = splitting_of_hermitian_type(args...;eiglat_cond=[eiglat_cond], kwargs...) splitting_of_prime_power(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_of_prime_power(args;eiglat_cond=[eiglat_cond], kwargs...) @@ -3064,3 +3065,7 @@ splitting_of_prime_power(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = s splitting_of_pure_mixed_prime_power(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_of_pure_mixed_prime_power(args;eiglat_cond=[eiglat_cond], kwargs...) splitting_of_mixed_prime_power(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_of_mixed_prime_power(args;eiglat_cond=[eiglat_cond], kwargs...) + +splitting(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting(args;eiglat_cond=[eiglat_cond], kwargs...) + +enumerate_classes_of_lattices_with_isometry(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = enumerate_classes_of_lattices_with_isometry(args;eiglat_cond=[eiglat_cond], kwargs...) From 3ebb301f709c03e8bacfc60d6ec2afc70207b148 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Mon, 20 Oct 2025 11:20:42 +0200 Subject: [PATCH 13/13] constructors --- src/NumberTheory/QuadFormAndIsom/enumeration.jl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/NumberTheory/QuadFormAndIsom/enumeration.jl b/src/NumberTheory/QuadFormAndIsom/enumeration.jl index 3f618fae4e89..9bc2e1e9600f 100644 --- a/src/NumberTheory/QuadFormAndIsom/enumeration.jl +++ b/src/NumberTheory/QuadFormAndIsom/enumeration.jl @@ -1938,7 +1938,7 @@ function splitting_of_mixed_prime_power( Lf::ZZLatWithIsom, p::Int, b::Int = 1; - eiglat_cond::Vector{Dict{Int, Vector{Int}}} = [Dict{Int, Vector{Int}}[]], + eiglat_cond::Vector{Dict{Int, Vector{Int}}} = [Dict{Int, Vector{Int}}()], fix_root::Int=-1, genusDB::Union{Nothing, Dict{ZZGenus, Vector{ZZLat}}}=nothing, root_test::Bool=false, @@ -3056,16 +3056,16 @@ end # Legacy interface ... to be deprecated at some point # ###################################################################################### -splitting_by_prime_power!(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_by_prime_power!(args;eiglat_cond=[eiglat_cond], kwargs...) +splitting_by_prime_power!(args...;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_by_prime_power!(args...;eiglat_cond=[eiglat_cond], kwargs...) splitting_of_hermitian_type(args...; eiglat_cond::Dict{Int, Vector{Int}}, kwargs...) = splitting_of_hermitian_type(args...;eiglat_cond=[eiglat_cond], kwargs...) -splitting_of_prime_power(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_of_prime_power(args;eiglat_cond=[eiglat_cond], kwargs...) +splitting_of_prime_power(args...;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_of_prime_power(args...;eiglat_cond=[eiglat_cond], kwargs...) -splitting_of_pure_mixed_prime_power(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_of_pure_mixed_prime_power(args;eiglat_cond=[eiglat_cond], kwargs...) +splitting_of_pure_mixed_prime_power(args...;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_of_pure_mixed_prime_power(args...;eiglat_cond=[eiglat_cond], kwargs...) -splitting_of_mixed_prime_power(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_of_mixed_prime_power(args;eiglat_cond=[eiglat_cond], kwargs...) +splitting_of_mixed_prime_power(args...;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting_of_mixed_prime_power(args...;eiglat_cond=[eiglat_cond], kwargs...) -splitting(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting(args;eiglat_cond=[eiglat_cond], kwargs...) +splitting(args...;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = splitting(args...;eiglat_cond=[eiglat_cond], kwargs...) -enumerate_classes_of_lattices_with_isometry(args;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = enumerate_classes_of_lattices_with_isometry(args;eiglat_cond=[eiglat_cond], kwargs...) +enumerate_classes_of_lattices_with_isometry(args...;eiglat_cond::Dict{Int,Vector{Int}}, kwargs...) = enumerate_classes_of_lattices_with_isometry(args...;eiglat_cond=[eiglat_cond], kwargs...)