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.
Pruning Modules
prune_with_map
— Methodprune_with_map(M::ModuleFP)
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
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> 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> N, phi = prune_with_map(M);
julia> N
Graded subquotient of submodule of R^1 generated by
1 -> e[1]
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]
Presentations
presentation
— Methodpresentation(M::ModuleFP; minimal = false)
Return a (free) presentation of M
.
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
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> 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> 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
Representation as Cokernel
present_as_cokernel
— Functionpresent_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
iftask = :with_morphism
, - return and cache an isomorphism
M
$\to$C
iftask = :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)
Free Resolutions
free_resolution
— Methodfree_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
for modules over polynomial rings and :sres
for modules over quotients of polynomial rings.
The function first computes a presentation of M
. It then successively computes higher syzygy modules.
- If
algorithm == mres
, andM
is positively graded, a minimal free resolution is returned. - If
algorithm == nres
, andM
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.
If algorithm == fres
, the function relies on an enhanced version of Schreyer's algorithm [EMSS16]. Typically, this is more efficient than the approaches above, but the resulting resolution is far from being minimal.
If M
is a module over a quotient of a polynomial ring then the length
keyword must be set to a nonzero value.
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 R
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> 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> 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^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 or quotients of polynomial rings, the method will default to a lazy, iterative kernel computation.
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_table
— Methodbetti_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
minimal_betti_table
— Methodminimal_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
.
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
minimal_betti_table
— Methodminimal_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
Castelnuovo-Mumford Regularity
cm_regularity
— Methodcm_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
Homology
homology
— Methodhomology(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]
homology
— Methodhomology(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]
Hom and Ext
hom
— Methodhom(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])
element_to_homomorphism
— Methodelement_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]
homomorphism_to_element
— Methodhomomorphism_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])
ext
— Methodext(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.
Tensorproduct and Tor
tensor_product
— Methodtensor_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]
tor
— Methodtor(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.
Fitting Ideals
fitting_ideal
— Methodfitting_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
Flatness
Checking flatness in OSCAR relies on characterizing flatness in terms of Fitting ideals.
is_flat
— Methodis_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
non_flat_locus
— Methodnon_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
Regular Sequence Test
is_regular_sequence
— Methodis_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
Koszul Complex
koszul_matrix
— Methodkoszul_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]
koszul_complex
— Methodkoszul_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]
Koszul Homology
koszul_homology
— Methodkoszul_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$.
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]
Depth
The computation of depth in OSCAR relies on expressing depth in terms of Koszul cohomology.
depth
— Methoddepth(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