# Free Modules

In this section, the expression free module refers to a free module of finite rank over a ring of type MPolyRing, MPolyQuoRing, MPolyLocRing, or MPolyQuoLocRing. More concretely, given a ring $R$ of one of these types, the free $R$-modules considered are of type $R^p$, where we think of $R^p$ as a free module with a given basis, namely the basis of standard unit vectors. Accordingly, elements of free modules are represented by coordinate vectors, and homomorphisms between free modules by matrices.

Note

By convention, vectors are row vectors, and matrices operate by multiplication on the right.

## Types

All OSCAR types for the modules considered here belong to the abstract type ModuleFP{T}, where T is the element type of the underlying ring. Graded or not, the free modules belong to the abstract subtype AbstractFreeMod{T} <: ModuleFP{T}, they are modelled as objects of the concrete type FreeMod{T} <: AbstractFreeMod{T}.

Note

Canonical maps such us the canonical projection onto a quotient module arise in many constructions in commutative algebra. The FreeMod type is designed so that it allows for the caching of such maps when executing functions. The direct_sum function discussed in this section provides an example.

## Constructors

free_moduleFunction
free_module(R::MPolyRing, p::Int, name::VarName = :e; cached::Bool = false)
free_module(R::MPolyQuoRing, p::Int, name::VarName = :e; cached::Bool = false)
free_module(R::MPolyLocRing, p::Int, name::VarName = :e; cached::Bool = false)
free_module(R::MPolyQuoLocRing, p::Int, name::VarName = :e; cached::Bool = false)

Return the free $R$-module $R^p$, created with its basis of standard unit vectors.

The string name specifies how the basis vectors are printed.

Examples

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

julia> FR = free_module(R, 2)
Free module of rank 2 over Multivariate polynomial ring in 3 variables over QQ

julia> x*FR
x*e

julia> P = ideal(R, [x, y, z]);

julia> U = complement_of_prime_ideal(P);

julia> RL, _ = Localization(R, U);

julia> FRL = free_module(RL, 2, "f")
Free module of rank 2 over Localization of multivariate polynomial ring in 3 variables over QQ at complement of prime ideal(x, y, z)

julia> RL(x)*FRL
x*f

julia> RQ, _ = quo(R, ideal(R, [2*x^2-y^3, 2*x^2-y^5]));

julia> FRQ =  free_module(RQ, 2, "g")
Free module of rank 2 over RQ

julia> RQ(x)*FRQ
x*g

julia> RQL, _ = Localization(RQ, U);

julia> FRQL =  free_module(RQL, 2, "h")
Free module of rank 2 over Localization of quotient of multivariate polynomial ring at complement of prime ideal

julia> RQL(x)*FRQL
x*h
source

Over graded multivariate polynomial rings and their quotients, there are two basic ways of creating graded free modules: While the grade function allows one to create a graded free module by assigning a grading to a free module already constructed, the graded_free_module function is meant to create a graded free module all at once.

gradeMethod
grade(F::FreeMod, W::Vector{GrpAbFinGenElem})

Given a free module F over a graded ring with grading group G, say, and given a vector W of ngens(F) elements of G, create a G-graded free module by assigning the entries of W as weights to the generators of F. Return the new module.

grade(F::FreeMod)

As above, with all weights set to zero(G).

Note

The function applies to free modules over both graded multivariate polynomial rings and their quotients.

Examples

julia> R, x, y = polynomial_ring(QQ, "x" => 1:2, "y" => 1:3);

julia> G = abelian_group([0, 0])
GrpAb: Z^2

julia> g = gens(G)
2-element Vector{GrpAbFinGenElem}:
Element of G with components [1 0]
Element of G with components [0 1]

julia> W = [g, g, g, g, g];

julia> S, _ = grade(R, W)
(Graded multivariate polynomial ring in 5 variables over QQ, MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}[x, x, y, y, y])

julia> F = free_module(S, 3)
Free module of rank 3 over S

Graded free module S^3([0 0]) of rank 3 over S

julia> F
Free module of rank 3 over S
source
gradeMethod
grade(F::FreeMod, W::Vector{<:Vector{<:IntegerUnion}})

Given a free module F over a graded ring with grading group $G = \mathbb Z^m$, and given a vector W of ngens(F) integer vectors of the same size m, say, define a $G$-grading on F by converting the vectors in W to elements of $G$, and assigning these elements as weights to the variables. Return the new module.

