diff --git a/src/Modules/UngradedModules/FreeMod.jl b/src/Modules/UngradedModules/FreeMod.jl index 94e53b20aeb1..151225e454e2 100644 --- a/src/Modules/UngradedModules/FreeMod.jl +++ b/src/Modules/UngradedModules/FreeMod.jl @@ -308,3 +308,67 @@ end rels(F::FreeMod) = elem_type(F)[] +function syzygy_generators( + g::Vector{T}; + parent::Union{<:FreeMod, Nothing}=nothing + ) where {T<:FreeModElem} + isempty(g) && return Vector{T}() + F = Oscar.parent(first(g)) + @assert all(Oscar.parent(x) === F for x in g) "parent mismatch" + R = base_ring(F) + m = length(g) + G = (parent === nothing ? FreeMod(R, m) : parent)::typeof(F) + @req ngens(G) == m "given parent does not have the correct number of generators" + phi = hom(G, F, g) + K, _ = kernel(phi) + return ambient_representatives_generators(K) +end + +@doc raw""" + syzygy_generators( + a::Vector{T}; + parent::Union{FreeMod{T}, Nothing} = nothing + ) where {T<:RingElem} + +Return generators for the syzygies on the polynomials given as elements of `a`. +The optional keyword argument can be used to specify the parent of the output. + +# Examples +```jldoctest +julia> R, (x, y) = polynomial_ring(QQ, [:x, :y]) +(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x, y]) + +julia> S = syzygy_generators([x^3+y+2,x*y^2-13*x^2,y-14]) +3-element Vector{FreeModElem{QQMPolyRingElem}}: + (-y + 14)*e[2] + (-13*x^2 + x*y^2)*e[3] + (-169*y + 2366)*e[1] + (-13*x*y + 182*x - 196*y + 2744)*e[2] + (13*x^2*y^2 - 2548*x^2 + 196*x*y^2 + 169*y + 338)*e[3] + (-13*x^2 + 196*x)*e[1] + (-x^3 - 16)*e[2] + (x^4*y + 14*x^4 + 13*x^2 + 16*x*y + 28*x)*e[3] +``` +""" +function syzygy_generators( + a::Vector{T}; + parent::Union{FreeMod{T}, Nothing} = nothing + ) where {T<:RingElem} + isempty(a) && return Vector{FreeModElem{T}}() + R = Oscar.parent(first(a)) + @assert all(Oscar.parent(x) === R for x in a) "parent mismatch" + F = FreeMod(R, 1) + return syzygy_generators(elem_type(F)[x*F[1] for x in a]; parent) +end + +function syzygy_generators( + a::Vector{T}; + parent::Union{FreeMod{T}, Nothing} = nothing + ) where {CT <: Union{<:FieldElem, ZZRingElem, QQPolyRingElem}, # Can be adjusted to whatever is digested by Singular + T<:MPolyRingElem{CT}} + isempty(a) && return Vector{FreeModElem{T}}() + R = Oscar.parent(first(a)) + @assert all(Oscar.parent(x) === R for x in a) "parent mismatch" + I = ideal(R, a) + s = Singular.syz(singular_generators(I)) + F = (parent === nothing ? FreeMod(R, length(a)) : parent)::FreeMod{T} + @req ngens(F) == length(a) "parent does not have the correct number of generators" + @assert rank(s) == length(a) + return elem_type(F)[F(s[i]) for i=1:Singular.ngens(s)] +end + diff --git a/src/Modules/UngradedModules/SubquoModule.jl b/src/Modules/UngradedModules/SubquoModule.jl index 792164dca70a..994e519b04e6 100644 --- a/src/Modules/UngradedModules/SubquoModule.jl +++ b/src/Modules/UngradedModules/SubquoModule.jl @@ -754,7 +754,11 @@ function set_default_ordering!(M::SubquoModule, ord::ModuleOrdering) set_default_ordering!(M.sum, ord) end -function standard_basis(M::SubquoModule; ordering::ModuleOrdering = default_ordering(M)) +function standard_basis(M::SubquoModule; ordering::Union{ModuleOrdering, Nothing} = nothing) + error("standard basis computation is not supported for modules over rings of type $(typeof(base_ring(M)))") +end + +function standard_basis(M::SubquoModule{<:MPolyRingElem{T}}; ordering::ModuleOrdering = default_ordering(M)) where {T<:Union{<:FieldElem, ZZRingElem}} @req is_exact_type(elem_type(base_ring(M))) "This functionality is only supported over exact fields." if !haskey(M.groebner_basis, ordering) if isdefined(M, :quo) diff --git a/src/Rings/groebner.jl b/src/Rings/groebner.jl index 3d4bb0027e25..1a0feb6626d6 100644 --- a/src/Rings/groebner.jl +++ b/src/Rings/groebner.jl @@ -506,30 +506,7 @@ function groebner_basis_with_transformation_matrix(I::MPolyIdeal; ordering::Mono end # syzygies ####################################################### -@doc raw""" - syzygy_generators(G::Vector{<:MPolyRingElem}) - -Return generators for the syzygies on the polynomials given as elements of `G`. - -# Examples -```jldoctest -julia> R, (x, y) = polynomial_ring(QQ, [:x, :y]) -(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x, y]) - -julia> S = syzygy_generators([x^3+y+2,x*y^2-13*x^2,y-14]) -3-element Vector{FreeModElem{QQMPolyRingElem}}: - (-y + 14)*e[2] + (-13*x^2 + x*y^2)*e[3] - (-169*y + 2366)*e[1] + (-13*x*y + 182*x - 196*y + 2744)*e[2] + (13*x^2*y^2 - 2548*x^2 + 196*x*y^2 + 169*y + 338)*e[3] - (-13*x^2 + 196*x)*e[1] + (-x^3 - 16)*e[2] + (x^4*y + 14*x^4 + 13*x^2 + 16*x*y + 28*x)*e[3] -``` -""" -function syzygy_generators(a::Vector{<:MPolyRingElem}) - I = ideal(a) - s = Singular.syz(singular_generators(I)) - F = free_module(parent(a[1]), length(a)) - @assert rank(s) == length(a) - return [F(s[i]) for i=1:Singular.ngens(s)] -end +# See src/Modules/UngradedModules/FreeMod.jl for the implementation. # leading ideal ####################################################### @doc raw""" diff --git a/test/Modules/UngradedModules.jl b/test/Modules/UngradedModules.jl index 09cccde6cd4a..5c4411fea1cf 100644 --- a/test/Modules/UngradedModules.jl +++ b/test/Modules/UngradedModules.jl @@ -1275,3 +1275,41 @@ end F = graded_free_module(Pn, 1) dualFIC = hom(FI.C, F) end + +@testset "issue 4203" begin + R, (x,y) = polynomial_ring(GF(2), ["x","y"]); + + g = [x+1, y+1] + s = syzygy_generators(g) + F = parent(first(s)) + s2 = syzygy_generators(g; parent=F) + @test s == s2 + s3 = syzygy_generators(g) + @test s2 != s3 + + A, _ = quo(R, ideal(R, [x^2+1, y^2+1])); + + g = A.([x+1, y+1]) + s = syzygy_generators(g) + F = parent(first(s)) + s2 = syzygy_generators(g; parent=F) + @test s == s2 + s3 = syzygy_generators(g) + @test s2 != s3 + + F = free_module(A,2); + M,_ = sub(F, [F([A(x+1),A(y+1)])]); + FF = free_module(A, ngens(M)); + phi = hom(FF, M, gens(M)); + K, = kernel(phi); + @test ambient_representatives_generators(K) == [(x*y + x + y + 1)*FF[1]] + @test_throws ErrorException standard_basis(K) + s1 = syzygy_generators(ambient_representatives_generators(M)) + G = parent(first(s1)) + s2 = syzygy_generators(ambient_representatives_generators(M); parent=G) + @test s1 == s2 + s3 = syzygy_generators(ambient_representatives_generators(M)) + @test s3 != s2 + @test_throws ArgumentError syzygy_generators(ambient_representatives_generators(M); parent=F) +end +