Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement syzygy_generators for lists of module elements #4204

Merged
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))
HechtiDerLachs marked this conversation as resolved.
Show resolved Hide resolved
@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
HechtiDerLachs marked this conversation as resolved.
Show resolved Hide resolved
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

Loading