grade(F::FreeMod, W::Union{ZZMatrix, Matrix{<:IntegerUnion}})

As above, converting the columns of W.

grade(F::FreeMod, W::Vector{<:IntegerUnion})

Given a free module F over a graded ring with grading group $G = \mathbb Z$, and given a vector W of ngens(F) integers, define a $G$-grading on F converting the entries of W to elements of G, and assigning these elements as weights to the variables. Return the new module.

Note

The function applies to free modules over both graded multivariate polynomial rings and their quotients.

Examples

julia> R, (x, y, z) = graded_polynomial_ring(QQ, ["x", "y", "z"],  [1 0 1; 0 1 1])
(Graded multivariate polynomial ring in 3 variables over QQ, MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}[x, y, z])

julia> F = free_module(R, 2)
Free module of rank 2 over R

julia> FF = grade(F,  [[1, 0], [0, 1]])
Graded free module R^1([-1 0]) + R^1([0 -1]) of rank 2 over R

julia> FFF = grade(F,  [1 0; 0 1])
Graded free module R^1([-1 0]) + R^1([0 -1]) of rank 2 over R
julia> R, (x, y) = graded_polynomial_ring(QQ, ["x", "y"])
(Graded multivariate polynomial ring in 2 variables over QQ, MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}[x, y])

julia> S, _ = quo(R, [x*y])
(Quotient of multivariate polynomial ring by ideal(x*y), Map: graded multivariate polynomial ring -> quotient of multivariate polynomial ring)

julia> F = free_module(S, 2)
Free module of rank 2 over S

julia> FF = grade(F, [1, 2])
Graded free module S^1([-1]) + S^1([-2]) of rank 2 over S
source
graded_free_moduleFunction
graded_free_module(R::Ring, p::Int, W::Vector{GrpAbFinGenElem}=[grading_group(R) for i in 1:p], name::String="e")

Given a graded ring R with grading group G, say, and given a vector W with p elements of G, create the free module $R^p$ equipped with its basis of standard unit vectors, and assign weights to these vectors according to the entries of W. Return the resulting graded free module.

graded_free_module(R::Ring, W::Vector{GrpAbFinGenElem}, name::String="e")

As above, with p = length(W).

Note

The function applies to graded multivariate polynomial rings and their quotients.

The string name specifies how the basis vectors are printed.

Examples

julia> R, (x,y) = graded_polynomial_ring(QQ, ["x", "y"])
(Graded multivariate polynomial ring in 2 variables over QQ, MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}[x, y])

Graded free module R^3() of rank 3 over R

GrpAb: Z

Graded free module R^1([-1]) + R^1([-2]) of rank 2 over R
source
graded_free_moduleFunction
graded_free_module(R::Ring, W::Vector{<:Vector{<:IntegerUnion}}, name::String="e")

Given a graded ring R with grading group $G = \mathbb Z^m$, and given a vector W of integer vectors of the same size p, say, create the free module $R^p$ equipped with its basis of standard unit vectors, and assign weights to these vectors according to the entries of W, converted to elements of G. Return the resulting graded free module.

graded_free_module(R::Ring, W::Union{ZZMatrix, Matrix{<:IntegerUnion}}, name::String="e")

As above, converting the columns of W.

graded_free_module(R::Ring, W::Vector{<:IntegerUnion}, name::String="e")

Given a graded ring R with grading group $G = \mathbb Z$, and given a vector W of integers, set p = length(W), create the free module $R^p$ equipped with its basis of standard unit vectors, and assign weights to these vectors according to the entries of W, converted to elements of G. Return the resulting graded free module.

The string name specifies how the basis vectors are printed.

Note

The function applies to graded multivariate polynomial rings and their quotients.

Examples

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

julia> F = graded_free_module(R, [1, 2])
Graded free module R^1([-1]) + R^1([-2]) of rank 2 over R
julia> S, (x, y, z) = graded_polynomial_ring(QQ, ["x", "y", "z"], [1 0 1; 0 1 1]);

julia> FF = graded_free_module(S, [[1, 2], [-1, 3]])
Graded free module S^1([-1 -2]) + S^1([1 -3]) of rank 2 over S

julia> FFF = graded_free_module(S, [1 -1; 2 3])
Graded free module S^1([-1 -2]) + S^1([1 -3]) of rank 2 over S

julia> FF == FFF
true
source

## Data Associated to Free Modules

If F is a free R-module, then

