diff --git a/docs/oscar_references.bib b/docs/oscar_references.bib index 9f41157264b9..5eb4ae50eeae 100644 --- a/docs/oscar_references.bib +++ b/docs/oscar_references.bib @@ -761,6 +761,20 @@ @Article{EM19 doi = {10.1112/jlms.12232} } +@Article{EMSS16, + author = {Er{\"o}cal, Bur{\c{c}}in and Motsak, Oleksandr and Schreyer, Frank-Olaf and Steenpa{\ss}, Andreas}, + title = {Refined algorithms to compute syzygies}, + zbl = {1405.14138}, + journal = {J. Symb. Comput.}, + fjournal = {Journal of Symbolic Computation}, + volume = {74}, + pages = {308--327}, + year = {2016}, + doi = {10.1016/j.jsc.2015.07.004}, + language = {English}, + zbmath = {6517845} +} + @Article{ES96, author = {Eisenbud, David and Sturmfels, Bernd}, title = {Binomial ideals}, diff --git a/docs/src/CommutativeAlgebra/homological_algebra.md b/docs/src/CommutativeAlgebra/homological_algebra.md index fc25f5605bb9..fdcd5f93aacf 100644 --- a/docs/src/CommutativeAlgebra/homological_algebra.md +++ b/docs/src/CommutativeAlgebra/homological_algebra.md @@ -12,6 +12,13 @@ for module homomorphisms and basic functions for handling chain and cochain comp discussed in the module section. Building on these functions, we here introduce further OSCAR functionality supporting computations in homological algebra. + +## Pruning Modules + +```@docs +prune_with_map(M::ModuleFP) +``` + ## Presentations ```@docs @@ -24,7 +31,7 @@ presentation(M::ModuleFP) present_as_cokernel(M::SubquoModule, task::Symbol = :none) ``` -## Syzygies and Free Resolutions +## Free Resolutions ```@docs free_resolution(M::SubquoModule{<:MPolyRingElem}; diff --git a/docs/src/CommutativeAlgebra/intro.md b/docs/src/CommutativeAlgebra/intro.md index 4927dd41dccf..f4d2f169ba38 100644 --- a/docs/src/CommutativeAlgebra/intro.md +++ b/docs/src/CommutativeAlgebra/intro.md @@ -27,8 +27,8 @@ a *Gröbner basis*. We refer to the corresponding [section](@ref gb_fields) in t !!! note In Oscar, it is possible to equip multivariate polynomial rings with gradings by finitely presented groups. - Most functions discussed in this chapter apply to both ungraded and graded polynomial rings. However, - for simplicity of the presentation, in this documentation, the functions are often only illustrated by examples with + Most functions related to multivariate polynomial rings discussed in this chapter apply to both the ungraded and graded case. + However, for simplicity of the presentation, in this documentation, the functions are often only illustrated by examples with focus on the former case, but work similarly for homogeneous ideals and graded modules in the latter case. !!! note diff --git a/src/Modules/UngradedModules/FreeResolutions.jl b/src/Modules/UngradedModules/FreeResolutions.jl index b7312236e7b0..81e32c5e6c8a 100644 --- a/src/Modules/UngradedModules/FreeResolutions.jl +++ b/src/Modules/UngradedModules/FreeResolutions.jl @@ -241,14 +241,28 @@ end @doc raw""" free_resolution(M::SubquoModule{<:MPolyRingElem}; ordering::ModuleOrdering = default_ordering(M), - length::Int=0, algorithm::Symbol=:fres + length::Int = 0, algorithm::Symbol = :fres ) Return a free resolution of `M`. If `length != 0`, the free resolution is only computed up to the `length`-th free module. -At the moment, options for `algorithm` are `:fres`, `:mres` and `:nres`. With `:mres` or `:nres`, -minimal free resolutions are returned. +Current options for `algorithm` are `:fres`, `:nres`, and `:mres`. + +!!! note + The function first computes a presentation of `M`. It then successively computes + higher syzygy modules. + +!!! note + - If `algorithm == mres`, and `M` is positively graded, a minimal free resolution is returned. + - If `algorithm == nres`, and `M` is positively graded, the function proceeds as above except + that it starts by computing a presentation which is not neccessarily minimal. + In both cases, if `M` is not (positively) graded, the function still aims at returning an ''improved'' resolution. + +!!! note + If `algorithm == fres`, the function relies on an enhanced version of Schreyer's algorithm + [EMSS16](@cite). Typically, this is more efficient than the approaches above, but the + resulting resolution is far from being minimal. # Examples ```jldoctest @@ -293,11 +307,98 @@ R^2 <---- R^6 <---- R^6 <---- R^2 <---- 0 julia> is_complete(fr) true +``` + +``` +julia> R, (w, x, y, z) = graded_polynomial_ring(QQ, ["w", "x", "y", "z"]); + +julia> Z = R(0) +0 + +julia> O = R(1) +1 + +julia> B = [Z Z Z O; w*y w*z-x*y x*z-y^2 Z]; -julia> fr = free_resolution(M, algorithm=:fres) +julia> A = transpose(matrix(B)); + +julia> M = graded_cokernel(A) +Graded subquotient of submodule of R^2 generated by +1 -> e[1] +2 -> e[2] +by submodule of R^2 generated by +1 -> w*y*e[2] +2 -> (w*z - x*y)*e[2] +3 -> (x*z - y^2)*e[2] +4 -> e[1] + +julia> FM1 = free_resolution(M) Free resolution of M -R^2 <---- R^6 <---- R^6 <---- R^2 <---- 0 +R^2 <---- R^7 <---- R^8 <---- R^3 <---- 0 0 1 2 3 4 + +julia> betti_table(FM1) + 0 1 2 3 +----------------- +-1 : - 1 - - +0 : 2 - - - +1 : - 3 3 1 +2 : - 3 5 2 +----------------- +total: 2 7 8 3 + + +julia> matrix(map(FM1, 1)) +[1 0] +[0 -x*z + y^2] +[0 -w*z + x*y] +[0 w*y] +[0 x^2*z] +[0 w*x*z] +[0 w^2*z] + +julia> FM2 = free_resolution(M, algorithm = :nres) +Free resolution of M +R^2 <---- R^4 <---- R^4 <---- R^2 <---- 0 +0 1 2 3 4 + +julia> betti_table(FM2) + 0 1 2 3 +----------------- +-1 : - 1 - - +0 : 2 - - - +1 : - 3 - - +2 : - - 4 2 +----------------- +total: 2 4 4 2 + + +julia> matrix(map(FM2, 1)) +[1 0] +[0 -x*z + y^2] +[0 -w*z + x*y] +[0 w*y] + +julia> FM3 = free_resolution(M, algorithm = :mres) +Free resolution of M +R^1 <---- R^3 <---- R^4 <---- R^2 <---- 0 +0 1 2 3 4 + +julia> betti_table(FM3) + 0 1 2 3 +----------------- +0 : 1 - - - +1 : - 3 - - +2 : - - 4 2 +----------------- +total: 1 3 4 2 + + +julia> matrix(map(FM3, 1)) +[-x*z + y^2] +[-w*z + x*y] +[ w*y] + ``` **Note:** Over rings other than polynomial rings, the method will default to a lazy, diff --git a/src/Modules/UngradedModules/Presentation.jl b/src/Modules/UngradedModules/Presentation.jl index 24ba8ce886df..f651509f872f 100644 --- a/src/Modules/UngradedModules/Presentation.jl +++ b/src/Modules/UngradedModules/Presentation.jl @@ -1,10 +1,13 @@ #################### @doc raw""" - presentation(M::SubquoModule; minimal=false) + presentation(M::SubquoModule; minimal = false) -Return a free presentation of `M`. If `minimal` is set to `true`, the returned -presentation is minimal. +Return a (free) presentation of `M`. + +!!! note + If `minimal` is `true`, and `M` is positively graded, a minimal presentation is returned. + If `minimal` is `true`, and `M` is not (positively) graded, the function still aims at returning an ''improved'' presentation. """ function presentation(SQ::SubquoModule; minimal=false) @@ -191,9 +194,9 @@ end @doc raw""" presentation(F::FreeMod) -Return a free presentation of `F`. +Return a (free) presentation of `F`. """ -function presentation(F::FreeMod) +function presentation(F::FreeMod; minimal = false) if is_graded(F) Z = graded_free_module(F.R, 0) else @@ -206,22 +209,48 @@ function presentation(F::FreeMod) end @doc raw""" - presentation(M::ModuleFP) + presentation(M::ModuleFP; minimal = false) + +Return a (free) presentation of `M`. -Return a free presentation of `M`. +!!! note + If `minimal` is `true`, and `M` is positively graded, a minimal presentation is returned. + If `minimal` is `true`, and `M` is not (positively) graded, the function still aims at returning an ''improved'' presentation. # Examples ```jldoctest -julia> R, (x, y, z) = polynomial_ring(QQ, ["x", "y", "z"]); +julia> R, (w, x, y, z) = graded_polynomial_ring(QQ, ["w", "x", "y", "z"]); -julia> A = R[x; y]; +julia> Z = R(0) +0 -julia> B = R[x^2; y^3; z^4]; +julia> O = R(1) +1 -julia> M = SubquoModule(A, B); +julia> B = [Z Z Z O; w*y w*z-x*y x*z-y^2 Z]; + +julia> A = transpose(matrix(B)) +[0 w*y] +[0 w*z - x*y] +[0 x*z - y^2] +[1 0] + +julia> M = graded_cokernel(A) +Graded subquotient of submodule of R^2 generated by +1 -> e[1] +2 -> e[2] +by submodule of R^2 generated by +1 -> w*y*e[2] +2 -> (w*z - x*y)*e[2] +3 -> (x*z - y^2)*e[2] +4 -> e[1] + +julia> PM1 = presentation(M) +0 <---- M <---- R^2 <---- R^4 + +julia> PM2 = presentation(M, minimal = true) +0 <---- M <---- R^1 <---- R^3 -julia> P = presentation(M) -0 <---- M <---- R^2 <---- R^5 ``` ```jldoctest @@ -313,7 +342,7 @@ e[5] -> z^4*e[2] Homogeneous module homomorphism ``` """ -function presentation(M::ModuleFP) +function presentation(M::ModuleFP; minimal=false) error("presentation is not implemented for the given types.") end @@ -477,36 +506,48 @@ end @doc raw""" prune_with_map(M::ModuleFP) -Returns another module `N` and an isomorphism from `N` to `M` such +If `M` is positively graded, return a module `N` and an isomorphism from `N` to `M` such that `N` is generated by a minimal number of elements. +If `M` is not (positively) graded, the function still aims at reducing the number of generators. + # Examples ```jldoctest -julia> R, (x, y) = polynomial_ring(QQ, ["x", "y"]); +julia> R, (w, x, y, z) = graded_polynomial_ring(QQ, ["w", "x", "y", "z"]); -julia> M = SubquoModule(identity_matrix(R, 2), R[1 x+y]) -Subquotient of Submodule with 2 generators +julia> Z = R(0) +0 + +julia> O = R(1) +1 + +julia> B = [Z Z Z O; w*y w*z-x*y x*z-y^2 Z]; + +julia> A = transpose(matrix(B)) +[0 w*y] +[0 w*z - x*y] +[0 x*z - y^2] +[1 0] + +julia> M = graded_cokernel(A) +Graded subquotient of submodule of R^2 generated by 1 -> e[1] 2 -> e[2] -by Submodule with 1 generator -1 -> e[1] + (x + y)*e[2] +by submodule of R^2 generated by +1 -> w*y*e[2] +2 -> (w*z - x*y)*e[2] +3 -> (x*z - y^2)*e[2] +4 -> e[1] -julia> N, phi = prune_with_map(M) -(Submodule with 1 generator -1 -> e[1] -represented as subquotient with no relations., Map with following data -Domain: -======= -Submodule with 1 generator -1 -> e[1] -represented as subquotient with no relations. -Codomain: -========= -Subquotient of Submodule with 2 generators +julia> N, phi = prune_with_map(M); + +julia> N +Graded subquotient of submodule of R^1 generated by 1 -> e[1] -2 -> e[2] -by Submodule with 1 generator -1 -> e[1] + (x + y)*e[2]) +by submodule of R^1 generated by +1 -> (-x*z + y^2)*e[1] +2 -> (-w*z + x*y)*e[1] +3 -> w*y*e[1] julia> phi(first(gens(N))) e[2] @@ -565,6 +606,7 @@ end function _presentation_minimal(SQ::ModuleFP{T}; minimal_kernel::Bool=true) where {T<:MPolyRingElem{<:FieldElem}} + R = base_ring(SQ) # Prepare to set some names