# Homological Algebra

Some OSCAR functions which are fundamental to homological algebra such as the kernel function and basic functions for handling chain and cochain complexes have already been discussed in previous sections. Building on these functions, we now 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);

julia> rank(P[1])
5

julia> rank(P[0])
2
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. algorithm can be set to :sres or :fres.

Examples

julia> R, (x, y, z) = polynomial_ring(QQ, ["x", "y", "z"])
(Multivariate Polynomial Ring in x, y, z over Rational Field, 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)

rank   | 6  2
-------|------
degree | 1  0

julia> is_complete(fr)
false

julia> fr[4]
Free module of rank 0 over Multivariate Polynomial Ring in x, y, z over Rational Field

julia> fr

rank   | 0  2  6  6  2
-------|---------------
degree | 4  3  2  1  0

julia> is_complete(fr)
true

julia> fr = free_resolution(M, algorithm=:sres)

rank   | 0  2  6  6  2
-------|---------------
degree | 4  3  2  1  0

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

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

homFunction
hom(M::ModuleFP, N::ModuleFP)

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.

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(F, V)[1]
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 (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], 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> 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(F, V)[1]
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(F, V)[1]
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> iswelldefined(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(F, V)[1]
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 -> x*(e[1] -> e[1])
2 -> y*(e[1] -> e[1])

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

julia> ext(M, M, 2)
Subquotient of Submodule with 1 generator
1 -> (e[1] -> e[1])
by Submodule with 3 generators
1 -> x*(e[1] -> e[1])
2 -> y*(e[1] -> e[1])
3 -> -y*(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 1 generator
1 -> -x*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(F,U)[1]
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(0)

julia> fitting_ideal(M, 0)
ideal(x^3 - y^2)

julia> fitting_ideal(M, 1)
ideal(y, x)

julia> fitting_ideal(M, 2)
ideal(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(F,U)[1]
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(F,U)[1]
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(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)
[z   -y   x]

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

julia> koszul_matrix(V, 1)
[x]
[y]
[z]
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    x   0]
[-z    0   x]
[ 0   -z   y]

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

julia> matrix(map(Kd, 1))
[-y   -z    0]
[ x    0   -z]
[ 0    x    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

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)
Submodule with 3 generators
1 -> y*z*e[1]
2 -> x*z*e[1]
3 -> x*y*e[1]
represented as subquotient with no relations.

julia> koszul_homology(V, F, 1)
Submodule with 3 generators
1 -> -z*e[1] + z*e[2]
2 -> y*e[2]
3 -> x*e[1]
represented as subquotient with no relations.

julia> koszul_homology(V, F, 2)
Submodule with 1 generator
1 -> 0
represented as subquotient with no relations.
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)
Submodule with 3 generators
1 -> (-x*z + y^2)*e[1]
2 -> (-w*z + x*y)*e[1]
3 -> (-w*y + x^2)*e[1]
represented as subquotient with no relations.

julia> koszul_homology(gens(TC), F, 1)
Submodule with 3 generators
1 -> y*e[1] - z*e[2]
2 -> x*e[1] - y*e[2]
3 -> w*e[1] - x*e[2]
represented as subquotient with no relations.

julia> koszul_homology(gens(TC), F, 2)
Submodule with 1 generator
1 -> 0
represented as subquotient with no relations.
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(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(y[1], y[2], y[3], y[4], y[5])

julia> depth(I, M)
1
source