• base_ring(F) refers to R,
• basis(F), gens(F) to the basis vectors of F,
• rank(F), ngens(F), dim(F) to the number of these vectors, and
• F[i], basis(F, i), gen(F, i) to the i-th such vector.
###### Examples
julia> R, (x, y) = polynomial_ring(QQ, ["x", "y"]);

julia> F = free_module(R, 3);

julia> basis(F)
3-element Vector{FreeModElem{QQMPolyRingElem}}:
e
e
e

julia> rank(F)
3

In the graded case, we also have:

grading_groupMethod
grading_group(F::FreeMod)

Return the grading group of base_ring(F).

Examples

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

Graded free module R^3() of rank 3 over R

GrpAb: Z
source
degrees_of_generatorsMethod
degrees_of_generators(F::FreeMod)

Return the degrees of the generators of F.

Examples

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

Graded free module R^2() of rank 2 over R

julia> degrees_of_generators(F)
2-element Vector{GrpAbFinGenElem}:


source

## Elements of Free Modules

All OSCAR types for elements of the modules considered here belong to the abstract type ModuleElemFP{T}, where T is the element type of the underlying ring. The free modules belong to the abstract subtype AbstractFreeModElem{T} <: ModuleFPElem{T}. They are modelled as objects of the concrete type FreeModElem{T} <: AbstractFreeModElem{T} which implements an element $f$ of a free module $F$ as a sparse row, that is, as an object of type SRow{T}. This object specifies the coordinates of $f$ with respect to the basis of standard unit vectors of $F$. To create an element, enter its coordinates as a sparse row or a vector:

(F::FreeMod{T})(c::SRow{T}) where T
(F::FreeMod{T})(c::Vector{T}) where T

Alternatively, directly write the element as a linear combination of basis vectors of $F$:

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

julia> F = free_module(R, 3);

julia> f = F(sparse_row(R, [(1,x),(3,y)]))
x*e + y*e

julia> g = F([x, zero(R), y])
x*e + y*e

julia> h = x*F + y*F
x*e + y*e

julia> f == g == h
true

Given an element f of a free module F over a multivariate polynomial ring with element type T,

• parent(f) refers to F, and
• coordinates(f) to the coordinate vector of f, returned as an object of type SRow{T}.
##### Examples
julia> R, (x, y) = polynomial_ring(QQ, ["x", "y"]);

julia> F = free_module(R, 3);

julia> f = x*F + y*F
x*e + y*e

julia> parent(f)
Free module of rank 3 over Multivariate polynomial ring in 2 variables over QQ

julia> coordinates(f)
Sparse row with positions [1, 3] and values QQMPolyRingElem[x, y]


The zero element of a free module is obtained as follows:

zeroMethod
zero(F::AbstractFreeMod)

Return the zero element of F.

source

Whether a given element of a free module is zero can be tested as follows:

is_zeroMethod
is_zero(f::AbstractFreeModElem)

Return true if f is zero, false otherwise.

source

is_homogeneousMethod
is_homogeneous(f::FreeModElem)

Given an element f of a graded free module, return true if f is homogeneous, false otherwise.

Examples

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

julia> F = free_module(R, 2)
Free module of rank 2 over R

Graded free module R^1([-1]) + R^1([-4]) of rank 2 over R

julia> f = y^2*2*FF-x*FF
2*y^2*e - x*e

julia> is_homogeneous(f)
true
source
degreeMethod
degree(f::FreeModElem)

Given a homogeneous element f of a graded free module, return the degree of f.

degree(::Type{Vector{Int}}, f::FreeModElem)

Given a homogeneous element f of a $\mathbb Z^m$-graded free module, return the degree of f, converted to a vector of integer numbers.

degree(::Type{Int}, f::FreeModElem)

Given a homogeneous element f of a $\mathbb Z$-graded free module, return the degree of f, converted to an integer number.

Examples

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

julia> f = y^2*z − x^2*w
-w*x^2 + y^2*z

julia> degree(f)


julia> typeof(degree(f))
GrpAbFinGenElem

julia> degree(Int, f)
3

julia> typeof(degree(Int, f))
Int64
source

## Tests on Free Modules

The tests is_graded, is_standard_graded, is_z_graded, and is_zm_graded carry over analogously to free modules. They return true if the corresponding property is satisfied, and false otherwise. In addition, we have:

==Method
==(F::FreeMod, G::FreeMod)

Return true if F and G are equal, false otherwise.

Here, F and G are equal iff either

