Homological Algebra

Some OSCAR functions which are fundamental to homological algebra such as the kernel function for module homomorphisms and basic functions for handling chain and cochain complexes are discussed in the module section. Building on these functions, we here introduce further OSCAR functionality supporting computations in homological algebra.

Presentations

presentationMethod
presentation(M::ModuleFP)

Return a free presentation of M.

Examples

julia> R, (x, y, z) = polynomial_ring(QQ, ["x", "y", "z"]);

julia> A = R[x; y];

julia> B = R[x^2; y^3; z^4];

julia> M = SubquoModule(A, B);

julia> P = presentation(M)
0 <---- M <---- R^2 <---- R^5
julia> Rg, (x, y, z) = graded_polynomial_ring(QQ, ["x", "y", "z"]);

julia> F = graded_free_module(Rg, [1,2,2]);

julia> p = presentation(F)
0 <---- F <---- F <---- 0

julia> p[-2]
Graded free module Rg^0 of rank 0 over Rg

julia> p[-1]
Graded free module Rg^1([-1]) + Rg^2([-2]) of rank 3 over Rg

julia> p[0]
Graded free module Rg^1([-1]) + Rg^2([-2]) of rank 3 over Rg

julia> p[1]
Graded free module Rg^0 of rank 0 over Rg

julia> map(p,-1)
F -> 0
e[1] -> 0
e[2] -> 0
e[3] -> 0
Homogeneous module homomorphism

julia> map(p,0)
F -> F
e[1] -> e[1]
e[2] -> e[2]
e[3] -> e[3]
Homogeneous module homomorphism

julia> map(p,1)
0 -> F
Homogeneous module homomorphism

julia> F = graded_free_module(Rg, 1);

julia> A = Rg[x; y];

julia> B = Rg[x^2; y^3; z^4];

julia> M = SubquoModule(F, A, B);

julia> P = presentation(M)
0 <---- M <---- Rg^2 <---- Rg^5

julia> P[-2]
Graded free module Rg^0 of rank 0 over Rg

julia> P[-1]
Graded subquotient of submodule of F generated by
1 -> x*e[1]
2 -> y*e[1]
by submodule of F generated by
1 -> x^2*e[1]
2 -> y^3*e[1]
3 -> z^4*e[1]

julia> P[0]
Graded free module Rg^2([-1]) of rank 2 over Rg

julia> P[1]
Graded free module Rg^2([-2]) + Rg^1([-3]) + Rg^2([-5]) of rank 5 over Rg

julia> map(P,-1)
M -> 0
x*e[1] -> 0
y*e[1] -> 0
Homogeneous module homomorphism

julia> map(P,0)
Rg^2 -> M
e[1] -> x*e[1]
e[2] -> y*e[1]
Homogeneous module homomorphism

julia> map(P,1)
Rg^5 -> Rg^2
e[1] -> x*e[1]
e[2] -> -y*e[1] + x*e[2]
e[3] -> y^2*e[2]
e[4] -> z^4*e[1]
e[5] -> z^4*e[2]
Homogeneous module homomorphism
source

Representation as Cokernel

present_as_cokernelFunction
present_as_cokernel(M::SubquoModule, task::Symbol = :none)

Return a subquotient C which is isomorphic to M, and whose generators are the standard unit vectors of its ambient free module.

Additionally,

  • return an isomorphism M $\to$ C if task = :with_morphism,
  • return and cache an isomorphism M $\to$ C if task = :cache_morphism,
  • do none of the above if task = :none (default).

If task = :only_morphism, return only an isomorphism.

Examples

julia> R, (x, y, z) = polynomial_ring(QQ, ["x", "y", "z"]);

julia> A = R[x; y];

julia> B = R[x^2; y^3; z^4];

julia> M = SubquoModule(A, B)
Subquotient of Submodule with 2 generators
1 -> x*e[1]
2 -> y*e[1]
by Submodule with 3 generators
1 -> x^2*e[1]
2 -> y^3*e[1]
3 -> z^4*e[1]

julia> C = present_as_cokernel(M)
Subquotient of Submodule with 2 generators
1 -> e[1]
2 -> e[2]
by Submodule with 5 generators
1 -> x*e[1]
2 -> -y*e[1] + x*e[2]
3 -> y^2*e[2]
4 -> z^4*e[1]
5 -> z^4*e[2]
julia> Rg, (x, y, z) = graded_polynomial_ring(QQ, ["x", "y", "z"]);

julia> F = graded_free_module(Rg, 1);

julia> A = Rg[x; y];

julia> B = Rg[x^2; y^3; z^4];

julia> M = SubquoModule(F, A, B);

julia> present_as_cokernel(M, :with_morphism)
(Graded subquotient of submodule of Rg^2 generated by
1 -> e[1]
2 -> e[2]
by submodule of Rg^2 generated by
1 -> x*e[1]
2 -> -y*e[1] + x*e[2]
3 -> y^2*e[2]
4 -> z^4*e[1]
5 -> z^4*e[2], Graded subquotient of submodule of Rg^2 generated by
1 -> e[1]
2 -> e[2]
by submodule of Rg^2 generated by
1 -> x*e[1]
2 -> -y*e[1] + x*e[2]
3 -> y^2*e[2]
4 -> z^4*e[1]
5 -> z^4*e[2] -> M
e[1] -> x*e[1]
e[2] -> y*e[1]
Homogeneous module homomorphism)
source

Syzygies and Free Resolutions

free_resolutionMethod
free_resolution(M::SubquoModule{<:MPolyRingElem}; 
    ordering::ModuleOrdering = default_ordering(M),
    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.

Examples

julia> R, (x, y, z) = polynomial_ring(QQ, ["x", "y", "z"])
(Multivariate polynomial ring in 3 variables over QQ, QQMPolyRingElem[x, y, z])

julia> A = R[x; y]
[x]
[y]

julia> B = R[x^2; x*y; y^2; z^4]
[x^2]
[x*y]
[y^2]
[z^4]

julia> M = SubquoModule(A, B)
Subquotient of Submodule with 2 generators
1 -> x*e[1]
2 -> y*e[1]
by Submodule with 4 generators
1 -> x^2*e[1]
2 -> x*y*e[1]
3 -> y^2*e[1]
4 -> z^4*e[1]

julia> fr = free_resolution(M, length=1)
Free resolution of M
R^2 <---- R^6
0         1

julia> is_complete(fr)
false

julia> fr[4]
Free module of rank 0 over Multivariate polynomial ring in 3 variables over QQ

julia> fr
Free resolution of M
R^2 <---- R^6 <---- R^6 <---- R^2 <---- 0
0         1         2         3         4

julia> is_complete(fr)
true

julia> fr = free_resolution(M, algorithm=:fres)
Free resolution of M
R^2 <---- R^6 <---- R^6 <---- R^2 <---- 0
0         1         2         3         4

Note: Over rings other than polynomial rings, the method will default to a lazy, iterative kernel computation.

source

Betti Tables

Given a $\mathbb Z$-graded multivariate polynomial ring $S$, and given a graded free resolution with finitely generated graded free $S$-modules

\[F_i=\bigoplus_j S(-j) ^{\beta_{ij}},\]

the numbers $\beta_{ij}$ are commonly known as the graded Betti numbers of the resolution. A convenient way of visualizing these numbers is to write a Betti table as in the example below:

       0  1  2  3  
------------------
0    : 1  -  -  -  
1    : -  2  1  -  
2    : -  2  3  1  
------------------
total: 1  4  4  1

A number $i$ in the top row of the table refers to the $i$-th free module $F_i$ of the resolution. More precisely, the column with first entry $i$ lists the number of free generators of $F_i$ in different degrees and, in the bottom row, the total number of free generators (that is, the rank of $F_i$). If $k$ is the first entry of a row containing a number $\beta$ in the column corresponding to $F_i$, then $F_i$ has $\beta$ generators in degree $k+i$. That is, for a free module $F_i$ written as a direct sum as above, $\beta$ is the number $\beta_{ij}$ with $j=k+i$. The explicit example table above indicates, for instance, that $F_2$ has one generator in degree 3 and three generators in degree 4. In total, the diagram corresponds to a graded free resolution of type

\[S \leftarrow S(-2)^2\oplus S(-3)^2 \leftarrow S(-3)\oplus S(-4)^3 \leftarrow S(-5) \leftarrow 0.\]

betti_tableMethod
betti_table(F::FreeResolution)

Given a $\mathbb Z$-graded free resolution F, return the graded Betti numbers of F in form of a Betti table.

Alternatively, use betti.

Examples

julia> R, (w, x, y, z) = graded_polynomial_ring(QQ, ["w", "x", "y", "z"]);

julia> I = ideal(R, [x*z, y*z, x*w^2, y*w^2])
ideal(x*z, y*z, w^2*x, w^2*y)

julia> A, _= quo(R, I)
(Quotient of multivariate polynomial ring by ideal with 4 generators, Map from
R to A defined by a julia-function with inverse)

julia> FA  = free_resolution(A)
Free resolution of A
R^1 <---- R^4 <---- R^4 <---- R^1 <---- 0
0         1         2         3         4

julia> betti_table(FA)
       0  1  2  3
------------------
0    : 1  -  -  -
1    : -  2  1  -
2    : -  2  3  1
------------------
total: 1  4  4  1

julia> R, (x, y) = graded_polynomial_ring(QQ, ["x", "y"]);

julia> I = ideal(R, [x, y, x+y]);

julia> M = quotient_ring_as_module(I);

julia> FM = free_resolution(M, algorithm = :nres);

julia> betti_table(FM)
       0  1  2
---------------
-1   : -  -  1
0    : 1  3  1
---------------
total: 1  3  2
source
minimal_betti_tableMethod
minimal_betti_table(F::FreeResolution{T}; check::Bool=true) where {T<:ModuleFP}

Given a graded free resolution F over a standard $\mathbb Z$-graded multivariate polynomial ring with coefficients in a field, return the Betti table of the minimal free resolution arising from F.

Note

The algorithm proceeds without actually minimizing the resolution.

Examples

julia> R, (w, x, y, z) = graded_polynomial_ring(QQ, ["w", "x", "y", "z"]);

julia> I = ideal(R, [w^2-x*z, w*x-y*z, x^2-w*y, x*y-z^2, y^2-w*z]);

julia> A, _ = quo(R, I)
(Quotient of multivariate polynomial ring by ideal with 5 generators, Map from
R to A defined by a julia-function with inverse)

julia> FA = free_resolution(A)
Free resolution of A
R^1 <---- R^5 <---- R^6 <---- R^2 <---- 0
0         1         2         3         4

julia> betti_table(FA)
       0  1  2  3  
------------------
0    : 1  -  -  -  
1    : -  5  5  1  
2    : -  -  1  1  
------------------
total: 1  5  6  2  


julia> minimal_betti_table(FA)
       0  1  2  3  
------------------
0    : 1  -  -  -  
1    : -  5  5  -  
2    : -  -  -  1  
------------------
total: 1  5  5  1  
source
minimal_betti_tableMethod
minimal_betti_table(M::ModuleFP{T}) where {T<:MPolyDecRingElem}
minimal_betti_table(A::MPolyQuoRing{T}) where {T<:MPolyDecRingElem}
minimal_betti_table(I::MPolyIdeal{T}) where {T<:MPolyDecRingElem}

Given a finitely presented graded module M over a standard $\mathbb Z$-graded multivariate polynomial ring with coefficients in a field, return the Betti Table of the minimal free resolution of M. Similarly for A and I.

Examples

julia> R, (w, x, y, z) = graded_polynomial_ring(QQ, ["w", "x", "y", "z"]);

julia> I = ideal(R, [w^2-x*z, w*x-y*z, x^2-w*y, x*y-z^2, y^2-w*z]);

julia> A, _ = quo(R, I)
(Quotient of multivariate polynomial ring by ideal with 5 generators, Map from
R to A defined by a julia-function with inverse)

julia> minimal_betti_table(A)
       0  1  2  3
------------------
0    : 1  -  -  -
1    : -  5  5  -
2    : -  -  -  1
------------------
total: 1  5  5  1
source

Castelnuovo-Mumford Regularity

cm_regularityMethod
cm_regularity(M::ModuleFP; check::Bool=true)

Given a finitely presented graded module M over a standard $\mathbb Z$-graded multivariate polynomial ring with coefficients in a field, return the Castelnuovo-Mumford regularity of M.

cm_regularity(I::MPolyIdeal)

Given a (homogeneous) ideal I in a standard $\mathbb Z$-graded multivariate polynomial ring with coefficients in a field, return the Castelnuovo-Mumford regularity of I.

Examples

julia> R, (x, y, z) = graded_polynomial_ring(QQ, ["x", "y", "z"]);

julia> F = graded_free_module(R, 1);

julia> M, _ = quo(F, [x^2*F[1], y^2*F[1], z^2*F[1]])
(Graded subquotient of submodule of F generated by
1 -> e[1]
by submodule of F generated by
1 -> x^2*e[1]
2 -> y^2*e[1]
3 -> z^2*e[1], F -> M
e[1] -> e[1]
Homogeneous module homomorphism)

julia> cm_regularity(M)
3

julia> minimal_betti_table(M)
       0 1 2 3 
--------------
0    : 1 - - - 
1    : - 3 - - 
2    : - - 3 - 
3    : - - - 1 
--------------
total: 1 3 3 1 
julia> R, (w, x, y, z) = graded_polynomial_ring(QQ, ["w", "x", "y", "z"]);

julia> I = ideal(R, [-x*z+y^2, x*y-w*z, x^2-w*y]);

julia> cm_regularity(I)
2

julia> A, _ = quo(R, I);

julia> minimal_betti_table(A)
       0 1 2 
------------
0    : 1 - - 
1    : - 3 2 
------------
total: 1 3 2 
source

Homology

homologyMethod
homology(C::ComplexOfMorphisms{<:ModuleFP})

Return the homology of C.

Examples

julia> R, (x,) = polynomial_ring(QQ, ["x"]);

julia> F = free_module(R, 1);

julia> A, _ = quo(F, [x^4*F[1]]);

julia> B, _ = quo(F, [x^3*F[1]]);

julia> a = hom(A, B, [x^2*B[1]]);

julia> b = hom(B, B, [x^2*B[1]]);

julia> C = ComplexOfMorphisms(ModuleFP, [a, b]);

julia> H = homology(C)
3-element Vector{SubquoModule{QQMPolyRingElem}}:
 Subquotient of Submodule with 1 generator
1 -> x*e[1]
by Submodule with 1 generator
1 -> x^4*e[1]
 Subquotient of Submodule with 1 generator
1 -> x*e[1]
by Submodule with 2 generators
1 -> x^3*e[1]
2 -> x^2*e[1]
 Subquotient of Submodule with 1 generator
1 -> e[1]
by Submodule with 2 generators
1 -> x^3*e[1]
2 -> x^2*e[1]
source
homologyMethod
homology(C::ComplexOfMorphisms{<:ModuleFP}, i::Int)

Return the i-th homology module of C.

Examples

julia> R, (x,) = polynomial_ring(QQ, ["x"]);

julia> F = free_module(R, 1);

julia> A, _ = quo(F, [x^4*F[1]]);

julia> B, _ = quo(F, [x^3*F[1]]);

julia> a = hom(A, B, [x^2*B[1]]);

julia> b = hom(B, B, [x^2*B[1]]);

julia> C = ComplexOfMorphisms(ModuleFP, [a, b]);

julia> H = homology(C, 1)
Subquotient of Submodule with 1 generator
1 -> x*e[1]
by Submodule with 2 generators
1 -> x^3*e[1]
2 -> x^2*e[1]
source

Hom and Ext

homMethod
hom(M::ModuleFP, N::ModuleFP; algorithm::Symbol=:maps)

Return the module Hom(M,N) as an object of type SubquoModule.

Additionally, if H is that object, return the map which sends an element of H to the corresponding homomorphism M $\to$N.

The keyword algorithm can be set to :maps for the default algorithm or to :matrices for an alternative based on matrices.

Examples

julia> R, (x, y) = polynomial_ring(QQ, ["x", "y"]);

julia> F = FreeMod(R, 2);

julia> V = [x*F[1], y^2*F[2]];

julia> M = quo_object(F, V)
Subquotient of Submodule with 2 generators
1 -> e[1]
2 -> e[2]
by Submodule with 2 generators
1 -> x*e[1]
2 -> y^2*e[2]

julia> H = hom(M, M)[1]
hom of (M, M)

julia> gens(H)
2-element Vector{SubquoModuleElem{QQMPolyRingElem}}:
 (e[1] -> e[1])
 (e[2] -> e[2])

julia> relations(H)
4-element Vector{FreeModElem{QQMPolyRingElem}}:
 x*(e[1] -> e[1])
 y^2*(e[1] -> e[2])
 x*(e[2] -> e[1])
 y^2*(e[2] -> e[2])
source
element_to_homomorphismMethod
element_to_homomorphism(f::ModuleFPElem)

If f is an element of a module created via hom(M,N), for some modules M and N, return the homomorphism M $\to$ N corresponding to f.

Examples

julia> R, (x, y) = polynomial_ring(QQ, ["x", "y"]);

julia> F = FreeMod(R, 2);

julia> V = [x*F[1], y^2*F[2]];

julia> M = quo_object(F, V)
Subquotient of Submodule with 2 generators
1 -> e[1]
2 -> e[2]
by Submodule with 2 generators
1 -> x*e[1]
2 -> y^2*e[2]

julia> H = hom(M, M)[1];

julia> gens(H)
2-element Vector{SubquoModuleElem{QQMPolyRingElem}}:
 (e[1] -> e[1])
 (e[2] -> e[2])

julia> relations(H)
4-element Vector{FreeModElem{QQMPolyRingElem}}:
 x*(e[1] -> e[1])
 y^2*(e[1] -> e[2])
 x*(e[2] -> e[1])
 y^2*(e[2] -> e[2])

julia> a = element_to_homomorphism(H[1]+y*H[2])
Map with following data
Domain:
=======
Subquotient of Submodule with 2 generators
1 -> e[1]
2 -> e[2]
by Submodule with 2 generators
1 -> x*e[1]
2 -> y^2*e[2]
Codomain:
=========
Subquotient of Submodule with 2 generators
1 -> e[1]
2 -> e[2]
by Submodule with 2 generators
1 -> x*e[1]
2 -> y^2*e[2]

julia> matrix(a)
[1   0]
[0   y]
source
homomorphism_to_elementMethod
homomorphism_to_element(H::ModuleFP, a::ModuleFPHom)

If the module H is created via hom(M,N), for some modules M and N, and a: M $\to$ N is a homomorphism, then return the element of H corresponding to a.

Examples

julia> R, (x, y) = polynomial_ring(QQ, ["x", "y"]);

julia> F = FreeMod(R, 2);

julia> V = [x*F[1], y^2*F[2]];

julia> M = quo_object(F, V)
Subquotient of Submodule with 2 generators
1 -> e[1]
2 -> e[2]
by Submodule with 2 generators
1 -> x*e[1]
2 -> y^2*e[2]

julia> H = hom(M, M)[1];

julia> gens(H)
2-element Vector{SubquoModuleElem{QQMPolyRingElem}}:
 (e[1] -> e[1])
 (e[2] -> e[2])

julia> relations(H)
4-element Vector{FreeModElem{QQMPolyRingElem}}:
 x*(e[1] -> e[1])
 y^2*(e[1] -> e[2])
 x*(e[2] -> e[1])
 y^2*(e[2] -> e[2])

julia> W =  [M[1], y*M[2]];

julia> a = hom(M, M, W);

julia> is_welldefined(a)
true

julia> matrix(a)
[1   0]
[0   y]

julia> m = homomorphism_to_element(H, a)
(e[1] -> e[1]) + y*(e[2] -> e[2])
source
extMethod
ext(M::ModuleFP, N::ModuleFP, i::Int)

Return $\text{Ext}^i(M,N)$.

Examples

julia> R, (x, y) = polynomial_ring(QQ, ["x", "y"]);

julia> F = FreeMod(R, 1);

julia> V = [x*F[1], y*F[1]];

julia> M = quo_object(F, V)
Subquotient of Submodule with 1 generator
1 -> e[1]
by Submodule with 2 generators
1 -> x*e[1]
2 -> y*e[1]

julia> ext(M, M, 0)
Subquotient of Submodule with 1 generator
1 -> (e[1] -> e[1])
by Submodule with 2 generators
1 -> y*(e[1] -> e[1])
2 -> x*(e[1] -> e[1])

julia> ext(M, M, 1)
Subquotient of Submodule with 2 generators
1 -> (e[1] -> e[1])
2 -> (e[2] -> e[1])
by Submodule with 4 generators
1 -> y*(e[1] -> e[1])
2 -> x*(e[1] -> e[1])
3 -> y*(e[2] -> e[1])
4 -> x*(e[2] -> e[1])

julia> ext(M, M, 2)
Subquotient of Submodule with 1 generator
1 -> (e[1] -> e[1])
by Submodule with 2 generators
1 -> y*(e[1] -> e[1])
2 -> x*(e[1] -> e[1])

julia> ext(M, M, 3)
Submodule with 0 generators
represented as subquotient with no relations.
source

Tensorproduct and Tor

tensor_productMethod
tensor_product(M::ModuleFP...; task::Symbol = :none)

Given a collection of modules, say, $M_1, \dots, M_n$ over a ring $R$, return $M_1\otimes_R \cdots \otimes_R M_n$.

If task = :map, additionally return the map which sends a tuple $(m_1,\dots, m_n)$ of elements $m_i\in M_i$ to the pure tensor $m_1\otimes\dots\otimes m_n$.

Examples

julia> R, (x, y, z) = polynomial_ring(QQ, ["x", "y", "z"]);

julia> F = free_module(R, 1);

julia> A = R[x; y];

julia> B = R[x^2; y^3; z^4];

julia> M = SubquoModule(F, A, B);

julia> gens(M)
2-element Vector{SubquoModuleElem{QQMPolyRingElem}}:
 x*e[1]
 y*e[1]

julia> T, t = tensor_product(M, M; task = :map);

julia> gens(T)
4-element Vector{SubquoModuleElem{QQMPolyRingElem}}:
 x^2*e[1] \otimes e[1]
 x*y*e[1] \otimes e[1]
 x*y*e[1] \otimes e[1]
 y^2*e[1] \otimes e[1]

julia> domain(t)
parent of tuples of type Tuple{SubquoModuleElem{QQMPolyRingElem}, SubquoModuleElem{QQMPolyRingElem}}

julia> t((M[1], M[2]))
x*y*e[1] \otimes e[1]
source
torMethod
tor(M::ModuleFP, N::ModuleFP, i::Int)

Return $\text{Tor}_i(M,N)$.

Examples

julia> R, (x, y, z) = polynomial_ring(QQ, ["x", "y", "z"]);

julia> A = R[x; y];

julia> B = R[x^2; y^3; z^4];

julia> M = SubquoModule(A, B);

julia> F = free_module(R, 1);

julia> Q, _ = quo(F, [x*F[1]]);

julia> T0 = tor(Q, M, 0)
Subquotient of Submodule with 2 generators
1 -> x*e[1] \otimes e[1]
2 -> y*e[1] \otimes e[1]
by Submodule with 4 generators
1 -> x^2*e[1] \otimes e[1]
2 -> y^3*e[1] \otimes e[1]
3 -> z^4*e[1] \otimes e[1]
4 -> x*y*e[1] \otimes e[1]

julia> T1 = tor(Q, M, 1)
Subquotient of Submodule with 2 generators
1 -> x*e[1] \otimes e[1]
2 -> x*y*e[1] \otimes e[1]
by Submodule with 3 generators
1 -> x^2*e[1] \otimes e[1]
2 -> y^3*e[1] \otimes e[1]
3 -> z^4*e[1] \otimes e[1]

julia> T2 =  tor(Q, M, 2)
Submodule with 0 generators
represented as subquotient with no relations.
source

Fitting Ideals

fitting_idealMethod
 fitting_ideal(M::ModuleFP{T}, i::Int) where T <: MPolyRingElem

Return the i-th Fitting ideal of M.

Examples

julia> R, (x, y) = polynomial_ring(QQ, ["x", "y"]);

julia> F = free_module(R, 2);

julia> o = zero(R)
0

julia> U = matrix([x^3-y^2 o; o x^3-y^2; -x^2 y; -y x])
[x^3 - y^2           0]
[        0   x^3 - y^2]
[     -x^2           y]
[       -y           x]

julia> M = quo_object(F,U)
Subquotient of Submodule with 2 generators
1 -> e[1]
2 -> e[2]
by Submodule with 4 generators
1 -> (x^3 - y^2)*e[1]
2 -> (x^3 - y^2)*e[2]
3 -> -x^2*e[1] + y*e[2]
4 -> -y*e[1] + x*e[2]

julia> fitting_ideal(M, -1)
Ideal generated by
  0

julia> fitting_ideal(M, 0)
Ideal generated by
  x^3 - y^2

julia> fitting_ideal(M, 1)
Ideal generated by
  y
  x

julia> fitting_ideal(M, 2)
Ideal generated by
  1
source

Flatness

Checking flatness in OSCAR relies on characterizing flatness in terms of Fitting ideals.

is_flatMethod
 is_flat(M::ModuleFP{T}) where T <: MPolyRingElem

Return true if M is flat, false otherwise.

Examples

julia> R, (x, y) = polynomial_ring(QQ, ["x", "y"]);

julia> F = free_module(R, 2);

julia> o = zero(R)
0

julia> U = matrix([x^3-y^2 o; o x^3-y^2; -x^2 y; -y x])
[x^3 - y^2           0]
[        0   x^3 - y^2]
[     -x^2           y]
[       -y           x]

julia> M = quo_object(F,U)
Subquotient of Submodule with 2 generators
1 -> e[1]
2 -> e[2]
by Submodule with 4 generators
1 -> (x^3 - y^2)*e[1]
2 -> (x^3 - y^2)*e[2]
3 -> -x^2*e[1] + y*e[2]
4 -> -y*e[1] + x*e[2]

julia> is_flat(M)
false
source
non_flat_locusMethod
 non_flat_locus(M::ModuleFP{T}) where T <: MPolyRingElem

Return an ideal of base_ring(M) which defines the non-flat-locus of M in the sense that the localization of M at a prime ideal of base_ring(M) is non-flat iff the prime ideal contains the returned ideal.

Examples

julia> R, (x, y) = polynomial_ring(QQ, ["x", "y"]);

julia> F = free_module(R, 2);

julia> o = zero(R)
0

julia> U = matrix([x^3-y^2 o; o x^3-y^2; -x^2 y; -y x])
[x^3 - y^2           0]
[        0   x^3 - y^2]
[     -x^2           y]
[       -y           x]

julia> M = quo_object(F,U)
Subquotient of Submodule with 2 generators
1 -> e[1]
2 -> e[2]
by Submodule with 4 generators
1 -> (x^3 - y^2)*e[1]
2 -> (x^3 - y^2)*e[2]
3 -> -x^2*e[1] + y*e[2]
4 -> -y*e[1] + x*e[2]

julia> non_flat_locus(M)
Ideal generated by
  x^3 - y^2
source

Regular Sequence Test

is_regular_sequenceMethod
 is_regular_sequence(V::Vector{T}, M::ModuleFP{T}) where T <: MPolyRingElem

Return true if the elements of V form, in the given order, a regular sequence on M. Return false, otherwise.

Examples

julia> R, (x, y, z) = polynomial_ring(QQ, ["x", "y", "z"]);

julia> F = free_module(R, 1);

julia> V =  [x*z-z, x*y-y, x]
3-element Vector{QQMPolyRingElem}:
 x*z - z
 x*y - y
 x

julia> is_regular_sequence(V, F)
false

julia> W = [x*z-z, x, x*y-y]
3-element Vector{QQMPolyRingElem}:
 x*z - z
 x
 x*y - y

julia> is_regular_sequence(W, F)
true
source

Koszul Complex

koszul_matrixMethod
 koszul_matrix(V::Vector{T}, p::Int) where T <: MPolyRingElem

If $f_1, \dots, f_r$ are the entries of V in the given order, return the matrix representing the p-th map of the Koszul complex $K(f_1, \dots, f_r)$.

Examples

julia> R, (x, y, z) = polynomial_ring(QQ, ["x", "y", "z"]);

julia> V = gens(R)
3-element Vector{QQMPolyRingElem}:
 x
 y
 z

julia> koszul_matrix(V, 3)
[x   y   z]

julia> koszul_matrix(V, 2)
[-y   -z    0]
[ x    0   -z]
[ 0    x    y]

julia> koszul_matrix(V, 1)
[ z]
[-y]
[ x]
source
koszul_complexMethod
 koszul_complex(V::Vector{T}) where T <: MPolyRingElem

If $f_1, \dots, f_r$ are the entries of V in the given order, return the Koszul complex $K(f_1, \dots, f_r)$.

Examples

julia> R, (x, y, z) = polynomial_ring(QQ, ["x", "y", "z"]);

julia> V = gens(R)
3-element Vector{QQMPolyRingElem}:
 x
 y
 z

julia> K = koszul_complex(V);

julia> matrix(map(K, 2))
[-y   -z    0]
[ x    0   -z]
[ 0    x    y]

julia> Kd = hom(K, free_module(R, 1));

julia> matrix(map(Kd, 1))
[-y    x   0]
[-z    0   x]
[ 0   -z   y]
source

Koszul Homology

koszul_homologyMethod
 koszul_homology(V::Vector{T}, M::ModuleFP{T}, p::Int) where T <: MPolyRingElem

If $f_1, \dots, f_r$ are the entries of V in the given order, return the p-th homology module of the complex $K(f_1, \dots, f_r)\otimes_R M$, where $K(f_1, \dots, f_r)$ is the Koszul complex defined by $f_1, \dots, f_r$.

Note

See [GP08] or [DL06] for the definition of the Koszul complex.

Examples

julia> R, (x, y, z) = polynomial_ring(QQ, ["x", "y", "z"]);

julia> F = free_module(R, 1);

julia> V =  [x*y, x*z, y*z]
3-element Vector{QQMPolyRingElem}:
 x*y
 x*z
 y*z

julia> koszul_homology(V, F, 0)
Subquotient of Submodule with 1 generator
1 -> e[1]^e[2]^e[3]
by Submodule with 3 generators
1 -> y*z*e[1]^e[2]^e[3]
2 -> -x*z*e[1]^e[2]^e[3]
3 -> x*y*e[1]^e[2]^e[3]

julia> koszul_homology(V, F, 1)
Subquotient of Submodule with 2 generators
1 -> y*e[1]^e[3] \otimes e[1] + z*e[2]^e[3] \otimes e[1]
2 -> x*e[1]^e[2] \otimes e[1] - z*e[2]^e[3] \otimes e[1]
by Submodule with 3 generators
1 -> -x*z*e[1]^e[2] \otimes e[1] - y*z*e[1]^e[3] \otimes e[1]
2 -> x*y*e[1]^e[2] \otimes e[1] - y*z*e[2]^e[3] \otimes e[1]
3 -> x*y*e[1]^e[3] \otimes e[1] + x*z*e[2]^e[3] \otimes e[1]

julia> koszul_homology(V, F, 2)
Subquotient of Submodule with 1 generator
1 -> x*y*e[1] \otimes e[1] + x*z*e[2] \otimes e[1] + y*z*e[3] \otimes e[1]
by Submodule with 1 generator
1 -> x*y*e[1] \otimes e[1] + x*z*e[2] \otimes e[1] + y*z*e[3] \otimes e[1]
julia> R, (w, x, y, z) = polynomial_ring(QQ, ["w", "x", "y", "z"]);

julia> TC = ideal(R, [x*z-y^2, w*z-x*y, w*y-x^2]);

julia> F = free_module(R, 1);

julia> koszul_homology(gens(TC), F, 0)
Subquotient of Submodule with 1 generator
1 -> e[1]^e[2]^e[3]
by Submodule with 3 generators
1 -> (w*y - x^2)*e[1]^e[2]^e[3]
2 -> (-w*z + x*y)*e[1]^e[2]^e[3]
3 -> (x*z - y^2)*e[1]^e[2]^e[3]

julia> koszul_homology(gens(TC), F, 1)
Subquotient of Submodule with 2 generators
1 -> z*e[1]^e[2] \otimes e[1] + y*e[1]^e[3] \otimes e[1] + x*e[2]^e[3] \otimes e[1]
2 -> y*e[1]^e[2] \otimes e[1] + x*e[1]^e[3] \otimes e[1] + w*e[2]^e[3] \otimes e[1]
by Submodule with 3 generators
1 -> (-w*z + x*y)*e[1]^e[2] \otimes e[1] + (-w*y + x^2)*e[1]^e[3] \otimes e[1]
2 -> (x*z - y^2)*e[1]^e[2] \otimes e[1] + (-w*y + x^2)*e[2]^e[3] \otimes e[1]
3 -> (x*z - y^2)*e[1]^e[3] \otimes e[1] + (w*z - x*y)*e[2]^e[3] \otimes e[1]

julia> koszul_homology(gens(TC), F, 2)
Subquotient of Submodule with 1 generator
1 -> (-x*z + y^2)*e[1] \otimes e[1] + (-w*z + x*y)*e[2] \otimes e[1] + (-w*y + x^2)*e[3] \otimes e[1]
by Submodule with 1 generator
1 -> (x*z - y^2)*e[1] \otimes e[1] + (w*z - x*y)*e[2] \otimes e[1] + (w*y - x^2)*e[3] \otimes e[1]
source

Depth

The computation of depth in OSCAR relies on expressing depth in terms of Koszul cohomology.

depthMethod
 depth(I::MPolyIdeal{T}, M::ModuleFP{T}) where T <: MPolyRingElem

Return the depth of I on M.

Examples

julia> R, (w, x, y, z) = polynomial_ring(QQ, ["w", "x", "y", "z"]);

julia> TC = ideal(R, [x*z-y^2, w*z-x*y, w*y-x^2]);

julia> dim(TC)
2

julia> F = free_module(R, 1);

julia> U = collect(gen(TC, i)*F[1] for i in 1:ngens(TC));

julia> M, _ = quo(F, U);

julia> I = ideal(R, gens(R))
Ideal generated by
  w
  x
  y
  z

julia> depth(I, M)
2
julia> S, x, y = polynomial_ring(QQ, "x" => 1:3, "y" => 1:5);

julia> W = [y[1]-x[1]^2,  y[2]-x[2]^2,   y[3]-x[3]^2, y[4]-x[2]*(x[1]-x[3]),  y[5]-(x[1]-x[2])*x[3]];

julia> J = eliminate(ideal(S, W), x);

julia> R, y = polynomial_ring(QQ, "y" => 1:5);

julia> W = append!(repeat([zero(R)], 3), gens(R))
8-element Vector{QQMPolyRingElem}:
 0
 0
 0
 y[1]
 y[2]
 y[3]
 y[4]
 y[5]

julia> P = hom(S, R, W);

julia> VP4 = P(J);

julia> dim(VP4)
3

julia> F = free_module(R, 1);

julia> U = collect(gen(VP4, i)*F[1] for i in 1:ngens(VP4));

julia> M, _ = quo(F, U);

julia> I = ideal(R, gens(R))
Ideal generated by
  y[1]
  y[2]
  y[3]
  y[4]
  y[5]

julia> depth(I, M)
1
source