Skip to content

Commit

Permalink
Implement syzygy_generators for lists of module elements (#4204)
Browse files Browse the repository at this point in the history
Co-authored-by: Tommy Hofmann <thofma@gmail.com>
  • Loading branch information
HechtiDerLachs and thofma authored Oct 17, 2024
1 parent 753fa25 commit 780f939
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 25 deletions.
64 changes: 64 additions & 0 deletions src/Modules/UngradedModules/FreeMod.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

6 changes: 5 additions & 1 deletion src/Modules/UngradedModules/SubquoModule.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
25 changes: 1 addition & 24 deletions src/Rings/groebner.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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"""
Expand Down
38 changes: 38 additions & 0 deletions test/Modules/UngradedModules.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 780f939

Please sign in to comment.