• both modules are ungraded and their base rings, ranks, and names for printing the basis elements are equal,

or else

• both modules are graded, the above holds, and for each $i$, the degrees of the $i$-th basis elements are equal.
source
is_isomorphicMethod
is_isomorphic(F::FreeMod, G::FreeMod)

Return true if F and G are isomorphic as (graded) modules, false otherwise.

That is, either

• both modules are ungraded and their base rings and ranks are equal,

or else

• both modules are graded, the above holds, and the multisets of the degrees of the basis elements are equal.

Examples

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

julia> Z = abelian_group(0);

julia> Rg, (x, y, z)=grade(R,[Z, Z, Z]);

julia> is_isomorphic(F, G1)
true

julia> is_isomorphic(F, G2)
false
source
is_zeroMethod
is_zero(F::AbstractFreeMod)

Return true if F is the zero module, false otherwise.

source

## Homomorphisms from Free Modules

All OSCAR types for homomorphisms of the modules considered here belong to the abstract type ModuleFPHom{T1, T2}, where T1 and T2 are the types of domain and codomain respectively. A homomorphism $F\to M$ from a free module $F$ is determined by specifying the images of the basis vectors of $F$ in $M$. For such homomorphisms, OSCAR provides the concrete type FreeModuleHom{T1, T2} <: ModuleFPHom{T1, T2} as well as the following constructors:

homMethod
hom(F::FreeMod, M::ModuleFP{T}, V::Vector{<:ModuleFPElem{T}}) where T

Given a vector V of rank(F) elements of M, return the homomorphism F $\to$ M which sends the i-th basis vector of F to the i-th entry of V.

hom(F::FreeMod, M::ModuleFP{T}, A::MatElem{T}) where T

Given a matrix A with rank(F) rows and ngens(M) columns, return the homomorphism F $\to$ M which sends the i-th basis vector of F to the linear combination $\sum_j A[i,j]*M[j]$ of the generators M[j] of M.

Note

The module M may be of type FreeMod or SubquoMod. If both modules F and M are graded, the data must define a graded module homomorphism of some degree. If this degree is the zero element of the (common) grading group, we refer to the homomorphism under consideration as a homogeneous module homomorphism.

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> F = free_module(R, 3)
Free module of rank 3 over Multivariate polynomial ring in 3 variables over QQ

julia> G = free_module(R, 2)
Free module of rank 2 over Multivariate polynomial ring in 3 variables over QQ

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

julia> a = hom(F, G, V)
Map with following data
Domain:
=======
Free module of rank 3 over Multivariate polynomial ring in 3 variables over QQ
Codomain:
=========
Free module of rank 2 over Multivariate polynomial ring in 3 variables over QQ

julia> a(F)
x*e + y*e

julia> B = R[y 0; x y; 0 z]
[y   0]
[x   y]
[0   z]

julia> b = hom(F, G, B)
Map with following data
Domain:
=======
Free module of rank 3 over Multivariate polynomial ring in 3 variables over QQ
Codomain:
=========
Free module of rank 2 over Multivariate polynomial ring in 3 variables over QQ

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

julia> Z = abelian_group(0);

julia> Rg, (x, y, z) = grade(R,[Z, Z, Z]);

Graded free module Rg^3() of rank 3 over Rg

Graded free module Rg^2() of rank 2 over Rg

julia> V1 = [y*G1, (x+y)*G1+y*G1, z*G1]
3-element Vector{FreeModElem{MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}}}:
y*e
(x + y)*e + y*e
z*e

julia> a1 = hom(F1, G1, V1)
F1 -> G1
e -> y*e
e -> (x + y)*e + y*e
e -> z*e
Graded module homomorphism of degree 

Graded free module Rg^3([-1]) of rank 3 over Rg

Graded free module Rg^2() of rank 2 over Rg

julia> V2 = [y*G2, (x+y)*G2+y*G2, z*G2]
3-element Vector{FreeModElem{MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}}}:
y*e
(x + y)*e + y*e
z*e

julia> a2 = hom(F2, G2, V2)
F2 -> G2
e -> y*e
e -> (x + y)*e + y*e
e -> z*e
Homogeneous module homomorphism

julia> B = Rg[y 0; x+y y; 0 z]
[    y   0]
[x + y   y]
[    0   z]

julia> b = hom(F2, G2, B)
F2 -> G2
e -> y*e
e -> (x + y)*e + y*e
e -> z*e
Homogeneous module homomorphism

