From 6b9dcc66ce9150f40dbe7cb3c1309ba9b359975b Mon Sep 17 00:00:00 2001 From: Rafael Mohr Date: Thu, 6 Jun 2024 17:00:20 +0200 Subject: [PATCH 01/16] adapt module gens to quotient rings --- src/Modules/UngradedModules/FreeResolutions.jl | 5 ++--- src/Modules/UngradedModules/ModuleGens.jl | 12 ++++++------ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Modules/UngradedModules/FreeResolutions.jl b/src/Modules/UngradedModules/FreeResolutions.jl index b7312236e7b0..d09680b42522 100644 --- a/src/Modules/UngradedModules/FreeResolutions.jl +++ b/src/Modules/UngradedModules/FreeResolutions.jl @@ -303,9 +303,8 @@ R^2 <---- R^6 <---- R^6 <---- R^2 <---- 0 **Note:** Over rings other than polynomial rings, the method will default to a lazy, iterative kernel computation. """ -function free_resolution(M::SubquoModule{<:MPolyRingElem}; - ordering::ModuleOrdering = default_ordering(M), - length::Int=0, algorithm::Symbol=:fres) +function free_resolution(M::SubquoModule{T}; + length::Int=0, algorithm::Symbol=:fres) where {T <: Union{MPolyRingElem, MPolyQuoRingElem}} coefficient_ring(base_ring(M)) isa AbstractAlgebra.Field || error("Must be defined over a field.") diff --git a/src/Modules/UngradedModules/ModuleGens.jl b/src/Modules/UngradedModules/ModuleGens.jl index 7a9f5933f376..d77cd1df6e9c 100644 --- a/src/Modules/UngradedModules/ModuleGens.jl +++ b/src/Modules/UngradedModules/ModuleGens.jl @@ -263,19 +263,19 @@ Convert a Singular vector to a free module element. """ function (F::FreeMod)(s::Singular.svector) pos = Int[] - values = [] Rx = base_ring(F) - R = base_ring(Rx) - for (i, e, c) = s + R = coefficient_ring(Rx) + values = elem_type(Rx)[] + for (i, e, c) in s f = Base.findfirst(x->x==i, pos) if f === nothing - push!(values, MPolyBuildCtx(base_ring(F))) + push!(values, zero(Rx)) f = length(values) push!(pos, i) end - push_term!(values[f], R(c), e) + values[f] += R(c)*prod(gens(Rx) .^ e) end - pv = Tuple{Int, elem_type(Rx)}[(pos[i], base_ring(F)(finish(values[i]))) for i=1:length(pos)] + pv = [(pos[i], values[i]) for i=1:length(pos)] return FreeModElem(sparse_row(base_ring(F), pv), F) end From f8a555bc6aebcda3e0c200b989dff5b99a98e50e Mon Sep 17 00:00:00 2001 From: Rafael Mohr Date: Tue, 18 Jun 2024 12:10:22 +0200 Subject: [PATCH 02/16] adjusts signatures of `prune_with_map` and `_presentation_minimal` --- src/Modules/UngradedModules/Presentation.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Modules/UngradedModules/Presentation.jl b/src/Modules/UngradedModules/Presentation.jl index 24ba8ce886df..121a15c0d72a 100644 --- a/src/Modules/UngradedModules/Presentation.jl +++ b/src/Modules/UngradedModules/Presentation.jl @@ -519,7 +519,7 @@ function prune_with_map(M::ModuleFP) return N, b end -function prune_with_map(M::ModuleFP{T}) where {T<:MPolyRingElem{<:FieldElem}} # The case that can be handled by Singular +function prune_with_map(M::ModuleFP{T}) where {T<:Union{MPolyRingElem, MPolyQuoRingElem}} # The case that can be handled by Singular # Singular presentation pm = presentation(M) @@ -564,7 +564,7 @@ function prune_with_map(M::ModuleFP{T}) where {T<:MPolyRingElem{<:FieldElem}} # end function _presentation_minimal(SQ::ModuleFP{T}; - minimal_kernel::Bool=true) where {T<:MPolyRingElem{<:FieldElem}} + minimal_kernel::Bool=true) where {T <: Union{MPolyRingElem, MPolyQuoRingElem}} R = base_ring(SQ) # Prepare to set some names From 6925b562295296d06022e7ffbe1af5cbb2f2b894 Mon Sep 17 00:00:00 2001 From: Rafael Mohr Date: Mon, 23 Sep 2024 16:25:46 +0200 Subject: [PATCH 03/16] compute free resolutions over quotients with sres --- src/Modules/UngradedModules/FreeResolutions.jl | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Modules/UngradedModules/FreeResolutions.jl b/src/Modules/UngradedModules/FreeResolutions.jl index f99b4e85cec5..3296fede85b7 100644 --- a/src/Modules/UngradedModules/FreeResolutions.jl +++ b/src/Modules/UngradedModules/FreeResolutions.jl @@ -396,11 +396,16 @@ julia> matrix(map(FM3, 1)) iterative kernel computation. """ function free_resolution(M::SubquoModule{T}; - length::Int=0, algorithm::Symbol=:fres) where {T <: Union{MPolyRingElem, MPolyQuoRingElem}} + length::Int=0, + algorithm::Symbol = T <:MPolyRingElem ? :fres : :sres) where {T <: Union{MPolyRingElem, MPolyQuoRingElem}} coefficient_ring(base_ring(M)) isa AbstractAlgebra.Field || error("Must be defined over a field.") + if T <: MPolyQuoRingElem + !iszero(length) || error("Specify a length up to which a free resolution should be computed") + end + cc_complete = false #= Start with presentation =# @@ -434,6 +439,9 @@ function free_resolution(M::SubquoModule{T}; elseif algorithm == :nres gbpres = singular_kernel_entry res = Singular.nres(gbpres, length) + elseif algorithm == :sres && T <: MPolyQuoRingElem + gbpres = Singular.std(singular_kernel_entry) + res = Singular.sres(gbpres, length) else error("Unsupported algorithm $algorithm") end From f47f4568f02c8192c601102dce26bd4298342ca4 Mon Sep 17 00:00:00 2001 From: Rafael Mohr Date: Mon, 23 Sep 2024 16:30:31 +0200 Subject: [PATCH 04/16] updates docu --- src/Modules/UngradedModules/FreeResolutions.jl | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Modules/UngradedModules/FreeResolutions.jl b/src/Modules/UngradedModules/FreeResolutions.jl index 3296fede85b7..8af80f5b6b6e 100644 --- a/src/Modules/UngradedModules/FreeResolutions.jl +++ b/src/Modules/UngradedModules/FreeResolutions.jl @@ -230,15 +230,15 @@ function _extend_free_resolution(cc::Hecke.ComplexOfMorphisms, idx::Int) end @doc raw""" - free_resolution(M::SubquoModule{<:MPolyRingElem}; - ordering::ModuleOrdering = default_ordering(M), - length::Int = 0, algorithm::Symbol = :fres - ) + free_resolution(M::SubquoModule{T}; + length::Int=0, + algorithm::Symbol = T <:MPolyRingElem ? :fres : :sres) where {T <: Union{MPolyRingElem, MPolyQuoRingElem}} Return a free resolution of `M`. If `length != 0`, the free resolution is only computed up to the `length`-th free module. -Current options for `algorithm` are `:fres`, `:nres`, and `:mres`. +Current options for `algorithm` are `:fres`, `:nres`, and `:mres` for modules over +polynomial rings and `:sres` for modules over quotients of polynomial rings. !!! note The function first computes a presentation of `M`. It then successively computes @@ -255,6 +255,10 @@ Current options for `algorithm` are `:fres`, `:nres`, and `:mres`. [EMSS16](@cite). Typically, this is more efficient than the approaches above, but the resulting resolution is far from being minimal. +!!! note + If `M` is a module over a quotient of a polynomial ring then the `length` keyword must + be set to a nonzero value. + # Examples ```jldoctest julia> R, (x, y, z) = polynomial_ring(QQ, ["x", "y", "z"]) @@ -392,7 +396,7 @@ julia> matrix(map(FM3, 1)) ``` -**Note:** Over rings other than polynomial rings, the method will default to a lazy, +**Note:** Over rings other than polynomial rings or quotients of polynomial rings, the method will default to a lazy, iterative kernel computation. """ function free_resolution(M::SubquoModule{T}; From 14c7ab3ad16424e64b747ec9bf92b2af9c848333 Mon Sep 17 00:00:00 2001 From: Rafael Mohr Date: Mon, 23 Sep 2024 16:34:59 +0200 Subject: [PATCH 05/16] adds test --- test/Modules/UngradedModules.jl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/Modules/UngradedModules.jl b/test/Modules/UngradedModules.jl index c417bbc9368c..55a8f5e64812 100644 --- a/test/Modules/UngradedModules.jl +++ b/test/Modules/UngradedModules.jl @@ -275,6 +275,14 @@ end @test relations(C) == [zero(F)] @test domain(isom) == F @test codomain(isom) == C + + R, (x, y, z) = polynomial_ring(QQ, ["x", "y", "z"]); + A, p = quo(R, ideal(R, x^5)) + M1 = identity_matrix(A, 2) + M2 = A[-x-y 2*x^2+x; z^4 0; 0 z^4; 8*x^3*y - 4*x^3 - 4*x^2*y + 2*x^2 + 2*x*y - x - y x; x^4 0] + M = SubquoModule(M1, M2) + fr = free_resolution(M, length = 9) + @test all(iszero, homology(fr[2:end])) end @testset "Prune With Map" begin From 452dd0279c98ee5f4952191b2c8926b64d750dd1 Mon Sep 17 00:00:00 2001 From: Rafael Mohr Date: Tue, 24 Sep 2024 10:28:12 +0200 Subject: [PATCH 06/16] fix tests --- test/Modules/UngradedModules.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Modules/UngradedModules.jl b/test/Modules/UngradedModules.jl index 55a8f5e64812..b696702483b4 100644 --- a/test/Modules/UngradedModules.jl +++ b/test/Modules/UngradedModules.jl @@ -282,7 +282,7 @@ end M2 = A[-x-y 2*x^2+x; z^4 0; 0 z^4; 8*x^3*y - 4*x^3 - 4*x^2*y + 2*x^2 + 2*x*y - x - y x; x^4 0] M = SubquoModule(M1, M2) fr = free_resolution(M, length = 9) - @test all(iszero, homology(fr[2:end])) + @test all(iszero, homology(fr)[2:end]) end @testset "Prune With Map" begin From 8588359603bff425d4ec528f5fb965978a9eedcd Mon Sep 17 00:00:00 2001 From: Rafael Mohr Date: Tue, 24 Sep 2024 16:22:35 +0200 Subject: [PATCH 07/16] fix another test --- test/Modules/MPolyQuo.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Modules/MPolyQuo.jl b/test/Modules/MPolyQuo.jl index ef654cacf178..4505b9e6c3a0 100644 --- a/test/Modules/MPolyQuo.jl +++ b/test/Modules/MPolyQuo.jl @@ -96,7 +96,7 @@ end A2 = FreeMod(A, 2) v = [x*A2[1] + y*A2[2], z*A2[1] + (x-1)*A2[2]] M, _ = quo(A2, v) - p = free_resolution(M) + p = free_resolution(M, length = 11) @test !iszero(p[10]) end From 71cbe8c4b8f6ea2c16eb436496724501f891d63d Mon Sep 17 00:00:00 2001 From: HechtiDerLachs Date: Tue, 24 Sep 2024 20:52:58 +0200 Subject: [PATCH 08/16] Add dispatch for singular-to-oscar conversion [no ci]. --- src/Modules/UngradedModules/ModuleGens.jl | 49 ++++++++++++++++++----- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/src/Modules/UngradedModules/ModuleGens.jl b/src/Modules/UngradedModules/ModuleGens.jl index d77cd1df6e9c..445269c65b83 100644 --- a/src/Modules/UngradedModules/ModuleGens.jl +++ b/src/Modules/UngradedModules/ModuleGens.jl @@ -261,22 +261,49 @@ end Convert a Singular vector to a free module element. """ -function (F::FreeMod)(s::Singular.svector) - pos = Int[] +function (F::FreeMod{<:MPolyRingElem})(s::Singular.svector) Rx = base_ring(F) R = coefficient_ring(Rx) - values = elem_type(Rx)[] + ctx = MPolyBuildCtx(Rx) + + # shortcut in order not to allocate the dictionary +# if isone(length(s)) # TODO: length doesn't work! +# (i, e, c) = first(s) +# push_term!(ctx, R(c), e) +# return FreeModElem(sparse_row(Qx, [(i, finish(ctx))])) +# end + + cache = IdDict{Int, typeof(ctx)}() for (i, e, c) in s - f = Base.findfirst(x->x==i, pos) - if f === nothing - push!(values, zero(Rx)) - f = length(values) - push!(pos, i) + ctx = get!(cache, i) do + MPolyBuildCtx(Rx) end - values[f] += R(c)*prod(gens(Rx) .^ e) + push_term!(ctx, R(c), e) end - pv = [(pos[i], values[i]) for i=1:length(pos)] - return FreeModElem(sparse_row(base_ring(F), pv), F) + return FreeModElem(sparse_row(Rx, [(i, finish(ctx)) for (i, ctx) in cache]), F) +end + +function (F::FreeMod{<:MPolyQuoRingElem})(s::Singular.svector) + Qx = base_ring(F)::MPolyQuoRing + Rx = base_ring(Qx)::MPolyRing + R = coefficient_ring(Rx) + ctx = MPolyBuildCtx(Rx) + + # shortcut in order not to allocate the dictionary +# if isone(length(s)) # TODO: length doesn't work! +# (i, e, c) = first(s) +# push_term!(ctx, R(c), e) +# return FreeModElem(sparse_row(Qx, [(i, Qx(finish(ctx)))])) +# end + + cache = IdDict{Int, typeof(ctx)}() + for (i, e, c) in s + ctx = get!(cache, i) do + MPolyBuildCtx(Rx) + end + push_term!(ctx, R(c), e) + end + return FreeModElem(sparse_row(Qx, [(i, Qx(finish(ctx))) for (i, ctx) in cache]), F) end # After creating the required infrastruture in Singular, From 5c2a895acb332fd3264666f7e018dc1be6ffe684 Mon Sep 17 00:00:00 2001 From: Matthias Zach Date: Wed, 25 Sep 2024 13:41:28 +0200 Subject: [PATCH 09/16] Enable length shortcut. --- src/Modules/UngradedModules/ModuleGens.jl | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/Modules/UngradedModules/ModuleGens.jl b/src/Modules/UngradedModules/ModuleGens.jl index 445269c65b83..b0feb8b5dec7 100644 --- a/src/Modules/UngradedModules/ModuleGens.jl +++ b/src/Modules/UngradedModules/ModuleGens.jl @@ -267,11 +267,11 @@ function (F::FreeMod{<:MPolyRingElem})(s::Singular.svector) ctx = MPolyBuildCtx(Rx) # shortcut in order not to allocate the dictionary -# if isone(length(s)) # TODO: length doesn't work! -# (i, e, c) = first(s) -# push_term!(ctx, R(c), e) -# return FreeModElem(sparse_row(Qx, [(i, finish(ctx))])) -# end + if isone(length(s)) + (i, e, c) = first(s) + push_term!(ctx, R(c), e) + return FreeModElem(sparse_row(Qx, [(i, finish(ctx))])) + end cache = IdDict{Int, typeof(ctx)}() for (i, e, c) in s @@ -283,6 +283,9 @@ function (F::FreeMod{<:MPolyRingElem})(s::Singular.svector) return FreeModElem(sparse_row(Rx, [(i, finish(ctx)) for (i, ctx) in cache]), F) end +# TODO: move this eventually +length(s::Singular.svector) = Int(Singular.libSingular.pLength(s.ptr)) + function (F::FreeMod{<:MPolyQuoRingElem})(s::Singular.svector) Qx = base_ring(F)::MPolyQuoRing Rx = base_ring(Qx)::MPolyRing @@ -290,11 +293,11 @@ function (F::FreeMod{<:MPolyQuoRingElem})(s::Singular.svector) ctx = MPolyBuildCtx(Rx) # shortcut in order not to allocate the dictionary -# if isone(length(s)) # TODO: length doesn't work! -# (i, e, c) = first(s) -# push_term!(ctx, R(c), e) -# return FreeModElem(sparse_row(Qx, [(i, Qx(finish(ctx)))])) -# end + if isone(length(s)) + (i, e, c) = first(s) + push_term!(ctx, R(c), e) + return FreeModElem(sparse_row(Qx, [(i, Qx(finish(ctx)))])) + end cache = IdDict{Int, typeof(ctx)}() for (i, e, c) in s From bb81af45fe487020e46f6e73b552749d925c1a5c Mon Sep 17 00:00:00 2001 From: Matthias Zach <85350711+HechtiDerLachs@users.noreply.github.com> Date: Wed, 25 Sep 2024 14:00:38 +0200 Subject: [PATCH 10/16] Update src/Modules/UngradedModules/ModuleGens.jl --- src/Modules/UngradedModules/ModuleGens.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/UngradedModules/ModuleGens.jl b/src/Modules/UngradedModules/ModuleGens.jl index b0feb8b5dec7..1d79160f7cdd 100644 --- a/src/Modules/UngradedModules/ModuleGens.jl +++ b/src/Modules/UngradedModules/ModuleGens.jl @@ -270,7 +270,7 @@ function (F::FreeMod{<:MPolyRingElem})(s::Singular.svector) if isone(length(s)) (i, e, c) = first(s) push_term!(ctx, R(c), e) - return FreeModElem(sparse_row(Qx, [(i, finish(ctx))])) + return FreeModElem(sparse_row(Rx, [(i, finish(ctx))])) end cache = IdDict{Int, typeof(ctx)}() From 16985d561fdd2ffead1f26f0ab7fd495ccd1b497 Mon Sep 17 00:00:00 2001 From: Matthias Zach Date: Wed, 25 Sep 2024 14:11:06 +0200 Subject: [PATCH 11/16] Fix tests. --- src/Modules/UngradedModules/ModuleGens.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Modules/UngradedModules/ModuleGens.jl b/src/Modules/UngradedModules/ModuleGens.jl index 1d79160f7cdd..39f02a098666 100644 --- a/src/Modules/UngradedModules/ModuleGens.jl +++ b/src/Modules/UngradedModules/ModuleGens.jl @@ -270,7 +270,7 @@ function (F::FreeMod{<:MPolyRingElem})(s::Singular.svector) if isone(length(s)) (i, e, c) = first(s) push_term!(ctx, R(c), e) - return FreeModElem(sparse_row(Rx, [(i, finish(ctx))])) + return FreeModElem(sparse_row(Rx, [(i, finish(ctx))]), F) end cache = IdDict{Int, typeof(ctx)}() @@ -296,7 +296,7 @@ function (F::FreeMod{<:MPolyQuoRingElem})(s::Singular.svector) if isone(length(s)) (i, e, c) = first(s) push_term!(ctx, R(c), e) - return FreeModElem(sparse_row(Qx, [(i, Qx(finish(ctx)))])) + return FreeModElem(sparse_row(Qx, [(i, Qx(finish(ctx)))]), F) end cache = IdDict{Int, typeof(ctx)}() From 846a46489f6c9cfedb48725c6cc45568e3f83822 Mon Sep 17 00:00:00 2001 From: Rafael Mohr Date: Wed, 25 Sep 2024 17:02:36 +0200 Subject: [PATCH 12/16] fix test --- test/Modules/MPolyQuo.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Modules/MPolyQuo.jl b/test/Modules/MPolyQuo.jl index 4505b9e6c3a0..cb179c5ded88 100644 --- a/test/Modules/MPolyQuo.jl +++ b/test/Modules/MPolyQuo.jl @@ -106,7 +106,7 @@ end A, _ = quo(R, I) A1 = FreeMod(A, 1) M, _ = quo(A1, [y*A1[1], z*A1[1]]) - p = free_resolution(M) + p = free_resolution(M, length = 11) @test iszero(p[10]) end From 11bf9f4f1563611e3c9ffba76361d68c49ff0fa7 Mon Sep 17 00:00:00 2001 From: Rafael Mohr <50295563+RafaelDavidMohr@users.noreply.github.com> Date: Thu, 26 Sep 2024 10:41:46 +0200 Subject: [PATCH 13/16] fix test Co-authored-by: Matthias Zach <85350711+HechtiDerLachs@users.noreply.github.com> --- test/Modules/MPolyQuo.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Modules/MPolyQuo.jl b/test/Modules/MPolyQuo.jl index cb179c5ded88..567e58134506 100644 --- a/test/Modules/MPolyQuo.jl +++ b/test/Modules/MPolyQuo.jl @@ -107,7 +107,7 @@ end A1 = FreeMod(A, 1) M, _ = quo(A1, [y*A1[1], z*A1[1]]) p = free_resolution(M, length = 11) - @test iszero(p[10]) + @test p[10] isa FreeMod end @testset "kernels of FreeMod -> SubquoModule" begin From de3ec6584b8f6d7332ca13abfe7fc9edb9214fe7 Mon Sep 17 00:00:00 2001 From: Rafael Mohr <50295563+RafaelDavidMohr@users.noreply.github.com> Date: Thu, 26 Sep 2024 10:42:04 +0200 Subject: [PATCH 14/16] fix test Co-authored-by: Matthias Zach <85350711+HechtiDerLachs@users.noreply.github.com> --- test/Modules/MPolyQuo.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Modules/MPolyQuo.jl b/test/Modules/MPolyQuo.jl index 567e58134506..43e639cf6900 100644 --- a/test/Modules/MPolyQuo.jl +++ b/test/Modules/MPolyQuo.jl @@ -97,7 +97,7 @@ end v = [x*A2[1] + y*A2[2], z*A2[1] + (x-1)*A2[2]] M, _ = quo(A2, v) p = free_resolution(M, length = 11) - @test !iszero(p[10]) + @test p[10] isa FreeMod end @testset "free resolutions II" begin From 3db4e446ee9a531f1ecbad1d8a07019253d4b890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Fri, 27 Sep 2024 17:59:50 +0200 Subject: [PATCH 15/16] Bump Singular compat --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 9f9318fb906e..e4dd0e14b516 100644 --- a/Project.toml +++ b/Project.toml @@ -40,7 +40,7 @@ Polymake = "0.11.20" Random = "1.6" RandomExtensions = "0.4.3" Serialization = "1.6" -Singular = "0.23.4" +Singular = "0.23.8" TOPCOM_jll = "0.17.8" UUIDs = "1.6" cohomCalg_jll = "0.32.0" From 64f6b4439cf77a27de44bafb3a294de5c6755844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Fri, 27 Sep 2024 18:00:22 +0200 Subject: [PATCH 16/16] Update src/Modules/UngradedModules/ModuleGens.jl --- src/Modules/UngradedModules/ModuleGens.jl | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Modules/UngradedModules/ModuleGens.jl b/src/Modules/UngradedModules/ModuleGens.jl index 39f02a098666..ec47c7dee1fc 100644 --- a/src/Modules/UngradedModules/ModuleGens.jl +++ b/src/Modules/UngradedModules/ModuleGens.jl @@ -283,9 +283,6 @@ function (F::FreeMod{<:MPolyRingElem})(s::Singular.svector) return FreeModElem(sparse_row(Rx, [(i, finish(ctx)) for (i, ctx) in cache]), F) end -# TODO: move this eventually -length(s::Singular.svector) = Int(Singular.libSingular.pLength(s.ptr)) - function (F::FreeMod{<:MPolyQuoRingElem})(s::Singular.svector) Qx = base_ring(F)::MPolyQuoRing Rx = base_ring(Qx)::MPolyRing