From 46f309032b476581ec57c584d5ef9f0c384ad46d Mon Sep 17 00:00:00 2001 From: Johannes Schmitt Date: Tue, 16 Apr 2024 14:25:46 +0200 Subject: [PATCH 1/3] Run formatter on `InvariantTheory` and `experimental/LinearQuotients` --- experimental/LinearQuotients/src/cox_rings.jl | 190 +++++++++++------- .../LinearQuotients/src/linear_quotients.jl | 26 ++- experimental/LinearQuotients/src/misc.jl | 28 +-- experimental/LinearQuotients/src/types.jl | 31 +-- .../LinearQuotients/test/cox_rings-test.jl | 74 ++++--- .../test/linear_quotients-test.jl | 28 +-- src/InvariantTheory/InvariantTheory.jl | 2 +- src/InvariantTheory/affine_algebra.jl | 78 ++++--- src/InvariantTheory/fundamental_invariants.jl | 82 +++++--- src/InvariantTheory/helpers.jl | 50 +++-- src/InvariantTheory/invariant_rings.jl | 134 +++++++----- src/InvariantTheory/iterators.jl | 134 +++++++----- src/InvariantTheory/primary_invariants.jl | 93 ++++++--- src/InvariantTheory/secondary_invariants.jl | 81 +++++--- src/InvariantTheory/types.jl | 144 +++++++------ test/InvariantTheory/affine_algebra.jl | 69 ++++--- .../InvariantTheory/fundamental_invariants.jl | 84 ++++---- test/InvariantTheory/invariant_rings.jl | 80 +++++--- test/InvariantTheory/iterators.jl | 12 +- test/InvariantTheory/primary_invariants.jl | 28 +-- test/InvariantTheory/secondary_invariants.jl | 111 +++++----- 21 files changed, 947 insertions(+), 612 deletions(-) diff --git a/experimental/LinearQuotients/src/cox_rings.jl b/experimental/LinearQuotients/src/cox_rings.jl index e92e09690d7f..6f504edaf187 100644 --- a/experimental/LinearQuotients/src/cox_rings.jl +++ b/experimental/LinearQuotients/src/cox_rings.jl @@ -26,7 +26,9 @@ power_base_to_hom_gens(HBB::HomBasisBuilder) = HBB.power_base_to_hom_gens # Computes for any element g in gens(G) a matrix N such that # (e_i*N)*polys == G_action(polys[i], g) -function action_on_basis(G::FinGenAbGroup, G_action::Function, polys::Vector{<: MPolyRingElem{T}}) where {T <: FieldElem} +function action_on_basis( + G::FinGenAbGroup, G_action::Function, polys::Vector{<:MPolyRingElem{T}} +) where {T<:FieldElem} @req !isempty(polys) "Input must not be empty" R = parent(polys[1]) @@ -37,21 +39,22 @@ function action_on_basis(G::FinGenAbGroup, G_action::Function, polys::Vector{<: res = SMat{elem_type(K)}[] for g in gens(G) - polys_g = [ G_action(f, g) for f in polys ] + polys_g = [G_action(f, g) for f in polys] N = polys_to_smat(polys_g, monomial_to_column) # Little bit of a waste to recompute the rref of M all the time. # But I don't see how to do it better and mats should not contain many # elements anyways. - sol = solve(M, N, side = :left) + sol = solve(M, N; side=:left) push!(res, sol) end return res end -function process_eigenvector!(HBB::HomBasisBuilder, d::Int, e::Vector{<:FieldElem}, v::MatElem, is_gen::BitVector) - +function process_eigenvector!( + HBB::HomBasisBuilder, d::Int, e::Vector{<:FieldElem}, v::MatElem, is_gen::BitVector +) C = power_product_cache(HBB) T = preimage_ring(HBB) basisd = all_power_products_of_degree!(C, d, true) @@ -104,11 +107,11 @@ function fill_degree!(HBB::HomBasisBuilder, d::Int) basisd = all_power_products_of_degree!(C, d, true) # Whether basisd[i] is an element of inhom_gens(HBB) or not - is_gen = BitVector( is_one(sum(get_exponent_vector(C, f))) for f in basisd ) + is_gen = BitVector(is_one(sum(get_exponent_vector(C, f))) for f in basisd) - gensGd = [ matrix(M) for M in action_on_basis(group(HBB), group_action(HBB), basisd) ] + gensGd = [matrix(M) for M in action_on_basis(group(HBB), group_action(HBB), basisd)] - ceig = common_eigenspaces(gensGd, side = :left) + ceig = common_eigenspaces(gensGd; side=:left) # Now translate every eigenvector into a polynomial in base_ring(HBB) and build # a basis of the degree d component by homogeneous polynomials (via their @@ -139,7 +142,7 @@ function fill_degree!(HBB::HomBasisBuilder, d::Int) M = vcat(M, N) end - sol = solve(V, M, side = :left) + sol = solve(V, M; side=:left) # The i-th row of sol gives the coefficient of inhom_gens[row_to_gen[i]] in # the basis hom_basisd. @@ -183,7 +186,7 @@ function homogeneous_generators(HBB::HomBasisBuilder) fill_degree!(HBB, d) end - phi = hom(T, T, [ power_base_to_hom_gens(HBB)[f] for f in inhom_gens(HBB) ]) + phi = hom(T, T, [power_base_to_hom_gens(HBB)[f] for f in inhom_gens(HBB)]) return hom_gens(HBB), degrees_of_hom_gens(HBB), phi end @@ -206,7 +209,7 @@ end # of V/G. # Return the degree of the polynomial f as an element of codomain(GtoA), # assuming that f is homogeneous. -function ab_g_degree(GtoA::Map, f::MPolyRingElem, zeta::Tuple{<:FieldElem, Int}) +function ab_g_degree(GtoA::Map, f::MPolyRingElem, zeta::Tuple{<:FieldElem,Int}) A = codomain(GtoA) K = coefficient_ring(parent(f)) @assert K === parent(zeta[1]) @@ -217,12 +220,12 @@ function ab_g_degree(GtoA::Map, f::MPolyRingElem, zeta::Tuple{<:FieldElem, Int}) c = zeros(ZZRingElem, ngens(A)) eldivs = elementary_divisors(A) for i in 1:ngens(A) - fi = right_action(f, GtoA\A[i]) + fi = right_action(f, GtoA \ A[i]) q, r = divrem(fi, f) @assert is_zero(r) "Polynomial is not homogeneous" z = first(AbstractAlgebra.coefficients(q)) @assert parent(q)(z) == q "Polynomial is not homogeneous" - k = (powers_of_zeta[z]*eldivs[i])//l + k = (powers_of_zeta[z] * eldivs[i])//l @assert is_integral(k) c[i] = numerator(k) end @@ -243,32 +246,35 @@ We use ideas from [DK17](@cite) to find homogeneous generators of the invariant To get a map from `group(G)` to the grading group of the returned ring, use [`class_group`](@ref). """ -function cox_ring(L::LinearQuotient; algo_gens::Symbol = :default, algo_rels::Symbol = :groebner_basis) +function cox_ring( + L::LinearQuotient; algo_gens::Symbol=:default, algo_rels::Symbol=:groebner_basis +) G = group(L) Grefl, GrefltoG = subgroup_of_pseudo_reflections(G) H, HtoG = derived_subgroup(G) # Compute H*Grefl - H = matrix_group(base_ring(G), degree(G), - vcat(map(HtoG, gens(H)), map(GrefltoG, gens(Grefl)))) + H = matrix_group( + base_ring(G), degree(G), vcat(map(HtoG, gens(H)), map(GrefltoG, gens(Grefl))) + ) A, GtoA = class_group(L) RH = invariant_ring(H) - Q, QtoR = affine_algebra(RH, algo_gens = algo_gens, algo_rels = algo_rels) + Q, QtoR = affine_algebra(RH; algo_gens=algo_gens, algo_rels=algo_rels) S = base_ring(Q) - StoR = hom(S, codomain(QtoR), [ QtoR(f) for f in gens(Q) ]) + StoR = hom(S, codomain(QtoR), [QtoR(f) for f in gens(Q)]) Rgraded = codomain(StoR) R = forget_grading(Rgraded) - invars = elem_type(R)[ forget_grading(StoR(x)) for x in gens(S) ] + invars = elem_type(R)[forget_grading(StoR(x)) for x in gens(S)] if is_trivial(A) - T = grade(forget_grading(S), [ zero(A) for i in 1:ngens(S) ])[1] + T = grade(forget_grading(S), [zero(A) for i in 1:ngens(S)])[1] - relsT = elem_type(T)[ T(forget_grading(r)) for r in gens(modulus(Q)) ] + relsT = elem_type(T)[T(forget_grading(r)) for r in gens(modulus(Q))] Q, TtoQ = quo(T, ideal(T, relsT)) - QtoR = hom(Q, Rgraded, [ Rgraded(f) for f in invars ]) + QtoR = hom(Q, Rgraded, [Rgraded(f) for f in invars]) return Q, QtoR end @@ -289,10 +295,10 @@ function cox_ring(L::LinearQuotient; algo_gens::Symbol = :default, algo_rels::Sy powers_of_zeta = _powers_of_root_of_unity(zeta...) l = zeta[2] eldiv = elementary_divisors(A) - @assert all(is_zero, [ mod(l, e) for e in eldiv ]) - l_div_eldiv = ZZRingElem[ div(l, e) for e in eldiv ] + @assert all(is_zero, [mod(l, e) for e in eldiv]) + l_div_eldiv = ZZRingElem[div(l, e) for e in eldiv] function eig_to_group(e::Vector{<:FieldElem}) - return A(ZZRingElem[ div(powers_of_zeta[e[k]], l_div_eldiv[k]) for k in 1:length(e) ]) + return A(ZZRingElem[div(powers_of_zeta[e[k]], l_div_eldiv[k]) for k in 1:length(e)]) end HBB = HomBasisBuilder(PowerProductCache(R, invars), A, A_action, eig_to_group) @@ -301,14 +307,18 @@ function cox_ring(L::LinearQuotient; algo_gens::Symbol = :default, algo_rels::Sy T = domain(phi) # Move the relations from S to T - StoT = hom(S, T, [ phi(gen(T, i)) for i in 1:ngens(T) ]) - relsT = elem_type(T)[ StoT(r) for r in gens(modulus(Q)) ] + StoT = hom(S, T, [phi(gen(T, i)) for i in 1:ngens(T)]) + relsT = elem_type(T)[StoT(r) for r in gens(modulus(Q))] T = grade(T, degrees)[1] # The relations are in general not homogeneous - relsT = reduce(vcat, [ collect(values(homogeneous_components(T(f)))) for f in relsT ], init = elem_type(T)[]) + relsT = reduce( + vcat, + [collect(values(homogeneous_components(T(f)))) for f in relsT]; + init=elem_type(T)[], + ) Q, TtoQ = quo(T, ideal(T, relsT)) - QtoR = hom(Q, Rgraded, [ Rgraded(f) for f in hom_invars ]) + QtoR = hom(Q, Rgraded, [Rgraded(f) for f in hom_invars]) return Q, QtoR end @@ -343,18 +353,21 @@ function cox_ring_of_qq_factorial_terminalization(L::LinearQuotient) R = codomain(RVGtoR) SAbG = base_ring(RVG) # RVG is a quotient ring graded by Ab(G) S = forget_grading(SAbG) - StoR = hom(S, R, [ RVGtoR(x) for x in gens(RVG) ]) + StoR = hom(S, R, [RVGtoR(x) for x in gens(RVG)]) I = forget_grading(modulus(RVG)) - Sdeg, _ = grade(S, [ degree(StoR(x)) for x in gens(S) ]) + Sdeg, _ = grade(S, [degree(StoR(x)) for x in gens(S)]) juniors = representatives_of_junior_elements(G, fixed_root_of_unity(L)) # TODO: make sure the case where G is not generated by junior elements # is handled correctly in what follows - vals = Dict{elem_type(G), Tuple}() + vals = Dict{elem_type(G),Tuple}() for g in juniors - vals[g] = (weights_of_action(R, g, fixed_root_of_unity(L)), monomial_valuation(R, g, fixed_root_of_unity(L))) + vals[g] = ( + weights_of_action(R, g, fixed_root_of_unity(L)), + monomial_valuation(R, g, fixed_root_of_unity(L)), + ) end # Phase 1: Assure (*{i}) for all i (see [Yam18], [Sch23]) @@ -372,7 +385,7 @@ function cox_ring_of_qq_factorial_terminalization(L::LinearQuotient) # Phase 2: Assure (*{1, 2}), (*{1, 3}), ..., (*{1, ..., length(juniors)}) for i in 2:length(juniors) - for j in 1:i - 1 + for j in 1:(i - 1) @vprint :LinearQuotients "Running phase 2 for i = $i and i' = $j\n" @vprint :LinearQuotients "Number of variables: $(ngens(S))\n" new_gens = new_generators_phase_2(StoR, I, Sdeg, SAbG, juniors, vals, i, j) @@ -389,7 +402,9 @@ function cox_ring_of_qq_factorial_terminalization(L::LinearQuotient) # subring of a Laurent polynomial ring over R, see [Sch23, Section 6.1]. # Transform the collected generators into Laurent polynomials - Rt, t = laurent_polynomial_ring(forget_grading(codomain(StoR)), [ "t$i" for i in 1:length(juniors) ]) + Rt, t = laurent_polynomial_ring( + forget_grading(codomain(StoR)), ["t$i" for i in 1:length(juniors)] + ) gensRt = Vector{elem_type(Rt)}() degsRt = Vector{Vector{ZZRingElem}}() for x in gens(S) @@ -407,7 +422,7 @@ function cox_ring_of_qq_factorial_terminalization(L::LinearQuotient) # Add the additional generators t_i^{-r_i} corresponding to the exceptional # divisors - r = [ order(s) for s in juniors ] + r = [order(s) for s in juniors] for i in 1:length(juniors) push!(gensRt, t[i]^-r[i]) d = zeros(ZZRingElem, length(juniors)) @@ -438,7 +453,7 @@ function minimal_parts(I::MPolyIdeal, w::Vector{ZZRingElem}) @assert nvars(R) == length(w) w1 = push!(copy(w), ZZRingElem(-1)) - S, t = graded_polynomial_ring(K, [ "t$i" for i in 1:nvars(R) + 1 ], w1) + S, t = graded_polynomial_ring(K, ["t$i" for i in 1:(nvars(R) + 1)], w1) Ihom = homogenize_at_last_variable(I, S) @@ -455,7 +470,7 @@ function group_homogeneous_ideal(I::MPolyIdeal, SAbG::MPolyDecRing) eldivs = elementary_divisors(A) for i in 1:ngens(A) - I = g_homogeneous_ideal(I, ZZRingElem[ degree(x)[i] for x in gens(SAbG) ], eldivs[i]) + I = g_homogeneous_ideal(I, ZZRingElem[degree(x)[i] for x in gens(SAbG)], eldivs[i]) if is_zero(I) break end @@ -468,14 +483,15 @@ function g_homogeneous_ideal(I::MPolyIdeal, weights::Vector{ZZRingElem}, order:: R = base_ring(I) w = push!(copy(weights), ZZRingElem(1)) - S, t = graded_polynomial_ring(coefficient_ring(R), [ "t$i" for i in 1:nvars(R) + 1 ], w) + S, t = graded_polynomial_ring(coefficient_ring(R), ["t$i" for i in 1:(nvars(R) + 1)], w) Ihom = homogenize_at_last_variable(I, S) # Have to dance around the fact that one cannot build an inhomogeneous ideal # in a graded ring... T = forget_grading(S) - J = ideal(T, [ forget_grading(x) for x in gens(Ihom) ]) + ideal(T, gen(T, nvars(T))^order - 1) + J = + ideal(T, [forget_grading(x) for x in gens(Ihom)]) + ideal(T, gen(T, nvars(T))^order - 1) phi = hom(R, T, gens(T)[1:nvars(R)]) return preimage(phi, J) end @@ -484,18 +500,24 @@ end # J = I + (h_1,\dots, h_l). # If both ideals are homogeneous (with respect to any weights), then the h_i # are homogeneous too. -function as_subideal(I::MPolyIdeal{T}, J::MPolyIdeal{T}) where {T <: MPolyDecRingElem} +function as_subideal(I::MPolyIdeal{T}, J::MPolyIdeal{T}) where {T<:MPolyDecRingElem} R = base_ring(I) Q, RtoQ = quo(R, I) - gensJQ = minimal_generating_set(ideal(Q, [ RtoQ(f) for f in gens(J) ])) - return elem_type(R)[ RtoQ\f for f in gensJQ ] + gensJQ = minimal_generating_set(ideal(Q, [RtoQ(f) for f in gens(J)])) + return elem_type(R)[RtoQ \ f for f in gensJQ] end # Ensures (after iterative calls) (*{k}) where k is the index of the element # junior in the array juniors # See [Sch23, Algorithm 6.2.2] -function new_generators_phase_1(StoR::MPolyAnyMap, I::MPolyIdeal, Sdeg::MPolyDecRing, SAbG::MPolyDecRing, junior::MatrixGroupElem, vals::Dict{<:MatrixGroupElem, <:Tuple}) - +function new_generators_phase_1( + StoR::MPolyAnyMap, + I::MPolyIdeal, + Sdeg::MPolyDecRing, + SAbG::MPolyDecRing, + junior::MatrixGroupElem, + vals::Dict{<:MatrixGroupElem,<:Tuple}, +) S = domain(StoR) R = codomain(StoR) @@ -520,12 +542,21 @@ function new_generators_phase_1(StoR::MPolyAnyMap, I::MPolyIdeal, Sdeg::MPolyDec minJ = ideal(Sdeg, group_homogeneous_ideal(J, SAbG)) @vprint :LinearQuotients "Phase 1: Representing as subideal\n" - return [ forget_grading(f) for f in as_subideal(minI, minJ) ] + return [forget_grading(f) for f in as_subideal(minI, minJ)] end # Ensures (after iterative calls) (*A\cup {l,k}) assuming (*A\cup {l}) and (*A\cup {k}), where A is any set of indices # See [Sch23, Algorithm 6.2.3] -function new_generators_phase_2(StoR::MPolyAnyMap, I::MPolyIdeal, Sdeg::MPolyDecRing, SAbG::MPolyDecRing, juniors::Vector{<:MatrixGroupElem}, vals::Dict{<:MatrixGroupElem, <:Tuple}, k::Int, l::Int) +function new_generators_phase_2( + StoR::MPolyAnyMap, + I::MPolyIdeal, + Sdeg::MPolyDecRing, + SAbG::MPolyDecRing, + juniors::Vector{<:MatrixGroupElem}, + vals::Dict{<:MatrixGroupElem,<:Tuple}, + k::Int, + l::Int, +) @req k > l "first index $k is not larger than the second index $l" S = domain(StoR) @@ -533,36 +564,38 @@ function new_generators_phase_2(StoR::MPolyAnyMap, I::MPolyIdeal, Sdeg::MPolyDec T = S Ihom = I - inds = [ l, k ] + inds = [l, k] for i in 1:2 @vprint :LinearQuotients "Phase 2: Homogenizing at $(inds[i])\n" - weights = ZZRingElem[ vals[juniors[inds[i]]][2](StoR(x)) for x in gens(S) ] + weights = ZZRingElem[vals[juniors[inds[i]]][2](StoR(x)) for x in gens(S)] append!(weights, zeros(ZZRingElem, i)) weights[end] = -1 - T, _ = graded_polynomial_ring(coefficient_ring(S), [ "t$j" for j in 1:nvars(S) + i ], weights) + T, _ = graded_polynomial_ring( + coefficient_ring(S), ["t$j" for j in 1:(nvars(S) + i)], weights + ) Ihom = homogenize_at_last_variable(Ihom, T) end @vprint :LinearQuotients "Phase 2: Setting up quotient ring\n" - Ilk = Ihom*ideal(T, gen(T, ngens(S) + 1)) + Ihom*ideal(T, gen(T, ngens(S) + 2)) + Ilk = Ihom * ideal(T, gen(T, ngens(S) + 1)) + Ihom * ideal(T, gen(T, ngens(S) + 2)) Q, TtoQ = quo(T, Ilk) - IhomQ = ideal(Q, [ TtoQ(x) for x in gens(Ihom) ]) - tlkQ = ideal(Q, [ TtoQ(gen(T, ngens(S) + 1)), TtoQ(gen(T, ngens(S) + 2)) ]) + IhomQ = ideal(Q, [TtoQ(x) for x in gens(Ihom)]) + tlkQ = ideal(Q, [TtoQ(gen(T, ngens(S) + 1)), TtoQ(gen(T, ngens(S) + 2))]) @vprint :LinearQuotients "Phase 2: Computing intersection\n" J = intersect(IhomQ, tlkQ) @vprint :LinearQuotients "Phase 2: Simplifying\n" J = simplify(J) @vprint :LinearQuotients "Phase 2: Moving generators around\n" - TtoS = hom(T, S, append!([ x for x in gens(S) ], [ one(S) for i in 1:2 ])) + TtoS = hom(T, S, append!([x for x in gens(S)], [one(S) for i in 1:2])) gensJ = elem_type(Q)[] for f in gens(J) if !iszero(f) push!(gensJ, f) end end - new_gens = elem_type(S)[ TtoS(TtoQ\x) for x in gensJ ] - Sk, _ = grade(S, ZZRingElem[ vals[juniors[k]][2](StoR(x)) for x in gens(S) ]) + new_gens = elem_type(S)[TtoS(TtoQ \ x) for x in gensJ] + Sk, _ = grade(S, ZZRingElem[vals[juniors[k]][2](StoR(x)) for x in gens(S)]) for i in 1:length(new_gens) f = new_gens[i] hc = homogeneous_components(Sk(f)) @@ -574,7 +607,13 @@ end # Update the data structures. # TODO: Should there be a struct for all this stuff one moves around? -function add_generators(StoRold::MPolyAnyMap, Iold::MPolyIdeal, new_gens::Vector{<:MPolyRingElem}, SAbGold::MPolyDecRing, L::LinearQuotient) +function add_generators( + StoRold::MPolyAnyMap, + Iold::MPolyIdeal, + new_gens::Vector{<:MPolyRingElem}, + SAbGold::MPolyDecRing, + L::LinearQuotient, +) R = codomain(StoRold) K = coefficient_ring(R) Sold = domain(StoRold) @@ -582,12 +621,15 @@ function add_generators(StoRold::MPolyAnyMap, Iold::MPolyIdeal, new_gens::Vector _, GtoAbG = class_group(L) zeta = fixed_root_of_unity(L) - new_gens_imgs = elem_type(R)[ StoRold(x) for x in new_gens] - imgs = append!(elem_type(R)[ StoRold(x) for x in gens(Sold) ], new_gens_imgs) + new_gens_imgs = elem_type(R)[StoRold(x) for x in new_gens] + imgs = append!(elem_type(R)[StoRold(x) for x in gens(Sold)], new_gens_imgs) S, _ = polynomial_ring(K, "t" => 1:(ngens(Sold) + length(new_gens))) - Sdeg, _ = grade(S, [ degree(f) for f in imgs ]) + Sdeg, _ = grade(S, [degree(f) for f in imgs]) - AbG_degrees = append!([ degree(x) for x in gens(SAbGold) ], [ ab_g_degree(GtoAbG, f, zeta) for f in new_gens_imgs ]) + AbG_degrees = append!( + [degree(x) for x in gens(SAbGold)], + [ab_g_degree(GtoAbG, f, zeta) for f in new_gens_imgs], + ) SAbG, _ = grade(S, AbG_degrees) StoR = hom(S, R, imgs) @@ -604,7 +646,13 @@ function add_generators(StoRold::MPolyAnyMap, Iold::MPolyIdeal, new_gens::Vector end # Relations of the Cox ring, see [Sch23, Algorithm 6.3.3]. -function relations(StoR::MPolyAnyMap, I::MPolyIdeal, juniors::Vector{<:MatrixGroupElem}, vals::Dict{<:MatrixGroupElem, <:Tuple}, degsRt::Vector{Vector{ZZRingElem}}) +function relations( + StoR::MPolyAnyMap, + I::MPolyIdeal, + juniors::Vector{<:MatrixGroupElem}, + vals::Dict{<:MatrixGroupElem,<:Tuple}, + degsRt::Vector{Vector{ZZRingElem}}, +) R = codomain(StoR) S = domain(StoR) @@ -612,27 +660,33 @@ function relations(StoR::MPolyAnyMap, I::MPolyIdeal, juniors::Vector{<:MatrixGro Ihom = I for i in 1:length(juniors) @vprint :LinearQuotients "Relations: Homogenizing at $i\n" - weights = ZZRingElem[ vals[juniors[i]][2](StoR(x)) for x in gens(S) ] + weights = ZZRingElem[vals[juniors[i]][2](StoR(x)) for x in gens(S)] append!(weights, zeros(ZZRingElem, i)) weights[end] = -1 - T, _ = graded_polynomial_ring(coefficient_ring(S), [ "t$j" for j in 1:nvars(S) + i ], weights) + T, _ = graded_polynomial_ring( + coefficient_ring(S), ["t$j" for j in 1:(nvars(S) + i)], weights + ) Ihom = homogenize_at_last_variable(Ihom, T) end @vprint :LinearQuotients "Relations: Computing Gröbner basis\n" # We need homogeneous generators (with respect to all gradings) of Ihom - gb = groebner_basis(Ihom, complete_reduction = true) - T, _ = graded_polynomial_ring(coefficient_ring(S), append!([ "X$i" for i in 1:ngens(S) ], [ "Y$i" for i in 1:length(juniors) ]), degsRt) + gb = groebner_basis(Ihom; complete_reduction=true) + T, _ = graded_polynomial_ring( + coefficient_ring(S), + append!(["X$i" for i in 1:ngens(S)], ["Y$i" for i in 1:length(juniors)]), + degsRt, + ) @assert ngens(T) == ngens(base_ring(Ihom)) @vprint :LinearQuotients "Relations: Finishing up\n" - r = [ order(s) for s in juniors ] + r = [order(s) for s in juniors] rels = Vector{elem_type(T)}() for f in gb F = MPolyBuildCtx(T) for (c, e) in zip(AbstractAlgebra.coefficients(f), AbstractAlgebra.exponent_vectors(f)) ee = deepcopy(e) - for i in ngens(S) + 1:ngens(T) + for i in (ngens(S) + 1):ngens(T) @assert is_zero(mod(ee[i], r[i - ngens(S)])) ee[i] = div(ee[i], r[i - ngens(S)]) end diff --git a/experimental/LinearQuotients/src/linear_quotients.jl b/experimental/LinearQuotients/src/linear_quotients.jl index a73980795ca1..b38a2262a558 100644 --- a/experimental/LinearQuotients/src/linear_quotients.jl +++ b/experimental/LinearQuotients/src/linear_quotients.jl @@ -87,8 +87,8 @@ function class_group(L::LinearQuotient) A = snfA KtoA = compose(KtoA, inv(snfAtoA)) if !is_trivial(H) - # TODO: this is an insane concatenation of maps and many of them might be identities. - # Can we have Hecke.compose_and_squash for groups? + # TODO: this is an insane concatenation of maps and many of them might be identities. + # Can we have Hecke.compose_and_squash for groups? GtoA = compose(GtoK, KtoA) else GtoA = KtoA @@ -112,13 +112,13 @@ If `zeta[2]` is not divisible by `order(g)` an error is raised. Note that `age(g)` depends on the choice of the root of unity, see [IR96](@cite). """ -function age(g::MatrixGroupElem{T}, zeta::Tuple{T, Int}) where T +function age(g::MatrixGroupElem{T}, zeta::Tuple{T,Int}) where {T} fl, q = divides(zeta[2], order(Int, g)) @req fl "Order $(zeta[2]) of given root of unity $(zeta[1]) is not divisible by $(order(g))" powers_of_zeta = _powers_of_root_of_unity(zeta[1]^q, order(Int, g)) eig = eigenvalues_with_multiplicities(g.elm) - return ZZRingElem(sum( m*powers_of_zeta[e] for (e, m) in eig ))//order(g) + return ZZRingElem(sum(m * powers_of_zeta[e] for (e, m) in eig))//order(g) end @doc raw""" @@ -127,7 +127,7 @@ end Return representatives of the conjugacy classes of `G` which consist of junior elements, that is, elements `g` in `G` with `age(g, zeta) == 1`. """ -function representatives_of_junior_elements(G::MatrixGroup{T}, zeta::Tuple{T, Int}) where T +function representatives_of_junior_elements(G::MatrixGroup{T}, zeta::Tuple{T,Int}) where {T} @req is_subgroup_of_sl(G) "Group is not a subgroup of SL" return filter!(g -> is_one(age(g, zeta)), map(representative, conjugacy_classes(G))) end @@ -137,7 +137,9 @@ end # This functions returns an automorphism of R into an eigenbasis of g. # Additionally, the codomain of this automorphism is graded by the weights of the # action. -function weights_of_action(R::MPolyRing{T}, g::MatrixGroupElem{T}, zeta::Tuple{T, Int}) where T +function weights_of_action( + R::MPolyRing{T}, g::MatrixGroupElem{T}, zeta::Tuple{T,Int} +) where {T} @req ngens(R) == degree(parent(g)) "Number of variables must match degree of the matrix" fl, q = divides(zeta[2], order(Int, g)) @req fl "Order $(zeta[2]) of given root of unity $(zeta[1]) is not divisible by $(order(g))" @@ -146,7 +148,7 @@ function weights_of_action(R::MPolyRing{T}, g::MatrixGroupElem{T}, zeta::Tuple{T powers_of_zeta = _powers_of_root_of_unity(zetaq, order(Int, g)) K = coefficient_ring(R) - eig = eigenspaces(g.elm, side = :left) + eig = eigenspaces(g.elm; side=:left) weights = Int[] V = zero_matrix(K, 0, ncols(g.elm)) @@ -158,10 +160,10 @@ function weights_of_action(R::MPolyRing{T}, g::MatrixGroupElem{T}, zeta::Tuple{T end to_eig = right_action(R, inv(V)) - S, t = graded_polynomial_ring(K, [ "t$i" for i in 1:ngens(R) ], weights) + S, t = graded_polynomial_ring(K, ["t$i" for i in 1:ngens(R)], weights) # The images of the generators of R are in general not homogeneous in S, so # we have to turn of the check, if we want to build this map... - RtoS = hom(R, S, [ to_eig(x)(t...) for x in gens(R) ], check = false) + RtoS = hom(R, S, [to_eig(x)(t...) for x in gens(R)]; check=false) return S, RtoS end @@ -177,11 +179,13 @@ surjective with this choice of root of unity, an error is raised. Note that monomial valuation depends on the choice of the root of unity, see [IR96](@cite). """ -function monomial_valuation(R::MPolyRing{T}, g::MatrixGroupElem{T}, zeta::Tuple{T, Int}) where T +function monomial_valuation( + R::MPolyRing{T}, g::MatrixGroupElem{T}, zeta::Tuple{T,Int} +) where {T} S, RtoS = weights_of_action(R, g, zeta) # If the weights are not coprime, the valuation is not surjective... - @assert is_one(gcd([ degree(gen(S, i))[1] for i in 1:ngens(S) ])) "Construction of well-defined valuation impossible with given choice of root of unity" + @assert is_one(gcd([degree(gen(S, i))[1] for i in 1:ngens(S)])) "Construction of well-defined valuation impossible with given choice of root of unity" function val(f::MPolyRingElem{T}) # TODO: Do we have a type-stable concept of infinity in OSCAR? diff --git a/experimental/LinearQuotients/src/misc.jl b/experimental/LinearQuotients/src/misc.jl index 292f5f922f55..060f73b06251 100644 --- a/experimental/LinearQuotients/src/misc.jl +++ b/experimental/LinearQuotients/src/misc.jl @@ -26,7 +26,7 @@ function subgroup_of_pseudo_reflections(G::MatrixGroup) append!(g, collect(c)) end end - return sub(G, g, check = false) + return sub(G, g; check=false) end @doc raw""" @@ -44,9 +44,9 @@ end # Assumes that zeta is a primitive l-th root of unity function _powers_of_root_of_unity(zeta::FieldElem, l::Int) K = parent(zeta) - powers_of_zeta = Dict{elem_type(K), Int}() + powers_of_zeta = Dict{elem_type(K),Int}() t = one(K) - for i in 0:l - 1 + for i in 0:(l - 1) powers_of_zeta[t] = i t *= zeta end @@ -78,16 +78,16 @@ function homogenize(f::MPolyRingElem, S::MPolyDecRing, start_pos::Int, positive: end degs_mons = Vector{Int}[] - degs_vars = [ [ Int(S.d[i][j]) for j in 1:ngens(S.D) ] for i in 1:ngens(S) ] + degs_vars = [[Int(S.d[i][j]) for j in 1:ngens(S.D)] for i in 1:ngens(S)] for e in exps - push!(degs_mons, sum(e.*degs_vars)) + push!(degs_mons, sum(e .* degs_vars)) end if positive - tdeg = maximum(hcat(degs_mons...), dims = 2)[:, 1] + tdeg = maximum(hcat(degs_mons...); dims=2)[:, 1] else - ldeg = minimum(hcat(degs_mons...), dims = 2)[:, 1] + ldeg = minimum(hcat(degs_mons...); dims=2)[:, 1] end F = MPolyBuildCtx(S) @@ -114,23 +114,23 @@ function homogenize_at_last_variable(I::MPolyIdeal, S::MPolyDecRing) # Permute the variables. The standard basis appears to be faster if the bigger # weights are in front. - p = sortperm([ S.d[i].coeff[1] for i in 1:ngens(S) - 1 ], rev = true) + p = sortperm([S.d[i].coeff[1] for i in 1:(ngens(S) - 1)]; rev=true) push!(p, ngens(S)) - w_perm = ZZRingElem[ S.d[p[i]].coeff[1] for i in 1:ngens(S) ] + w_perm = ZZRingElem[S.d[p[i]].coeff[1] for i in 1:ngens(S)] @assert !iszero(w_perm[1]) "All given weights are zero" R = base_ring(I) Rp = polynomial_ring(coefficient_ring(R), "t" => 1:ngens(R))[1] - RtoRp = hom(R, Rp, [ gen(Rp, findfirst(isequal(i), p)) for i in 1:ngens(Rp) ]) + RtoRp = hom(R, Rp, [gen(Rp, findfirst(isequal(i), p)) for i in 1:ngens(Rp)]) Sp, _ = graded_polynomial_ring(coefficient_ring(S), ["t$i" for i in 1:ngens(S)], w_perm) - SptoS = hom(Sp, S, [ gens(S)[p[i]] for i in 1:ngens(S) ]) + SptoS = hom(Sp, S, [gens(S)[p[i]] for i in 1:ngens(S)]) # Homogenize the generators positive = (Sp.d[ngens(Sp)].coeff[1] > 0) - J = ideal(Sp, [ homogenize(RtoRp(f), Sp, ngens(Sp), positive) for f in gens(I) ]) + J = ideal(Sp, [homogenize(RtoRp(f), Sp, ngens(Sp), positive) for f in gens(I)]) # Now saturate w.r.t. the last variable using a variant of Bayer's method @@ -148,12 +148,12 @@ function homogenize_at_last_variable(I::MPolyIdeal, S::MPolyDecRing) M[2, ncols(M)] = -1 non_zero_weight = false - for i in 2:nvars(Sp) - 1 + for i in 2:(nvars(Sp) - 1) M[i + 1, i] = 1 end o = matrix_ordering(gens(Sp), M) - gb = standard_basis(J, ordering = o) + gb = standard_basis(J; ordering=o) t = gen(Sp, nvars(Sp)) res = elem_type(Sp)[] diff --git a/experimental/LinearQuotients/src/types.jl b/experimental/LinearQuotients/src/types.jl index 49a5d2e171ab..9103db3b0e89 100644 --- a/experimental/LinearQuotients/src/types.jl +++ b/experimental/LinearQuotients/src/types.jl @@ -1,14 +1,14 @@ -mutable struct LinearQuotient{S, T} - group::MatrixGroup{S, T} +mutable struct LinearQuotient{S,T} + group::MatrixGroup{S,T} # We fix a primitive e-th root of unity, where e is the exponent of the group # for consistency - root_of_unity::Tuple{S, Int} + root_of_unity::Tuple{S,Int} - class_group::Tuple{FinGenAbGroup, Generic.CompositeMap{MatrixGroup{S, T}, FinGenAbGroup}} + class_group::Tuple{FinGenAbGroup,Generic.CompositeMap{MatrixGroup{S,T},FinGenAbGroup}} - function LinearQuotient(G::MatrixGroup{S, T}) where {S, T} - L = new{S, T}() + function LinearQuotient(G::MatrixGroup{S,T}) where {S,T} + L = new{S,T}() L.group = G return L end @@ -16,11 +16,11 @@ end # Helper object for the computation of Cox rings. # See function `homogeneous_generators(::HomBasisBuilder)`. -mutable struct HomBasisBuilder{RingType, RingElemType} +mutable struct HomBasisBuilder{RingType,RingElemType} R::RingType # Base ring # We work with a subalgebra A of R generated by power_base(C) - C::PowerProductCache{RingType, RingElemType} + C::PowerProductCache{RingType,RingElemType} # Group acting linearly on the subalgebra A via action G::FinGenAbGroup @@ -35,15 +35,22 @@ mutable struct HomBasisBuilder{RingType, RingElemType} hom_gens::Vector{RingElemType} degrees::Vector{FinGenAbGroupElem} - power_base_to_hom_gens::Dict{RingElemType, RingElemType} + power_base_to_hom_gens::Dict{RingElemType,RingElemType} - function HomBasisBuilder(C::PowerProductCache{RingType, RingElemType}, G::FinGenAbGroup, action::Function, eigenvalues_to_group::Function) where {RingType, RingElemType} + function HomBasisBuilder( + C::PowerProductCache{RingType,RingElemType}, + G::FinGenAbGroup, + action::Function, + eigenvalues_to_group::Function, + ) where {RingType,RingElemType} R = base_ring(C) T, _ = polynomial_ring(coefficient_ring(R), "t" => 1:length(power_base(C))) hom_gens = elem_type(T)[] degrees = elem_type(G)[] - power_base_to_hom_gens = Dict{elem_type(R), elem_type(T)}() + power_base_to_hom_gens = Dict{elem_type(R),elem_type(T)}() - return new{RingType, RingElemType}(R, C, G, action, eigenvalues_to_group, T, hom_gens, degrees, power_base_to_hom_gens) + return new{RingType,RingElemType}( + R, C, G, action, eigenvalues_to_group, T, hom_gens, degrees, power_base_to_hom_gens + ) end end diff --git a/experimental/LinearQuotients/test/cox_rings-test.jl b/experimental/LinearQuotients/test/cox_rings-test.jl index e390e42ea2db..145cae231c52 100644 --- a/experimental/LinearQuotients/test/cox_rings-test.jl +++ b/experimental/LinearQuotients/test/cox_rings-test.jl @@ -1,69 +1,83 @@ @testset "Cox rings of linear quotients" begin - C2 = matrix_group(matrix(QQ, 2, 2, [ -1, 0, 0, -1 ])) + C2 = matrix_group(matrix(QQ, 2, 2, [-1, 0, 0, -1])) L = linear_quotient(C2) R, RtoS = cox_ring(L) @test is_zero(modulus(R)) @test ngens(R) == 2 A = grading_group(R) - @test A.snf == ZZRingElem[ 2 ] - @test degree(gen(R, 1)) == A([ 1 ]) - @test degree(gen(R, 2)) == A([ 1 ]) + @test A.snf == ZZRingElem[2] + @test degree(gen(R, 1)) == A([1]) + @test degree(gen(R, 2)) == A([1]) K, a = cyclotomic_field(4, "a") - D4 = matrix_group(matrix(K, 2, 2, [ a, 0, 0, inv(a) ]), matrix(K, 2, 2, [ 0, -1, 1, 0 ])) + D4 = matrix_group(matrix(K, 2, 2, [a, 0, 0, inv(a)]), matrix(K, 2, 2, [0, -1, 1, 0])) L = linear_quotient(D4) R, RtoS = cox_ring(L) A, GtoA = class_group(L) @test A === grading_group(R) - for i = 1:ngens(R) - @test Oscar.ab_g_degree(GtoA, RtoS(gen(R, i)), Oscar.fixed_root_of_unity(L)) == degree(gen(R, i)) + for i in 1:ngens(R) + @test Oscar.ab_g_degree(GtoA, RtoS(gen(R, i)), Oscar.fixed_root_of_unity(L)) == + degree(gen(R, i)) end K, a = cyclotomic_field(60, "a") b = a^15 - M1 = matrix(K, 2, 2, [ b, 0, 0, inv(b) ]) + M1 = matrix(K, 2, 2, [b, 0, 0, inv(b)]) c = a^6 r = c + inv(c) - s = b*(c^3 + inv(c)^3) - M2 = K(1//2)*matrix(K, 2, 2, [ r + s, K(1), K(-1), r - s ]) - I = matrix_group([ M1, M2 ]) + s = b * (c^3 + inv(c)^3) + M2 = K(1//2) * matrix(K, 2, 2, [r + s, K(1), K(-1), r - s]) + I = matrix_group([M1, M2]) L = linear_quotient(I) - R, RtoS = cox_ring(L, algo_rels = :linear_algebra) + R, RtoS = cox_ring(L; algo_rels=:linear_algebra) @test is_trivial(grading_group(R)) A, GtoA = class_group(L) @test A === grading_group(R) - for i = 1:ngens(R) - @test Oscar.ab_g_degree(GtoA, RtoS(gen(R, i)), Oscar.fixed_root_of_unity(L)) == degree(gen(R, i)) + for i in 1:ngens(R) + @test Oscar.ab_g_degree(GtoA, RtoS(gen(R, i)), Oscar.fixed_root_of_unity(L)) == + degree(gen(R, i)) end K, a = cyclotomic_field(12, "a") - g1 = matrix(K, 4, 4, [ 1 0 0 0; 0 a^4 0 0; 0 0 1 0; 0 0 0 a^-4 ]) - g2 = 1//3*matrix(K, 4, 4, [ 2*a^4 + 1 a^4 - 1 0 0; 2*a^4 - 2 a^4 + 2 0 0; - 0 0 -2*a^4 - 1 -2*a^4 - 4; 0 0 -a^4 - 2 -a^4 + 1 ]) + g1 = matrix(K, 4, 4, [1 0 0 0; 0 a^4 0 0; 0 0 1 0; 0 0 0 a^-4]) + g2 = + 1//3 * matrix( + K, + 4, + 4, + [ + 2 * a^4+1 a^4-1 0 0 + 2 * a^4-2 a^4+2 0 0 + 0 0 -2 * a^4-1 -2 * a^4-4 + 0 0 -a^4-2 -a^4+1 + ], + ) G = matrix_group(g1, g2) # symplectic reflection representation of reflection group G_4 L = linear_quotient(G) - R, RtoS = cox_ring(L, algo_rels = :linear_algebra) + R, RtoS = cox_ring(L; algo_rels=:linear_algebra) @test ngens(R) == 18 - @test grading_group(R).snf == ZZRingElem[ 3 ] + @test grading_group(R).snf == ZZRingElem[3] A, GtoA = class_group(L) @test A === grading_group(R) - for i = 1:ngens(R) - @test Oscar.ab_g_degree(GtoA, RtoS(gen(R, i)), Oscar.fixed_root_of_unity(L)) == degree(gen(R, i)) + for i in 1:ngens(R) + @test Oscar.ab_g_degree(GtoA, RtoS(gen(R, i)), Oscar.fixed_root_of_unity(L)) == + degree(gen(R, i)) end # An example containing reflections K, a = cyclotomic_field(6, "a") - g1 = matrix(K, 3, 3, [ -1 0 0; 0 1 0; 0 0 1 ]) - g2 = matrix(K, 3, 3, [ 0 0 1; 1 0 0; 0 1 0 ]) + g1 = matrix(K, 3, 3, [-1 0 0; 0 1 0; 0 0 1]) + g2 = matrix(K, 3, 3, [0 0 1; 1 0 0; 0 1 0]) G = matrix_group(g1, g2) L = linear_quotient(G) R, RtoS = cox_ring(L) @test ngens(R) == 3 - @test grading_group(R).snf == ZZRingElem[ 3 ] + @test grading_group(R).snf == ZZRingElem[3] A, GtoA = class_group(L) @test A === grading_group(R) - for i = 1:ngens(R) - @test Oscar.ab_g_degree(GtoA, RtoS(gen(R, i)), Oscar.fixed_root_of_unity(L)) == degree(gen(R, i)) + for i in 1:ngens(R) + @test Oscar.ab_g_degree(GtoA, RtoS(gen(R, i)), Oscar.fixed_root_of_unity(L)) == + degree(gen(R, i)) end @test is_zero(modulus(R)) end @@ -71,15 +85,15 @@ end @testset "Cox rings of QQ-factorial terminalizations" begin K, a = cyclotomic_field(4) G = matrix_group( - matrix(K, 4, 4, [ 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0 ]), - matrix(K, 4, 4, [ a, 0, 0, 0, 0, inv(a), 0, 0, 0, 0, inv(a), 0, 0, 0, 0, a ]) - ) # symplectic reflection representation of dihedral group of order 8 + matrix(K, 4, 4, [0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0]), + matrix(K, 4, 4, [a, 0, 0, 0, 0, inv(a), 0, 0, 0, 0, inv(a), 0, 0, 0, 0, a]), + ) # symplectic reflection representation of dihedral group of order 8 L = linear_quotient(G) C, CtoRt = Oscar.cox_ring_of_qq_factorial_terminalization(L) # Can't really do tests of correctness, so this is more a test of "does the # function still exists" @test is_isomorphic(grading_group(C), abelian_group([0, 0])) - for i = 1:ngens(C) + for i in 1:ngens(C) f = CtoRt(gen(C, i)) exps = collect(AbstractAlgebra.exponent_vectors(f)) @test length(exps) == 1 diff --git a/experimental/LinearQuotients/test/linear_quotients-test.jl b/experimental/LinearQuotients/test/linear_quotients-test.jl index e436ae75d7b9..5f84fc151715 100644 --- a/experimental/LinearQuotients/test/linear_quotients-test.jl +++ b/experimental/LinearQuotients/test/linear_quotients-test.jl @@ -1,10 +1,10 @@ @testset "Linear quotients" begin - G = matrix_group(matrix(QQ, 1, 1, [ 2 ] )) + G = matrix_group(matrix(QQ, 1, 1, [2])) @test_throws ArgumentError linear_quotient(G) K, a = cyclotomic_field(4, "a") - r = matrix(K, 2, 2, [ -1, 0, 0, 1 ]) - s = matrix(K, 2, 2, [ a, 0, 0, inv(a) ]) + r = matrix(K, 2, 2, [-1, 0, 0, 1]) + s = matrix(K, 2, 2, [a, 0, 0, inv(a)]) G = matrix_group(r, s) L = linear_quotient(G) @@ -13,22 +13,22 @@ A, GtoA = class_group(L) @test is_snf(A) - @test A.snf == ZZRingElem[ 2 ] + @test A.snf == ZZRingElem[2] @test is_zero(GtoA(G(r))) - @test GtoA(G(s)) == A([ 1 ]) + @test GtoA(G(s)) == A([1]) K, a = cyclotomic_field(6, "a") - g = diagonal_matrix([ a^2, a^2, a^2 ]) + g = diagonal_matrix([a^2, a^2, a^2]) G = matrix_group(g) @test Oscar.age(G(g), (a, 6)) == 1 @test Oscar.age(G(g), (a^2, 3)) == 1 @test Oscar.age(G(g), (a^5, 6)) == 2 - @test Oscar.representatives_of_junior_elements(G, (a^2, 3)) == elem_type(G)[ G(g) ] + @test Oscar.representatives_of_junior_elements(G, (a^2, 3)) == elem_type(G)[G(g)] L = linear_quotient(G) @test has_canonical_singularities(L) @test !has_terminal_singularities(L) - g = diagonal_matrix([ QQ(-1), QQ(-1), QQ(-1), QQ(-1) ]) + g = diagonal_matrix([QQ(-1), QQ(-1), QQ(-1), QQ(-1)]) G = matrix_group(g) @test Oscar.age(G(g), (QQ(-1), 2)) == 2 @test isempty(Oscar.representatives_of_junior_elements(G, (QQ(-1), 2))) @@ -36,7 +36,7 @@ @test has_canonical_singularities(L) @test has_terminal_singularities(L) - g = diagonal_matrix([ QQ(-1) ]) + g = diagonal_matrix([QQ(-1)]) G = matrix_group(g) @test Oscar.age(G(g), (QQ(-1), 2)) == QQFieldElem(1, 2) L = linear_quotient(G) @@ -44,7 +44,7 @@ @test !has_terminal_singularities(L) K, a = cyclotomic_field(12, "a") - g = matrix(K, 2, 2, [ 0, a^4, a^4, 0 ]) + g = matrix(K, 2, 2, [0, a^4, a^4, 0]) G = matrix_group(g) R, x = polynomial_ring(K, 2) val = Oscar.monomial_valuation(R, G(g), (a, 12)) @@ -65,13 +65,13 @@ # An example containing pseudo-reflections K, a = cyclotomic_field(6, "a") - g1 = matrix(K, 3, 3, [ -1 0 0; 0 1 0; 0 0 1 ]) - g2 = matrix(K, 3, 3, [ 0 0 1; 1 0 0; 0 1 0 ]) + g1 = matrix(K, 3, 3, [-1 0 0; 0 1 0; 0 0 1]) + g2 = matrix(K, 3, 3, [0 0 1; 1 0 0; 0 1 0]) G = matrix_group(g1, g2) L = linear_quotient(G) A, GtoA = class_group(L) @test is_snf(A) - @test A.snf == ZZRingElem[ 3 ] + @test A.snf == ZZRingElem[3] @test is_zero(GtoA(G(g1))) - @test GtoA(G(g2)) == A([ 1 ]) + @test GtoA(G(g2)) == A([1]) end diff --git a/src/InvariantTheory/InvariantTheory.jl b/src/InvariantTheory/InvariantTheory.jl index 25caf32dbdf7..8337dc2ce4a0 100644 --- a/src/InvariantTheory/InvariantTheory.jl +++ b/src/InvariantTheory/InvariantTheory.jl @@ -8,4 +8,4 @@ include("fundamental_invariants.jl") include("affine_algebra.jl") # postponed inclusion from src/Modules/Modules.jl due to dependency -include("../Modules/Iterators.jl") +include("../Modules/Iterators.jl") diff --git a/src/InvariantTheory/affine_algebra.jl b/src/InvariantTheory/affine_algebra.jl index 29fff4fda231..94451a3d57e5 100644 --- a/src/InvariantTheory/affine_algebra.jl +++ b/src/InvariantTheory/affine_algebra.jl @@ -68,10 +68,14 @@ julia> affine_algebra(IR) (Quotient of multivariate polynomial ring by ideal (9*y1^6 + y1^3*y2^3 - 6*y1^3*y2*y3 + 3*y1^3*y4 - y2*y3*y4 + y3^3 + y4^2), Hom: quotient of multivariate polynomial ring -> graded multivariate polynomial ring) ``` """ -function affine_algebra(IR::FinGroupInvarRing; algo_gens::Symbol = :default, algo_rels::Symbol = :groebner_basis) +function affine_algebra( + IR::FinGroupInvarRing; algo_gens::Symbol=:default, algo_rels::Symbol=:groebner_basis +) if !isdefined(IR, :presentation) if algo_gens == :king && algo_rels == :linear_algebra - error("Combination of arguments :$(algo_gens) for algo_gens and :$(algo_rels) for algo_rels not possible") + error( + "Combination of arguments :$(algo_gens) for algo_gens and :$(algo_rels) for algo_rels not possible", + ) end if algo_rels == :groebner_basis @@ -91,7 +95,9 @@ end # ################################################################################ -function relations_via_groebner_basis(RG::FinGroupInvarRing, algo_fundamental::Symbol = :default) +function relations_via_groebner_basis( + RG::FinGroupInvarRing, algo_fundamental::Symbol=:default +) R = polynomial_ring(RG) fund_invars = fundamental_invariants(RG, algo_fundamental) @@ -112,7 +118,7 @@ function relations_via_linear_algebra(RG::FinGroupInvarRing) T = base_ring(Q) S = RG.fundamental.S - TtoS = hom(T, S, [ RG.fundamental.toS[QtoR(gen(Q, i))] for i = 1:ngens(T) ]) + TtoS = hom(T, S, [RG.fundamental.toS[QtoR(gen(Q, i))] for i in 1:ngens(T)]) I = TtoS(modulus(Q)) @@ -128,14 +134,14 @@ function relations_primary_and_irreducible_secondary(RG::FinGroupInvarRing) R = forget_grading(Rgraded) K = coefficient_ring(R) - p_invars = [ f.f for f in primary_invariants(RG) ] - s_invars = [ f.f for f in secondary_invariants(RG) ] - is_invars = [ f.f for f in irreducible_secondary_invariants(RG) ] + p_invars = [f.f for f in primary_invariants(RG)] + s_invars = [f.f for f in secondary_invariants(RG)] + is_invars = [f.f for f in irreducible_secondary_invariants(RG)] s_invars_cache = RG.secondary np = length(p_invars) - w = append!([ total_degree(f) for f in p_invars ], [ total_degree(f) for f in is_invars ]) + w = append!([total_degree(f) for f in p_invars], [total_degree(f) for f in is_invars]) S, t = graded_polynomial_ring(K, "t" => 1:(np + length(is_invars)), w) if isempty(is_invars) @@ -146,10 +152,10 @@ function relations_primary_and_irreducible_secondary(RG::FinGroupInvarRing) end RtoS = Vector{elem_type(S)}(undef, np + length(s_invars)) - for i = 1:np + for i in 1:np RtoS[i] = t[i] end - for i = 1:length(s_invars) + for i in 1:length(s_invars) exps = append!(zeros(Int, np), s_invars_cache.sec_in_irred[i]) g = set_exponent_vector!(one(S), 1, exps) RtoS[np + i] = g @@ -160,23 +166,23 @@ function relations_primary_and_irreducible_secondary(RG::FinGroupInvarRing) # Assumes that s_invars and is_invars are sorted by degree maxd = total_degree(s_invars[end]) + total_degree(is_invars[end]) - products_sorted = Vector{Vector{Tuple{elem_type(R), elem_type(S)}}}(undef, maxd) - for d = 1:maxd - products_sorted[d] = Vector{Tuple{elem_type(R), elem_type(S)}}() + products_sorted = Vector{Vector{Tuple{elem_type(R),elem_type(S)}}}(undef, maxd) + for d in 1:maxd + products_sorted[d] = Vector{Tuple{elem_type(R),elem_type(S)}}() end - for i = 1:length(s_invars) - for j = 1:length(s_invars) + for i in 1:length(s_invars) + for j in 1:length(s_invars) if !s_invars_cache.is_irreducible[j] continue end if s_invars_cache.is_irreducible[i] && i > j continue end - m = RtoS[np + i]*RtoS[np + j] + m = RtoS[np + i] * RtoS[np + j] if m in RtoS continue end - f = s_invars[i]*s_invars[j] + f = s_invars[i] * s_invars[j] push!(products_sorted[total_degree(f)], (f, m)) end end @@ -187,7 +193,7 @@ function relations_primary_and_irreducible_secondary(RG::FinGroupInvarRing) rels = elem_type(S)[] C = PowerProductCache(R, p_invars) - for d = 1:maxd + for d in 1:maxd if isempty(products_sorted[d]) continue end @@ -196,22 +202,22 @@ function relations_primary_and_irreducible_secondary(RG::FinGroupInvarRing) monomial_to_column = enumerate_monomials(gensd) - M = polys_to_smat(gensd, monomial_to_column, copy = false) + M = polys_to_smat(gensd, monomial_to_column; copy=false) - N = polys_to_smat([ t[1] for t in products_sorted[d] ], monomial_to_column, copy = false) + N = polys_to_smat([t[1] for t in products_sorted[d]], monomial_to_column; copy=false) N.c = M.c # Write the products (in N) in the basis of K[V]^G_d given by the secondary # invariants (in M) - x = solve(M, N, side = :left) + x = solve(M, N; side=:left) # Translate the relations to the free algebra S - for i = 1:nrows(x) + for i in 1:nrows(x) s = -products_sorted[d][i][2] - for j = 1:length(x.rows[i]) + for j in 1:length(x.rows[i]) m = S(x.rows[i].values[j]) e = expsd[gensd[x.rows[i].pos[j]]] - for k = 1:np + length(s_invars) + for k in 1:(np + length(s_invars)) if iszero(e[k]) continue end @@ -232,7 +238,7 @@ function relations_primary_and_irreducible_secondary(RG::FinGroupInvarRing) f = S() for (i, c) in coordinates(x) cS = c(gens_np...) - f += cS*RtoS[np + i] + f += cS * RtoS[np + i] end push!(rels, f) end @@ -240,7 +246,12 @@ function relations_primary_and_irreducible_secondary(RG::FinGroupInvarRing) I = ideal(S, rels) Q, StoQ = quo(S, I) - QtoR = hom(Q, Rgraded, append!(primary_invariants(RG), irreducible_secondary_invariants(RG)), check = false) + QtoR = hom( + Q, + Rgraded, + append!(primary_invariants(RG), irreducible_secondary_invariants(RG)); + check=false, + ) return Q, QtoR end @@ -282,8 +293,9 @@ function module_syzygies(RG::FinGroupInvarRing) # This is the same as generators of the vector space R/I by Nakayama. r_gens = map(x -> forget_grading(Rgraded(x)), _kbase(quo(Rgraded, I)[1])) - S, t = graded_polynomial_ring(K, length(p_invars), "t", - [ total_degree(f) for f in p_invars ]) + S, t = graded_polynomial_ring( + K, length(p_invars), "t", [total_degree(f) for f in p_invars] + ) F = free_module(S, length(r_gens)) # isomorphic to R as an S-module # Represent the secondary invariants as elements of F @@ -307,21 +319,21 @@ function module_syzygies(RG::FinGroupInvarRing) monomial_to_column = enumerate_monomials(gens_d) M = polys_to_smat(gens_d, monomial_to_column) N = polys_to_smat(s_invars_d, monomial_to_column) - sol = solve(M, N, side = :left) + sol = solve(M, N; side=:left) for i in 1:length(s_invars_d) a = F() for (j, c) in sol[i] # Translate gens_d[j] to an element of F via exps_d[gens_d[j]] # The first "half" of indices corresponds to the primary invariants - f = S([ c ], [ exps_d[gens_d[j]][1:length(p_invars)] ]) + f = S([c], [exps_d[gens_d[j]][1:length(p_invars)]]) # The second "half" of indices corresponds to r_gens g = F() for l in 1:rank(F) is_zero(exps_d[gens_d[j]][l + length(p_invars)]) && continue g += F[l] end - a += f*g + a += f * g end push!(s_invars_in_F, a) end @@ -339,11 +351,11 @@ function module_syzygies(RG::FinGroupInvarRing) # A bit cheated; this is not just the map from Q to R, but also from M to R, # to allow us to map the relations of Q back to R. - function QtoR(x::Union{FreeModElem, SubquoModuleElem}) + function QtoR(x::Union{FreeModElem,SubquoModuleElem}) @assert parent(x) === M || parent(x) === Q f = zero(Rgraded) for (i, c) in coordinates(x) - f += StoR(c)*Rgraded(s_invars[i]) + f += StoR(c) * Rgraded(s_invars[i]) end return f end diff --git a/src/InvariantTheory/fundamental_invariants.jl b/src/InvariantTheory/fundamental_invariants.jl index cfb7f2519ab9..d160494ee3b7 100644 --- a/src/InvariantTheory/fundamental_invariants.jl +++ b/src/InvariantTheory/fundamental_invariants.jl @@ -8,19 +8,21 @@ # Computes a d-truncated Gröbner basis of I # TODO: This should not be in this file and integrated in the general groebner_basis # functionality -function _groebner_basis(I::MPolyIdeal, d::Int; ordering::MonomialOrdering = default_ordering(base_ring(I))) +function _groebner_basis( + I::MPolyIdeal, d::Int; ordering::MonomialOrdering=default_ordering(base_ring(I)) +) sI = singular_generators(I.gens, ordering) R = base_ring(sI) J = Singular.Ideal(R, gens(sI)...) G = Singular.with_degBound(d) do - return Singular.std(J) - end + return Singular.std(J) + end BA = IdealGens(base_ring(I), G) return BA end # [Kin13, p. 5] See also [DK15, Algorithm 3.8.2] -function fundamental_invariants_via_king(RG::FinGroupInvarRing, beta::Int = 0) +function fundamental_invariants_via_king(RG::FinGroupInvarRing, beta::Int=0) @assert !is_modular(RG) Rgraded = _internal_polynomial_ring(RG) @@ -38,9 +40,9 @@ function fundamental_invariants_via_king(RG::FinGroupInvarRing, beta::Int = 0) else # We get a somewhat better bound if the group is not cyclic, see [DK15, Theorem 3.2.8] if iseven(g) - dmax = floor(Int, 3//4*g) + dmax = floor(Int, 3//4 * g) else - dmax = floor(Int, 5//8*g) + dmax = floor(Int, 5//8 * g) end end if beta > 0 && beta < dmax @@ -56,10 +58,10 @@ function fundamental_invariants_via_king(RG::FinGroupInvarRing, beta::Int = 0) # can save many truncated Gröbner bases if we don't add any new invariants # in the following rounds. I = ideal(R, GO) - GO = gens(groebner_basis(I, ordering = ordR)) + GO = gens(groebner_basis(I; ordering=ordR)) if is_zero(dim(I)) mons = gens(ideal(R, Singular.kbase(I.gb[ordR].S))) - dmax = maximum( total_degree(f) for f in mons ) + dmax = maximum(total_degree(f) for f in mons) d > dmax ? break : nothing end G = I.gb[ordR] @@ -73,7 +75,7 @@ function fundamental_invariants_via_king(RG::FinGroupInvarRing, beta::Int = 0) if !gb_is_full # We don't have a full Gröbner basis, so we compute a degree truncated one. - G = _groebner_basis(ideal(R, GO), d, ordering = ordR) + G = _groebner_basis(ideal(R, GO), d; ordering=ordR) GO = collect(G) end @@ -96,16 +98,22 @@ function fundamental_invariants_via_king(RG::FinGroupInvarRing, beta::Int = 0) end # Runtime estimates, see [KS99, Section17.2] - time_rey = length(mons)*d*order(group(RG)) - time_lin_alg = ngens(group(RG))*length(monomials_of_degree(R, d))^2 - X = 1/2*order(Int, group(RG)) # magical extra factor (see above) + time_rey = length(mons) * d * order(group(RG)) + time_lin_alg = ngens(group(RG)) * length(monomials_of_degree(R, d))^2 + X = 1 / 2 * order(Int, group(RG)) # magical extra factor (see above) - if X*time_rey < time_lin_alg + if X * time_rey < time_lin_alg # Reynolds approach - invs = ( _cast_in_internal_poly_ring(RG, reynolds_operator(RG, _cast_in_external_poly_ring(RG, Rgraded(m)))) for m in mons ) + invs = ( + _cast_in_internal_poly_ring( + RG, reynolds_operator(RG, _cast_in_external_poly_ring(RG, Rgraded(m))) + ) for m in mons + ) else # Linear algebra approach - invs = ( _cast_in_internal_poly_ring(RG, f) for f in iterate_basis(RG, d, :linear_algebra) ) + invs = ( + _cast_in_internal_poly_ring(RG, f) for f in iterate_basis(RG, d, :linear_algebra) + ) end for m in invs @@ -127,13 +135,15 @@ function fundamental_invariants_via_king(RG::FinGroupInvarRing, beta::Int = 0) d += 1 end - invars_cache = FundamentalInvarsCache{elem_type(Rgraded), typeof(Rgraded)}() - polys_ext = [ _cast_in_external_poly_ring(RG, Rgraded(f)) for f in S ] + invars_cache = FundamentalInvarsCache{elem_type(Rgraded),typeof(Rgraded)}() + polys_ext = [_cast_in_external_poly_ring(RG, Rgraded(f)) for f in S] # Cancelling the leading coefficient is not mathematically necessary and # should be done with the ordering that is used for the printing - invars_cache.invars = [ inv(AbstractAlgebra.leading_coefficient(f))*f for f in polys_ext ] + invars_cache.invars = [inv(AbstractAlgebra.leading_coefficient(f)) * f for f in polys_ext] invars_cache.via_primary_and_secondary = false - invars_cache.S = graded_polynomial_ring(coefficient_ring(R), [ "y$i" for i = 1:length(S) ], [ total_degree(f) for f in S ])[1] + invars_cache.S = graded_polynomial_ring( + coefficient_ring(R), ["y$i" for i in 1:length(S)], [total_degree(f) for f in S] + )[1] return invars_cache end @@ -154,7 +164,7 @@ function fundamental_invariants_via_primary_and_secondary(IR::FinGroupInvarRing) R = polynomial_ring(IR) K = coefficient_ring(R) - invars_cache = FundamentalInvarsCache{elem_type(R), typeof(R)}() + invars_cache = FundamentalInvarsCache{elem_type(R),typeof(R)}() invars_cache.via_primary_and_secondary = true if isempty(irreducible_secondary_invariants(IR)) @@ -162,29 +172,45 @@ function fundamental_invariants_via_primary_and_secondary(IR::FinGroupInvarRing) # generated by the primary invariants invars_cache.invars = primary_invariants(IR) - invars_cache.S = graded_polynomial_ring(K, [ "y$i" for i = 1:length(invars_cache.invars) ], [ total_degree(forget_grading(f)) for f in invars_cache.invars ])[1] - invars_cache.toS = Dict{elem_type(R), elem_type(invars_cache.S)}(invars_cache.invars[i] => gen(invars_cache.S, i) for i = 1:length(invars_cache.invars)) + invars_cache.S = graded_polynomial_ring( + K, + ["y$i" for i in 1:length(invars_cache.invars)], + [total_degree(forget_grading(f)) for f in invars_cache.invars], + )[1] + invars_cache.toS = Dict{elem_type(R),elem_type(invars_cache.S)}( + invars_cache.invars[i] => gen(invars_cache.S, i) for + i in 1:length(invars_cache.invars) + ) return invars_cache end invars = append!(irreducible_secondary_invariants(IR), primary_invariants(IR)) - res, rels = _minimal_subalgebra_generators_with_relations(invars, ideal(R, [ zero(R) ]), check = false, start = length(irreducible_secondary_invariants(IR))) + res, rels = _minimal_subalgebra_generators_with_relations( + invars, + ideal(R, [zero(R)]); + check=false, + start=length(irreducible_secondary_invariants(IR)), + ) # Sort the result by degree - sp = sortperm(res, lt = (x, y) -> total_degree(forget_grading(x)) < total_degree(forget_grading(y))) + sp = sortperm( + res; lt=(x, y) -> total_degree(forget_grading(x)) < total_degree(forget_grading(y)) + ) res = res[sp] # Bookkeeping: we need to transform the relations in rels to the new ordering # (and potentially less variables) - T, _ = graded_polynomial_ring(K, [ "y$i" for i = 1:length(res) ], [ total_degree(forget_grading(x)) for x in res ]) + T, _ = graded_polynomial_ring( + K, ["y$i" for i in 1:length(res)], [total_degree(forget_grading(x)) for x in res] + ) invars_cache.invars = res invars_cache.S = T t = gens(T)[invperm(sp)] - invars_cache.toS = Dict{elem_type(R), elem_type(T)}() + invars_cache.toS = Dict{elem_type(R),elem_type(T)}() for (f, g) in zip(invars, rels) invars_cache.toS[f] = g(t...) end @@ -253,7 +279,9 @@ julia> fundamental_invariants(IR) x[1]^3*x[2]^6 + x[1]^6*x[3]^3 + x[2]^3*x[3]^6 ``` """ -function fundamental_invariants(IR::FinGroupInvarRing, algorithm::Symbol = :default; beta::Int = 0) +function fundamental_invariants( + IR::FinGroupInvarRing, algorithm::Symbol=:default; beta::Int=0 +) if !isdefined(IR, :fundamental) if algorithm == :default algorithm = is_modular(IR) ? :primary_and_secondary : :king diff --git a/src/InvariantTheory/helpers.jl b/src/InvariantTheory/helpers.jl index e20eb79c25ca..fff65ec37d1a 100644 --- a/src/InvariantTheory/helpers.jl +++ b/src/InvariantTheory/helpers.jl @@ -7,7 +7,7 @@ base_ring(C::PowerProductCache) = C.ring # Don't want to call it `exponent_vector` because I don't want it to be exported. -function get_exponent_vector(C::PowerProductCache{S, T}, f::T) where {S, T} +function get_exponent_vector(C::PowerProductCache{S,T}, f::T) where {S,T} @assert C.exponent_vectors_known[total_degree(f)] "exponent vectors for this degree were not computed, please trigger a re-computation with `remember_exponents = true`" return C.exponent_vectors[f] @@ -16,7 +16,9 @@ end power_base(C::PowerProductCache) = C.base # Add a base element to the cache. -function add_base_element!(C::PowerProductCache{S, T}, f::T, remember_exponents::Bool = true) where {S, T} +function add_base_element!( + C::PowerProductCache{S,T}, f::T, remember_exponents::Bool=true +) where {S,T} @assert !iszero(f) push!(C.base, f) @@ -33,7 +35,9 @@ end # Extend the already computed power products by powers of C.base[i]. # Only used internally. -function extend!(C::PowerProductCache{S, T}, d::Int, i::Int, remember_exponents::Bool = true) where {S, T <: MPolyRingElem} +function extend!( + C::PowerProductCache{S,T}, d::Int, i::Int, remember_exponents::Bool=true +) where {S,T<:MPolyRingElem} @assert d >= 0 @assert 1 <= i && i <= length(C.base) @@ -65,14 +69,14 @@ function extend!(C::PowerProductCache{S, T}, d::Int, i::Int, remember_exponents: # Build all products with elements of degree d - total_degree(C.base[i]) dd = d - di all_power_products_of_degree!(C, dd, remember_exponents) - for j = 1:length(C.power_products[dd]) + for j in 1:length(C.power_products[dd]) # We only need the products for which the second factor (of degree dd) does # not involve any factor of index > i. Otherwise we will get duplicates. if C.last_factor[C.power_products[dd][j]] > i continue end - f = C.power_products[dd][j]*C.base[i] + f = C.power_products[dd][j] * C.base[i] push!(C.power_products[d], f) if remember_exponents C.exponent_vectors[f] = copy(C.exponent_vectors[C.power_products[dd][j]]) @@ -93,7 +97,9 @@ end # products will be stored in the dictionary C.exponent_vectors, that is, if # C.base = [ f_1, ..., f_k ] and we compute f = f_1^e_1 \cdots f_k^e_k, then # C.exponent_vectors[f] = [ e_1, ..., e_k ]. -function all_power_products_of_degree!(C::PowerProductCache{S, T}, d::Int, remember_exponents::Bool = true) where {S, T <: MPolyRingElem} +function all_power_products_of_degree!( + C::PowerProductCache{S,T}, d::Int, remember_exponents::Bool=true +) where {S,T<:MPolyRingElem} @assert d >= 0 # Degree d has already been computed? @@ -106,12 +112,16 @@ function all_power_products_of_degree!(C::PowerProductCache{S, T}, d::Int, remem if d == 0 push!(C.power_products[d], one(C.ring)) - remember_exponents ? C.exponent_vectors[one(C.ring)] = zeros(Int, length(C.base)) : nothing + if remember_exponents + C.exponent_vectors[one(C.ring)] = zeros(Int, length(C.base)) + else + nothing + end C.last_factor[one(C.ring)] = 0 return C.power_products[d] end - for i = 1:length(C.base) + for i in 1:length(C.base) extend!(C, d, i, remember_exponents) end @@ -126,16 +136,18 @@ end # f = f_1^e_1 \cdots f_n^e_k \cdot g_1^e_{k + 1} \cdots g_m^{e_{k + m}} was # computed, then D[f] = [ e_1, ..., e_{k + m} ] where e_l in { 0, 1 } for l > k. # (If remember_exponents is false, the dictionary is empty.) -function generators_for_given_degree!(C::PowerProductCache{S, T}, module_gens::Vector{T}, d::Int, remember_exponents::Bool = true) where {S, T <: MPolyRingElem} +function generators_for_given_degree!( + C::PowerProductCache{S,T}, module_gens::Vector{T}, d::Int, remember_exponents::Bool=true +) where {S,T<:MPolyRingElem} @assert !isempty(module_gens) @assert all(!iszero, module_gens) R = C.ring generators = elem_type(R)[] - exps = Dict{T, Vector{Int}}() + exps = Dict{T,Vector{Int}}() coords = zeros(Int, length(C.base) + length(module_gens)) - for i = 1:length(module_gens) + for i in 1:length(module_gens) di = total_degree(module_gens[i]) if di > d continue @@ -143,7 +155,7 @@ function generators_for_given_degree!(C::PowerProductCache{S, T}, module_gens::V if di == d push!(generators, module_gens[i]) if remember_exponents - for j = 1:length(C.base) + for j in 1:length(C.base) coords[j] = 0 end coords[length(C.base) + i] = 1 @@ -154,8 +166,8 @@ function generators_for_given_degree!(C::PowerProductCache{S, T}, module_gens::V end dd = d - di all_power_products_of_degree!(C, dd, remember_exponents) - for j = 1:length(C.power_products[dd]) - f = C.power_products[dd][j]*module_gens[i] + for j in 1:length(C.power_products[dd]) + f = C.power_products[dd][j] * module_gens[i] push!(generators, f) if remember_exponents @@ -199,8 +211,10 @@ function add_to_basis!(B::BasisOfPolynomials, f::MPolyRingElem) return Hecke._add_row_to_rref!(B.M, srow) end -function enumerate_monomials(polys::Vector{PolyRingElemT}) where {PolyRingElemT <: MPolyRingElem} - enum_mons = Dict{Vector{Int}, Int}() +function enumerate_monomials( + polys::Vector{PolyRingElemT} +) where {PolyRingElemT<:MPolyRingElem} + enum_mons = Dict{Vector{Int},Int}() c = 0 for f in polys for e in AbstractAlgebra.exponent_vectors(f) @@ -213,7 +227,9 @@ function enumerate_monomials(polys::Vector{PolyRingElemT}) where {PolyRingElemT return enum_mons end -function polys_to_smat(polys::Vector{PolyRingElemT}, monomial_to_column::Dict{Vector{Int}, Int}; copy = true) where {PolyRingElemT <: MPolyRingElem} +function polys_to_smat( + polys::Vector{PolyRingElemT}, monomial_to_column::Dict{Vector{Int},Int}; copy=true +) where {PolyRingElemT<:MPolyRingElem} @assert !isempty(polys) K = coefficient_ring(parent(polys[1])) M = sparse_matrix(K) diff --git a/src/InvariantTheory/invariant_rings.jl b/src/InvariantTheory/invariant_rings.jl index c1509e040b9b..5cfa94453f88 100644 --- a/src/InvariantTheory/invariant_rings.jl +++ b/src/InvariantTheory/invariant_rings.jl @@ -23,7 +23,7 @@ end # Return f as an element of R. Assumes that ngens(R) == ngens(parent(f)) # and coefficient_ring(R) === coefficient_ring(parent(f)). This is not checked. -function __cast_forced(R::MPolyRing{T}, f::MPolyRingElem{T}) where T +function __cast_forced(R::MPolyRing{T}, f::MPolyRingElem{T}) where {T} F = MPolyBuildCtx(R) for (c, e) in zip(AbstractAlgebra.coefficients(f), AbstractAlgebra.exponent_vectors(f)) push_term!(F, c, e) @@ -54,24 +54,24 @@ end # ################################################################################ -function invariant_ring(M::Vector{<: MatrixElem}) +function invariant_ring(M::Vector{<:MatrixElem}) return invariant_ring(base_ring(M[1]), M) end -function invariant_ring(R::MPolyDecRing, M::Vector{<: MatrixElem}) +function invariant_ring(R::MPolyDecRing, M::Vector{<:MatrixElem}) K = coefficient_ring(R) return invariant_ring(R, matrix_group([change_base_ring(K, g) for g in M])) end -function invariant_ring(m::MatrixElem{T}, ms::MatrixElem{T}...) where {T} +function invariant_ring(m::MatrixElem{T}, ms::MatrixElem{T}...) where {T} return invariant_ring([m, ms...]) end -function invariant_ring(R::MPolyDecRing, m::MatrixElem{T}, ms::MatrixElem{T}...) where {T} +function invariant_ring(R::MPolyDecRing, m::MatrixElem{T}, ms::MatrixElem{T}...) where {T} return invariant_ring(R, [m, ms...]) end -function invariant_ring(K::Field, M::Vector{<: MatrixElem}) +function invariant_ring(K::Field, M::Vector{<:MatrixElem}) return invariant_ring(matrix_group([change_base_ring(K, g) for g in M])) end @@ -128,7 +128,8 @@ invariant_ring(K::Field, G::PermGroup) = FinGroupInvarRing(K, G, gens(G)) invariant_ring(G::PermGroup) = invariant_ring(QQ, G) -invariant_ring(R::MPolyDecRing, G::PermGroup) = FinGroupInvarRing(coefficient_ring(R), G, gens(G), R) +invariant_ring(R::MPolyDecRing, G::PermGroup) = + FinGroupInvarRing(coefficient_ring(R), G, gens(G), R) function Base.show(io::IO, ::MIME"text/plain", RG::FinGroupInvarRing) io = pretty(io) @@ -147,7 +148,7 @@ function Base.show(io::IO, RG::FinGroupInvarRing) end # Return a map performing the right action of M on the ring R. -function right_action(R::MPolyRing{T}, M::MatrixElem{T}) where T +function right_action(R::MPolyRing{T}, M::MatrixElem{T}) where {T} @assert nvars(R) == ncols(M) @assert nrows(M) == ncols(M) n = nvars(R) @@ -161,12 +162,12 @@ function right_action(R::MPolyRing{T}, M::MatrixElem{T}) where T # We now compute these actions of M on the variables of R. vars = zeros(R, n) x = gens(R) - for i = 1:n - for j = 1:n + for i in 1:n + for j in 1:n if iszero(M[i, j]) continue end - vars[i] = addeq!(vars[i], M[i, j]*x[j]) + vars[i] = addeq!(vars[i], M[i, j] * x[j]) end end @@ -177,11 +178,12 @@ function right_action(R::MPolyRing{T}, M::MatrixElem{T}) where T return MapFromFunc(R, R, right_action_by_M) end -right_action(R::MPolyRing{T}, M::MatrixGroupElem{T}) where T = right_action(R, M.elm) -right_action(f::MPolyRingElem{T}, M::MatrixElem{T}) where T = right_action(parent(f), M)(f) -right_action(f::MPolyRingElem{T}, M::MatrixGroupElem{T}) where T = right_action(f, M.elm) +right_action(R::MPolyRing{T}, M::MatrixGroupElem{T}) where {T} = right_action(R, M.elm) +right_action(f::MPolyRingElem{T}, M::MatrixElem{T}) where {T} = + right_action(parent(f), M)(f) +right_action(f::MPolyRingElem{T}, M::MatrixGroupElem{T}) where {T} = right_action(f, M.elm) -function right_action(R::MPolyRing{T}, p::PermGroupElem) where T +function right_action(R::MPolyRing{T}, p::PermGroupElem) where {T} n = nvars(R) @assert n == degree(parent(p)) @@ -198,20 +200,22 @@ right_action(f::MPolyRingElem, p::PermGroupElem) = right_action(parent(f), p)(f) # ################################################################################ -function reynolds_operator(IR::FinGroupInvarRing{FldT, GrpT, PolyRingElemT}) where {FldT, GrpT, PolyRingElemT} +function reynolds_operator( + IR::FinGroupInvarRing{FldT,GrpT,PolyRingElemT} +) where {FldT,GrpT,PolyRingElemT} @assert !is_modular(IR) if isdefined(IR, :reynolds_operator) return nothing end - actions = [ right_action(polynomial_ring(IR), g) for g in group(IR) ] + actions = [right_action(polynomial_ring(IR), g) for g in group(IR)] function reynolds(f::PolyRingElemT) g = parent(f)() for action in actions g = addeq!(g, action(f)) end - return g*base_ring(f)(1//order(group(IR))) + return g * base_ring(f)(1//order(group(IR))) end IR.reynolds_operator = MapFromFunc(polynomial_ring(IR), polynomial_ring(IR), reynolds) @@ -303,7 +307,9 @@ julia> reynolds_operator(IR, f) 0 ``` """ -function reynolds_operator(IR::FinGroupInvarRing{FldT, GrpT, T}, f::T) where {FldT, GrpT, T <: MPolyRingElem} +function reynolds_operator( + IR::FinGroupInvarRing{FldT,GrpT,T}, f::T +) where {FldT,GrpT,T<:MPolyRingElem} @assert !is_modular(IR) @assert parent(f) === polynomial_ring(IR) @@ -318,8 +324,10 @@ function reynolds_operator(IR::FinGroupInvarRing, f::MPolyRingElem) return reynolds_operator(IR, polynomial_ring(IR)(f)) end -function reynolds_operator(IR::FinGroupInvarRing{FldT, GrpT, PolyRingElemT}, chi::GAPGroupClassFunction) where {FldT, GrpT, PolyRingElemT} -# I expect that this also works in the non-modular case, but haven't found a reference. +function reynolds_operator( + IR::FinGroupInvarRing{FldT,GrpT,PolyRingElemT}, chi::GAPGroupClassFunction +) where {FldT,GrpT,PolyRingElemT} + # I expect that this also works in the non-modular case, but haven't found a reference. # The only reference for this version of the reynolds operator appears to be [Gat96]. @assert is_zero(characteristic(coefficient_ring(IR))) @assert is_irreducible(chi) @@ -328,14 +336,16 @@ function reynolds_operator(IR::FinGroupInvarRing{FldT, GrpT, PolyRingElemT}, chi conjchi = conj(chi) - actions_and_values = [ (right_action(polynomial_ring(IR), g), K(conjchi(g).data)) for g in group(IR) ] + actions_and_values = [ + (right_action(polynomial_ring(IR), g), K(conjchi(g).data)) for g in group(IR) + ] function reynolds(f::PolyRingElemT) g = parent(f)() for (action, val) in actions_and_values - g = addeq!(g, action(f)*val) + g = addeq!(g, action(f) * val) end - return g*base_ring(f)(1//order(group(IR))) + return g * base_ring(f)(1//order(group(IR))) end return MapFromFunc(polynomial_ring(IR), polynomial_ring(IR), reynolds) @@ -396,11 +406,15 @@ julia> reynolds_operator(IR, x[1], chi) 1//2*x[1] - 1//2*x[2] ``` """ -function reynolds_operator(IR::FinGroupInvarRing{FldT, GrpT, T}, f::T, chi::GAPGroupClassFunction) where {FldT, GrpT, T <: MPolyRingElem} +function reynolds_operator( + IR::FinGroupInvarRing{FldT,GrpT,T}, f::T, chi::GAPGroupClassFunction +) where {FldT,GrpT,T<:MPolyRingElem} return reynolds_operator(IR, chi)(f) end -function reynolds_operator(IR::FinGroupInvarRing, f::MPolyRingElem, chi::GAPGroupClassFunction) +function reynolds_operator( + IR::FinGroupInvarRing, f::MPolyRingElem, chi::GAPGroupClassFunction +) @assert parent(f) === forget_grading(polynomial_ring(IR)) return reynolds_operator(IR, polynomial_ring(IR)(f), chi) end @@ -477,7 +491,8 @@ julia> basis(IR, 3) x[1]^2*x[3] + 2*x[2]^2*x[3] ``` """ -basis(IR::FinGroupInvarRing, d::Int, algorithm::Symbol = :default) = collect(iterate_basis(IR, d, algorithm)) +basis(IR::FinGroupInvarRing, d::Int, algorithm::Symbol=:default) = + collect(iterate_basis(IR, d, algorithm)) @doc raw""" basis(IR::FinGroupInvarRing, d::Int, chi::GAPGroupClassFunction) @@ -528,7 +543,8 @@ julia> basis(R, 3, chi) ``` """ -basis(IR::FinGroupInvarRing, d::Int, chi::GAPGroupClassFunction) = collect(iterate_basis(IR, d, chi)) +basis(IR::FinGroupInvarRing, d::Int, chi::GAPGroupClassFunction) = + collect(iterate_basis(IR, d, chi)) ################################################################################ # @@ -556,7 +572,7 @@ function _molien_series_char0(S::PolyRing, I::FinGroupInvarRing) G = group(I) n = degree(G) K = coefficient_ring(I) - Kt, _ = polynomial_ring(K, "t", cached = false) + Kt, _ = polynomial_ring(K, "t"; cached=false) C = conjugacy_classes(G) res = zero(fraction_field(Kt)) for c in C @@ -571,14 +587,14 @@ function _molien_series_char0(S::PolyRing, I::FinGroupInvarRing) res = res + length(c)::ZZRingElem * 1//reverse(f) end res = divexact(res, order(ZZRingElem, G)) - num = change_coefficient_ring(coefficient_ring(S), - numerator(res), parent = S) - den = change_coefficient_ring(coefficient_ring(S), - denominator(res), parent = S) + num = change_coefficient_ring(coefficient_ring(S), numerator(res); parent=S) + den = change_coefficient_ring(coefficient_ring(S), denominator(res); parent=S) return num//den end -function _molien_series_nonmodular_via_gap(S::PolyRing, I::FinGroupInvarRing, chi::Union{GAPGroupClassFunction, Nothing} = nothing) +function _molien_series_nonmodular_via_gap( + S::PolyRing, I::FinGroupInvarRing, chi::Union{GAPGroupClassFunction,Nothing}=nothing +) @assert !is_modular(I) G = group(I) @assert G isa MatrixGroup || G isa PermGroup @@ -587,23 +603,35 @@ function _molien_series_nonmodular_via_gap(S::PolyRing, I::FinGroupInvarRing, ch if is_zero(characteristic(coefficient_ring(I))) psi = natural_character(G).values else - psi = [GAP.Globals.BrauerCharacterValue(GAPWrap.Representative(c)) - for c in GAPWrap.ConjugacyClasses(t)] + psi = [ + GAP.Globals.BrauerCharacterValue(GAPWrap.Representative(c)) for + c in GAPWrap.ConjugacyClasses(t) + ] end else deg = GAP.Obj(degree(G)) - psi = [deg - GAP.Globals.NrMovedPoints(GAPWrap.Representative(c)) - for c in GAPWrap.ConjugacyClasses(t)] + psi = [ + deg - GAP.Globals.NrMovedPoints(GAPWrap.Representative(c)) for + c in GAPWrap.ConjugacyClasses(t) + ] end if chi === nothing - info = GAP.Globals.MolienSeriesInfo(GAP.Globals.MolienSeries(t, - GAP.GapObj(psi))) + info = GAP.Globals.MolienSeriesInfo(GAP.Globals.MolienSeries(t, GAP.GapObj(psi))) else - info = GAP.Globals.MolienSeriesInfo(GAP.Globals.MolienSeries(t, - GAP.GapObj(psi), chi.values)) + info = GAP.Globals.MolienSeriesInfo( + GAP.Globals.MolienSeries(t, GAP.GapObj(psi), chi.values) + ) end - num = S(Vector{ZZRingElem}(GAP.Globals.CoefficientsOfUnivariatePolynomial(info.numer))::Vector{ZZRingElem}) - den = S(Vector{ZZRingElem}(GAP.Globals.CoefficientsOfUnivariatePolynomial(info.denom))::Vector{ZZRingElem}) + num = S( + Vector{ZZRingElem}( + GAP.Globals.CoefficientsOfUnivariatePolynomial(info.numer) + )::Vector{ZZRingElem}, + ) + den = S( + Vector{ZZRingElem}( + GAP.Globals.CoefficientsOfUnivariatePolynomial(info.denom) + )::Vector{ZZRingElem}, + ) return num//den end @@ -659,13 +687,17 @@ julia> molien_series(IR, chi) t//(t^3 - t^2 - t + 1) ``` """ -function molien_series(S::PolyRing, I::FinGroupInvarRing, chi::Union{GAPGroupClassFunction, Nothing} = nothing) +function molien_series( + S::PolyRing, I::FinGroupInvarRing, chi::Union{GAPGroupClassFunction,Nothing}=nothing +) if isdefined(I, :molien_series) && chi === nothing if parent(I.molien_series) === S return I.molien_series end - num = change_coefficient_ring(coefficient_ring(S), numerator(I.molien_series), parent = S) - den = change_coefficient_ring(coefficient_ring(S), denominator(I.molien_series), parent = S) + num = change_coefficient_ring(coefficient_ring(S), numerator(I.molien_series); parent=S) + den = change_coefficient_ring( + coefficient_ring(S), denominator(I.molien_series); parent=S + ) return num//den end @@ -680,15 +712,17 @@ function molien_series(S::PolyRing, I::FinGroupInvarRing, chi::Union{GAPGroupCla end end -function molien_series(I::FinGroupInvarRing, chi::Union{GAPGroupClassFunction, Nothing} = nothing) +function molien_series( + I::FinGroupInvarRing, chi::Union{GAPGroupClassFunction,Nothing}=nothing +) if chi === nothing if !isdefined(I, :molien_series) - S, t = polynomial_ring(QQ, "t", cached = false) + S, t = polynomial_ring(QQ, "t"; cached=false) I.molien_series = molien_series(S, I) end return I.molien_series else - S, t = polynomial_ring(QQ, "t", cached = false) + S, t = polynomial_ring(QQ, "t"; cached=false) return molien_series(S, I, chi) end end diff --git a/src/InvariantTheory/iterators.jl b/src/InvariantTheory/iterators.jl index c227127f333f..d4da8c6d3a99 100644 --- a/src/InvariantTheory/iterators.jl +++ b/src/InvariantTheory/iterators.jl @@ -41,7 +41,8 @@ monomials_of_degree monomials_of_degree(R::MPolyRing, d::Int) = AllMonomials(R, d) monomials_of_degree(R::MPolyRing, d::Int, vars::Vector{Int}) = AllMonomials(R, d, vars) -monomials_of_degree(R::MPolyRing, d::Int, r::UnitRange{Int}) = AllMonomials(R, d, collect(r)) +monomials_of_degree(R::MPolyRing, d::Int, r::UnitRange{Int}) = + AllMonomials(R, d, collect(r)) AllMonomials(R::MPolyRing, d::Int) = AllMonomials{typeof(R)}(R, d) AllMonomials(R::MPolyRing, d::Int, vars::Vector{Int}) = AllMonomials{typeof(R)}(R, d, vars) @@ -65,17 +66,17 @@ function _build_monomial(AM::AllMonomials, c::WeakComposition{Int}) return set_exponent_vector!(one(AM.R), 1, data(c)) end - for i in 1:AM.n_vars + for i in 1:(AM.n_vars) AM.tmp[AM.used_vars[i]] = c[i] end f = set_exponent_vector!(one(AM.R), 1, AM.tmp) - for i in 1:AM.n_vars + for i in 1:(AM.n_vars) AM.tmp[AM.used_vars[i]] = 0 end return f end -function Base.iterate(AM::AllMonomials, state::Union{Nothing, Vector{Int}} = nothing) +function Base.iterate(AM::AllMonomials, state::Union{Nothing,Vector{Int}}=nothing) c = iterate(AM.weak_comp_iter, state) if c === nothing return nothing @@ -108,14 +109,16 @@ end # Return the dimension of the graded component of degree d. # If we cannot compute the Molien series (so far in the modular case), we return # -1. -function dimension_via_molien_series(::Type{T}, R::FinGroupInvarRing, d::Int, chi::Union{GAPGroupClassFunction, Nothing} = nothing) where T <: IntegerUnion +function dimension_via_molien_series( + ::Type{T}, R::FinGroupInvarRing, d::Int, chi::Union{GAPGroupClassFunction,Nothing}=nothing +) where {T<:IntegerUnion} if !is_molien_series_implemented(R) return -1 end Qt, t = power_series_ring(QQ, d + 1, "t") F = molien_series(R, chi) - k = coeff(numerator(F)(t)*inv(denominator(F)(t)), d) + k = coeff(numerator(F)(t) * inv(denominator(F)(t)), d) @assert is_integral(k) return T(numerator(k))::T end @@ -194,7 +197,7 @@ julia> collect(B) x[3]^2 ``` """ -function iterate_basis(R::FinGroupInvarRing, d::Int, algorithm::Symbol = :default) +function iterate_basis(R::FinGroupInvarRing, d::Int, algorithm::Symbol=:default) @assert d >= 0 "Degree must be non-negative" if algorithm == :default @@ -214,7 +217,7 @@ function iterate_basis(R::FinGroupInvarRing, d::Int, algorithm::Symbol = :defaul g = order(Int, group(R)) n = degree(group(R)) k = binomial(n + d - 1, n - 1) - if k > d*g/s + if k > d * g / s algorithm = :reynolds else algorithm = :linear_algebra @@ -290,9 +293,12 @@ julia> collect(B) ``` """ -iterate_basis(R::FinGroupInvarRing, d::Int, chi::GAPGroupClassFunction) = iterate_basis_reynolds(R, d, chi) +iterate_basis(R::FinGroupInvarRing, d::Int, chi::GAPGroupClassFunction) = + iterate_basis_reynolds(R, d, chi) -function iterate_basis_reynolds(R::FinGroupInvarRing, d::Int, chi::Union{GAPGroupClassFunction, Nothing} = nothing) +function iterate_basis_reynolds( + R::FinGroupInvarRing, d::Int, chi::Union{GAPGroupClassFunction,Nothing}=nothing +) @assert !is_modular(R) @assert d >= 0 "Degree must be non-negative" if chi !== nothing @@ -311,7 +317,11 @@ function iterate_basis_reynolds(R::FinGroupInvarRing, d::Int, chi::Union{GAPGrou N = zero_matrix(base_ring(polynomial_ring(R)), 0, 0) - return FinGroupInvarRingBasisIterator{typeof(R), typeof(reynolds), typeof(monomials), eltype(monomials), typeof(N)}(R, d, k, true, reynolds, monomials, Vector{eltype(monomials)}(), N) + return FinGroupInvarRingBasisIterator{ + typeof(R),typeof(reynolds),typeof(monomials),eltype(monomials),typeof(N) + }( + R, d, k, true, reynolds, monomials, Vector{eltype(monomials)}(), N + ) end # Sadly, we can't really do much iteratively here. @@ -325,7 +335,11 @@ function iterate_basis_linear_algebra(IR::FinGroupInvarRing, d::Int) N = zero_matrix(base_ring(R), 0, 0) mons = elem_type(R)[] dummy_mons = monomials_of_degree(R, 0) - return FinGroupInvarRingBasisIterator{typeof(IR), Nothing, typeof(dummy_mons), eltype(mons), typeof(N)}(IR, d, k, false, nothing, dummy_mons, mons, N) + return FinGroupInvarRingBasisIterator{ + typeof(IR),Nothing,typeof(dummy_mons),eltype(mons),typeof(N) + }( + IR, d, k, false, nothing, dummy_mons, mons, N + ) end mons_iterator = monomials_of_degree(R, d) @@ -333,10 +347,14 @@ function iterate_basis_linear_algebra(IR::FinGroupInvarRing, d::Int) if d == 0 N = identity_matrix(base_ring(R), 1) dummy_mons = monomials_of_degree(R, 0) - return FinGroupInvarRingBasisIterator{typeof(IR), Nothing, typeof(mons_iterator), eltype(mons), typeof(N)}(IR, d, k, false, nothing, mons_iterator, mons, N) + return FinGroupInvarRingBasisIterator{ + typeof(IR),Nothing,typeof(mons_iterator),eltype(mons),typeof(N) + }( + IR, d, k, false, nothing, mons_iterator, mons, N + ) end - mons_to_rows = Dict{elem_type(R), Int}(mons .=> 1:length(mons)) + mons_to_rows = Dict{elem_type(R),Int}(mons .=> 1:length(mons)) K = base_ring(R) @@ -344,15 +362,15 @@ function iterate_basis_linear_algebra(IR::FinGroupInvarRing, d::Int) M = sparse_matrix(K) M.c = length(mons) - M.r = length(group_gens)*length(mons) - for i = 1:M.r + M.r = length(group_gens) * length(mons) + for i in 1:(M.r) push!(M.rows, sparse_row(K)) end - for i = 1:length(group_gens) - offset = (i - 1)*length(mons) + for i in 1:length(group_gens) + offset = (i - 1) * length(mons) phi = right_action(R, group_gens[i]) - for j = 1:length(mons) + for j in 1:length(mons) f = mons[j] g = phi(f) - f for (c, m) in zip(AbstractAlgebra.coefficients(g), AbstractAlgebra.monomials(g)) @@ -363,9 +381,13 @@ function iterate_basis_linear_algebra(IR::FinGroupInvarRing, d::Int) end end end - N = kernel(M, side = :right) + N = kernel(M; side=:right) - return FinGroupInvarRingBasisIterator{typeof(IR), Nothing, typeof(mons_iterator), eltype(mons), typeof(N)}(IR, d, ncols(N), false, nothing, mons_iterator, mons, N) + return FinGroupInvarRingBasisIterator{ + typeof(IR),Nothing,typeof(mons_iterator),eltype(mons),typeof(N) + }( + IR, d, ncols(N), false, nothing, mons_iterator, mons, N + ) end Base.eltype(BI::FinGroupInvarRingBasisIterator) = elem_type(polynomial_ring(BI.R)) @@ -431,8 +453,8 @@ function iterate_reynolds(BI::FinGroupInvarRingBasisIterator) end # Cancelling the leading coefficient is not mathematically necessary and # should be done with the ordering that is used for the printing - g = inv(AbstractAlgebra.leading_coefficient(g))*g - B = BasisOfPolynomials(polynomial_ring(BI.R), [ g ]) + g = inv(AbstractAlgebra.leading_coefficient(g)) * g + B = BasisOfPolynomials(polynomial_ring(BI.R), [g]) return g, (B, state) end end @@ -466,7 +488,7 @@ function iterate_reynolds(BI::FinGroupInvarRingBasisIterator, state) if add_to_basis!(B, g) # Cancelling the leading coefficient is not mathematically necessary and # should be done with the ordering that is used for the printing - return inv(AbstractAlgebra.leading_coefficient(g))*g, (B, monomial_state) + return inv(AbstractAlgebra.leading_coefficient(g)) * g, (B, monomial_state) end end end @@ -479,18 +501,18 @@ function iterate_linear_algebra(BI::FinGroupInvarRingBasisIterator) f = polynomial_ring(BI.R)() N = BI.kernel - for i = 1:nrows(N) + for i in 1:nrows(N) if iszero(N[i, 1]) continue end - f += N[i, 1]*BI.monomials_collected[i] + f += N[i, 1] * BI.monomials_collected[i] end # Have to (should...) divide by the leading coefficient again: # The matrix was in echelon form, but the columns were not necessarily sorted # w.r.t. the monomial ordering. # Cancelling the leading coefficient is not mathematically necessary and # should be done with the ordering that is used for the printing - return inv(AbstractAlgebra.leading_coefficient(f))*f, 2 + return inv(AbstractAlgebra.leading_coefficient(f)) * f, 2 end function iterate_linear_algebra(BI::FinGroupInvarRingBasisIterator, state::Int) @@ -501,15 +523,15 @@ function iterate_linear_algebra(BI::FinGroupInvarRingBasisIterator, state::Int) f = polynomial_ring(BI.R)() N = BI.kernel - for i = 1:nrows(N) + for i in 1:nrows(N) if iszero(N[i, state]) continue end - f += N[i, state]*BI.monomials_collected[i] + f += N[i, state] * BI.monomials_collected[i] end # Cancelling the leading coefficient is not mathematically necessary and # should be done with the ordering that is used for the printing - return inv(AbstractAlgebra.leading_coefficient(f))*f, state + 1 + return inv(AbstractAlgebra.leading_coefficient(f)) * f, state + 1 end ################################################################################ @@ -518,15 +540,24 @@ end # ################################################################################ -function vector_space_iterator(K::FieldT, basis_iterator::IteratorT) where {FieldT <: Union{Nemo.fpField, Nemo.FpField, fqPolyRepField, FqPolyRepField, FqField}, IteratorT} +function vector_space_iterator( + K::FieldT, basis_iterator::IteratorT +) where { + FieldT<:Union{Nemo.fpField,Nemo.FpField,fqPolyRepField,FqPolyRepField,FqField},IteratorT +} return VectorSpaceIteratorFiniteField(K, basis_iterator) end -vector_space_iterator(K::FieldT, basis_iterator::IteratorT, bound::Int = 10^5) where {FieldT, IteratorT} = VectorSpaceIteratorRand(K, basis_iterator, bound) +vector_space_iterator( + K::FieldT, basis_iterator::IteratorT, bound::Int=10^5 +) where {FieldT,IteratorT} = VectorSpaceIteratorRand(K, basis_iterator, bound) -Base.eltype(VSI::VectorSpaceIterator{FieldT, IteratorT, ElemT}) where {FieldT, IteratorT, ElemT} = ElemT +Base.eltype( + VSI::VectorSpaceIterator{FieldT,IteratorT,ElemT} +) where {FieldT,IteratorT,ElemT} = ElemT -Base.length(VSI::VectorSpaceIteratorFiniteField) = BigInt(order(VSI.field))^length(VSI.basis_iterator) - 1 +Base.length(VSI::VectorSpaceIteratorFiniteField) = + BigInt(order(VSI.field))^length(VSI.basis_iterator) - 1 # The "generic" iterate for all subtypes of VectorSpaceIterator function _iterate(VSI::VectorSpaceIterator) @@ -538,11 +569,11 @@ function _iterate(VSI::VectorSpaceIterator) b = VSI.basis_collected[1] else b, s = iterate(VSI.basis_iterator) - VSI.basis_collected = [ b ] + VSI.basis_collected = [b] VSI.basis_iterator_state = s end phase = length(VSI.basis_iterator) != 1 ? 1 : 3 - return b, (2, Int[ 1, 2 ], phase) + return b, (2, Int[1, 2], phase) end Base.iterate(VSI::VectorSpaceIteratorRand) = _iterate(VSI) @@ -555,7 +586,7 @@ function Base.iterate(VSI::VectorSpaceIteratorFiniteField) b, state = _iterate(VSI) e, s = iterate(VSI.field) elts = fill(e, length(VSI.basis_iterator)) - states = [ deepcopy(s) for i = 1:length(VSI.basis_iterator) ] + states = [deepcopy(s) for i in 1:length(VSI.basis_iterator)] return b, (state..., elts, states) end @@ -584,17 +615,17 @@ function _iterate(VSI::VectorSpaceIterator, state) # Iterate all possible sums of basis elements @assert length(VSI.basis_iterator) > 1 s = state[2] - b = sum([ VSI.basis_collected[i] for i in s ]) + b = sum([VSI.basis_collected[i] for i in s]) expand = true if s[end] < length(VSI.basis_collected) s[end] += 1 expand = false else - for i = length(s) - 1:-1:1 + for i in (length(s) - 1):-1:1 if s[i] + 1 < s[i + 1] s[i] += 1 - for j = i + 1:length(s) + for j in (i + 1):length(s) s[j] = s[j - 1] + 1 end expand = false @@ -605,7 +636,7 @@ function _iterate(VSI::VectorSpaceIterator, state) if expand if length(s) < length(VSI.basis_collected) - s = collect(1:length(s) + 1) + s = collect(1:(length(s) + 1)) else phase = 3 end @@ -619,8 +650,9 @@ function Base.iterate(VSI::VectorSpaceIteratorRand, state) end # Phase 3: Random linear combinations - coeffs = rand(-VSI.rand_bound:VSI.rand_bound, length(VSI.basis_collected)) - return sum([ coeffs[i]*VSI.basis_collected[i] for i = 1:length(VSI.basis_collected) ]), (state[1], state[2], 3) + coeffs = rand((-VSI.rand_bound):(VSI.rand_bound), length(VSI.basis_collected)) + return sum([coeffs[i] * VSI.basis_collected[i] for i in 1:length(VSI.basis_collected)]), + (state[1], state[2], 3) end function Base.iterate(VSI::VectorSpaceIteratorFiniteField, state) @@ -647,7 +679,7 @@ function Base.iterate(VSI::VectorSpaceIteratorFiniteField, state) end a[j], b[j] = ab[1], ab[2] - if all( x -> iszero(x) || isone(x), a) + if all(x -> iszero(x) || isone(x), a) # We already visited this element in phase 2 return iterate(VSI, (state[1:3]..., a, b)) end @@ -676,19 +708,19 @@ end iterate_partitions(M::MSet) = MSetPartitions(M) -Base.eltype(MSP::MSetPartitions{T}) where T = Vector{MSet{T}} +Base.eltype(MSP::MSetPartitions{T}) where {T} = Vector{MSet{T}} function Base.iterate(MSP::MSetPartitions) if isempty(MSP.M) return nothing end - return [ MSP.M ], MSetPartitionsState(MSP) + return [MSP.M], MSetPartitionsState(MSP) end # This is basically Knu11, p. 429, Algorithm 7.2.1.5M # M2 - 6 in the comments correspond to the steps in the pseudocode -function Base.iterate(MSP::MSetPartitions{T}, state::MSetPartitionsState) where T +function Base.iterate(MSP::MSetPartitions{T}, state::MSetPartitionsState) where {T} c = state.c u = state.u v = state.v @@ -720,7 +752,7 @@ function Base.iterate(MSP::MSetPartitions{T}, state::MSetPartitionsState) where end end v[j] = v[j] - 1 - for k = j + 1:b - 1 + for k in (j + 1):(b - 1) v[k] = u[k] end @@ -730,7 +762,7 @@ function Base.iterate(MSP::MSetPartitions{T}, state::MSetPartitionsState) where k = b range_increased = false v_changed = false - for j = a:b - 1 + for j in a:(b - 1) u[k] = u[j] - v[j] if iszero(u[k]) v_changed = true @@ -758,9 +790,9 @@ function Base.iterate(MSP::MSetPartitions{T}, state::MSetPartitionsState) where # M4 part = Vector{typeof(MSP.M)}() - for j = 1:l + for j in 1:l N = MSet{T}() - for k = f[j]:f[j + 1] - 1 + for k in f[j]:(f[j + 1] - 1) if iszero(v[k]) continue end diff --git a/src/InvariantTheory/primary_invariants.jl b/src/InvariantTheory/primary_invariants.jl index 95df0f9447d4..ae0e2b9b9a3e 100644 --- a/src/InvariantTheory/primary_invariants.jl +++ b/src/InvariantTheory/primary_invariants.jl @@ -20,13 +20,21 @@ function test_primary_degrees_via_hilbert_series(R::FinGroupInvarRing, degrees:: return true end -function reduce_hilbert_series_by_primary_degrees(R::FinGroupInvarRing, chi::Union{GAPGroupClassFunction, Nothing} = nothing) - fl, h = _reduce_hilbert_series_by_primary_degrees(R, [ total_degree(forget_grading(f)) for f in primary_invariants(R) ], chi) +function reduce_hilbert_series_by_primary_degrees( + R::FinGroupInvarRing, chi::Union{GAPGroupClassFunction,Nothing}=nothing +) + fl, h = _reduce_hilbert_series_by_primary_degrees( + R, [total_degree(forget_grading(f)) for f in primary_invariants(R)], chi + ) @assert fl return h end -function _reduce_hilbert_series_by_primary_degrees(R::FinGroupInvarRing, degrees::Vector{Int}, chi::Union{GAPGroupClassFunction, Nothing} = nothing) +function _reduce_hilbert_series_by_primary_degrees( + R::FinGroupInvarRing, + degrees::Vector{Int}, + chi::Union{GAPGroupClassFunction,Nothing}=nothing, +) mol = molien_series(R, chi) f = numerator(mol) g = denominator(mol) @@ -40,15 +48,16 @@ end # Return possible degrees of primary invariants d_1, ..., d_n with # d_1 \cdots d_n == k*|G|, where G = group(R). # (Note that |G| must divide d_1 \cdots d_n, see DK15, Prop. 3.5.5.) -function candidates_primary_degrees(R::FinGroupInvarRing, k::Int, bad_prefixes::Vector{Vector{Int}} = Vector{Vector{Int}}()) - +function candidates_primary_degrees( + R::FinGroupInvarRing, k::Int, bad_prefixes::Vector{Vector{Int}}=Vector{Vector{Int}}() +) factors = MSet{Int}() - for n in [ k, order(group(R)) ] + for n in [k, order(group(R))] # If we can't factor the group order in reasonable time, we might as well # give up. fac = factor(n) for (p, e) in fac - for i = 1:e + for i in 1:e push!(factors, Int(p)) end end @@ -64,9 +73,9 @@ function candidates_primary_degrees(R::FinGroupInvarRing, k::Int, bad_prefixes:: continue end ds = ones(Int, n) - for i = 1:length(part) + for i in 1:length(part) for (p, e) in part[i].dict - ds[i + n - length(part)] *= p^e + ds[i + n - length(part)] *= p^e end end @@ -103,7 +112,7 @@ function candidates_primary_degrees(R::FinGroupInvarRing, k::Int, bad_prefixes:: push!(degrees, ds) end - sort!(degrees, lt = (x, y) -> sum(x) < sum(y) || x < y) + sort!(degrees; lt=(x, y) -> sum(x) < sum(y) || x < y) return degrees end @@ -112,12 +121,19 @@ end # RG/< invars, f_1, ..., f_k > has Krull dimension n - k, where n == length(invars). # If the base field is finite, the answer "true" might be wrong (for theoretical reasons). # See Kem99, Theorem 2. -function check_primary_degrees(RG::FinGroupInvarRing{FldT, GrpT, PolyRingElemT}, degrees::Vector{Int}, invars::Vector{PolyRingElemT}, k::Int, iters::Dict{Int, <: VectorSpaceIterator}, ideals::Dict{Set{PolyRingElemT}, Tuple{MPolyIdeal{PolyRingElemT}, Int}}) where {FldT, GrpT, PolyRingElemT} +function check_primary_degrees( + RG::FinGroupInvarRing{FldT,GrpT,PolyRingElemT}, + degrees::Vector{Int}, + invars::Vector{PolyRingElemT}, + k::Int, + iters::Dict{Int,<:VectorSpaceIterator}, + ideals::Dict{Set{PolyRingElemT},Tuple{MPolyIdeal{PolyRingElemT},Int}}, +) where {FldT,GrpT,PolyRingElemT} R = polynomial_ring(RG) n = length(degrees) - deg_dict = Dict{ZZRingElem, Int}() - for e in degrees[length(invars) + 1:length(invars) + k] + deg_dict = Dict{ZZRingElem,Int}() + for e in degrees[(length(invars) + 1):(length(invars) + k)] deg_dict[e] = get(deg_dict, e, 0) + 1 end for degs in Hecke.subsets(Set(keys(deg_dict))) @@ -141,14 +157,24 @@ function check_primary_degrees(RG::FinGroupInvarRing{FldT, GrpT, PolyRingElemT}, return true end -function _primary_invariants_via_optimal_hsop(RG::FinGroupInvarRing; ensure_minimality::Int = 0, degree_bound::Int = 1, primary_degrees::Vector{Int} = Int[]) - iters = Dict{Int, VectorSpaceIterator}() - ideals = Dict{Set{elem_type(polynomial_ring(RG))}, Tuple{MPolyIdeal{elem_type(polynomial_ring(RG))}, Int}}() +function _primary_invariants_via_optimal_hsop( + RG::FinGroupInvarRing; + ensure_minimality::Int=0, + degree_bound::Int=1, + primary_degrees::Vector{Int}=Int[], +) + iters = Dict{Int,VectorSpaceIterator}() + ideals = Dict{ + Set{elem_type(polynomial_ring(RG))}, + Tuple{MPolyIdeal{elem_type(polynomial_ring(RG))},Int}, + }() if !isempty(primary_degrees) @assert length(primary_degrees) == degree(group(RG)) invars_cache = PrimaryInvarsCache{elem_type(polynomial_ring(RG))}() - b, k = primary_invariants_via_optimal_hsop!(RG, primary_degrees, invars_cache, iters, ideals, ensure_minimality, 0) + b, k = primary_invariants_via_optimal_hsop!( + RG, primary_degrees, invars_cache, iters, ideals, ensure_minimality, 0 + ) if !b error("No primary invariants of the given degrees exist") end @@ -161,7 +187,9 @@ function _primary_invariants_via_optimal_hsop(RG::FinGroupInvarRing; ensure_mini degrees = candidates_primary_degrees(RG, l, bad_prefixes) for ds in degrees invars_cache = PrimaryInvarsCache{elem_type(polynomial_ring(RG))}() - b, k = primary_invariants_via_optimal_hsop!(RG, ds, invars_cache, iters, ideals, ensure_minimality, 0) + b, k = primary_invariants_via_optimal_hsop!( + RG, ds, invars_cache, iters, ideals, ensure_minimality, 0 + ) b && return invars_cache push!(bad_prefixes, ds[1:k]) end @@ -174,8 +202,15 @@ end # b == true iff primary invariants of the given degrees exist. In this case # invars_cache will contain those invariants. # k is only needed for recursive calls of the function. -function primary_invariants_via_optimal_hsop!(RG::FinGroupInvarRing{FldT, GrpT, PolyRingElemT}, degrees::Vector{Int}, invars_cache::PrimaryInvarsCache{PolyRingElemT}, iters::Dict{Int, <: VectorSpaceIterator}, ideals::Dict{Set{PolyRingElemT}, Tuple{MPolyIdeal{PolyRingElemT}, Int}}, ensure_minimality::Int = 0, k::Int = 0) where {FldT, GrpT, PolyRingElemT} - +function primary_invariants_via_optimal_hsop!( + RG::FinGroupInvarRing{FldT,GrpT,PolyRingElemT}, + degrees::Vector{Int}, + invars_cache::PrimaryInvarsCache{PolyRingElemT}, + iters::Dict{Int,<:VectorSpaceIterator}, + ideals::Dict{Set{PolyRingElemT},Tuple{MPolyIdeal{PolyRingElemT},Int}}, + ensure_minimality::Int=0, + k::Int=0, +) where {FldT,GrpT,PolyRingElemT} n = length(degrees) - length(invars_cache.invars) R = polynomial_ring(RG) @@ -202,7 +237,9 @@ function primary_invariants_via_optimal_hsop!(RG::FinGroupInvarRing{FldT, GrpT, continue end end - b, kk = primary_invariants_via_optimal_hsop!(RG, degrees, invars_cache, iters, ideals, ensure_minimality, max(0, k - 1)) + b, kk = primary_invariants_via_optimal_hsop!( + RG, degrees, invars_cache, iters, ideals, ensure_minimality, max(0, k - 1) + ) if b return true, 0 end @@ -292,9 +329,19 @@ julia> primary_invariants(IR, primary_degrees = [ 3, 6, 6 ]) ``` """ -function primary_invariants(RG::FinGroupInvarRing; ensure_minimality::Int = 0, degree_bound::Int = 1, primary_degrees::Vector{Int} = Int[]) +function primary_invariants( + RG::FinGroupInvarRing; + ensure_minimality::Int=0, + degree_bound::Int=1, + primary_degrees::Vector{Int}=Int[], +) if !isdefined(RG, :primary) - RG.primary = _primary_invariants_via_optimal_hsop(RG; ensure_minimality = ensure_minimality, degree_bound = degree_bound, primary_degrees = primary_degrees) + RG.primary = _primary_invariants_via_optimal_hsop( + RG; + ensure_minimality=ensure_minimality, + degree_bound=degree_bound, + primary_degrees=primary_degrees, + ) end return copy(RG.primary.invars) end diff --git a/src/InvariantTheory/secondary_invariants.jl b/src/InvariantTheory/secondary_invariants.jl index a20152519d3e..bf420252e564 100644 --- a/src/InvariantTheory/secondary_invariants.jl +++ b/src/InvariantTheory/secondary_invariants.jl @@ -1,4 +1,6 @@ -function add_invariant!(C::SecondaryInvarsCache{T}, f::T, isirred::Bool, exps::Vector{Int}) where T +function add_invariant!( + C::SecondaryInvarsCache{T}, f::T, isirred::Bool, exps::Vector{Int} +) where {T} push!(C.invars, f) push!(C.is_irreducible, isirred) if isirred @@ -25,19 +27,19 @@ function secondary_invariants_modular(RG::FinGroupInvarRing) R = forget_grading(Rgraded) K = coefficient_ring(R) - p_invars = elem_type(R)[ forget_grading(f) for f in primary_invariants(RG) ] + p_invars = elem_type(R)[forget_grading(f) for f in primary_invariants(RG)] - s_invars = elem_type(R)[ one(R) ] + s_invars = elem_type(R)[one(R)] s_invars_cache = SecondaryInvarsCache{elem_type(Rgraded)}() add_invariant!(s_invars_cache, one(Rgraded), false, Int[]) # The maximal degree in which we have to look for secondary invariants by [Sym11]. - maxdeg = sum( total_degree(f) - 1 for f in p_invars ) + maxdeg = sum(total_degree(f) - 1 for f in p_invars) # Store the secondary invariants sorted by their total degree. # We only store the indices in s_invars_cache.invars. s_invars_sorted = Vector{Vector{Int}}(undef, maxdeg) - for d = 1:maxdeg + for d in 1:maxdeg s_invars_sorted[d] = Int[] end @@ -46,7 +48,7 @@ function secondary_invariants_modular(RG::FinGroupInvarRing) is_invars = Vector{Int}() C = PowerProductCache(R, p_invars) - for d = 1:maxdeg + for d in 1:maxdeg Md = generators_for_given_degree!(C, s_invars, d, false)[1] # We have to find invariants of degree d which are not in the linear span of Md. @@ -57,7 +59,10 @@ function secondary_invariants_modular(RG::FinGroupInvarRing) # We need to reverse the columns of this matrix, see below. Bd = iterate_basis_linear_algebra(RG, d) ncB1 = length(Bd.monomials_collected) + 1 - mons_to_cols = Dict{Vector{Int}, Int}(first(AbstractAlgebra.exponent_vectors(forget_grading(Bd.monomials_collected[i]))) => ncB1 - i for i = 1:length(Bd.monomials_collected)) + mons_to_cols = Dict{Vector{Int},Int}( + first(AbstractAlgebra.exponent_vectors(forget_grading(Bd.monomials_collected[i]))) => + ncB1 - i for i in 1:length(Bd.monomials_collected) + ) B = BasisOfPolynomials(R, Md, mons_to_cols) # Do a slight detour and first try to build invariants as products of ones @@ -69,14 +74,14 @@ function secondary_invariants_modular(RG::FinGroupInvarRing) # i is an irreducible secondary invariant of degree < d and s a secondary # invariant of degree d - deg(i). products = Set{elem_type(R)}() - for i = 1:length(is_invars) + for i in 1:length(is_invars) f = forget_grading(s_invars_cache.invars[is_invars[i]]) @assert total_degree(f) < d dd = d - total_degree(f) for j in s_invars_sorted[dd] g = forget_grading(s_invars_cache.invars[j]) lp = length(products) - fg = f*g + fg = f * g push!(products, fg) if lp == length(products) # We already constructed this product from other factors. @@ -107,7 +112,7 @@ function secondary_invariants_modular(RG::FinGroupInvarRing) c = ncols(N) b = 1 - for r = nrows(N):-1:1 + for r in nrows(N):-1:1 if c < 1 break end @@ -128,17 +133,19 @@ function secondary_invariants_modular(RG::FinGroupInvarRing) end f = R() - for j = 1:nrows(N) + for j in 1:nrows(N) if iszero(N[j, c]) continue end - f += N[j, c]*forget_grading(Bd.monomials_collected[j]) + f += N[j, c] * forget_grading(Bd.monomials_collected[j]) end # Cancelling the leading coefficient is not mathematically necessary and # should be done with the ordering that is used for the printing - f = inv(AbstractAlgebra.leading_coefficient(f))*f + f = inv(AbstractAlgebra.leading_coefficient(f)) * f push!(s_invars, f) - add_invariant!(s_invars_cache, Rgraded(f), true, push!(zeros(Int, length(is_invars)), 1)) + add_invariant!( + s_invars_cache, Rgraded(f), true, push!(zeros(Int, length(is_invars)), 1) + ) push!(s_invars_sorted[total_degree(f)], length(s_invars_cache.invars)) push!(is_invars, length(s_invars_cache.invars)) c -= 1 @@ -160,10 +167,10 @@ function secondary_invariants_nonmodular(RG::FinGroupInvarRing) Rgraded = _internal_polynomial_ring(RG) R = forget_grading(Rgraded) - p_invars = [ _cast_in_internal_poly_ring(RG, f) for f in primary_invariants(RG) ] + p_invars = [_cast_in_internal_poly_ring(RG, f) for f in primary_invariants(RG)] I = ideal_of_primary_invariants(RG) - LI = leading_ideal(I, ordering = default_ordering(base_ring(I))) - gensLI = [ _cast_in_internal_poly_ring(RG, f) for f in gens(LI) ] + LI = leading_ideal(I; ordering=default_ordering(base_ring(I))) + gensLI = [_cast_in_internal_poly_ring(RG, f) for f in gens(LI)] h = reduce_hilbert_series_by_primary_degrees(RG) @@ -174,7 +181,7 @@ function secondary_invariants_nonmodular(RG::FinGroupInvarRing) # Store the secondary invariants sorted by their total degree. # We only store the indices in s_invars_cache.invars. s_invars_sorted = Vector{Vector{Int}}(undef, degree(h)) - for d = 1:degree(h) + for d in 1:degree(h) s_invars_sorted[d] = Int[] end @@ -183,9 +190,12 @@ function secondary_invariants_nonmodular(RG::FinGroupInvarRing) is_invars = Vector{Int}() # The Groebner basis should already be cached - gbI = [ forget_grading(_cast_in_internal_poly_ring(RG, f)) for f in groebner_basis(I, ordering = degrevlex(Rext)) ] + gbI = [ + forget_grading(_cast_in_internal_poly_ring(RG, f)) for + f in groebner_basis(I; ordering=degrevlex(Rext)) + ] - for d = 1:degree(h) + for d in 1:degree(h) k = coeff(h, d) # number of invariants we need in degree d if iszero(k) continue @@ -201,14 +211,14 @@ function secondary_invariants_nonmodular(RG::FinGroupInvarRing) # i is an irreducible secondary invariant of degree < d and s a secondary # invariant of degree d - deg(i). products = Set{elem_type(R)}() - for i = 1:length(is_invars) + for i in 1:length(is_invars) f = forget_grading(s_invars_cache.invars[is_invars[i]]) @assert total_degree(f) < d dd = d - total_degree(f) for j in s_invars_sorted[dd] g = forget_grading(s_invars_cache.invars[j]) lp = length(products) - fg = f*g + fg = f * g push!(products, fg) if lp == length(products) # We already constructed this product from other factors. @@ -249,14 +259,20 @@ function secondary_invariants_nonmodular(RG::FinGroupInvarRing) end skip && continue - f = forget_grading(_cast_in_internal_poly_ring(RG, reynolds_operator(RG, _cast_in_external_poly_ring(RG, m)))) + f = forget_grading( + _cast_in_internal_poly_ring( + RG, reynolds_operator(RG, _cast_in_external_poly_ring(RG, m)) + ), + ) if iszero(f) continue end _, r = divrem(f, gb) # via degrevlex if !is_zero(r) - f = inv(AbstractAlgebra.leading_coefficient(f))*f - add_invariant!(s_invars_cache, Rgraded(f), true, push!(zeros(Int, length(is_invars)), 1)) + f = inv(AbstractAlgebra.leading_coefficient(f)) * f + add_invariant!( + s_invars_cache, Rgraded(f), true, push!(zeros(Int, length(is_invars)), 1) + ) push!(s_invars_sorted[total_degree(f)], length(s_invars_cache.invars)) push!(is_invars, length(s_invars_cache.invars)) push!(gb, r) @@ -268,10 +284,10 @@ function secondary_invariants_nonmodular(RG::FinGroupInvarRing) if Rext !== Rgraded ext_cache = SecondaryInvarsCache{elem_type(Rext)}() - ext = [ _cast_in_external_poly_ring(RG, f) for f in s_invars_cache.invars ] + ext = [_cast_in_external_poly_ring(RG, f) for f in s_invars_cache.invars] # Cancelling the leading coefficient is not mathematically necessary and # should be done with the ordering that is used for the printing - ext_cache.invars = [ inv(AbstractAlgebra.leading_coefficient(f))*f for f in ext ] + ext_cache.invars = [inv(AbstractAlgebra.leading_coefficient(f)) * f for f in ext] ext_cache.is_irreducible = s_invars_cache.is_irreducible ext_cache.sec_in_irred = s_invars_cache.sec_in_irred s_invars_cache = ext_cache @@ -390,7 +406,7 @@ julia> irreducible_secondary_invariants(IR) function irreducible_secondary_invariants(IR::FinGroupInvarRing) _secondary_invariants(IR) is_invars = elem_type(polynomial_ring(IR))[] - for i = 1:length(IR.secondary.invars) + for i in 1:length(IR.secondary.invars) IR.secondary.is_irreducible[i] ? push!(is_invars, IR.secondary.invars[i]) : nothing end return is_invars @@ -442,7 +458,7 @@ function semi_invariants(RG::FinGroupInvarRing, chi::GAPGroupClassFunction) p_invars = primary_invariants(RG) I = ideal_of_primary_invariants(RG) - LI = leading_ideal(I, ordering = default_ordering(base_ring(I))) + LI = leading_ideal(I; ordering=default_ordering(base_ring(I))) h = reduce_hilbert_series_by_primary_degrees(RG, chi) @@ -455,7 +471,7 @@ function semi_invariants(RG::FinGroupInvarRing, chi::GAPGroupClassFunction) rey_op = reynolds_operator(RG, chi) - for d = 0:degree(h) + for d in 0:degree(h) k = coeff(h, d) # number of invariants we need in degree d if iszero(k) continue @@ -483,7 +499,7 @@ function semi_invariants(RG::FinGroupInvarRing, chi::GAPGroupClassFunction) if add_to_basis!(B, nf) # Cancelling the leading coefficient is not mathematically necessary and # should be done with the ordering that is used for the printing - f = inv(AbstractAlgebra.leading_coefficient(f))*f + f = inv(AbstractAlgebra.leading_coefficient(f)) * f push!(semi_invars, Rgraded(f)) invars_found += 1 invars_found == k && break @@ -494,4 +510,5 @@ function semi_invariants(RG::FinGroupInvarRing, chi::GAPGroupClassFunction) return semi_invars end -relative_invariants(RG::FinGroupInvarRing, chi::GAPGroupClassFunction) = semi_invariants(RG, chi) +relative_invariants(RG::FinGroupInvarRing, chi::GAPGroupClassFunction) = + semi_invariants(RG, chi) diff --git a/src/InvariantTheory/types.jl b/src/InvariantTheory/types.jl index fb94b1c63b24..3347886e2f61 100644 --- a/src/InvariantTheory/types.jl +++ b/src/InvariantTheory/types.jl @@ -2,7 +2,7 @@ mutable struct PrimaryInvarsCache{T} invars::Vector{T} # primary invariants ideal::MPolyIdeal{T} # ideal generated by the primary invariants - function PrimaryInvarsCache{T}() where {T <: MPolyRingElem} + function PrimaryInvarsCache{T}() where {T<:MPolyRingElem} z = new{T}() z.invars = T[] return z @@ -17,7 +17,7 @@ mutable struct SecondaryInvarsCache{T} # secondary invariants (hence length(sec_in_irred[i]) is equal to the number of # irreducible secondary invariants and not to length(invars)) - function SecondaryInvarsCache{T}() where {T <: MPolyRingElem} + function SecondaryInvarsCache{T}() where {T<:MPolyRingElem} z = new{T}() z.invars = T[] z.is_irreducible = BitVector() @@ -26,7 +26,7 @@ mutable struct SecondaryInvarsCache{T} end end -mutable struct FundamentalInvarsCache{PolyRingElemT, PolyRingT} +mutable struct FundamentalInvarsCache{PolyRingElemT,PolyRingT} invars::Vector{PolyRingElemT} # fundamental invariants # Graded polynomial ring in length(invars) variables such that @@ -40,16 +40,18 @@ mutable struct FundamentalInvarsCache{PolyRingElemT, PolyRingT} # For a primary or irreducible secondary invariant f, toS[f] gives the # representation of f as a polynomial in the fundamental invariants. # This field is only set, if via_primary_and_secondary is true. - toS::Dict{PolyRingElemT, PolyRingElemT} + toS::Dict{PolyRingElemT,PolyRingElemT} - function FundamentalInvarsCache{PolyRingElemT, PolyRingT}() where {PolyRingElemT <: MPolyRingElem, PolyRingT <: MPolyRing} - z = new{PolyRingElemT, PolyRingT}() + function FundamentalInvarsCache{ + PolyRingElemT,PolyRingT + }() where {PolyRingElemT<:MPolyRingElem,PolyRingT<:MPolyRing} + z = new{PolyRingElemT,PolyRingT}() z.invars = PolyRingElemT[] return z end end -mutable struct FinGroupInvarRing{FldT, GrpT, PolyRingElemT, PolyRingT, ActionT} +mutable struct FinGroupInvarRing{FldT,GrpT,PolyRingElemT,PolyRingT,ActionT} field::FldT poly_ring::PolyRingT @@ -67,28 +69,32 @@ mutable struct FinGroupInvarRing{FldT, GrpT, PolyRingElemT, PolyRingT, ActionT} primary::PrimaryInvarsCache{PolyRingElemT} secondary::SecondaryInvarsCache{PolyRingElemT} - fundamental::FundamentalInvarsCache{PolyRingElemT, PolyRingT} + fundamental::FundamentalInvarsCache{PolyRingElemT,PolyRingT} - presentation::MPolyAnyMap{MPolyQuoRing{PolyRingElemT}, PolyRingT, Nothing, PolyRingElemT} + presentation::MPolyAnyMap{MPolyQuoRing{PolyRingElemT},PolyRingT,Nothing,PolyRingElemT} - reynolds_operator::MapFromFunc{PolyRingT, PolyRingT} + reynolds_operator::MapFromFunc{PolyRingT,PolyRingT} molien_series::Generic.FracFieldElem{QQPolyRingElem} - function FinGroupInvarRing(K::FldT, G::GrpT, action::Vector{ActionT}) where {FldT <: Field, GrpT <: AbstractAlgebra.Group, ActionT} + function FinGroupInvarRing( + K::FldT, G::GrpT, action::Vector{ActionT} + ) where {FldT<:Field,GrpT<:AbstractAlgebra.Group,ActionT} n = degree(G) # We want to use divrem w.r.t. degrevlex for the computation of secondary # invariants and fundamental invariants - R, = graded_polynomial_ring(K, "x" => 1:n, cached = false, internal_ordering = :degrevlex) + R, = graded_polynomial_ring(K, "x" => 1:n; cached=false, internal_ordering=:degrevlex) return FinGroupInvarRing(K, G, action, R) end - function FinGroupInvarRing(K::FldT, G::GrpT, action::Vector{ActionT}, poly_ring::PolyRingT) where {FldT <: Field, GrpT <: AbstractAlgebra.Group, ActionT, PolyRingT <: MPolyDecRing} + function FinGroupInvarRing( + K::FldT, G::GrpT, action::Vector{ActionT}, poly_ring::PolyRingT + ) where {FldT<:Field,GrpT<:AbstractAlgebra.Group,ActionT,PolyRingT<:MPolyDecRing} @assert coefficient_ring(poly_ring) === K @assert ngens(poly_ring) == degree(G) PolyRingElemT = elem_type(poly_ring) - z = new{FldT, GrpT, PolyRingElemT, PolyRingT, ActionT}() + z = new{FldT,GrpT,PolyRingElemT,PolyRingT,ActionT}() z.field = K z.poly_ring = poly_ring z.group = G @@ -105,7 +111,9 @@ mutable struct FinGroupInvarRing{FldT, GrpT, PolyRingElemT, PolyRingT, ActionT} # We want to use divrem w.r.t. degrevlex for the computation of secondary # invariants and fundamental invariants if internal_ordering(poly_ring) != :degrevlex - z.poly_ring_internal, _ = graded_polynomial_ring(K, ngens(poly_ring), cached = false, internal_ordering = :degrevlex) + z.poly_ring_internal, _ = graded_polynomial_ring( + K, ngens(poly_ring); cached=false, internal_ordering=:degrevlex + ) end return z @@ -123,16 +131,18 @@ struct AllMonomials{PolyRingT} used_vars::Vector{Int} # indices of the variables we work on tmp::Vector{Int} # of length ngens(R), should be put back to zero after use - function AllMonomials{PolyRingT}(R::PolyRingT, d::Int) where PolyRingT + function AllMonomials{PolyRingT}(R::PolyRingT, d::Int) where {PolyRingT} @assert d >= 0 return new{PolyRingT}(R, d, weak_compositions(d, ngens(R)), true, ngens(R)) end - function AllMonomials{PolyRingT}(R::PolyRingT, d::Int, vars::Vector{Int}) where PolyRingT + function AllMonomials{PolyRingT}( + R::PolyRingT, d::Int, vars::Vector{Int} + ) where {PolyRingT} @assert d >= 0 vars = sort!(unique(vars)) - @assert minimum(vars, init = 1) >= 1 - @assert maximum(vars, init = 1) <= nvars(R) + @assert minimum(vars; init=1) >= 1 + @assert maximum(vars; init=1) <= nvars(R) n_vars = length(vars) if n_vars == ngens(R) return AllMonomials{PolyRingT}(R, d) @@ -143,7 +153,9 @@ struct AllMonomials{PolyRingT} end end -struct FinGroupInvarRingBasisIterator{FinGroupInvarRingT, ReynoldsT, IteratorT, PolyRingElemT, MatrixT} +struct FinGroupInvarRingBasisIterator{ + FinGroupInvarRingT,ReynoldsT,IteratorT,PolyRingElemT,MatrixT +} R::FinGroupInvarRingT degree::Int dim::Int @@ -158,7 +170,7 @@ struct FinGroupInvarRingBasisIterator{FinGroupInvarRingT, ReynoldsT, IteratorT, kernel::MatrixT # used iff reynolds == false end -abstract type VectorSpaceIterator{FieldT, IteratorT, ElemT} end +abstract type VectorSpaceIterator{FieldT,IteratorT,ElemT} end # This takes a basis of a vector space as an iterator and then "iterates" the # space in three "phases": @@ -173,16 +185,19 @@ abstract type VectorSpaceIterator{FieldT, IteratorT, ElemT} end # must always be a state of basis_iterator, so that # iterate(basis_iterator, basis_iterator_state) returns the next element in the # basis coming after basis_collected[end]. -mutable struct VectorSpaceIteratorRand{FieldT, IteratorT, ElemT} <: VectorSpaceIterator{FieldT, IteratorT, ElemT} +mutable struct VectorSpaceIteratorRand{FieldT,IteratorT,ElemT} <: + VectorSpaceIterator{FieldT,IteratorT,ElemT} field::FieldT basis_iterator::IteratorT basis_collected::Vector{ElemT} basis_iterator_state::Any # I don't know the type of this and I don't think there - # is a "type-stable" way of finding it out + # is a "type-stable" way of finding it out rand_bound::Int - function VectorSpaceIteratorRand(K::FieldT, basis_iterator::IteratorT, bound::Int = 10^5) where {FieldT, IteratorT} - VSI = new{FieldT, IteratorT, eltype(basis_iterator)}() + function VectorSpaceIteratorRand( + K::FieldT, basis_iterator::IteratorT, bound::Int=10^5 + ) where {FieldT,IteratorT} + VSI = new{FieldT,IteratorT,eltype(basis_iterator)}() VSI.field = K VSI.basis_iterator = basis_iterator VSI.basis_collected = eltype(basis_iterator)[] @@ -194,15 +209,20 @@ end # The same things as for VectorSpaceIteratorRand apply besides that in "phase 3" # all elements of the vector space are iterated in deterministic order (it is # supposed to be finite after all). -mutable struct VectorSpaceIteratorFiniteField{FieldT, IteratorT, ElemT} <: VectorSpaceIterator{FieldT, IteratorT, ElemT} +mutable struct VectorSpaceIteratorFiniteField{FieldT,IteratorT,ElemT} <: + VectorSpaceIterator{FieldT,IteratorT,ElemT} field::FieldT basis_iterator::IteratorT basis_collected::Vector{ElemT} basis_iterator_state::Any # I don't know the type of this and I don't think there - # is a "type-stable" way of finding it out - - function VectorSpaceIteratorFiniteField(K::FieldT, basis_iterator::IteratorT) where {FieldT <: Union{Nemo.fpField, Nemo.FpField, fqPolyRepField, FqPolyRepField, FqField}, IteratorT} - VSI = new{FieldT, IteratorT, eltype(basis_iterator)}() + # is a "type-stable" way of finding it out + + function VectorSpaceIteratorFiniteField( + K::FieldT, basis_iterator::IteratorT + ) where { + FieldT<:Union{Nemo.fpField,Nemo.FpField,fqPolyRepField,FqPolyRepField,FqField},IteratorT + } + VSI = new{FieldT,IteratorT,eltype(basis_iterator)}() VSI.field = K VSI.basis_iterator = basis_iterator VSI.basis_collected = eltype(basis_iterator)[] @@ -213,12 +233,12 @@ end struct MSetPartitions{T} M::MSet{T} num_to_key::Vector{Int} - key_to_num::Dict{T, Int} + key_to_num::Dict{T,Int} - function MSetPartitions(M::MSet{T}) where T + function MSetPartitions(M::MSet{T}) where {T} num_to_key = collect(keys(M.dict)) - key_to_num = Dict{T, Int}() - for i = 1:length(num_to_key) + key_to_num = Dict{T,Int}() + for i in 1:length(num_to_key) key_to_num[num_to_key[i]] = i end return new{T}(M, num_to_key, key_to_num) @@ -238,11 +258,11 @@ mutable struct MSetPartitionsState m = length(MSP.num_to_key) n = length(MSP.M) f = zeros(Int, n + 1) - c = zeros(Int, n*m + 1) - u = zeros(Int, n*m + 1) - v = zeros(Int, n*m + 1) + c = zeros(Int, n * m + 1) + u = zeros(Int, n * m + 1) + v = zeros(Int, n * m + 1) - for j = 1:m + for j in 1:m c[j] = j u[j] = MSP.M.dict[MSP.num_to_key[j]] v[j] = MSP.M.dict[MSP.num_to_key[j]] @@ -259,11 +279,11 @@ end # Handle vector spaces of multivariate polynomials by writing them in the basis # of the monomials. -mutable struct BasisOfPolynomials{PolyRingT, FieldElemT} +mutable struct BasisOfPolynomials{PolyRingT,FieldElemT} R::PolyRingT # Number the basis monomials, we identify a monomial with its exponent vector - monomial_to_column::Dict{Vector{Int}, Int} + monomial_to_column::Dict{Vector{Int},Int} # Write the polynomials coefficient-wise in the rows of a sparse matrix. The # column i contains the coefficients corresponding to the monomial m with @@ -272,30 +292,34 @@ mutable struct BasisOfPolynomials{PolyRingT, FieldElemT} function BasisOfPolynomials(R::MPolyRing) K = coefficient_ring(R) - B = new{typeof(R), elem_type(K)}() + B = new{typeof(R),elem_type(K)}() B.R = R - B.monomial_to_column = Dict{Vector{Int}, Int}() + B.monomial_to_column = Dict{Vector{Int},Int}() B.M = sparse_matrix(K) return B end - function BasisOfPolynomials(R::PolyRingT, polys::Vector{<: MPolyRingElem}) where {PolyRingT <: MPolyRing} + function BasisOfPolynomials( + R::PolyRingT, polys::Vector{<:MPolyRingElem} + ) where {PolyRingT<:MPolyRing} return BasisOfPolynomials(R, polys, enumerate_monomials(polys)) end - function BasisOfPolynomials(R::PolyRingT, polys::Vector{<: MPolyRingElem}, monomial_to_column::Dict{Vector{Int}, Int}) where {PolyRingT <: MPolyRing} + function BasisOfPolynomials( + R::PolyRingT, polys::Vector{<:MPolyRingElem}, monomial_to_column::Dict{Vector{Int},Int} + ) where {PolyRingT<:MPolyRing} if isempty(polys) return BasisOfPolynomials(R) end K = coefficient_ring(R) - B = new{typeof(R), elem_type(K)}() + B = new{typeof(R),elem_type(K)}() B.R = R B.monomial_to_column = monomial_to_column - M = polys_to_smat(polys, monomial_to_column, copy = true) - rref!(M, truncate = true) + M = polys_to_smat(polys, monomial_to_column; copy=true) + rref!(M; truncate=true) B.M = M return B @@ -303,29 +327,31 @@ mutable struct BasisOfPolynomials{PolyRingT, FieldElemT} end # Cache power products (= monomials) of elements in `base` of certain degrees. -mutable struct PowerProductCache{RingType, T} +mutable struct PowerProductCache{RingType,T} # The base ring (needed for empty `base`) ring::RingType base::Vector{T} # Store all power products of degree d - power_products::Dict{Int, Vector{T}} + power_products::Dict{Int,Vector{T}} # The exponent vector of a power product w.r.t. `base` - exponent_vectors::Dict{T, Vector{Int}} + exponent_vectors::Dict{T,Vector{Int}} # Whether the exponent vectors for a certain degree were computed - exponent_vectors_known::Dict{Int, Bool} + exponent_vectors_known::Dict{Int,Bool} # The last entry of `base` involved in the power product - last_factor::Dict{T, Int} - - function PowerProductCache(R::S, base::Vector{T}) where {S <: Ring, T <: RingElem} - power_products = Dict{Int, Vector{T}}() - exponent_vectors = Dict{T, Vector{Int}}() - exponent_vectors_known = Dict{Int, Bool}() - last_factor = Dict{T, Int}() - return new{typeof(R), T}(R, copy(base), power_products, exponent_vectors, exponent_vectors_known, last_factor) + last_factor::Dict{T,Int} + + function PowerProductCache(R::S, base::Vector{T}) where {S<:Ring,T<:RingElem} + power_products = Dict{Int,Vector{T}}() + exponent_vectors = Dict{T,Vector{Int}}() + exponent_vectors_known = Dict{Int,Bool}() + last_factor = Dict{T,Int}() + return new{typeof(R),T}( + R, copy(base), power_products, exponent_vectors, exponent_vectors_known, last_factor + ) end end diff --git a/test/InvariantTheory/affine_algebra.jl b/test/InvariantTheory/affine_algebra.jl index fe5ddc4e50a9..6db8e1c00005 100644 --- a/test/InvariantTheory/affine_algebra.jl +++ b/test/InvariantTheory/affine_algebra.jl @@ -1,43 +1,45 @@ @testset "Presentation as affine algebra" begin K, a = cyclotomic_field(3, "a") - M1 = matrix(K, 3, 3, [ 0, 1, 0, 0, 0, 1, 1, 0, 0 ]) - M2 = matrix(K, 3, 3, [ 1, 0, 0, 0, a, 0, 0, 0, -a - 1 ]) + M1 = matrix(K, 3, 3, [0, 1, 0, 0, 0, 1, 1, 0, 0]) + M2 = matrix(K, 3, 3, [1, 0, 0, 0, a, 0, 0, 0, -a - 1]) RG = invariant_ring(M1, M2) A, AtoR = affine_algebra(RG) - @test [ AtoR(x) for x in gens(A) ] == fundamental_invariants(RG) + @test [AtoR(x) for x in gens(A)] == fundamental_invariants(RG) @test is_injective(AtoR) RG = invariant_ring(M1, M2) - A, AtoR = affine_algebra(RG, algo_rels = :linear_algebra) - @test [ AtoR(x) for x in gens(A) ] == fundamental_invariants(RG) + A, AtoR = affine_algebra(RG; algo_rels=:linear_algebra) + @test [AtoR(x) for x in gens(A)] == fundamental_invariants(RG) @test is_injective(AtoR) # [KS99, Example 17.7] K, a = cyclotomic_field(3, "a") - M = matrix(K, 2, 2, [ a, 0, 0, a ]) - for algo in [ :groebner_basis, :linear_algebra ] + M = matrix(K, 2, 2, [a, 0, 0, a]) + for algo in [:groebner_basis, :linear_algebra] RG = invariant_ring(M) - A, AtoR = affine_algebra(RG, algo_rels = algo) + A, AtoR = affine_algebra(RG; algo_rels=algo) R = polynomial_ring(RG).R x = gens(R) # Compute the preimages of the primary and irreducible secondary invariants in # KS99 under AtoR - fs = [ x[1]^3, x[2]^3, x[1]*x[2]^2, x[1]^2*x[2] ] + fs = [x[1]^3, x[2]^3, x[1] * x[2]^2, x[1]^2 * x[2]] S = base_ring(A) y = gens(S) Fs = elem_type(S)[] for f in fs - q, r = divrem(f, [ g.f for g in fundamental_invariants(RG) ]) + q, r = divrem(f, [g.f for g in fundamental_invariants(RG)]) @test is_zero(r) @test all(g -> total_degree(g) <= 0, q) - push!(Fs, sum([ q[i]([ K(1), K(1) ]...)*y[i] for i = 1:length(y) ])) + push!(Fs, sum([q[i]([K(1), K(1)]...) * y[i] for i in 1:length(y)])) end - I = ideal(S, [ Fs[3]^2 - Fs[2]*Fs[4], Fs[4]^2 - Fs[1]*Fs[3], Fs[3]*Fs[4] - Fs[1]*Fs[2] ]) + I = ideal( + S, [Fs[3]^2 - Fs[2] * Fs[4], Fs[4]^2 - Fs[1] * Fs[3], Fs[3] * Fs[4] - Fs[1] * Fs[2]] + ) J = modulus(A) @test I == J end @@ -45,37 +47,37 @@ # S_4 as matrix group M1 = matrix(QQ, 4, 4, [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0]) M2 = matrix(QQ, 4, 4, [0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]) - for algo in [ :groebner_basis, :linear_algebra ] + for algo in [:groebner_basis, :linear_algebra] RG = invariant_ring(M1, M2) - A, = affine_algebra(RG, algo_rels = algo) + A, = affine_algebra(RG; algo_rels=algo) @test is_zero(modulus(A)) end # S_4 as permutation group - for algo in [ :groebner_basis, :linear_algebra ] + for algo in [:groebner_basis, :linear_algebra] RG = invariant_ring(symmetric_group(4)) - A, = affine_algebra(RG, algo_rels = algo) + A, = affine_algebra(RG; algo_rels=algo) @test is_zero(modulus(A)) end # Example of an invariant ring which is not Cohen--Macaulay, see Kemper, # "Calculating invariant rings of finite groups over arbitrary fields", # Example 10. - G = permutation_group(4, [ cperm([1, 2, 3, 4]) ]) + G = permutation_group(4, [cperm([1, 2, 3, 4])]) RG = invariant_ring(GF(2), G) - A, AtoR = affine_algebra(RG, algo_rels = :groebner_basis) - @test [ AtoR(x) for x in gens(A) ] == fundamental_invariants(RG) + A, AtoR = affine_algebra(RG; algo_rels=:groebner_basis) + @test [AtoR(x) for x in gens(A)] == fundamental_invariants(RG) @test is_injective(AtoR) RG = invariant_ring(GF(2), G) - A, AtoR = affine_algebra(RG, algo_rels = :linear_algebra) - @test [ AtoR(x) for x in gens(A) ] == fundamental_invariants(RG) + A, AtoR = affine_algebra(RG; algo_rels=:linear_algebra) + @test [AtoR(x) for x in gens(A)] == fundamental_invariants(RG) @test is_injective(AtoR) end @testset "Module syzygies" begin - G = permutation_group(4, [ cperm([1, 2, 3, 4]) ]) - for K in [ QQ, GF(2), GF(3) ] + G = permutation_group(4, [cperm([1, 2, 3, 4])]) + for K in [QQ, GF(2), GF(3)] RG = invariant_ring(K, G) p_invars = primary_invariants(RG) s_invars = secondary_invariants(RG) @@ -108,14 +110,21 @@ end # Another example of a ring which is not Cohen--Macaulay, # see DK15, Example 3.6.3. - for p in [ 2, 3, 5 ] # works for an arbitrary prime + for p in [2, 3, 5] # works for an arbitrary prime K = GF(p) - M = matrix(K, 6, 6, [ 1 0 0 0 0 0 ; - 0 1 0 0 0 0 ; - 0 0 1 0 0 0 ; - 1 0 0 1 0 0 ; - 0 1 0 0 1 0 ; - 0 0 1 0 0 1 ]) + M = matrix( + K, + 6, + 6, + [ + 1 0 0 0 0 0 + 0 1 0 0 0 0 + 0 0 1 0 0 0 + 1 0 0 1 0 0 + 0 1 0 0 1 0 + 0 0 1 0 0 1 + ], + ) RG = invariant_ring(matrix_group(M)) p_invars = primary_invariants(RG) s_invars = secondary_invariants(RG) diff --git a/test/InvariantTheory/fundamental_invariants.jl b/test/InvariantTheory/fundamental_invariants.jl index 609c8ea57a53..87343d93441e 100644 --- a/test/InvariantTheory/fundamental_invariants.jl +++ b/test/InvariantTheory/fundamental_invariants.jl @@ -2,20 +2,20 @@ # Char 0 K, a = cyclotomic_field(3, "a") # Force use of internal polynomial_ring with internal_ordering = :lex - R, _ = graded_polynomial_ring(K, 3, internal_ordering = :lex) - M1 = matrix(K, 3, 3, [ 0, 1, 0, 0, 0, 1, 1, 0, 0 ]) - M2 = matrix(K, 3, 3, [ 1, 0, 0, 0, a, 0, 0, 0, -a - 1 ]) + R, _ = graded_polynomial_ring(K, 3; internal_ordering=:lex) + M1 = matrix(K, 3, 3, [0, 1, 0, 0, 0, 1, 1, 0, 0]) + M2 = matrix(K, 3, 3, [1, 0, 0, 0, a, 0, 0, 0, -a - 1]) RG0 = invariant_ring(R, matrix_group(M1, M2)) # Call it once without specifying `algo` @test length(fundamental_invariants(RG0)) == 4 - for algo in [ :king, :primary_and_secondary ] + for algo in [:king, :primary_and_secondary] RG = invariant_ring(M1, M2) # redefine to avoid caching invars = fundamental_invariants(RG, algo) @test length(invars) == 4 - @test [ total_degree(f.f) for f in invars ] == [ 3, 3, 6, 9 ] + @test [total_degree(f.f) for f in invars] == [3, 3, 6, 9] for f in invars @test reynolds_operator(RG, f) == f end @@ -23,9 +23,9 @@ # Let's test whether invars are algebra generators for the degree 9 homogeneous # component. R = polynomial_ring(RG).R - C = Oscar.PowerProductCache(R, [ f.f for f in invars ]) + C = Oscar.PowerProductCache(R, [f.f for f in invars]) B = Oscar.BasisOfPolynomials(R, Oscar.all_power_products_of_degree!(C, 9, false)) - b2 = [ f.f for f in basis(RG, 9) ] + b2 = [f.f for f in basis(RG, 9)] for f in b2 @test !Oscar.add_to_basis!(B, f) end @@ -33,15 +33,15 @@ # Char p, non-modular F = GF(3) - N1 = matrix(F, 3, 3, [ 0, 1, 0, 2, 0, 0, 0, 0, 2 ]) - N2 = matrix(F, 3, 3, [ 2, 0, 0, 0, 2, 0, 0, 0, 2 ]) + N1 = matrix(F, 3, 3, [0, 1, 0, 2, 0, 0, 0, 0, 2]) + N2 = matrix(F, 3, 3, [2, 0, 0, 0, 2, 0, 0, 0, 2]) - for algo in [ :king, :primary_and_secondary ] + for algo in [:king, :primary_and_secondary] RG = invariant_ring(N1, N2) # redefine to avoid caching invars = fundamental_invariants(RG, algo) @test length(invars) == 4 - @test [ total_degree(f.f) for f in invars ] == [ 2, 2, 4, 4 ] + @test [total_degree(f.f) for f in invars] == [2, 2, 4, 4] for f in invars @test reynolds_operator(RG, f) == f end @@ -49,9 +49,9 @@ # Let's test whether invars are algebra generators for the degree 6 homogeneous # component. R = polynomial_ring(RG).R - C = Oscar.PowerProductCache(R, [ f.f for f in invars ]) + C = Oscar.PowerProductCache(R, [f.f for f in invars]) B = Oscar.BasisOfPolynomials(R, Oscar.all_power_products_of_degree!(C, 6, false)) - b2 = [ f.f for f in basis(RG, 6) ] + b2 = [f.f for f in basis(RG, 6)] for f in b2 @test !Oscar.add_to_basis!(B, f) end @@ -59,15 +59,15 @@ # Char p, modular F9, b = finite_field(3, 2, "b") - N3 = matrix(F9, [ 1 0 0 0; b + 1 1 0 0; -1 0 1 0; b 0 -1 1 ]) - N4 = matrix(F9, [ 1 0 0 0; 1 1 0 0; 1 0 1 0; b -b b 1 ]) + N3 = matrix(F9, [1 0 0 0; b+1 1 0 0; -1 0 1 0; b 0 -1 1]) + N4 = matrix(F9, [1 0 0 0; 1 1 0 0; 1 0 1 0; b -b b 1]) RGm = invariant_ring(N3, N4) @test_throws AssertionError fundamental_invariants(RGm, :king) invars = fundamental_invariants(RGm) @test length(invars) == 6 - @test [ total_degree(f.f) for f in invars ] == [ 1, 2, 3, 3, 4, 9 ] + @test [total_degree(f.f) for f in invars] == [1, 2, 3, 3, 4, 9] actionN3 = Oscar.right_action(polynomial_ring(RGm), N3) actionN4 = Oscar.right_action(polynomial_ring(RGm), N4) @@ -79,56 +79,56 @@ # Let's test whether invars are algebra generators for the degree 6 homogeneous # component. R = polynomial_ring(RGm).R - C = Oscar.PowerProductCache(R, [ f.f for f in invars ]) + C = Oscar.PowerProductCache(R, [f.f for f in invars]) B = Oscar.BasisOfPolynomials(R, Oscar.all_power_products_of_degree!(C, 6, false)) - b2 = [ f.f for f in basis(RGm, 6) ] + b2 = [f.f for f in basis(RGm, 6)] for f in b2 @test !Oscar.add_to_basis!(B, f) end # Test some special cases # Cyclic group in King's algorithm - M = matrix(QQ, [ 0 1 ; 1 0 ]) + M = matrix(QQ, [0 1; 1 0]) RG = invariant_ring(M) invars = fundamental_invariants(RG, :king) @test length(invars) == 2 - @test [ total_degree(f.f) for f in invars ] == [ 1, 2 ] + @test [total_degree(f.f) for f in invars] == [1, 2] for f in invars @test reynolds_operator(RG, f) == f end # Specify degree bound K, a = cyclotomic_field(3, "a") - M1 = matrix(K, 3, 3, [ 0, 1, 0, 1, 0, 0, 0, 0, 1 ]) - M2 = matrix(K, 3, 3, [ 1, 0, 0, 0, a, 0, 0, 0, -a - 1 ]) + M1 = matrix(K, 3, 3, [0, 1, 0, 1, 0, 0, 0, 0, 1]) + M2 = matrix(K, 3, 3, [1, 0, 0, 0, a, 0, 0, 0, -a - 1]) invars1 = fundamental_invariants(invariant_ring(M1, M2)) - invars2 = fundamental_invariants(invariant_ring(M1, M2), beta = 6) + invars2 = fundamental_invariants(invariant_ring(M1, M2); beta=6) - @test [ f(gens(parent(invars1[1]))...) for f in invars2 ] == invars1 + @test [f(gens(parent(invars1[1]))...) for f in invars2] == invars1 # No irreducible secondary invariants - M = matrix(QQ, [ 0 1 ; 1 0 ]) + M = matrix(QQ, [0 1; 1 0]) RG = invariant_ring(M) invars = fundamental_invariants(RG, :primary_and_secondary) @test length(invars) == 2 - @test [ total_degree(f.f) for f in invars ] == [ 1, 2 ] + @test [total_degree(f.f) for f in invars] == [1, 2] for f in invars @test reynolds_operator(RG, f) == f end # `:primary_and_secondary` actually removes invariants K, a = cyclotomic_field(3, "a") - M1 = matrix(K, 3, 3, [ 0, 1, 0, 1, 0, 0, 0, 0, 1 ]) - M2 = matrix(K, 3, 3, [ 1, 0, 0, 0, a, 0, 0, 0, -a - 1 ]) + M1 = matrix(K, 3, 3, [0, 1, 0, 1, 0, 0, 0, 0, 1]) + M2 = matrix(K, 3, 3, [1, 0, 0, 0, a, 0, 0, 0, -a - 1]) RG = invariant_ring(M1, M2) - primary_invariants(RG, primary_degrees = [ 3, 6, 6 ]) + primary_invariants(RG; primary_degrees=[3, 6, 6]) invars = fundamental_invariants(RG, :primary_and_secondary) - @test [ total_degree(f.f) for f in invars ] == [ 3, 3, 3, 6 ] + @test [total_degree(f.f) for f in invars] == [3, 3, 3, 6] S = RG.fundamental.S RtoS = RG.fundamental.toS @@ -143,12 +143,12 @@ end G = sylow_subgroup(symmetric_group(6), 2)[1] # Char 0 - for algo in [ :king, :primary_and_secondary ] + for algo in [:king, :primary_and_secondary] RG = invariant_ring(G) # redefine to avoid caching invars = fundamental_invariants(RG, algo) @test length(invars) == 7 - @test [ total_degree(f.f) for f in invars ] == [ 1, 1, 2, 2, 2, 3, 4 ] + @test [total_degree(f.f) for f in invars] == [1, 1, 2, 2, 2, 3, 4] for f in invars @test reynolds_operator(RG, f) == f end @@ -156,21 +156,21 @@ end # Let's test whether invars are algebra generators for the degree 9 homogeneous # component. R = polynomial_ring(RG).R - C = Oscar.PowerProductCache(R, [ f.f for f in invars ]) + C = Oscar.PowerProductCache(R, [f.f for f in invars]) B = Oscar.BasisOfPolynomials(R, Oscar.all_power_products_of_degree!(C, 9, false)) - b2 = [ f.f for f in basis(RG, 9) ] + b2 = [f.f for f in basis(RG, 9)] for f in b2 @test !Oscar.add_to_basis!(B, f) end end # Char p, non-modular - for algo in [ :king, :primary_and_secondary ] + for algo in [:king, :primary_and_secondary] RG = invariant_ring(GF(7), G) # redefine to avoid caching invars = fundamental_invariants(RG, algo) @test length(invars) == 7 - @test [ total_degree(f.f) for f in invars ] == [ 1, 1, 2, 2, 2, 3, 4 ] + @test [total_degree(f.f) for f in invars] == [1, 1, 2, 2, 2, 3, 4] for f in invars @test reynolds_operator(RG, f) == f end @@ -178,9 +178,9 @@ end # Let's test whether invars are algebra generators for the degree 9 homogeneous # component. R = polynomial_ring(RG).R - C = Oscar.PowerProductCache(R, [ f.f for f in invars ]) + C = Oscar.PowerProductCache(R, [f.f for f in invars]) B = Oscar.BasisOfPolynomials(R, Oscar.all_power_products_of_degree!(C, 9, false)) - b2 = [ f.f for f in basis(RG, 9) ] + b2 = [f.f for f in basis(RG, 9)] for f in b2 @test !Oscar.add_to_basis!(B, f) end @@ -192,9 +192,9 @@ end invars = fundamental_invariants(RG) @test length(invars) == 7 - @test [ total_degree(f.f) for f in invars ] == [ 1, 1, 2, 2, 2, 3, 4 ] + @test [total_degree(f.f) for f in invars] == [1, 1, 2, 2, 2, 3, 4] - actions = [ Oscar.right_action(polynomial_ring(RG), x) for x in gens(G) ] + actions = [Oscar.right_action(polynomial_ring(RG), x) for x in gens(G)] for f in invars @test all(act -> act(f) == f, actions) end @@ -202,9 +202,9 @@ end # Let's test whether invars are algebra generators for the degree 9 homogeneous # component. R = polynomial_ring(RG).R - C = Oscar.PowerProductCache(R, [ f.f for f in invars ]) + C = Oscar.PowerProductCache(R, [f.f for f in invars]) B = Oscar.BasisOfPolynomials(R, Oscar.all_power_products_of_degree!(C, 9, false)) - b2 = [ f.f for f in basis(RG, 9) ] + b2 = [f.f for f in basis(RG, 9)] for f in b2 @test !Oscar.add_to_basis!(B, f) end diff --git a/test/InvariantTheory/invariant_rings.jl b/test/InvariantTheory/invariant_rings.jl index b6999af78eed..2e058241101b 100644 --- a/test/InvariantTheory/invariant_rings.jl +++ b/test/InvariantTheory/invariant_rings.jl @@ -1,25 +1,25 @@ @testset "Invariant rings (for matrix groups)" begin K, a = cyclotomic_field(3, "a") - M1 = matrix(K, 3, 3, [ 0, 1, 0, 1, 0, 0, 0, 0, 1 ]) - M2 = matrix(K, 3, 3, [ 1, 0, 0, 0, a, 0, 0, 0, -a - 1 ]) + M1 = matrix(K, 3, 3, [0, 1, 0, 1, 0, 0, 0, 0, 1]) + M2 = matrix(K, 3, 3, [1, 0, 0, 0, a, 0, 0, 0, -a - 1]) RG0 = invariant_ring(M1, M2) # Explicitly call the other constructors - invariant_ring([ M1, M2 ]) - invariant_ring(K, [ M1, M2 ]) - invariant_ring(matrix_group([ M1, M2 ])) + invariant_ring([M1, M2]) + invariant_ring(K, [M1, M2]) + invariant_ring(matrix_group([M1, M2])) - R, _ = graded_polynomial_ring(K, 3, "x", ones(Int, 3), internal_ordering = :degrevlex) - @test polynomial_ring(invariant_ring(R, [ M1, M2 ])) === R + R, _ = graded_polynomial_ring(K, 3, "x", ones(Int, 3); internal_ordering=:degrevlex) + @test polynomial_ring(invariant_ring(R, [M1, M2])) === R @test polynomial_ring(invariant_ring(R, M1, M2)) === R @test polynomial_ring(invariant_ring(R, matrix_group(M1, M2))) === R F = GF(3) - N1 = matrix(F, 3, 3, [ 0, 1, 0, 2, 0, 0, 0, 0, 2 ]) - N2 = matrix(F, 3, 3, [ 2, 0, 0, 0, 2, 0, 0, 0, 2 ]) + N1 = matrix(F, 3, 3, [0, 1, 0, 2, 0, 0, 0, 0, 2]) + N2 = matrix(F, 3, 3, [2, 0, 0, 0, 2, 0, 0, 0, 2]) RGp = invariant_ring(N1, N2) # char p, non-modular - N3 = matrix(F, 2, 2, [ 1, 1, 0, 1 ]) + N3 = matrix(F, 2, 2, [1, 1, 0, 1]) RGm = invariant_ring(N3) # charp, modular @test coefficient_ring(RG0) == K @@ -37,8 +37,10 @@ @test reynolds_operator(RG0, gen(R0, 3)^3) == gen(R0, 3)^3 @test reynolds_operator(RG0, gen(R0, 1)) == zero(R0) - @test reynolds_operator(RG0, gen(R0, 3)^3) == reynolds_operator(RG0, gen(R0, 3)^3, trivial_character(group(RG0))) - @test reynolds_operator(RG0, gen(R0, 1)) == reynolds_operator(RG0, gen(R0, 1), trivial_character(group(RG0))) + @test reynolds_operator(RG0, gen(R0, 3)^3) == + reynolds_operator(RG0, gen(R0, 3)^3, trivial_character(group(RG0))) + @test reynolds_operator(RG0, gen(R0, 1)) == + reynolds_operator(RG0, gen(R0, 1), trivial_character(group(RG0))) @test reynolds_operator(RGp, gen(Rp, 3)^2) == gen(Rp, 3)^2 @test reynolds_operator(RGp, gen(Rp, 1)) == zero(Rp) @@ -77,32 +79,46 @@ @test mol == (-t^4 - 1)//(t^8 - 2t^6 + 2t^2 - 1) # S5 (deleted permutation module) - G = matrix_group(matrix(QQ, [-1 1 0 0; - -1 0 1 0; - -1 0 0 1; - -1 0 0 0]), - matrix(QQ, [0 1 0 0; - 1 0 0 0; - 0 0 1 0; - 0 0 0 1])) + G = matrix_group( + matrix( + QQ, + [ + -1 1 0 0 + -1 0 1 0 + -1 0 0 1 + -1 0 0 0 + ], + ), + matrix( + QQ, + [ + 0 1 0 0 + 1 0 0 0 + 0 0 1 0 + 0 0 0 1 + ], + ), + ) I = invariant_ring(G) S, t = QQ["t"] m = @inferred molien_series(S, I) - @test m == 1//((1 - t^2)*(1 - t^3)*(1 - t^4)*(1 - t^5)) + @test m == 1//((1 - t^2) * (1 - t^3) * (1 - t^4) * (1 - t^5)) # S4 (natural permutation module in characteristic 5) gl = general_linear_group(4, 5) - gapmats = [GAP.Globals.PermutationMat(elm.X, 4, GAP.Globals.GF(5)) - for elm in gens(symmetric_group(4))] + gapmats = [ + GAP.Globals.PermutationMat(elm.X, 4, GAP.Globals.GF(5)) for + elm in gens(symmetric_group(4)) + ] s4 = sub(gl, [MatrixGroupElem(gl, x) for x in gapmats])[1] I = invariant_ring(s4) m = @inferred molien_series(S, I) - @test m == 1//((1 - t)*(1 - t^2)*(1 - t^3)*(1 - t^4)) + @test m == 1//((1 - t) * (1 - t^2) * (1 - t^3) * (1 - t^4)) F = GF(3) I = invariant_ring(-identity_matrix(F, 2)) m = @inferred molien_series(S, I) - @test m == (t^2 + 1)//(t^4 - 2*t^2 + 1) + @test m == (t^2 + 1)//(t^4 - 2 * t^2 + 1) end @testset "Invariant rings (for permutation groups)" begin @@ -118,7 +134,7 @@ end F3 = GF(3) RGM = invariant_ring(F3, G) # char. p, modular - R, _ = graded_polynomial_ring(K, 3, "x", ones(Int, 3), internal_ordering = :degrevlex) + R, _ = graded_polynomial_ring(K, 3, "x", ones(Int, 3); internal_ordering=:degrevlex) @test polynomial_ring(invariant_ring(R, G)) === R @test coefficient_ring(RGQ) == QQ @@ -165,26 +181,28 @@ end mol = molien_series(RGK) F = parent(mol) t = gens(base_ring(F))[1] - @test mol == 1//((1-t^3)*(1-t^2)*(1-t)) + @test mol == 1//((1 - t^3) * (1 - t^2) * (1 - t)) mol = molien_series(RGF) F = parent(mol) t = gens(base_ring(F))[1] - @test mol == 1//((1-t^3)*(1-t^2)*(1-t)) + @test mol == 1//((1 - t^3) * (1 - t^2) * (1 - t)) # S4 (natural permutation module in characteristic 5) s4 = symmetric_group(4) S, t = QQ["t"] I = invariant_ring(GF(5), s4) m = @inferred molien_series(S, I) - @test m == 1//((1 - t)*(1 - t^2)*(1 - t^3)*(1 - t^4)) + @test m == 1//((1 - t) * (1 - t^2) * (1 - t^3) * (1 - t^4)) S2 = symmetric_group(2) RS2 = invariant_ring(S2) R = polynomial_ring(RS2) x = gens(R) F = abelian_closure(QQ)[1] - chi = Oscar.class_function(S2, [ F(sign(representative(c))) for c in conjugacy_classes(S2) ]) + chi = Oscar.class_function( + S2, [F(sign(representative(c))) for c in conjugacy_classes(S2)] + ) @test reynolds_operator(RS2, x[1] - x[2], chi) == x[1] - x[2] @test reynolds_operator(RS2, x[1] + x[2], chi) == zero(R) @@ -192,7 +210,7 @@ end F = parent(mol) t = gens(base_ring(F))[1] @test mol == 1//(t^3 - t^2 - t + 1) - @test molien_series(base_ring(F), RS2, chi) == t*mol + @test molien_series(base_ring(F), RS2, chi) == t * mol @test length(basis(RS2, 1, chi)) == 1 end diff --git a/test/InvariantTheory/iterators.jl b/test/InvariantTheory/iterators.jl index 8ddf76b389ee..02df41e57123 100644 --- a/test/InvariantTheory/iterators.jl +++ b/test/InvariantTheory/iterators.jl @@ -1,11 +1,11 @@ @testset "Monomials of a given degree" begin - for R in [ QQ["x", "y", "z"][1], graded_polynomial_ring(QQ, ["x", "y", "z"])[1] ] + for R in [QQ["x", "y", "z"][1], graded_polynomial_ring(QQ, ["x", "y", "z"])[1]] x, y, z = gens(R) - @test collect(monomials_of_degree(R, 2)) == [x^2, x*y, x*z, y^2, y*z, z^2] - @test collect(monomials_of_degree(R, 2, 1:3)) == [x^2, x*y, x*z, y^2, y*z, z^2] - @test collect(monomials_of_degree(R, 3, [1, 3])) == [x^3, x^2*z, x*z^2, z^3] - @test collect(monomials_of_degree(R, 3, [3, 1, 1])) == [x^3, x^2*z, x*z^2, z^3] - @test collect(monomials_of_degree(R, 3, 1:2)) == [x^3, x^2*y, x*y^2, y^3] + @test collect(monomials_of_degree(R, 2)) == [x^2, x * y, x * z, y^2, y * z, z^2] + @test collect(monomials_of_degree(R, 2, 1:3)) == [x^2, x * y, x * z, y^2, y * z, z^2] + @test collect(monomials_of_degree(R, 3, [1, 3])) == [x^3, x^2 * z, x * z^2, z^3] + @test collect(monomials_of_degree(R, 3, [3, 1, 1])) == [x^3, x^2 * z, x * z^2, z^3] + @test collect(monomials_of_degree(R, 3, 1:2)) == [x^3, x^2 * y, x * y^2, y^3] @test collect(monomials_of_degree(R, 3, 1:1)) == [x^3] @test isempty(monomials_of_degree(R, 2, Int[])) end diff --git a/test/InvariantTheory/primary_invariants.jl b/test/InvariantTheory/primary_invariants.jl index b87a21aadbe9..5f2cbe964b90 100644 --- a/test/InvariantTheory/primary_invariants.jl +++ b/test/InvariantTheory/primary_invariants.jl @@ -1,8 +1,8 @@ @testset "Primary invariants (for matrix groups)" begin # Char 0 K, a = cyclotomic_field(3, "a") - M1 = matrix(K, 3, 3, [ 0, 1, 0, 1, 0, 0, 0, 0, 1 ]) - M2 = matrix(K, 3, 3, [ 1, 0, 0, 0, a, 0, 0, 0, -a - 1 ]) + M1 = matrix(K, 3, 3, [0, 1, 0, 1, 0, 0, 0, 0, 1]) + M2 = matrix(K, 3, 3, [1, 0, 0, 0, a, 0, 0, 0, -a - 1]) RG = invariant_ring(M1, M2) invars = primary_invariants(RG) @test dim(ideal(polynomial_ring(RG), invars)) == 0 @@ -12,8 +12,8 @@ # Char p, non-modular F3 = GF(3) - N1 = matrix(F3, 3, 3, [ 0, 1, 0, 2, 0, 0, 0, 0, 2 ]) - N2 = matrix(F3, 3, 3, [ 2, 0, 0, 0, 2, 0, 0, 0, 2 ]) + N1 = matrix(F3, 3, 3, [0, 1, 0, 2, 0, 0, 0, 0, 2]) + N2 = matrix(F3, 3, 3, [2, 0, 0, 0, 2, 0, 0, 0, 2]) RG = invariant_ring(N1, N2) invars = primary_invariants(RG) @test dim(ideal(polynomial_ring(RG), invars)) == 0 @@ -23,8 +23,8 @@ # Char p, modular F9, b = finite_field(3, 2, "b") - N3 = matrix(F9, [ 1 0 0 0; b + 1 1 0 0; -1 0 1 0; b 0 -1 1 ]) - N4 = matrix(F9, [ 1 0 0 0; 1 1 0 0; 1 0 1 0; b -b b 1 ]) + N3 = matrix(F9, [1 0 0 0; b+1 1 0 0; -1 0 1 0; b 0 -1 1]) + N4 = matrix(F9, [1 0 0 0; 1 1 0 0; 1 0 1 0; b -b b 1]) RG = invariant_ring(N3, N4) invars = primary_invariants(RG) @test dim(ideal(polynomial_ring(RG), invars)) == 0 @@ -37,29 +37,29 @@ # Kem99, Example 1 K, a = cyclotomic_field(9, "a") - M = matrix(K, 2, 2, [ a, 0, 0, -a^3 ]) + M = matrix(K, 2, 2, [a, 0, 0, -a^3]) RG = invariant_ring(M) invars = primary_invariants(RG) @test length(invars) == 2 - @test sort([ total_degree(f.f) for f in invars ]) == [ 6, 9 ] + @test sort([total_degree(f.f) for f in invars]) == [6, 9] @test dim(ideal(polynomial_ring(RG), invars)) == 0 # Kem99, Example 2 K, a = cyclotomic_field(9, "a") - M = matrix(K, 3, 3, [ a, 0, 0, 0, a^2, 0, 0, 0, a^6 ]) + M = matrix(K, 3, 3, [a, 0, 0, 0, a^2, 0, 0, 0, a^6]) RG = invariant_ring(M) invars = primary_invariants(RG) @test length(invars) == 3 - @test sort([ total_degree(f.f) for f in invars ]) == [ 3, 5, 9 ] + @test sort([total_degree(f.f) for f in invars]) == [3, 5, 9] @test dim(ideal(polynomial_ring(RG), invars)) == 0 # Kem99, p. 183: S_3^3 - M1 = diagonal_matrix([ matrix(QQ, 3, 3, [ 0, 1, 0, 1, 0, 0, 0, 0, 1 ]) for i = 1:3 ]) - M2 = diagonal_matrix([ matrix(QQ, 3, 3, [ 0, 1, 0, 0, 0, 1, 1, 0, 0 ]) for i = 1:3 ]) + M1 = diagonal_matrix([matrix(QQ, 3, 3, [0, 1, 0, 1, 0, 0, 0, 0, 1]) for i in 1:3]) + M2 = diagonal_matrix([matrix(QQ, 3, 3, [0, 1, 0, 0, 0, 1, 1, 0, 0]) for i in 1:3]) RG = invariant_ring(M1, M2) invars = primary_invariants(RG) @test length(invars) == 9 - @test sort([ total_degree(f.f) for f in invars ]) == [ 1, 1, 1, 2, 2, 2, 3, 3, 3 ] + @test sort([total_degree(f.f) for f in invars]) == [1, 1, 1, 2, 2, 2, 3, 3, 3] @test dim(ideal(polynomial_ring(RG), invars)) == 0 end @@ -100,6 +100,6 @@ end RG = invariant_ring(G) invars = primary_invariants(RG) @test length(invars) == 9 - @test sort([ total_degree(f.f) for f in invars ]) == [ 1, 1, 1, 2, 2, 2, 3, 3, 3 ] + @test sort([total_degree(f.f) for f in invars]) == [1, 1, 1, 2, 2, 2, 3, 3, 3] @test dim(ideal(polynomial_ring(RG), invars)) == 0 end diff --git a/test/InvariantTheory/secondary_invariants.jl b/test/InvariantTheory/secondary_invariants.jl index d60f8b141dd8..da33810c902a 100644 --- a/test/InvariantTheory/secondary_invariants.jl +++ b/test/InvariantTheory/secondary_invariants.jl @@ -1,9 +1,9 @@ @testset "Secondary invariants (for matrix groups)" begin K, a = cyclotomic_field(3, "a") # Force use of internal polynomial_ring with internal_ordering = :lex - R, _ = graded_polynomial_ring(K, 3, internal_ordering = :lex) - M1 = matrix(K, 3, 3, [ 0, 1, 0, 1, 0, 0, 0, 0, 1 ]) - M2 = matrix(K, 3, 3, [ 1, 0, 0, 0, a, 0, 0, 0, -a - 1 ]) + R, _ = graded_polynomial_ring(K, 3; internal_ordering=:lex) + M1 = matrix(K, 3, 3, [0, 1, 0, 1, 0, 0, 0, 0, 1]) + M2 = matrix(K, 3, 3, [1, 0, 0, 0, a, 0, 0, 0, -a - 1]) RG0 = invariant_ring(R, matrix_group(M1, M2)) # Should fail if the wrong monomial ordering is used in @@ -12,16 +12,16 @@ RGQQ = invariant_ring(M) F3 = GF(3) - N1 = matrix(F3, 3, 3, [ 0, 1, 0, 2, 0, 0, 0, 0, 2 ]) - N2 = matrix(F3, 3, 3, [ 2, 0, 0, 0, 2, 0, 0, 0, 2 ]) + N1 = matrix(F3, 3, 3, [0, 1, 0, 2, 0, 0, 0, 0, 2]) + N2 = matrix(F3, 3, 3, [2, 0, 0, 0, 2, 0, 0, 0, 2]) RGp = invariant_ring(N1, N2) # char p, non-modular F9, b = finite_field(3, 2, "b") - N3 = matrix(F9, [ 1 0 0 0; b + 1 1 0 0; -1 0 1 0; b 0 -1 1 ]) - N4 = matrix(F9, [ 1 0 0 0; 1 1 0 0; 1 0 1 0; b -b b 1 ]) + N3 = matrix(F9, [1 0 0 0; b+1 1 0 0; -1 0 1 0; b 0 -1 1]) + N4 = matrix(F9, [1 0 0 0; 1 1 0 0; 1 0 1 0; b -b b 1]) RGm = invariant_ring(N3, N4) # char p, modular - for RG in [ RG0, RGQQ, RGp ] + for RG in [RG0, RGQQ, RGp] s_invars = secondary_invariants(RG) m = molien_series(RG) S = base_ring(parent(m)) @@ -31,15 +31,17 @@ @test reynolds_operator(RG, f) == f n += t^total_degree(f.f) end - d = prod( 1 - t^total_degree(f.f) for f in primary_invariants(RG) ) + d = prod(1 - t^total_degree(f.f) for f in primary_invariants(RG)) @test m == n//d # The secondary invariants have to be a module basis. Let's test this for # the degree 9 homogeneous component. R = polynomial_ring(RG).R - C = Oscar.PowerProductCache(R, [ f.f for f in primary_invariants(RG) ]) - b1, _ = Oscar.generators_for_given_degree!(C, [ f.f for f in secondary_invariants(RG) ], 9, false) - b2 = [ f.f for f in basis(RG, 9) ] + C = Oscar.PowerProductCache(R, [f.f for f in primary_invariants(RG)]) + b1, _ = Oscar.generators_for_given_degree!( + C, [f.f for f in secondary_invariants(RG)], 9, false + ) + b2 = [f.f for f in basis(RG, 9)] B = Oscar.BasisOfPolynomials(R, b1) for f in b2 @test !Oscar.add_to_basis!(B, f) @@ -57,15 +59,17 @@ # The secondary invariants have to be a module basis. Let's test this for # the degree 6 homogeneous component. R = polynomial_ring(RGm).R - C = Oscar.PowerProductCache(R, [ f.f for f in primary_invariants(RGm) ]) - b1, _ = Oscar.generators_for_given_degree!(C, [ f.f for f in secondary_invariants(RGm) ], 6, false) - b2 = [ f.f for f in basis(RGm, 6) ] + C = Oscar.PowerProductCache(R, [f.f for f in primary_invariants(RGm)]) + b1, _ = Oscar.generators_for_given_degree!( + C, [f.f for f in secondary_invariants(RGm)], 6, false + ) + b2 = [f.f for f in basis(RGm, 6)] B = Oscar.BasisOfPolynomials(R, b1) for f in b2 @test !Oscar.add_to_basis!(B, f) end - for RG in [ RG0, RGp ] + for RG in [RG0, RGp] is_invars = irreducible_secondary_invariants(RG) @test issubset(is_invars, secondary_invariants(RG)) @test length(is_invars) == 1 @@ -73,9 +77,11 @@ # The irreducible secondary invariants have to be algebra generators. Let's # test this for the degree 9 homogeneous component. R = polynomial_ring(RG).R - C = Oscar.PowerProductCache(R, append!([ f.f for f in primary_invariants(RG) ], [ f.f for f in is_invars ])) + C = Oscar.PowerProductCache( + R, append!([f.f for f in primary_invariants(RG)], [f.f for f in is_invars]) + ) b1 = Oscar.all_power_products_of_degree!(C, 9, false) - b2 = [ f.f for f in basis(RG, 9) ] + b2 = [f.f for f in basis(RG, 9)] B = Oscar.BasisOfPolynomials(R, b1) for f in b2 @test !Oscar.add_to_basis!(B, f) @@ -88,21 +94,23 @@ # The irreducible secondary invariants have to be algebra generators. Let's # test this for the degree 9 homogeneous component. R = polynomial_ring(RGm).R - C = Oscar.PowerProductCache(R, append!([ f.f for f in primary_invariants(RGm) ], [ f.f for f in is_invars ])) + C = Oscar.PowerProductCache( + R, append!([f.f for f in primary_invariants(RGm)], [f.f for f in is_invars]) + ) b1 = Oscar.all_power_products_of_degree!(C, 6, false) - b2 = [ f.f for f in basis(RGm, 6) ] + b2 = [f.f for f in basis(RGm, 6)] B = Oscar.BasisOfPolynomials(R, b1) for f in b2 @test !Oscar.add_to_basis!(B, f) end - for RG in [ RG0, RGp, RGm ] + for RG in [RG0, RGp, RGm] is_invars = irreducible_secondary_invariants(RG) - for i = 1:length(RG.secondary.invars) + for i in 1:length(RG.secondary.invars) f = RG.secondary.invars[i] @test in(f, is_invars) == RG.secondary.is_irreducible[i] t = one(polynomial_ring(RG)) - for j = 1:length(is_invars) + for j in 1:length(is_invars) t *= is_invars[j]^RG.secondary.sec_in_irred[i][j] end @test f == t @@ -111,7 +119,8 @@ R, x = polynomial_ring(QQ, "x" => 1:3) C = Oscar.PowerProductCache(R, x) - @test Set(Oscar.all_power_products_of_degree!(C, 3, false)) == Set(collect(monomials_of_degree(R, 3))) + @test Set(Oscar.all_power_products_of_degree!(C, 3, false)) == + Set(collect(monomials_of_degree(R, 3))) mons = Oscar.all_power_products_of_degree!(C, 3, true) @test Set(mons) == Set(collect(monomials_of_degree(R, 3))) for m in mons @@ -119,9 +128,9 @@ @test set_exponent_vector!(one(R), 1, C.exponent_vectors[m]) == m end - C = Oscar.PowerProductCache(R, [ x[1], x[2] ]) - gens, exps = Oscar.generators_for_given_degree!(C, [ x[3] ], 3, true) - @test Set(gens) == Set([ x[1]^2*x[3], x[1]*x[2]*x[3], x[2]^2*x[3] ]) + C = Oscar.PowerProductCache(R, [x[1], x[2]]) + gens, exps = Oscar.generators_for_given_degree!(C, [x[3]], 3, true) + @test Set(gens) == Set([x[1]^2 * x[3], x[1] * x[2] * x[3], x[2]^2 * x[3]]) for m in gens @test haskey(exps, m) @test set_exponent_vector!(one(R), 1, exps[m]) == m @@ -137,15 +146,15 @@ @test reynolds_operator(RG0, f, chi) == f n += t^total_degree(f.f) end - d = prod( 1 - t^total_degree(f.f) for f in primary_invariants(RG0) ) + d = prod(1 - t^total_degree(f.f) for f in primary_invariants(RG0)) @test m == n//d # The semi-invariants have to be a module basis. Let's test this for # the degree 9 homogeneous component. R = polynomial_ring(RG0).R - C = Oscar.PowerProductCache(R, [ f.f for f in primary_invariants(RG0) ]) - b1, _ = Oscar.generators_for_given_degree!(C, [ f.f for f in semi_invars ], 9, false) - b2 = [ f.f for f in basis(RG0, 9, chi) ] + C = Oscar.PowerProductCache(R, [f.f for f in primary_invariants(RG0)]) + b1, _ = Oscar.generators_for_given_degree!(C, [f.f for f in semi_invars], 9, false) + b2 = [f.f for f in basis(RG0, 9, chi)] B = Oscar.BasisOfPolynomials(R, b1) for f in b2 @test !Oscar.add_to_basis!(B, f) @@ -162,7 +171,7 @@ end F2 = GF(2) RGm = invariant_ring(F2, G) # char. p, modular - for RG in [ RG0, RGp ] + for RG in [RG0, RGp] s_invars = secondary_invariants(RG) m = molien_series(RG) S = base_ring(parent(m)) @@ -172,15 +181,17 @@ end @test reynolds_operator(RG, f) == f n += t^total_degree(f.f) end - d = prod( 1 - t^total_degree(f.f) for f in primary_invariants(RG) ) + d = prod(1 - t^total_degree(f.f) for f in primary_invariants(RG)) @test m == n//d # The secondary invariants have to be a module basis. Let's test this for # the degree 9 homogeneous component. R = polynomial_ring(RG).R - C = Oscar.PowerProductCache(R, [ f.f for f in primary_invariants(RG) ]) - b1, _ = Oscar.generators_for_given_degree!(C, [ f.f for f in secondary_invariants(RG) ], 9, false) - b2 = [ f.f for f in basis(RG, 9) ] + C = Oscar.PowerProductCache(R, [f.f for f in primary_invariants(RG)]) + b1, _ = Oscar.generators_for_given_degree!( + C, [f.f for f in secondary_invariants(RG)], 9, false + ) + b2 = [f.f for f in basis(RG, 9)] B = Oscar.BasisOfPolynomials(R, b1) for f in b2 @test !Oscar.add_to_basis!(B, f) @@ -196,15 +207,17 @@ end # The secondary invariants have to be a module basis. Let's test this for # the degree 9 homogeneous component. R = polynomial_ring(RGm).R - C = Oscar.PowerProductCache(R, [ f.f for f in primary_invariants(RGm) ]) - b1, _ = Oscar.generators_for_given_degree!(C, [ f.f for f in secondary_invariants(RGm) ], 9, false) - b2 = [ f.f for f in basis(RGm, 9) ] + C = Oscar.PowerProductCache(R, [f.f for f in primary_invariants(RGm)]) + b1, _ = Oscar.generators_for_given_degree!( + C, [f.f for f in secondary_invariants(RGm)], 9, false + ) + b2 = [f.f for f in basis(RGm, 9)] B = Oscar.BasisOfPolynomials(R, b1) for f in b2 @test !Oscar.add_to_basis!(B, f) end - for RG in [ RG0, RGp ] + for RG in [RG0, RGp] is_invars = irreducible_secondary_invariants(RG) @test issubset(is_invars, secondary_invariants(RG)) @test length(is_invars) == 1 @@ -212,9 +225,11 @@ end # The irreducible secondary invariants have to be algebra generators. Let's # test this for the degree 9 homogeneous component. R = polynomial_ring(RG).R - C = Oscar.PowerProductCache(R, append!([ f.f for f in primary_invariants(RG) ], [ f.f for f in is_invars ])) + C = Oscar.PowerProductCache( + R, append!([f.f for f in primary_invariants(RG)], [f.f for f in is_invars]) + ) b1 = Oscar.all_power_products_of_degree!(C, 9, false) - b2 = [ f.f for f in basis(RG, 9) ] + b2 = [f.f for f in basis(RG, 9)] B = Oscar.BasisOfPolynomials(R, b1) for f in b2 @test !Oscar.add_to_basis!(B, f) @@ -227,21 +242,23 @@ end # The irreducible secondary invariants have to be algebra generators. Let's # test this for the degree 9 homogeneous component. R = polynomial_ring(RGm).R - C = Oscar.PowerProductCache(R, append!([ f.f for f in primary_invariants(RGm) ], [ f.f for f in is_invars ])) + C = Oscar.PowerProductCache( + R, append!([f.f for f in primary_invariants(RGm)], [f.f for f in is_invars]) + ) b1 = Oscar.all_power_products_of_degree!(C, 6, false) - b2 = [ f.f for f in basis(RGm, 6) ] + b2 = [f.f for f in basis(RGm, 6)] B = Oscar.BasisOfPolynomials(R, b1) for f in b2 @test !Oscar.add_to_basis!(B, f) end - for RG in [ RG0, RGp, RGm ] + for RG in [RG0, RGp, RGm] is_invars = irreducible_secondary_invariants(RG) - for i = 1:length(RG.secondary.invars) + for i in 1:length(RG.secondary.invars) f = RG.secondary.invars[i] @test in(f, is_invars) == RG.secondary.is_irreducible[i] t = one(polynomial_ring(RG)) - for j = 1:length(is_invars) + for j in 1:length(is_invars) t *= is_invars[j]^RG.secondary.sec_in_irred[i][j] end @test f == t From 86166ac66f63b590d65a357e743b8c68cde421f9 Mon Sep 17 00:00:00 2001 From: Johannes Schmitt Date: Tue, 16 Apr 2024 14:29:43 +0200 Subject: [PATCH 2/3] Enable test and add commit to ignore list --- .git-blame-ignore-revs | 3 +++ etc/test_formatting.jl | 2 ++ 2 files changed, 5 insertions(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 49c867af5d6a..2221656d212d 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -3,3 +3,6 @@ ab444bbc46b5493588b2c3217ed35d86396d1260 # Ran JuliaFormatter on experimental/{BasisLieHighestWieght,ExperimentalTemplate,ExteriorAlgebra,LieAlgebras} e71dcb305491f26d13225c0339e2e22129bb27f3 + +# Ran JuliaFormatter on src/InvariantTheory and experimental/LinearQuotients +46f309032b476581ec57c584d5ef9f0c384ad46d diff --git a/etc/test_formatting.jl b/etc/test_formatting.jl index c6d6f423ea37..2d5931b00095 100644 --- a/etc/test_formatting.jl +++ b/etc/test_formatting.jl @@ -41,12 +41,14 @@ result = 0 # Since right now only very few files are formatted, we also use a whitelist # approach. enabled = [ + "src/InvariantTheory", "src/PolyhedralGeometry", "src/aliases.jl", "experimental/BasisLieHighestWeight", "experimental/ExperimentalTemplate", "experimental/ExteriorAlgebra", "experimental/LieAlgebras", + "experimental/LinearQuotients", ] skip = [ "src/PolyhedralGeometry/Polyhedron/standard_constructions.jl", From 447716ce4f25cf75c69c57f906ddfced667a315e Mon Sep 17 00:00:00 2001 From: Johannes Schmitt Date: Tue, 16 Apr 2024 14:53:41 +0200 Subject: [PATCH 3/3] Disable test for `experimental/InvariantTheory` --- etc/test_formatting.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/etc/test_formatting.jl b/etc/test_formatting.jl index 2d5931b00095..92ad9522dbf9 100644 --- a/etc/test_formatting.jl +++ b/etc/test_formatting.jl @@ -53,6 +53,7 @@ result = 0 skip = [ "src/PolyhedralGeometry/Polyhedron/standard_constructions.jl", "src/PolyhedralGeometry/Polyhedron/properties.jl", + "experimental/InvariantTheory/src/InvariantTheory.jl",# the path matches the whitelist entry "src/InvariantTheory" ] # Collect all code files.