julia> a2 == b
true
source
homMethod
hom(F::FreeMod, M::ModuleFP{T}, V::Vector{<:ModuleFPElem{T}}, h::RingMapType) where {T, RingMapType}

Given a vector V of rank(F) elements of M and a ring map h from base_ring(F) to base_ring(M), return the base_ring(F)-homomorphism F $\to$ M which sends the i-th basis vector of F to the i-th entry of V, and the scalars in base_ring(F) to their images under h.

hom(F::FreeMod, M::ModuleFP{T}, A::MatElem{T}, h::RingMapType) where {T, RingMapType}

Given a matrix A over base_ring(M) with rank(F) rows and ngens(M) columns and a ring map h from base_ring(F) to base_ring(M), return the base_ring(F)-homomorphism F $\to$ M which sends the i-th basis vector of F to the linear combination $\sum_j A[i,j]*M[j]$ of the generators M[j] of M, and the scalars in base_ring(F) to their images under h.

Note

The module M may be of type FreeMod or SubquoMod. If both modules F and M are graded, the data must define a graded module homomorphism of some degree. If this degree is the zero element of the (common) grading group, we refer to the homomorphism under consideration as a homogeneous module homomorphism.

source

Given a homomorphism of type FreeModuleHom, a matrix representing it is recovered by the following function:

matrixMethod
matrix(a::FreeModuleHom)

Given a homomorphism a : F → M of type FreeModuleHom, return a matrix A over base_ring(M) with rank(F) rows and ngens(M) columns such that $a(F[i]) = \sum_j A[i,j]*M[j]$.

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> F = free_module(R, 3)
Free module of rank 3 over Multivariate polynomial ring in 3 variables over QQ

julia> G = free_module(R, 2)
Free module of rank 2 over Multivariate polynomial ring in 3 variables over QQ

julia> V = [y*G, x*G+y*G, z*G];

julia> a = hom(F, G, V);

julia> matrix(a)
[y   0]
[x   y]
[0   z]
source

The domain and codomain of a homomorphism a of type FreeModuleHom can be recovered by entering domain(a) and codomain(a), respectively.

The functions below test whether a homomorphism of type FreeModuleHom is graded and homogeneous, respectively.

is_gradedMethod
is_graded(a::FreeModuleHom)

Return true if a is graded, false otherwise.

Examples

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

Graded free module R^3() of rank 3 over R

Graded free module R^2() of rank 2 over R

julia> V = [y*G, x*G+y*G, z*G]
3-element Vector{FreeModElem{MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}}}:
y*e
x*e + y*e
z*e

julia> a = hom(F, G, V)
F -> G
e -> y*e
e -> x*e + y*e
e -> z*e
Graded module homomorphism of degree 

true
source
is_homogeneousMethod
is_homogeneous(a::FreeModuleHom)

Return true if a is homogeneous, false otherwise

Here, if G is the grading group of a, a is homogeneous if a is graded of degree zero(G).

Examples

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

Graded free module R^3() of rank 3 over R

Graded free module R^2() of rank 2 over R

julia> V = [y*G, x*G+y*G, z*G]
3-element Vector{FreeModElem{MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}}}:
y*e
x*e + y*e
z*e

julia> a = hom(F, G, V)
F -> G
e -> y*e
e -> x*e + y*e
e -> z*e
Graded module homomorphism of degree 

julia> is_homogeneous(a)
false
source

degreeMethod
degree(a::FreeModuleHom)

If a is graded, return the degree of a.

Examples

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

Graded free module R^3() of rank 3 over R

Graded free module R^2() of rank 2 over R

julia> V = [y*G, x*G+y*G, z*G]
3-element Vector{FreeModElem{MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}}}:
y*e
x*e + y*e
z*e

julia> a = hom(F, G, V)
F -> G
e -> y*e
e -> x*e + y*e
e -> z*e
Graded module homomorphism of degree 

julia> degree(a)

source
grading_groupMethod
grading_group(a::FreeModuleHom)

If a is graded, return the grading group of a.

Examples

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

Graded free module R^3() of rank 3 over R

Graded free module R^2() of rank 2 over R

julia> V = [y*G, x*G+y*G, z*G]
3-element Vector{FreeModElem{MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}}}:
y*e
x*e + y*e
z*e

julia> a = hom(F, G, V)
F -> G
e -> y*e
e -> x*e + y*e
e -> z*e
Graded module homomorphism of degree 

GrpAb: Z