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

Attempt to clear up mpolyquo modules #4147

Closed
29 changes: 20 additions & 9 deletions src/Modules/UngradedModules/FreeResolutions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"])
Expand Down Expand Up @@ -392,16 +396,20 @@ 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{<:MPolyRingElem};
ordering::ModuleOrdering = default_ordering(M),
length::Int=0, algorithm::Symbol=:fres)
function free_resolution(M::SubquoModule{T};
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 =#
Expand Down Expand Up @@ -435,6 +443,9 @@ function free_resolution(M::SubquoModule{<:MPolyRingElem};
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
Expand Down
53 changes: 40 additions & 13 deletions src/Modules/UngradedModules/ModuleGens.jl
Original file line number Diff line number Diff line change
Expand Up @@ -261,22 +261,49 @@ end

Convert a Singular vector to a free module element.
"""
function (F::FreeMod)(s::Singular.svector)
pos = Int[]
values = []
function (F::FreeMod{<:MPolyRingElem})(s::Singular.svector)
Rx = base_ring(F)
R = base_ring(Rx)
for (i, e, c) = s
f = Base.findfirst(==(i), pos)
if f === nothing
push!(values, MPolyBuildCtx(base_ring(F)))
f = length(values)
push!(pos, i)
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, finish(ctx))]))
# end

cache = IdDict{Int, typeof(ctx)}()
for (i, e, c) in s
ctx = get!(cache, i) do
MPolyBuildCtx(Rx)
end
push_term!(values[f], R(c), e)
push_term!(ctx, R(c), e)
end
pv = Tuple{Int, elem_type(Rx)}[(pos[i], base_ring(F)(finish(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,
Expand Down
5 changes: 3 additions & 2 deletions src/Modules/UngradedModules/Presentation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,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)
Expand Down Expand Up @@ -577,7 +577,8 @@ 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)

R = base_ring(SQ)

Expand Down
22 changes: 11 additions & 11 deletions src/Modules/mpolyquo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@
DomainType<:FreeMod{<:MPolyQuoRingElem},
CodomainType<:FreeMod{<:MPolyQuoRingElem}
}
@show "this kernel"
R = base_ring(codomain(f))
P = base_ring(R)
F = _poly_module(domain(f))
M = _as_poly_module(codomain(f))
id = _iso_with_poly_module(codomain(f))
# Why does img_gens(f) return a list of SubQuoElems???
phi = _lifting_iso(codomain(f))
g = hom(F, M, phi.(f.(gens(domain(f)))))
K, inc = kernel(g)
tr = compose(inc, _poly_module_restriction(domain(f)))
KK, inc2 = sub(domain(f), unique!(filter!(!iszero, tr.(gens(K)))))
return KK, inc2
SR = singular_poly_ring(R)
F = domain(f)
G = codomain(f)
img_gens = images_of_generators(f)
MG = ModuleGens(img_gens, G)
singular_assure(MG)
sing_ker_gens = Singular.syz(singular_generators(MG))
@show "done with syzygy computations"
KG = ModuleGens(F, sing_ker_gens)
return sub(F, oscar_generators(KG))
end

function Base.in(a::FreeModElem{T}, M::SubModuleOfFreeModule{T}) where {T<:MPolyQuoRingElem}
Expand Down
34 changes: 27 additions & 7 deletions src/Rings/MPolyMap/MPolyAnyMap.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,37 @@ const _DomainTypes = Union{MPolyRing, MPolyQuoRing}
coeff_map::U
img_gens::Vector{V}
temp_ring # temporary ring used when evaluating maps
variable_indices::Vector{Int} # a table where the i-th entry contains the
# index of the variable where it's mapped to
# in case the mapping takes such a particularly
# simple form.

function MPolyAnyMap{D, C, U, V}(domain::D,
codomain::C,
coeff_map::U,
img_gens::Vector{V}) where {D, C, U, V}
@assert V === elem_type(C)
for g in img_gens
@assert parent(g) === codomain "elements does not have the correct parent"
end
codomain::C,
coeff_map::U,
img_gens::Vector{V}) where {D, C, U, V}
@assert V === elem_type(C)
for g in img_gens
@assert parent(g) === codomain "elements does not have the correct parent"
end
return new{D, C, U, V}(domain, codomain, coeff_map, img_gens)
end
function MPolyAnyMap{D, C, U, V}(domain::D,
codomain::C,
coeff_map::U,
img_gens::Vector{V}) where {D <: Union{<:MPolyRing, <:MPolyQuoRing},
C <: Union{<:MPolyRing, <:MPolyQuoRing},
U, V}
@assert V === elem_type(C)
for g in img_gens
@assert parent(g) === codomain "elements does not have the correct parent"
end
result = new{D, C, U, V}(domain, codomain, coeff_map, img_gens)
if all(is_gen(x) for x in img_gens) && allunique(img_gens)
result.variable_indices = [findfirst(x==y for y in gens(codomain)) for x in img_gens]
end
return result
end
end

function MPolyAnyMap(d::D, c::C, cm::U, ig::Vector{V}) where {D, C, U, V}
Expand Down
86 changes: 85 additions & 1 deletion src/Rings/MPolyMap/MPolyRing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -132,17 +132,101 @@ end
#
################################################################################

# Some additional methods needed for the test in the constructor for MPolyAnyMap
is_gen(x::MPolyQuoRingElem) = is_gen(lift(x))
is_gen(x::MPolyDecRingElem) = is_gen(forget_grading(x))

function _evaluate_plain(F::MPolyAnyMap{<:MPolyRing, <:MPolyRing}, u)
if isdefined(F, :variable_indices)
S = codomain(F)::MPolyRing
r = ngens(S)
ctx = MPolyBuildCtx(S)
for (c, e) in zip(AbstractAlgebra.coefficients(u), AbstractAlgebra.exponent_vectors(u))
ee = [0 for _ in 1:r]
for (i, k) in enumerate(e)
ee[F.variable_indices[i]] = k
end
push_term!(ctx, c, ee)
end
return finish(ctx)
end

return evaluate(u, F.img_gens)
end

function _evaluate_plain(F::MPolyAnyMap{<: MPolyRing}, u)
return evaluate(u, F.img_gens)
end

# See the comment in MPolyQuo.jl
function _evaluate_plain(F::MPolyAnyMap{<:MPolyRing, <:MPolyQuoRing}, u)
if isdefined(F, :variable_indices)
S = base_ring(codomain(F))::MPolyRing
r = ngens(S)
ctx = MPolyBuildCtx(S)
for (c, e) in zip(coefficients(u), exponents(u))
ee = [0 for _ in 1:r]
for (i, k) in enumerate(e)
ee[F.variable_indices[i]] = k
end
push_term!(ctx, c, ee)
end
return codomain(F)(finish(ctx))
end
A = codomain(F)
v = evaluate(lift(u), lift.(_images(F)))
return simplify(A(v))
end

function _evaluate_general(F::MPolyAnyMap{<:MPolyRing, <:MPolyRing}, u)
if domain(F) === codomain(F) && coefficient_map(F) === nothing
return evaluate(map_coefficients(coefficient_map(F), u,
parent = domain(F)), F.img_gens)
else
S = temp_ring(F)
if S !== nothing
if !isdefined(F, :variable_indices) || coefficient_ring(S) !== codomain(F)
return evaluate(map_coefficients(coefficient_map(F), u,
parent = S), F.img_gens)
else
tmp_poly = map_coefficients(coefficient_map(F), u, parent = S)
cod_ring = codomain(F)::MPolyRing
r = ngens(cod_ring)
ctx = MPolyBuildCtx(cod_ring)
for (p, e) in zip(coefficients(tmp_poly), exponents(tmp_poly))
ee = [0 for _ in 1:r]
for (i, k) in enumerate(e)
ee[F.variable_indices[i]] = k
end
p::MPolyRingElem
@assert parent(p) === cod_ring
for (c, d) in zip(coefficients(p), exponents(p))
push_term!(ctx, c, ee+d)
end
end
return finish(ctx)
end
else
if !isdefined(F, :variable_indices)
return evaluate(map_coefficients(coefficient_map(F), u), F.img_gens)
else
tmp_poly = map_coefficients(coefficient_map(F), u)
cod_ring = codomain(F)::MPolyRing
r = ngens(cod_ring)
ctx = MPolyBuildCtx(cod_ring)
for (c, e) in zip(coefficients(tmp_poly), exponents(tmp_poly))
ee = [0 for _ in 1:r]
for (i, k) in enumerate(e)
ee[F.variable_indices[i]] = k
end
push_term!(ctx, c, ee)
end
return finish(ctx)
end
end
end
end

function _evaluate_general(F::MPolyAnyMap{<: MPolyRing}, u)
if domain(F) === codomain(F) && coefficient_map(F) === nothing
return evaluate(map_coefficients(coefficient_map(F), u,
Expand All @@ -151,7 +235,7 @@ function _evaluate_general(F::MPolyAnyMap{<: MPolyRing}, u)
S = temp_ring(F)
if S !== nothing
return evaluate(map_coefficients(coefficient_map(F), u,
parent = S), F.img_gens)
parent = S), F.img_gens)
else
return evaluate(map_coefficients(coefficient_map(F), u), F.img_gens)
end
Expand Down
2 changes: 1 addition & 1 deletion test/Modules/MPolyQuo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
8 changes: 8 additions & 0 deletions test/Modules/UngradedModules.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading