Finitely generated modules
Singular.jl allows the creation of submodules of a free module over a Singular polynomial ring, given by a finite generating set. These are internally stored as a list of elements of a free module over a polynomial ring $R$. This list of generators can also have the property of being a Groebner basis.
The default finitely generated module type in Singular.jl is the Singular smodule
type.
Module objects have a parent object which represents the class of $R$-modules they belong to, the data for which is given by the polynomial ring $R$ over which the modules are defined.
The types of modules and associated parent objects are given in the following table according to the library providing them.
Library | Element type | Parent type |
---|---|---|
Singular | smodule{T} | Singular.ModuleClass{T} |
These types are parameterised by the type of elements in the polynomial ring $R$.
All module types belong directly to the abstract type Module{T}
and all the module class parent object types belong to the abstract type Set
.
Module functionality
Singular.jl modules implement standard operations one would expect on modules. These include:
- Operations common to all AbstractAlgebra objects, such as
parent
,base_ring
,elem_type
,parent_type
,parent
,deepcopy
, etc.
Below, we describe all of the functionality for Singular.jl modules that is not included in this list of basic operations.
Constructors
Given a Singular polynomial ring $R$, the following constructors are available for creating modules.
Module{T <: Nemo.RingElem}(R::PolyRing{T}, vecs::svector{spoly{T}}...)
Construct the module over the polynomial ring $R$ whose generators are given by the given parameter list of vectors (of length $n$), each component of which is a polynomial. These vectors represent elements of the free module $R^n$.
Note that Module
must be prepended with the package name Singular
to disambiguate from Base.Module
.
Examples
julia> R, (x, y) = polynomial_ring(QQ, ["x", "y"])
(Singular polynomial ring (QQ),(x,y),(dp(2),C), spoly{n_Q}[x, y])
julia> v1 = vector(R, x + 1, x*y + 1, y)
x*y*gen(2)+x*gen(1)+y*gen(3)+gen(2)+gen(1)
julia> v2 = vector(R, x^2 + 1, 2x + 3y, x)
x^2*gen(1)+x*gen(3)+2*x*gen(2)+3*y*gen(2)+gen(1)
julia> M = Singular.Module(R, v1, v2)
Singular module over Singular polynomial ring (QQ),(x,y),(dp(2),C), with generators:
x*y*gen(2)+x*gen(1)+y*gen(3)+gen(2)+gen(1)
x^2*gen(1)+x*gen(3)+2*x*gen(2)+3*y*gen(2)+gen(1)
Basic manipulation
AbstractAlgebra.number_of_generators
— Methodnumber_of_generators(I::smodule)
Return the number of generators in the current representation of the module (as a list of vectors).
LinearAlgebra.rank
— Methodrank(I::smodule)
Return the rank $n$ of the ambient space $R^n$ of which this module is a submodule.
Singular.jl overloads the setindex!
and getindex
functions so that one can access the generators of a module using array notation. Each entry is a vector in $R^n$.
M[n::Int]
Base.iszero
— Methodiszero(p::smodule)
Return true
if this is algebraically the zero module.
Examples
julia> R, (x, y) = polynomial_ring(QQ, ["x", "y"])
(Singular polynomial ring (QQ),(x,y),(dp(2),C), spoly{n_Q}[x, y])
julia> v1 = vector(R, x + 1, x*y + 1, y)
x*y*gen(2)+x*gen(1)+y*gen(3)+gen(2)+gen(1)
julia> v2 = vector(R, x^2 + 1, 2x + 3y, x)
x^2*gen(1)+x*gen(3)+2*x*gen(2)+3*y*gen(2)+gen(1)
julia> M = Singular.Module(R, v1, v2)
Singular module over Singular polynomial ring (QQ),(x,y),(dp(2),C), with generators:
x*y*gen(2)+x*gen(1)+y*gen(3)+gen(2)+gen(1)
x^2*gen(1)+x*gen(3)+2*x*gen(2)+3*y*gen(2)+gen(1)
julia> iszero(M) == false
true
julia> M[1] == v1
true
julia> n = rank(M)
3
julia> d = number_of_generators(M)
2
Standard basis
Statistics.std
— Methodstd(I::smodule; complete_reduction::Bool=false)
Compute the Groebner basis of the module $I$. If complete_reduction
is set to true
, the result is unique, up to permutation of the generators and multiplication by constants. If not, only the leading terms are unique (up to permutation of the generators and multiplication by constants, of course). Presently the polynomial ring used must be over a field or over the Singular integers.
Singular.lift_std
— Methodlift_std(M::smodule)
Computes the Groebner base G
of M
and the transformation matrix T
such that (Matrix(G) = Matrix(M) * T)
.
Singular.lift_std_syz
— Methodlift_std_syz(M::smodule)
Computes the Groebner base G
of M
, the transformation matrix T
and the syzygies of M. Returns a tuple (G,T,S)
satisfying (Matrix(G) = Matrix(M) * T, 0=Matrix(M)*Matrix(S))
.
Examples
julia> R, (x, y) = polynomial_ring(QQ, ["x", "y"])
(Singular polynomial ring (QQ),(x,y),(dp(2),C), spoly{n_Q}[x, y])
julia> v1 = vector(R, x + 1, x*y + 1, y)
x*y*gen(2)+x*gen(1)+y*gen(3)+gen(2)+gen(1)
julia> v2 = vector(R, x^2 + 1, 2x + 3y, x)
x^2*gen(1)+x*gen(3)+2*x*gen(2)+3*y*gen(2)+gen(1)
julia> v3 = x*v1 + y*v2 + vector(R, x, y + 1, y^2)
x^2*y*gen(2)+x^2*y*gen(1)+x^2*gen(1)+2*x*y*gen(3)+2*x*y*gen(2)+y^2*gen(3)+3*y^2*gen(2)+x*gen(2)+2*x*gen(1)+y*gen(2)+y*gen(1)+gen(2)
julia> M = Singular.Module(R, v1, v2, v3)
Singular module over Singular polynomial ring (QQ),(x,y),(dp(2),C), with generators:
x*y*gen(2)+x*gen(1)+y*gen(3)+gen(2)+gen(1)
x^2*gen(1)+x*gen(3)+2*x*gen(2)+3*y*gen(2)+gen(1)
x^2*y*gen(2)+x^2*y*gen(1)+x^2*gen(1)+2*x*y*gen(3)+2*x*y*gen(2)+y^2*gen(3)+3*y^2*gen(2)+x*gen(2)+2*x*gen(1)+y*gen(2)+y*gen(1)+gen(2)
julia> G = std(M; complete_reduction=true)
Singular module over Singular polynomial ring (QQ),(x,y),(dp(2),C), with generators:
y^2*gen(3)+x*gen(1)+y*gen(2)+gen(2)
x*y*gen(2)+x*gen(1)+y*gen(3)+gen(2)+gen(1)
x^2*gen(1)+x*gen(3)+2*x*gen(2)+3*y*gen(2)+gen(1)
Reduction
Base.reduce
— Methodreduce(M::smodule, G::smodule; complete_reduction::Bool = true)
Return a submodule whose generators are the generators of $M$ reduced by the submodule $G$. The submodule $G$ need not be a Groebner basis. The returned submodule will have the same number of generators as $M$, even if they are zero.
Examples
julia> R, (x, y, z) = polynomial_ring(QQ, ["x", "y", "z"])
(Singular polynomial ring (QQ),(x,y,z),(dp(3),C), spoly{n_Q}[x, y, z])
julia> v1 = vector(R, R(0), z, -y)
-y*gen(3)+z*gen(2)
julia> v2 = vector(R, -z, R(0), x)
x*gen(3)-z*gen(1)
julia> v3 = vector(R, y, x, R(0))
x*gen(2)+y*gen(1)
julia> v = y*v1+x*v2+z*v3
x^2*gen(3)-y^2*gen(3)+x*z*gen(2)-x*z*gen(1)+y*z*gen(2)+y*z*gen(1)
julia> M = Singular.Module(R, v1, v2, v3)
Singular module over Singular polynomial ring (QQ),(x,y,z),(dp(3),C), with generators:
-y*gen(3)+z*gen(2)
x*gen(3)-z*gen(1)
x*gen(2)+y*gen(1)
julia> B = std(M; complete_reduction=true)
Singular module over Singular polynomial ring (QQ),(x,y,z),(dp(3),C), with generators:
y*gen(3)-z*gen(2)
x*gen(2)+y*gen(1)
x*gen(3)-z*gen(1)
y*z*gen(1)
julia> V = Singular.Module(R, v)
Singular module over Singular polynomial ring (QQ),(x,y,z),(dp(3),C), with generators:
x^2*gen(3)-y^2*gen(3)+x*z*gen(2)-x*z*gen(1)+y*z*gen(2)+y*z*gen(1)
julia> reduce(V,B)
Singular module over Singular polynomial ring (QQ),(x,y,z),(dp(3),C), with generators:
0
Syzygies
Singular.syz
— Methodsyz(M::smodule)
Compute the module of syzygies of the given module. This will be given as a set of generators in an ambient space $R^n$, where $n$ is the number of generators in $M$.
Examples
julia> R, (x, y) = polynomial_ring(QQ, ["x", "y"])
(Singular polynomial ring (QQ),(x,y),(dp(2),C), spoly{n_Q}[x, y])
julia> v1 = vector(R, (x + 1)*y, (x*y + 1)*y, y)
x*y^2*gen(2)+x*y*gen(1)+y*gen(3)+y*gen(2)+y*gen(1)
julia> v2 = vector(R, (x + 1)*x, (x*y + 1)*x, x)
x^2*y*gen(2)+x^2*gen(1)+x*gen(3)+x*gen(2)+x*gen(1)
julia> M = Singular.Module(R, v1, v2)
Singular module over Singular polynomial ring (QQ),(x,y),(dp(2),C), with generators:
x*y^2*gen(2)+x*y*gen(1)+y*gen(3)+y*gen(2)+y*gen(1)
x^2*y*gen(2)+x^2*gen(1)+x*gen(3)+x*gen(2)+x*gen(1)
julia> Z = syz(M)
Singular module over Singular polynomial ring (QQ),(x,y),(dp(2),C), with generators:
x*gen(1)-y*gen(2)
Free resolutions
Singular.sres
— Methodsres(I::smodule{spoly{T}}, max_length::Int) where T <: Singular.FieldElem
Compute a free resolution of the given module $I$ of length up to the given maximum length. If max_length
is set to zero, a full length free resolution is computed. Each element of the resolution is itself a module.
Examples
julia> R, (x, y) = polynomial_ring(QQ, ["x", "y"])
(Singular polynomial ring (QQ),(x,y),(dp(2),C), spoly{n_Q}[x, y])
julia> v1 = vector(R, x + 1, x*y + 1, y)
x*y*gen(2)+x*gen(1)+y*gen(3)+gen(2)+gen(1)
julia> v2 = vector(R, x^2 + 1, 2x + 3y, x)
x^2*gen(1)+x*gen(3)+2*x*gen(2)+3*y*gen(2)+gen(1)
julia> M = std(Singular.Module(R, v1, v2))
Singular module over Singular polynomial ring (QQ),(x,y),(dp(2),C), with generators:
x*y*gen(2)+x*gen(1)+y*gen(3)+gen(2)+gen(1)
x^2*gen(1)+x*gen(3)+2*x*gen(2)+3*y*gen(2)+gen(1)
julia> F = sres(M, 0)
Singular resolution: R^3 <- R^2
julia> M1 = Singular.Matrix(M)
[x + 1, x^2 + 1
x*y + 1, 2*x + 3*y
y, x]
julia> M2 = Singular.Matrix(F[2])
[0
0]
julia> iszero(M1*M2) # test we have a complex
true
Jet of module
Singular.jet
— Methodjet(M::smodule, n::Int)
Given a module $M$ this function truncates the generators of $M$ up to degree $n$.
Examples
julia> R, (x, y) = polynomial_ring(QQ, ["x", "y"])
(Singular polynomial ring (QQ),(x,y),(dp(2),C), spoly{n_Q}[x, y])
julia> v1 = vector(R, x + 1, x*y + 1, y)
x*y*gen(2)+x*gen(1)+y*gen(3)+gen(2)+gen(1)
julia> v2 = vector(R, x^5 + 1, 2x^3 + 3y^2, x^2)
x^5*gen(1)+2*x^3*gen(2)+x^2*gen(3)+3*y^2*gen(2)+gen(1)
julia> M = Singular.Module(R, v1, v2)
Singular module over Singular polynomial ring (QQ),(x,y),(dp(2),C), with generators:
x*y*gen(2)+x*gen(1)+y*gen(3)+gen(2)+gen(1)
x^5*gen(1)+2*x^3*gen(2)+x^2*gen(3)+3*y^2*gen(2)+gen(1)
julia> N = jet(M,3)
Singular module over Singular polynomial ring (QQ),(x,y),(dp(2),C), with generators:
x*y*gen(2)+x*gen(1)+y*gen(3)+gen(2)+gen(1)
2*x^3*gen(2)+x^2*gen(3)+3*y^2*gen(2)+gen(1)
Operations over local rings
If the base ring R
is a local ring, a minimal generating set can be computed using the following function
Singular.minimal_generating_set
— Methodminimal_generating_set(M::smodule)
Return a vector containing the minimal generators of $M$.
Examples
julia> R, (x, y) = polynomial_ring(QQ, ["x", "y"]; ordering=:negdegrevlex)
(Singular polynomial ring (QQ),(x,y),(ds(2),C), spoly{n_Q}[x, y])
julia> has_local_ordering(R) == true
true
julia> v1 = vector(R, x, y^2)
x*gen(1)+y^2*gen(2)
julia> v2 = vector(R, y - x, y - y^2)
-x*gen(1)+y*gen(2)+y*gen(1)-y^2*gen(2)
julia> v3 = v1 + v2
y*gen(2)+y*gen(1)
julia> M = Singular.Module(R, v1, v2, v3)
Singular module over Singular polynomial ring (QQ),(x,y),(ds(2),C), with generators:
x*gen(1)+y^2*gen(2)
-x*gen(1)+y*gen(2)+y*gen(1)-y^2*gen(2)
y*gen(2)+y*gen(1)
julia> min = minimal_generating_set(M)
2-element Vector{svector{spoly{n_Q}}}:
y*gen(2)+y*gen(1)
x*gen(1)-y*gen(2)-y*gen(1)+y^2*gen(2)