diff --git a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Morphisms/Methods.jl b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Morphisms/Methods.jl index 5f86d5c6ad19..f3e7e1feef23 100644 --- a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Morphisms/Methods.jl +++ b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Morphisms/Methods.jl @@ -231,7 +231,7 @@ function pushforward(inc::ProjectiveClosedEmbedding, M::SubquoModule) G, inc_G = sub(FT, vcat(gT, relT)) Q, inc_Q = sub(G, gens(G)[length(gT)+1:end]) MT = cokernel(inc_Q) - id = hom(MT, M, vcat(gens(M), elem_type(M)[zero(M) for i in 1:length(relT)]); check=false) + id = hom(MT, M, vcat(gens(M), elem_type(M)[zero(M) for i in 1:length(relT)]), S; check=false) return MT, id end diff --git a/src/Modules/ModuleTypes.jl b/src/Modules/ModuleTypes.jl index b771dfac76a2..cdbfe1ed9571 100644 --- a/src/Modules/ModuleTypes.jl +++ b/src/Modules/ModuleTypes.jl @@ -1,26 +1,33 @@ import AbstractAlgebra.WeakKeyIdDict +# The following type union gathers all types for elements for which +# we expect the `ModuleFP` framework to be functional and/or working. +# It can gradually be extended, but should not be considered to be +# visible or accessible to the outside world. +const AdmissibleModuleFPRingElem = Union{RingElem, PBWAlgQuoElem, PBWAlgElem} +const AdmissibleModuleFPRing = Union{Ring, PBWAlgQuo, PBWAlgRing} + @doc raw""" ModuleFP{T} The abstract supertype of all finitely presented modules. The type variable `T` refers to the type of the elements of the base ring. """ -abstract type ModuleFP{T} <: AbstractAlgebra.Module{T} end +abstract type ModuleFP{T <: AdmissibleModuleFPRingElem} <: AbstractAlgebra.Module{T} end @doc raw""" AbstractFreeMod{T} <: ModuleFP{T} The abstract supertype of all finitely generated free modules. """ -abstract type AbstractFreeMod{T} <: ModuleFP{T} end +abstract type AbstractFreeMod{T <: AdmissibleModuleFPRingElem} <: ModuleFP{T} end @doc raw""" AbstractSubQuo{T} <: ModuleFP{T} The abstract supertype of all finitely presented subquotient modules. """ -abstract type AbstractSubQuo{T} <: ModuleFP{T} end +abstract type AbstractSubQuo{T <: AdmissibleModuleFPRingElem} <: ModuleFP{T} end @doc raw""" @@ -28,21 +35,21 @@ abstract type AbstractSubQuo{T} <: ModuleFP{T} end The abstract supertype of all elements of finitely presented modules. """ -abstract type ModuleFPElem{T} <: ModuleElem{T} end +abstract type ModuleFPElem{T <: AdmissibleModuleFPRingElem} <: ModuleElem{T} end @doc raw""" AbstractFreeModElem{T} <: ModuleFPElem{T} The abstract supertype of all elements of finitely generated free modules. """ -abstract type AbstractFreeModElem{T} <: ModuleFPElem{T} end +abstract type AbstractFreeModElem{T <: AdmissibleModuleFPRingElem} <: ModuleFPElem{T} end @doc raw""" AbstractSubQuoElem{T} <: ModuleFPElem{T} The abstract supertype of all elements of subquotient modules. """ -abstract type AbstractSubQuoElem{T} <: ModuleFPElem{T} end +abstract type AbstractSubQuoElem{T <: AdmissibleModuleFPRingElem} <: ModuleFPElem{T} end abstract type ModuleFPHomDummy end @@ -70,8 +77,8 @@ Moreover, canonical incoming and outgoing morphisms are stored if the correspond option is set in suitable functions. `FreeMod{T}` is a subtype of `AbstractFreeMod{T}`. """ -@attributes mutable struct FreeMod{T <: RingElem} <: AbstractFreeMod{T} - R::Ring +@attributes mutable struct FreeMod{T <: AdmissibleModuleFPRingElem} <: AbstractFreeMod{T} + R::NCRing n::Int S::Vector{Symbol} d::Union{Vector{FinGenAbGroupElem}, Nothing} @@ -91,7 +98,7 @@ option is set in suitable functions. incoming::WeakKeyIdDict{<:ModuleFP, <:Tuple{<:SMat, <:Any}} outgoing::WeakKeyIdDict{<:ModuleFP, <:Tuple{<:SMat, <:Any}} - function FreeMod{T}(n::Int,R::Ring,S::Vector{Symbol}) where T <: RingElem + function FreeMod{T}(n::Int, R::AdmissibleModuleFPRing, S::Vector{Symbol}) where T <: AdmissibleModuleFPRingElem r = new{elem_type(R)}() r.n = n r.R = R @@ -105,7 +112,7 @@ option is set in suitable functions. end @doc raw""" - FreeModElem{T} <: AbstractFreeModElem{T} + FreeModElem{T <: AdmissibleModuleFPRingElem} <: AbstractFreeModElem{T} The type of free module elements. An element of a free module $F$ is given by a sparse row (`SRow`) which specifies its coordinates with respect to the basis of standard unit vectors of $F$. @@ -131,7 +138,7 @@ julia> f == g true ``` """ -mutable struct FreeModElem{T} <: AbstractFreeModElem{T} +mutable struct FreeModElem{T <: AdmissibleModuleFPRingElem} <: AbstractFreeModElem{T} coords::SRow{T} # also usable via coeffs() parent::FreeMod{T} d::Union{FinGenAbGroupElem, Nothing} @@ -155,7 +162,7 @@ and all the conversion is taken care of here. This data structure is also used for representing Gröbner / standard bases. Relative Gröbner / standard bases are also supported. """ -@attributes mutable struct ModuleGens{T} # T is the type of the elements of the ground ring. +@attributes mutable struct ModuleGens{T <: AdmissibleModuleFPRingElem} # T is the type of the elements of the ground ring. O::Vector{FreeModElem{T}} S::Singular.smodule F::FreeMod{T} @@ -166,7 +173,7 @@ Relative Gröbner / standard bases are also supported. ordering::ModuleOrdering quo_GB::ModuleGens{T} # Pointer to the quotient GB when having a relative GB - function ModuleGens{T}(O::Vector{<:FreeModElem}, F::FreeMod{T}) where {T} + function ModuleGens{T}(O::Vector{<:FreeModElem}, F::FreeMod{T}) where {T <: AdmissibleModuleFPRingElem} r = new{T}() r.O = O r.F = F @@ -175,7 +182,7 @@ Relative Gröbner / standard bases are also supported. # ModuleGens from an Array of Oscar free module elements, specifying the free module # and Singular free module, only useful indirectly - function ModuleGens{T}(O::Vector{<:FreeModElem}, F::FreeMod{T}, SF::Singular.FreeMod) where {T} + function ModuleGens{T}(O::Vector{<:FreeModElem}, F::FreeMod{T}, SF::Singular.FreeMod) where {T <: AdmissibleModuleFPRingElem} r = new{T}() r.O = O r.SF = SF @@ -184,7 +191,7 @@ Relative Gröbner / standard bases are also supported. end # ModuleGens from a Singular submodule - function ModuleGens{S}(F::FreeMod{S}, s::Singular.smodule) where {S} # FreeMod is necessary due to type S + function ModuleGens{S}(F::FreeMod{S}, s::Singular.smodule) where {S <: AdmissibleModuleFPRingElem} # FreeMod is necessary due to type S r = new{S}() r.F = F if Singular.ngens(s) == 0 @@ -198,14 +205,14 @@ Relative Gröbner / standard bases are also supported. end @doc raw""" - SubModuleOfFreeModule{T} <: ModuleFP{T} + SubModuleOfFreeModule{T <: AdmissibleModuleFPRingElem} <: ModuleFP{T} Data structure for submodules of free modules. `SubModuleOfFreeModule` shouldn't be used by the end user. When computed, a standard basis (computed via `standard_basis()`) and generating matrix (that is the rows of the matrix generate the submodule) (computed via `generator_matrix()`) are cached. """ -@attributes mutable struct SubModuleOfFreeModule{T} <: ModuleFP{T} +@attributes mutable struct SubModuleOfFreeModule{T <: AdmissibleModuleFPRingElem} <: ModuleFP{T} F::FreeMod{T} gens::ModuleGens{T} groebner_basis::Dict{ModuleOrdering, ModuleGens{T}} @@ -224,7 +231,7 @@ end @doc raw""" - SubquoModule{T} <: AbstractSubQuo{T} + SubquoModule{T <: AdmissibleModuleFPRingElem} <: AbstractSubQuo{T} The type of subquotient modules. A subquotient module $M$ is a module where $M = A + B / B$ where $A$ and $B$ are @@ -236,7 +243,7 @@ Moreover, canonical incoming and outgoing morphisms are stored if the correspond option is set in suitable functions. `SubquoModule{T}` is a subtype of `ModuleFP{T}`. """ -@attributes mutable struct SubquoModule{T} <: AbstractSubQuo{T} +@attributes mutable struct SubquoModule{T <: AdmissibleModuleFPRingElem} <: AbstractSubQuo{T} #meant to represent sub+ quo mod quo - as lazy as possible F::FreeMod{T} sub::SubModuleOfFreeModule @@ -264,7 +271,7 @@ end @doc raw""" - SubquoModuleElem{T} <: AbstractSubQuoElem{T} + SubquoModuleElem{T <: AdmissibleModuleFPRingElem} <: AbstractSubQuoElem{T} The type of subquotient elements. An element $f$ of a subquotient $M$ over the ring $R$ is given by a sparse row (`SRow`) which specifies the coefficients of an $R$-linear @@ -308,13 +315,13 @@ julia> f == g true ``` """ -mutable struct SubquoModuleElem{T} <: AbstractSubQuoElem{T} +mutable struct SubquoModuleElem{T <: AdmissibleModuleFPRingElem} <: AbstractSubQuoElem{T} parent::SubquoModule{T} coeffs::SRow{T} # Need not be defined! Use `coordinates` as getter repres::FreeModElem{T} # Need not be defined! Use `repres` as getter is_reduced::Bool # `false` by default. Will be set by `simplify` and `simplify!`. - function SubquoModuleElem{R}(v::SRow{R}, SQ::SubquoModule) where {R} + function SubquoModuleElem{R}(v::SRow{R}, SQ::SubquoModule) where {R <: AdmissibleModuleFPRingElem} @assert length(v) <= ngens(SQ.sub) if isempty(v) r = new{R}(SQ, v, zero(SQ.F)) @@ -326,7 +333,7 @@ mutable struct SubquoModuleElem{T} <: AbstractSubQuoElem{T} return r end - function SubquoModuleElem{R}(a::FreeModElem{R}, SQ::SubquoModule; is_reduced::Bool=false) where {R} + function SubquoModuleElem{R}(a::FreeModElem{R}, SQ::SubquoModule; is_reduced::Bool=false) where {R <: AdmissibleModuleFPRingElem} @assert a.parent === SQ.F r = new{R}(SQ) r.repres = a diff --git a/src/Modules/ModulesGraded.jl b/src/Modules/ModulesGraded.jl index 63d186a83de2..2e9458312b0b 100644 --- a/src/Modules/ModulesGraded.jl +++ b/src/Modules/ModulesGraded.jl @@ -5,14 +5,14 @@ ############################################################################### @doc raw""" - graded_free_module(R::Ring, p::Int, W::Vector{FinGenAbGroupElem}=[grading_group(R)[0] for i in 1:p], name::String="e") + graded_free_module(R::AdmissibleModuleFPRing, p::Int, W::Vector{FinGenAbGroupElem}=[grading_group(R)[0] for i in 1:p], name::String="e") Given a graded ring `R` with grading group `G`, say, and given a vector `W` with `p` elements of `G`, create the free module $R^p$ equipped with its basis of standard unit vectors, and assign weights to these vectors according to the entries of `W`. Return the resulting graded free module. - graded_free_module(R::Ring, W::Vector{FinGenAbGroupElem}, name::String="e") + graded_free_module(R::AdmissibleModuleFPRing, W::Vector{FinGenAbGroupElem}, name::String="e") As above, with `p = length(W)`. @@ -36,7 +36,7 @@ julia> graded_free_module(R, [G[1], 2*G[1]]) Graded free module R^1([-1]) + R^1([-2]) of rank 2 over R ``` """ -function graded_free_module(R::Ring, p::Int, W::Vector{FinGenAbGroupElem}=[grading_group(R)[0] for i in 1:p], name::String="e") +function graded_free_module(R::AdmissibleModuleFPRing, p::Int, W::Vector{FinGenAbGroupElem}=[grading_group(R)[0] for i in 1:p], name::String="e") @assert length(W) == p @assert is_graded(R) all(x -> parent(x) == grading_group(R), W) || error("entries of W must be elements of the grading group of the base ring") @@ -45,7 +45,7 @@ function graded_free_module(R::Ring, p::Int, W::Vector{FinGenAbGroupElem}=[gradi return M end -function graded_free_module(R::Ring, p::Int, W::Vector{Any}, name::String="e") +function graded_free_module(R::AdmissibleModuleFPRing, p::Int, W::Vector{Any}, name::String="e") @assert length(W) == p @assert is_graded(R) p == 0 || error("W should be either an empty array or a Vector{FinGenAbGroupElem}") @@ -53,12 +53,12 @@ function graded_free_module(R::Ring, p::Int, W::Vector{Any}, name::String="e") return graded_free_module(R, p, W, name) end -function graded_free_module(R::Ring, W::Vector{FinGenAbGroupElem}, name::String="e") +function graded_free_module(R::AdmissibleModuleFPRing, W::Vector{FinGenAbGroupElem}, name::String="e") p = length(W) return graded_free_module(R, p, W, name) end -function graded_free_module(R::Ring, W::Vector{Any}, name::String="e") +function graded_free_module(R::AdmissibleModuleFPRing, W::Vector{Any}, name::String="e") p = length(W) @assert is_graded(R) p == 0 || error("W should be either an empty array or a Vector{FinGenAbGroupElem}") @@ -67,7 +67,7 @@ function graded_free_module(R::Ring, W::Vector{Any}, name::String="e") end @doc raw""" - graded_free_module(R::Ring, W::Vector{<:Vector{<:IntegerUnion}}, name::String="e") + graded_free_module(R::AdmissibleModuleFPRing, W::Vector{<:Vector{<:IntegerUnion}}, name::String="e") Given a graded ring `R` with grading group $G = \mathbb Z^m$, and given a vector `W` of integer vectors of the same size `p`, say, create the free @@ -75,11 +75,11 @@ module $R^p$ equipped with its basis of standard unit vectors, and assign weight vectors according to the entries of `W`, converted to elements of `G`. Return the resulting graded free module. - graded_free_module(R::Ring, W::Union{ZZMatrix, Matrix{<:IntegerUnion}}, name::String="e") + graded_free_module(R::AdmissibleModuleFPRing, W::Union{ZZMatrix, Matrix{<:IntegerUnion}}, name::String="e") As above, converting the columns of `W`. - graded_free_module(R::Ring, W::Vector{<:IntegerUnion}, name::String="e") + graded_free_module(R::AdmissibleModuleFPRing, W::Vector{<:IntegerUnion}, name::String="e") Given a graded ring `R` with grading group $G = \mathbb Z$, and given a vector `W` of integers, set `p = length(W)`, create the free module $R^p$ @@ -113,7 +113,7 @@ julia> FF == FFF true ``` """ -function graded_free_module(R::Ring, W::Vector{<:Vector{<:IntegerUnion}}, name::String="e") +function graded_free_module(R::AdmissibleModuleFPRing, W::Vector{<:Vector{<:IntegerUnion}}, name::String="e") @assert is_zm_graded(R) n = length(W[1]) @assert all(x->length(x) == n, W) @@ -122,14 +122,14 @@ function graded_free_module(R::Ring, W::Vector{<:Vector{<:IntegerUnion}}, name:: return graded_free_module(R, length(W), d, name) end -function graded_free_module(R::Ring, W::Union{ZZMatrix, Matrix{<:IntegerUnion}}, name::String="e") +function graded_free_module(R::AdmissibleModuleFPRing, W::Union{ZZMatrix, Matrix{<:IntegerUnion}}, name::String="e") @assert is_zm_graded(R) A = grading_group(R) d = [A(W[:, i]) for i = 1:size(W, 2)] return graded_free_module(R, size(W, 2), d, name) end -function graded_free_module(R::Ring, W::Vector{<:IntegerUnion}, name::String="e") +function graded_free_module(R::AdmissibleModuleFPRing, W::Vector{<:IntegerUnion}, name::String="e") @assert is_graded(R) A = grading_group(R) d = [W[i] * A[1] for i in 1:length(W)] @@ -652,7 +652,7 @@ function graded_map(A::MatElem) return graded_map(Fcdm, A) end -function graded_map(F::FreeMod{T}, A::MatrixElem{T}; check::Bool=true) where {T <: RingElement} +function graded_map(F::FreeMod{T}, A::MatrixElem{T}; check::Bool=true) where {T <: AdmissibleModuleFPRingElem} R = base_ring(F) G = grading_group(R) source_degrees = Vector{eltype(G)}() @@ -669,7 +669,7 @@ function graded_map(F::FreeMod{T}, A::MatrixElem{T}; check::Bool=true) where {T return phi end -function graded_map(F::FreeMod{T}, V::Vector{<:AbstractFreeModElem{T}}; check::Bool=true) where {T <: RingElement} +function graded_map(F::FreeMod{T}, V::Vector{<:AbstractFreeModElem{T}}; check::Bool=true) where {T <: AdmissibleModuleFPRingElem} R = base_ring(F) G = grading_group(R) nrows = length(V) @@ -697,7 +697,7 @@ function graded_map(F::FreeMod{T}, V::Vector{<:AbstractFreeModElem{T}}; check::B end -function graded_map(F::SubquoModule{T}, V::Vector{<:ModuleFPElem{T}}; check::Bool=true) where {T <: RingElement} +function graded_map(F::SubquoModule{T}, V::Vector{<:ModuleFPElem{T}}; check::Bool=true) where {T <: AdmissibleModuleFPRingElem} R = base_ring(F) G = grading_group(R) nrows = length(V) diff --git a/src/Modules/UngradedModules/FreeMod.jl b/src/Modules/UngradedModules/FreeMod.jl index 6531cf49367c..a204a0385b60 100644 --- a/src/Modules/UngradedModules/FreeMod.jl +++ b/src/Modules/UngradedModules/FreeMod.jl @@ -10,15 +10,15 @@ Additionally one can provide names for the generators. If one does not provide names for the generators, the standard names e_i are used for the standard unit vectors. """ -function FreeMod(R::Ring, n::Int, name::VarName = :e; cached::Bool = false) # TODO cached? +function FreeMod(R::AdmissibleModuleFPRing, n::Int, name::VarName = :e; cached::Bool = false) # TODO cached? return FreeMod{elem_type(R)}(n, R, [Symbol("$name[$i]") for i=1:n]) end -function FreeMod(R::Ring, names::Vector{String}; cached::Bool=false) +function FreeMod(R::AdmissibleModuleFPRing, names::Vector{String}; cached::Bool=false) return FreeMod{elem_type(R)}(length(names), R, Symbol.(names)) end -function FreeMod(R::Ring, names::Vector{Symbol}; cached::Bool=false) +function FreeMod(R::AdmissibleModuleFPRing, names::Vector{Symbol}; cached::Bool=false) return FreeMod{elem_type(R)}(length(names), R, names) end @@ -76,6 +76,8 @@ free_module(R::MPolyQuoRing, p::Int, name::VarName = :e; cached::Bool = false) = free_module(R::MPolyLocRing, p::Int, name::VarName = :e; cached::Bool = false) = FreeMod(R, p, name, cached = cached) free_module(R::MPolyQuoLocRing, p::Int, name::VarName = :e; cached::Bool = false) = FreeMod(R, p, name, cached = cached) +#free_module(R::NCRing, p::Int, name::VarName = :e; cached::Bool = false) = FreeMod(R, p, name, cached = cached) + #=XXX this cannot be as it is inherently ambiguous - free_module(R, n) - direct sum of rings, ie. a ring diff --git a/src/Modules/UngradedModules/FreeModElem.jl b/src/Modules/UngradedModules/FreeModElem.jl index e70b3508cfe2..6a197b1b64fc 100644 --- a/src/Modules/UngradedModules/FreeModElem.jl +++ b/src/Modules/UngradedModules/FreeModElem.jl @@ -254,28 +254,39 @@ function Base.deepcopy_internal(a::AbstractFreeModElem, dict::IdDict) end # scalar multiplication with polynomials, integers -function *(a::MPolyDecRingElem, b::AbstractFreeModElem) - @req parent(a) === base_ring(parent(b)) "elements not compatible" - return parent(b)(a*coordinates(b)) +*(a::Any, b::AbstractFreeModElem) = parent(b)(base_ring(parent(b))(a)*coordinates(b)) + +function *(a::T, b::AbstractFreeModElem{T}) where {T <: AdmissibleModuleFPRingElem} + @assert is_left(parent(b)) "left multiplication is not defined for non-left module $(parent(b))" + parent(a) === base_ring(parent(b)) && return parent(b)(a*coordinates(b)) + return parent(b)(base_ring(parent(b))(a)*coordinates(b)) end -function *(a::MPolyRingElem, b::AbstractFreeModElem) - if parent(a) !== base_ring(parent(b)) - return base_ring(parent(b))(a)*b # this will throw if conversion is not possible - end - return parent(b)(a*coordinates(b)) +function *(b::AbstractFreeModElem{T}, a::T) where {T <: AdmissibleModuleFPRingElem} + @assert is_right(parent(b)) "right multiplication not defined for non-right module $(parent(b))" + error("right multiplication is not supported at the moment") end -function *(a::RingElem, b::AbstractFreeModElem) - if parent(a) !== base_ring(parent(b)) - return base_ring(parent(b))(a)*b # this will throw if conversion is not possible - end - return parent(b)(a*coordinates(b)) +function *(b::AbstractFreeModElem{T}, a::Any) where {T <: RingElem} + error("scalar multiplication from the right is not yet supported") end -*(a::Int, b::AbstractFreeModElem) = parent(b)(a*coordinates(b)) -*(a::Integer, b::AbstractFreeModElem) = parent(b)(base_ring(parent(b))(a)*coordinates(b)) -*(a::QQFieldElem, b::AbstractFreeModElem) = parent(b)(base_ring(parent(b))(a)*coordinates(b)) +# Methods to determine whether a module is a left-, right-, or bi-module. +# We plan to have flags set for this. But for the moment the generic code only supports left-multiplication, +# so we can decide this from the type alone. How we do it in the long run is not yet decided, but in either case +# we want to use these functions to decide as they are already there for ideals. +is_left(M::ModuleFP) = is_left(typeof(M)) +is_left(::Type{T}) where {RET<:RingElem, T<:ModuleFP{RET}} = true +is_left(::Type{T}) where {RET<:AdmissibleModuleFPRingElem, T<:ModuleFP{RET}} = true # Left multiplication is generically supported + +is_right(M::ModuleFP) = is_right_module(typeof(M)) +is_right(::Type{T}) where {RET<:RingElem, T<:ModuleFP{RET}} = true +is_right(::Type{T}) where {RET<:AdmissibleModuleFPRingElem, T<:ModuleFP{RET}} = false # Right multiplication is not supported by the generic code at the moment, but we plan to do so eventually. + +is_two_sided(M::ModuleFP) = is_right_module(typeof(M)) +is_two_sided(::Type{T}) where {RET<:RingElem, T<:ModuleFP{RET}} = true +is_two_sided(::Type{T}) where {RET<:AdmissibleModuleFPRingElem, T<:ModuleFP{RET}} = false # see above + @doc raw""" zero(F::AbstractFreeMod) diff --git a/src/Modules/UngradedModules/SubQuoHom.jl b/src/Modules/UngradedModules/SubQuoHom.jl index 948c369009f2..be65c668a968 100644 --- a/src/Modules/UngradedModules/SubQuoHom.jl +++ b/src/Modules/UngradedModules/SubQuoHom.jl @@ -267,8 +267,8 @@ julia> is_welldefined(c) false ``` """ -hom(M::SubquoModule, N::ModuleFP{T}, V::Vector{<:ModuleFPElem{T}}; check::Bool=true) where T = SubQuoHom(M, N, V; check) -hom(M::SubquoModule, N::ModuleFP{T}, A::MatElem{T}; check::Bool=true) where T = SubQuoHom(M, N, A; check) +hom(M::SubquoModule{T}, N::ModuleFP{T}, V::Vector{<:ModuleFPElem{T}}; check::Bool=true) where T = SubQuoHom(M, N, V; check) +hom(M::SubquoModule{T}, N::ModuleFP{T}, A::MatElem{T}; check::Bool=true) where T = SubQuoHom(M, N, A; check) @doc raw""" @@ -964,12 +964,12 @@ function +(h::ModuleFPHom{D, C, Nothing}, g::ModuleFPHom{D, C, Nothing}) where { return hom(domain(h), codomain(h), elem_type(codomain(h))[h(x) + g(x) for x in gens(domain(h))], check=false) end -function *(a::RingElem, g::ModuleFPHom{D, C, Nothing}) where {D, C} +function *(a::AdmissibleModuleFPRingElem, g::ModuleFPHom{D, C, Nothing}) where {D, C} @assert base_ring(codomain(g)) === parent(a) return hom(domain(g), codomain(g), elem_type(codomain(g))[a*g(x) for x in gens(domain(g))], check=false) end -function *(a::RingElem, g::ModuleFPHom{D, C, T}) where {D, C, T} +function *(a::AdmissibleModuleFPRingElem, g::ModuleFPHom{D, C, T}) where {D, C, T} @assert base_ring(codomain(g)) === parent(a) return hom(domain(g), codomain(g), elem_type(codomain(g))[a*g(x) for x in gens(domain(g))], base_ring_map(g), check=false) end diff --git a/src/Modules/UngradedModules/SubquoModule.jl b/src/Modules/UngradedModules/SubquoModule.jl index 8c66a77c44a6..1fd90ec88deb 100644 --- a/src/Modules/UngradedModules/SubquoModule.jl +++ b/src/Modules/UngradedModules/SubquoModule.jl @@ -157,7 +157,7 @@ end Construct the subquotient with ambient free module `F`, generators `g` and relations `q`. """ -function SubquoModule(F::FreeMod{T}, g::Vector{FreeModElem{T}}, q::Vector{FreeModElem{T}}) where {T<:RingElem} +function SubquoModule(F::FreeMod{T}, g::Vector{FreeModElem{T}}, q::Vector{FreeModElem{T}}) where {T<:AdmissibleModuleFPRingElem} return SubquoModule(SubModuleOfFreeModule(F, g), SubModuleOfFreeModule(F, q)) end diff --git a/src/Modules/UngradedModules/SubquoModuleElem.jl b/src/Modules/UngradedModules/SubquoModuleElem.jl index 493f940164fd..76ef28f697de 100644 --- a/src/Modules/UngradedModules/SubquoModuleElem.jl +++ b/src/Modules/UngradedModules/SubquoModuleElem.jl @@ -409,7 +409,7 @@ function *(a::MPolyRingElem, b::SubquoModuleElem) return SubquoModuleElem(a*repres(b), b.parent) end -function *(a::RingElem, b::SubquoModuleElem) +function *(a::NCRingElem, b::SubquoModuleElem) if parent(a) !== base_ring(parent(b)) return base_ring(parent(b))(a)*b # this will throw if conversion is not possible end diff --git a/test/Modules/PBWModules.jl b/test/Modules/PBWModules.jl new file mode 100644 index 000000000000..1045b5b3793a --- /dev/null +++ b/test/Modules/PBWModules.jl @@ -0,0 +1,60 @@ +@testset "modules over PBWAlgQuo" begin + #Free Module tests + E,x = exterior_algebra(QQ, 3) + M = FreeMod(E, 3) + @test ngens(M) == 3 + @test parent(M[1]) === M + v = [x[1], x[1] + x[2], 5*x[1]*x[2]] + @test M(2*v) == 2*M(v) + + #SubModuleOfFreeModule tests + N = Oscar.SubModuleOfFreeModule(M, gens(M)[1:2]) + @test gens(N) == gens(M)[1:2] + @test N[1] in M + #fails! #NEEDS A 'DEFAULT ORDERING' on the PBWAlgQuo ie on E + #@test M(v) in N + + #FreeModuleHom tests + W = FreeMod(E,2) + G = hom(W,M, gens(M)[1:2]) + @test ngens(image(G)[1]) == 2 + + #SubQuoModule tests + Q1 = SubquoModule(M, [x[1]*M[1]]) + Q2 = SubquoModule(M, [x[2]*M[1]]) + #fail! #NEEDS A 'DEFAULT ORDERING' on the PBWAlgQuo ie on E + #@test !is_canonically_isomorphic(Q2,Q1) + #simplify(Q[1]) +end + +@testset "modules over PBWAlgRing" begin + R, (x, y, z) = QQ["x", "y", "z"] + L = [x*y, x*z, y*z + 1] + REL = strictly_upper_triangular_matrix(L) + A, (x, y, z) = pbw_algebra(R, REL, deglex(gens(R))) + M = FreeMod(A, 3) + @test ngens(M) == 3 + @test gens(M)[1] in M + @test parent(M[1]) == M + v = [x, x+y, x*y] + @test v == Vector(M(v)) + + #SubModuleOfFreeModule tests + N = Oscar.SubModuleOfFreeModule(M, gens(M)[1:2]) + @test gens(N) == gens(M)[1:2] + @test N[1] in M + #fails! #NEEDS A 'DEFAULT ORDERING' on the PBWAlgQuo ie on E + #@test M(v) in N + + #FreeModuleHom tests + W = FreeMod(A,2) + G = hom(W,M, gens(M)[1:2]) + @test ngens(image(G)[1]) == 2 + + #SubQuoModule tests + Q1 = SubquoModule(M, [x*M[1]]) + Q2 = SubquoModule(M, [y*M[1]]) + #fail! #NEEDS A 'DEFAULT ORDERING' on the PBWAlgQuo ie on E + #@test !is_canonically_isomorphic(Q2,Q1) + #simplify(Q[1]) +end