diff --git a/src/module/module.jl b/src/module/module.jl index fd7c9c3b4..60e85327f 100644 --- a/src/module/module.jl +++ b/src/module/module.jl @@ -1,6 +1,6 @@ export jet, minimal_generating_set, ModuleClass, rank, smodule, slimgb, eliminate, modulo, lift, division, divrem, prune_with_map, - prune_with_map_projection + prune_with_map_projection, quotient, contains, saturation, saturation2 ############################################################################### # @@ -446,6 +446,7 @@ function nres(I::smodule{spoly{T}}, max_length::Int) where T <: Nemo.FieldElem return sresolution{spoly{T}}(R, r, Bool(minimal), false) end + ############################################################################### # # Module constructors @@ -650,3 +651,60 @@ function hilbert_series(M::smodule{spoly{T}}, w::Vector{<:Integer}, shifts::Vect GC.@preserve M R libSingular.scHilbWeighted(M.ptr, R.ptr, w, shifts, z) return z end + +############################################################################### +# +# Containment +# +############################################################################### + +function contains(I::smodule{spoly{T}}, J::smodule{spoly{T}}) where T <: Nemo.FieldElem + check_parent(I, J) + if !I.isGB + I = std(I) + end + return iszero(reduce(J, I)) +end + +############################################################################### +# +# Quotient +# +############################################################################### + +function quotient(I::smodule{spoly{T}}, J::smodule{spoly{T}}) where T <: Nemo.FieldElem + R = base_ring(I) + S = elem_type(R) + ptr = GC.@preserve I J R libSingular.id_Quotient(I.ptr, J.ptr, I.isGB, R.ptr) + return Module(smatrix{spoly{T}}(R, ptr)) +end + +############################################################################### +# +# Saturation +# +############################################################################### +function saturation(I::smodule{spoly{T}}, J::smodule{spoly{T}}) where T <: Nemo.FieldElem + check_parent(I, J) + has_global_ordering(base_ring(I)) || error("Must be over a ring with global ordering") + if !I.isGB + I = std(I) + end + k = 0 + done = false + while !done + Q = quotient(I, J) + done = contains(I, Q) + I = std(Q) + k += 1 + end + return I, k - 1 +end + +function saturation2(I::smodule{spoly{T}}, J::smodule{spoly{T}}) where T <: Nemo.FieldElem + check_parent(I, J) + R = base_ring(I) + has_global_ordering(R) || error("Must be over a ring with global ordering") + ptr_res,k=libSingular.id_Saturation(I.ptr,J.ptr,R.ptr) + return (Module(smatrix{spoly{T}}(R,ptr_res))),k +end diff --git a/test/module/smodule-test.jl b/test/module/smodule-test.jl index f15a93dfe..1beaa86d3 100644 --- a/test/module/smodule-test.jl +++ b/test/module/smodule-test.jl @@ -330,3 +330,45 @@ end @test p[3] == 2 end + +@testset "smodule.contains" begin + R, (x, y) = polynomial_ring(QQ, ["x", "y"]) + + I = Singular.Module(R, vector(R,y^3)) + J = Singular.Module(R, vector(R,y^2)) + + @test contains(I, J) == false + @test contains(J, I) == true +end + +@testset "smodule.quotient" begin + R, (x, y) = polynomial_ring(QQ, ["x", "y"]) + + I = Singular.Module(R, vector(R,x^2 + x*y + 1), vector(R,2y^2 + 3)) + J = Singular.Module(R, vector(R,x*y^2 + x + 1), vector(R,2x*y + 1), vector(R,x*y + 1)) + + A = quotient(I, J) + B = Singular.Module(R, vector(R, 2*y^2+3), vector(R, x^2+x*y+1)) + @test A[1] == B[1] + @test A[2] == B[2] +end + +@testset "smodule.saturation" begin + R, (x, y) = polynomial_ring(QQ, ["x", "y"]) + + I = Singular.Module(R, vector(R,(x^2 + x*y + 1)*(2y^2+1)^3), vector(R,(2y^2 + 3)*(2y^2+1)^2)) + J = Singular.Module(R, vector(R,2y^2 + 1)) + + A,k = saturation(I, J) + + B = Singular.Module(R, vector(R,2*y^2+3), vector(R,x^2+x*y+1)) + @test A[1] == B[1] + @test A[2] == B[2] + @test k == 2 + + A,k = saturation2(I, J) + + @test A[1] == B[1] + @test A[2] == B[2] + @test k == 2 +end