diff --git a/src/Map.jl b/src/Map.jl index a5255261b..1e8199e81 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 00d80d5c7..f129cd9e8 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 4a6d8e176..138e7d1da 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,21 @@ function check_parent(M::FPModuleElem{T}, N::FPModuleElem{T}) where T <: RingEle parent(M) !== parent(N) && error("Incompatible modules") end +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 +317,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 238ad3655..504ff4d2c 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 1500d41fc..82e672ac3 100644 --- a/src/generic/DirectSum.jl +++ b/src/generic/DirectSum.jl @@ -20,6 +20,8 @@ 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) +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)] @@ -247,6 +249,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) diff --git a/src/generic/FreeModule.jl b/src/generic/FreeModule.jl index ab20cec12..79f8403df 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 38dbb762f..14dbb220f 100644 --- a/src/generic/Map.jl +++ b/src/generic/Map.jl @@ -91,6 +91,8 @@ end Base.inv(f::AbstractAlgebra.Map(AbstractAlgebra.IdentityMap)) = f +AbstractAlgebra.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 7d323d82c..3d50943a2 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 136e53ba8..920cad8fe 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 6ea87f6b6..517cbfd10 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