From 902682af76025338fa7655c83d8b91c040c2a858 Mon Sep 17 00:00:00 2001 From: ThomasBreuer Date: Wed, 17 Apr 2024 15:51:44 +0200 Subject: [PATCH 1/5] move code from `Oscar.jl/experimental/GModule/Misc.jl` here The idea is to add this code to AbstractAlgebra.jl, and then to remove it from Oscar.jl. Once we agree what shall be really added here, tests and documentation has to be added. (I am quite sure that I have put certain parts into the wrong files, and that some functions have to be changed.) --- src/Map.jl | 4 +++ src/Matrix.jl | 3 ++ src/Module.jl | 49 ++++++++++++++++++++++++++++ src/exports.jl | 2 ++ src/generic/DirectSum.jl | 9 ++++++ src/generic/FreeModule.jl | 2 ++ src/generic/Map.jl | 2 ++ src/generic/Misc/Poly.jl | 5 +++ src/generic/ModuleHomomorphism.jl | 53 +++++++++++++++++++++++++++++++ src/generic/exports.jl | 1 + 10 files changed, 130 insertions(+) diff --git a/src/Map.jl b/src/Map.jl index a5255261b3..1e8199e811 100644 --- a/src/Map.jl +++ b/src/Map.jl @@ -17,6 +17,10 @@ function domain end function codomain end function image_fn end +function coimage(h::Map) + return quo(domain(h), kernel(h)[1]) +end + function check_composable(a::Map, b::Map) codomain(a) !== domain(b) && error("Incompatible maps") end diff --git a/src/Matrix.jl b/src/Matrix.jl index 00d80d5c7e..f129cd9e88 100644 --- a/src/Matrix.jl +++ b/src/Matrix.jl @@ -502,6 +502,9 @@ end Base.IteratorSize(::Type{<:MatrixElem}) = Base.HasShape{2}() Base.IteratorEltype(::Type{<:MatrixElem}) = Base.HasEltype() # default +Base.pairs(M::MatElem) = Base.pairs(IndexCartesian(), M) +Base.pairs(::IndexCartesian, M::MatElem) = Base.Iterators.Pairs(M, CartesianIndices(axes(M))) + ############################################################################### # # Block replacement diff --git a/src/Module.jl b/src/Module.jl index 4a6d8e1764..4ef68bcfdc 100644 --- a/src/Module.jl +++ b/src/Module.jl @@ -10,6 +10,8 @@ # ############################################################################### +Base.eltype(M::FPModule{T}) where T <: FinFieldElem = elem_type(M) + function zero(M::FPModule{T}) where T <: RingElement R = base_ring(M) return M(zero_matrix(R, 1, ngens(M))) @@ -27,6 +29,23 @@ function check_parent(M::FPModuleElem{T}, N::FPModuleElem{T}) where T <: RingEle parent(M) !== parent(N) && error("Incompatible modules") end +gen(M::FPModule, i::Int) = M[i] + +is_finite(M::FPModule{<:FinFieldElem}) = true + +function is_sub_with_data(M::FPModule{T}, N::FPModule{T}) where T <: RingElement + fl = is_submodule(N, M) + if fl + return fl, hom(M, N, elem_type(N)[N(m) for m = gens(M)]) + else + return fl, hom(M, N, elem_type(N)[zero(N) for m = gens(M)]) + end +end + +Base.issubset(M::FPModule{T}, N::FPModule{T}) where T <: RingElement = is_submodule(M, N) + +order(M::FPModule{<:FinFieldElem}) = order(base_ring(M))^dim(M) + ############################################################################### # # Unary operators @@ -300,3 +319,33 @@ function rand(rng::AbstractRNG, M::FPModule{T}, vals...) where T <: RingElement end rand(M::FPModule, vals...) = rand(Random.GLOBAL_RNG, M, vals...) + +############################################################################### +# +# Iteration +# +############################################################################### + +Base.length(M::FPModule{T}) where T <: FinFieldElem = Int(order(M)) + +function Base.iterate(M::FPModule{T}) where T <: FinFieldElem + k = base_ring(M) + if dim(M) == 0 + return zero(M), iterate([1]) + end + p = Base.Iterators.ProductIterator(Tuple([k for i=1:dim(M)])) + f = iterate(p) + return M(elem_type(k)[f[1][i] for i=1:dim(M)]), (f[2], p) +end + +function Base.iterate(M::FPModule{T}, st::Tuple{<:Tuple, <:Base.Iterators.ProductIterator}) where T <: FinFieldElem + n = iterate(st[2], st[1]) + if n === nothing + return n + end + return M(elem_type(base_ring(M))[n[1][i] for i=1:dim(M)]), (n[2], st[2]) +end + +function Base.iterate(::FPModule{<:FinFieldElem}, ::Tuple{Int64, Int64}) + return nothing +end diff --git a/src/exports.jl b/src/exports.jl index 238ad36551..504ff4d2ce 100644 --- a/src/exports.jl +++ b/src/exports.jl @@ -273,6 +273,7 @@ export is_even export is_exact_type export is_finite export is_finite_order +export is_free export is_gen export is_hermitian export is_hessenberg @@ -308,6 +309,7 @@ export is_square_with_sqrt export is_squarefree export is_submodule export is_subset +export is_sub_with_data export is_symmetric export is_term export is_term_recursive diff --git a/src/generic/DirectSum.jl b/src/generic/DirectSum.jl index 1500d41fc6..1111605ba5 100644 --- a/src/generic/DirectSum.jl +++ b/src/generic/DirectSum.jl @@ -20,6 +20,10 @@ base_ring(N::DirectSumModule{T}) where T <: RingElement = base_ring(N.m[1]) base_ring(v::DirectSumModuleElem{T}) where T <: RingElement = base_ring(v.parent) +is_free(M::DirectSumModule) = all(is_free, M.m) + +dim(M::DirectSumModule{<:FieldElem}) = sum(dim(x) for x = M.m) + number_of_generators(N::DirectSumModule{T}) where T <: RingElement = sum(ngens(M) for M in N.m) gens(N::DirectSumModule{T}) where T <: RingElement = [gen(N, i) for i = 1:ngens(N)] @@ -220,6 +224,11 @@ function direct_sum(m::Vector{<:AbstractAlgebra.FPModule{T}}) where T <: RingEle return M, inj, pro end +function direct_sum(M::DirectSumModule{T}, N::DirectSumModule{T}, mp::Vector{ModuleHomomorphism{T}}) where T + @assert length(M.m) == length(mp) == length(N.m) + return hom(M, N, cat(map(matrix, mp)..., dims = (1,2))) +end + function ModuleHomomorphism(D::DirectSumModule{T}, A::AbstractAlgebra.FPModule{T}, m::Vector{<:ModuleHomomorphism{T}}) where T <: RingElement S = summands(D) length(S) == length(m) || error("map array has wrong length") diff --git a/src/generic/FreeModule.jl b/src/generic/FreeModule.jl index ab20cec12c..79f8403df1 100644 --- a/src/generic/FreeModule.jl +++ b/src/generic/FreeModule.jl @@ -29,6 +29,8 @@ function check_parent(m1::FreeModuleElem{T}, m2::FreeModuleElem{T}) where T <: U parent(m1) !== parent(m2) && error("Incompatible free modules") end +is_free(M::FreeModule) = true + @doc raw""" rank(M::FreeModule{T}) where T <: Union{RingElement, NCRingElem} diff --git a/src/generic/Map.jl b/src/generic/Map.jl index 38dbb762fd..bb9cffb334 100644 --- a/src/generic/Map.jl +++ b/src/generic/Map.jl @@ -91,6 +91,8 @@ end Base.inv(f::AbstractAlgebra.Map(AbstractAlgebra.IdentityMap)) = f +matrix(phi::IdentityMap{<:AbstractAlgebra.FPModule}) = identity_matrix(base_ring(domain(phi)), dim(domain(phi))) + ################################################################################ # # FunctionalMap diff --git a/src/generic/Misc/Poly.jl b/src/generic/Misc/Poly.jl index 7d323d82c2..3d50943a27 100644 --- a/src/generic/Misc/Poly.jl +++ b/src/generic/Misc/Poly.jl @@ -75,6 +75,11 @@ function roots(R::Field, f::PolyRingElem) return roots(f1) end +function roots(a::FinFieldElem, i::Int) + _, x = polynomial_ring(parent(a), cached = false) + return roots(x^i-a) +end + function sturm_sequence(f::PolyRingElem{<:FieldElem}) g = f h = derivative(g) diff --git a/src/generic/ModuleHomomorphism.jl b/src/generic/ModuleHomomorphism.jl index 136e53ba8f..920cad8fe9 100644 --- a/src/generic/ModuleHomomorphism.jl +++ b/src/generic/ModuleHomomorphism.jl @@ -22,6 +22,44 @@ inverse_mat(f::Map(ModuleIsomorphism)) = f.inverse_matrix inverse_image_fn(f::Map(ModuleIsomorphism)) = f.inverse_image_fn +############################################################################### +# +# Unary operators +# +############################################################################### + +Base.:-(a::ModuleHomomorphism) = hom(domain(a), codomain(a), -matrix(a)) + +############################################################################### +# +# Binary operators +# +############################################################################### + +Base.:*(a::T, b::ModuleHomomorphism{T}) where {T} = hom(domain(b), codomain(b), a * matrix(b)) +Base.:*(a::T, b::ModuleIsomorphism{T}) where {T} = hom(domain(b), codomain(b), a * matrix(b)) +Base.:+(a::ModuleHomomorphism, b::ModuleHomomorphism) = hom(domain(a), codomain(a), matrix(a) + matrix(b)) +Base.:-(a::ModuleHomomorphism, b::ModuleHomomorphism) = hom(domain(a), codomain(a), matrix(a) - matrix(b)) + +############################################################################### +# +# Comparison +# +############################################################################### + +function Base.:(==)(a::Union{ModuleHomomorphism, ModuleIsomorphism}, b::Union{ModuleHomomorphism, ModuleIsomorphism}) + domain(a) === domain(b) || return false + codomain(a) === codomain(b) || return false + return matrix(a) == matrix(b) +end + +function Base.hash(a::Union{ModuleHomomorphism, ModuleIsomorphism}, h::UInt) + h = hash(domain(a), h) + h = hash(codomain(a), h) + h = hash(matrix(a), h) + return h +end + ############################################################################### # # String I/O @@ -68,6 +106,10 @@ function Base.inv(f::Map(ModuleIsomorphism)) return ModuleIsomorphism{T}(codomain(f), domain(f), inverse_mat(f), matrix(f)) end +function Base.inv(f::ModuleHomomorphism) + return hom(codomain(f), domain(f), inv(matrix(f))) +end + ############################################################################### # # Call overload @@ -139,3 +181,14 @@ function ModuleIsomorphism(M1::AbstractAlgebra.FPModule{T}, end return ModuleIsomorphism{T}(M1, M2, M, M_inv) end + +function hom(V::AbstractAlgebra.Module, W::AbstractAlgebra.Module, v::Vector{<:ModuleElem}; check::Bool = true) + if ngens(V) == 0 + return ModuleHomomorphism(V, W, zero_matrix(base_ring(V), ngens(V), ngens(W))) + end + return ModuleHomomorphism(V, W, reduce(vcat, [x.v for x = v])) +end + +function hom(V::AbstractAlgebra.Module, W::AbstractAlgebra.Module, v::MatElem; check::Bool = true) + return ModuleHomomorphism(V, W, v) +end diff --git a/src/generic/exports.jl b/src/generic/exports.jl index 6ea87f6b6a..517cbfd106 100644 --- a/src/generic/exports.jl +++ b/src/generic/exports.jl @@ -47,6 +47,7 @@ export inverse_mat export invmod export is_compatible export is_divisible_by +export is_free export is_homogeneous export is_power export is_rimhook From 1780be1de8f8a91e85bd7655badb41e6fa7a6926 Mon Sep 17 00:00:00 2001 From: ThomasBreuer Date: Thu, 18 Apr 2024 12:40:54 +0200 Subject: [PATCH 2/5] remove a method: will the test failures disappear? I do not understand what is happening here: Installing a `matrix(phi::IdentityMap{<:AbstractAlgebra.FPModule})` method seems to make another `matrix` method unavailable? --- src/generic/Map.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generic/Map.jl b/src/generic/Map.jl index bb9cffb334..5d6f17b7c4 100644 --- a/src/generic/Map.jl +++ b/src/generic/Map.jl @@ -91,7 +91,7 @@ end Base.inv(f::AbstractAlgebra.Map(AbstractAlgebra.IdentityMap)) = f -matrix(phi::IdentityMap{<:AbstractAlgebra.FPModule}) = identity_matrix(base_ring(domain(phi)), dim(domain(phi))) +#matrix(phi::IdentityMap{<:AbstractAlgebra.FPModule}) = identity_matrix(base_ring(domain(phi)), dim(domain(phi))) ################################################################################ # From 894cfe2617f98ee68c4ebd9fa9aff7b474a06496 Mon Sep 17 00:00:00 2001 From: ThomasBreuer Date: Fri, 19 Apr 2024 10:06:30 +0200 Subject: [PATCH 3/5] fix the new `matrix` method --- src/generic/Map.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generic/Map.jl b/src/generic/Map.jl index 5d6f17b7c4..14dbb220f4 100644 --- a/src/generic/Map.jl +++ b/src/generic/Map.jl @@ -91,7 +91,7 @@ end Base.inv(f::AbstractAlgebra.Map(AbstractAlgebra.IdentityMap)) = f -#matrix(phi::IdentityMap{<:AbstractAlgebra.FPModule}) = identity_matrix(base_ring(domain(phi)), dim(domain(phi))) +AbstractAlgebra.matrix(phi::IdentityMap{<:AbstractAlgebra.FPModule}) = identity_matrix(base_ring(domain(phi)), dim(domain(phi))) ################################################################################ # From 6f71ea20d6efc68e2e1f1b329c12440257df4bd7 Mon Sep 17 00:00:00 2001 From: ThomasBreuer Date: Fri, 19 Apr 2024 10:24:08 +0200 Subject: [PATCH 4/5] rename `direct_sum` to `hom`, as suggested --- src/generic/DirectSum.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/generic/DirectSum.jl b/src/generic/DirectSum.jl index 1111605ba5..26c291f3cd 100644 --- a/src/generic/DirectSum.jl +++ b/src/generic/DirectSum.jl @@ -224,11 +224,6 @@ function direct_sum(m::Vector{<:AbstractAlgebra.FPModule{T}}) where T <: RingEle return M, inj, pro end -function direct_sum(M::DirectSumModule{T}, N::DirectSumModule{T}, mp::Vector{ModuleHomomorphism{T}}) where T - @assert length(M.m) == length(mp) == length(N.m) - return hom(M, N, cat(map(matrix, mp)..., dims = (1,2))) -end - function ModuleHomomorphism(D::DirectSumModule{T}, A::AbstractAlgebra.FPModule{T}, m::Vector{<:ModuleHomomorphism{T}}) where T <: RingElement S = summands(D) length(S) == length(m) || error("map array has wrong length") @@ -256,6 +251,11 @@ function ModuleHomomorphism(D::DirectSumModule{T}, A::DirectSumModule{T}, m::Mat return ModuleHomomorphism(D, A, transpose(hvcat(Tuple([length(SD) for i = 1:length(SA)]), map(x->transpose(x.matrix), m)...))) end +function AbstractAlgebra.hom(M::DirectSumModule{T}, N::DirectSumModule{T}, mp::Vector{ModuleHomomorphism{T}}) where T + @assert length(M.m) == length(mp) == length(N.m) + return hom(M, N, cat(map(matrix, mp)..., dims = (1,2))) +end + function AbstractAlgebra.hom(A::AbstractAlgebra.Generic.DirectSumModule{T}, B::AbstractAlgebra.Generic.DirectSumModule{T}, M::Matrix{<:Map{<:AbstractAlgebra.FPModule{T}, <:AbstractAlgebra.FPModule{T}}}) where {T} pro = canonical_projections(A) im = canonical_injections(B) From 79658261befd976096e7a7d822687271f59002f4 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 25 Apr 2024 13:53:31 +0200 Subject: [PATCH 5/5] Apply suggestions from code review --- src/Module.jl | 2 -- src/generic/DirectSum.jl | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/Module.jl b/src/Module.jl index 4ef68bcfdc..138e7d1daa 100644 --- a/src/Module.jl +++ b/src/Module.jl @@ -29,8 +29,6 @@ function check_parent(M::FPModuleElem{T}, N::FPModuleElem{T}) where T <: RingEle parent(M) !== parent(N) && error("Incompatible modules") end -gen(M::FPModule, i::Int) = M[i] - is_finite(M::FPModule{<:FinFieldElem}) = true function is_sub_with_data(M::FPModule{T}, N::FPModule{T}) where T <: RingElement diff --git a/src/generic/DirectSum.jl b/src/generic/DirectSum.jl index 26c291f3cd..82e672ac35 100644 --- a/src/generic/DirectSum.jl +++ b/src/generic/DirectSum.jl @@ -20,8 +20,6 @@ base_ring(N::DirectSumModule{T}) where T <: RingElement = base_ring(N.m[1]) base_ring(v::DirectSumModuleElem{T}) where T <: RingElement = base_ring(v.parent) -is_free(M::DirectSumModule) = all(is_free, M.m) - dim(M::DirectSumModule{<:FieldElem}) = sum(dim(x) for x = M.m) number_of_generators(N::DirectSumModule{T}) where T <: RingElement = sum(ngens(M) for M in N.m)