# 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.

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 modeled as objects of the concrete type `FreeMod{T} <: AbstractFreeMod{T}`

.

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_module`

— Function```
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 R
julia> x*FR[1]
x*e[1]
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 R at complement of prime ideal (x, y, z)
julia> RL(x)*FRL[1]
x*f[1]
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[1]
x*g[1]
julia> RQL, _ = localization(RQ, U);
julia> FRQL = free_module(RQL, 2, "h")
Free module of rank 2 over Localization of RQ at complement of prime ideal
julia> RQL(x)*FRQL[1]
x*h[1]
```

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.

`grade`

— Method`grade(F::FreeMod, W::Vector{FinGenAbGroupElem})`

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)`

.

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])
Z^2
julia> g = gens(G)
2-element Vector{FinGenAbGroupElem}:
[1, 0]
[0, 1]
julia> W = [g[1], g[1], g[2], g[2], g[2]];
julia> S, _ = grade(R, W)
(Graded multivariate polynomial ring in 5 variables over QQ, MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}[x[1], x[2], y[1], y[2], y[3]])
julia> F = free_module(S, 3)
Free module of rank 3 over S
julia> FF = grade(F)
Graded free module S^3([0, 0]) of rank 3 over S
julia> F
Free module of rank 3 over S
```

`grade`

— Method`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.

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: R -> S)
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
```

`graded_free_module`

— Function`graded_free_module(R::Ring, p::Int, W::Vector{FinGenAbGroupElem}=[grading_group(R)[0] 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{FinGenAbGroupElem}, name::String="e")`

As above, with `p = length(W)`

.

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])
julia> graded_free_module(R,3)
Graded free module R^3([0]) of rank 3 over R
julia> G = grading_group(R)
Z
julia> graded_free_module(R, [G[1], 2*G[1]])
Graded free module R^1([-1]) + R^1([-2]) of rank 2 over R
```

`graded_free_module`

— Function`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.

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
```

## 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)`

,`number_of_generators(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[1]
e[2]
e[3]
julia> rank(F)
3
```

In the graded case, we also have:

`grading_group`

— Method`grading_group(F::FreeMod)`

Return the grading group of `base_ring(F)`

.

**Examples**

```
julia> R, (x,y) = graded_polynomial_ring(QQ, ["x", "y"]);
julia> F = graded_free_module(R, 3)
Graded free module R^3([0]) of rank 3 over R
julia> grading_group(F)
Z
```

`degrees_of_generators`

— Method`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"]);
julia> F = graded_free_module(R, 2)
Graded free module R^2([0]) of rank 2 over R
julia> degrees_of_generators(F)
2-element Vector{FinGenAbGroupElem}:
[0]
[0]
```

## 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 modeled 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[1] + y*e[3]
julia> g = F([x, zero(R), y])
x*e[1] + y*e[3]
julia> h = x*F[1] + y*F[3]
x*e[1] + y*e[3]
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[1] + y*F[3]
x*e[1] + y*e[3]
julia> parent(f)
Free module of rank 3 over R
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:

`zero`

— Method`zero(F::AbstractFreeMod)`

Return the zero element of `F`

.

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

`is_zero`

— Method`is_zero(f::AbstractFreeModElem)`

Return `true`

if `f`

is zero, `false`

otherwise.

In the graded case, we additionally have:

`is_homogeneous`

— Method`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
julia> FF = grade(F, [1,4])
Graded free module R^1([-1]) + R^1([-4]) of rank 2 over R
julia> f = y^2*2*FF[1]-x*FF[2]
2*y^2*e[1] - x*e[2]
julia> is_homogeneous(f)
true
```

`degree`

— Method`degree(f::FreeModElem{T}; check::Bool=true) where {T<:AnyGradedRingElem}`

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.

If `check`

is set to `false`

, then there is no check for homegeneity. This should be called internally on provably sane input, as it speeds up computation significantly.

**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)
[3]
julia> typeof(degree(f))
FinGenAbGroupElem
julia> degree(Int, f)
3
julia> typeof(degree(Int, f))
Int64
```

## 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.

`is_isomorphic`

— Method`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> Rg, (x, y, z) = graded_polynomial_ring(QQ, ["x", "y", "z"]);
julia> F = graded_free_module(Rg, [1,1,3,2]);
julia> G1 = graded_free_module(Rg, [1,1,2,3]);
julia> is_isomorphic(F, G1)
true
julia> G2 = graded_free_module(Rg, [1,1,5,6]);
julia> is_isomorphic(F, G2)
false
```

`is_zero`

— Method`is_zero(F::AbstractFreeMod)`

Return `true`

if `F`

is the zero module, `false`

otherwise.

## 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:

`hom`

— Method`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`

.

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 R
julia> G = free_module(R, 2)
Free module of rank 2 over R
julia> V = [y*G[1], x*G[1]+y*G[2], z*G[2]]
3-element Vector{FreeModElem{QQMPolyRingElem}}:
y*e[1]
x*e[1] + y*e[2]
z*e[2]
julia> a = hom(F, G, V)
Map with following data
Domain:
=======
Free module of rank 3 over R
Codomain:
=========
Free module of rank 2 over R
julia> a(F[2])
x*e[1] + y*e[2]
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 R
Codomain:
=========
Free module of rank 2 over R
julia> a == b
true
```

```
julia> Rg, (x, y, z) = graded_polynomial_ring(QQ, ["x", "y", "z"]);
julia> F1 = graded_free_module(Rg, 3)
Graded free module Rg^3([0]) of rank 3 over Rg
julia> G1 = graded_free_module(Rg, 2)
Graded free module Rg^2([0]) of rank 2 over Rg
julia> V1 = [y*G1[1], (x+y)*G1[1]+y*G1[2], z*G1[2]]
3-element Vector{FreeModElem{MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}}}:
y*e[1]
(x + y)*e[1] + y*e[2]
z*e[2]
julia> a1 = hom(F1, G1, V1)
F1 -> G1
e[1] -> y*e[1]
e[2] -> (x + y)*e[1] + y*e[2]
e[3] -> z*e[2]
Graded module homomorphism of degree [1]
julia> F2 = graded_free_module(Rg, [1,1,1])
Graded free module Rg^3([-1]) of rank 3 over Rg
julia> G2 = graded_free_module(Rg, [0,0])
Graded free module Rg^2([0]) of rank 2 over Rg
julia> V2 = [y*G2[1], (x+y)*G2[1]+y*G2[2], z*G2[2]]
3-element Vector{FreeModElem{MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}}}:
y*e[1]
(x + y)*e[1] + y*e[2]
z*e[2]
julia> a2 = hom(F2, G2, V2)
F2 -> G2
e[1] -> y*e[1]
e[2] -> (x + y)*e[1] + y*e[2]
e[3] -> z*e[2]
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[1] -> y*e[1]
e[2] -> (x + y)*e[1] + y*e[2]
e[3] -> z*e[2]
Homogeneous module homomorphism
julia> a2 == b
true
```

`hom`

— Method`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`

.

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*.

Given a homomorphism of type `FreeModuleHom`

, a matrix representing it is recovered by the following function:

`matrix`

— Method`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 R
julia> G = free_module(R, 2)
Free module of rank 2 over R
julia> V = [y*G[1], x*G[1]+y*G[2], z*G[2]];
julia> a = hom(F, G, V);
julia> matrix(a)
[y 0]
[x y]
[0 z]
```

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_graded`

— Method`is_graded(a::ModuleFPHom)`

Return `true`

if `a`

is graded, `false`

otherwise.

**Examples**

```
julia> R, (x, y, z) = graded_polynomial_ring(QQ, ["x", "y", "z"]);
julia> F = graded_free_module(R, 3)
Graded free module R^3([0]) of rank 3 over R
julia> G = graded_free_module(R, 2)
Graded free module R^2([0]) of rank 2 over R
julia> V = [y*G[1], x*G[1]+y*G[2], z*G[2]]
3-element Vector{FreeModElem{MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}}}:
y*e[1]
x*e[1] + y*e[2]
z*e[2]
julia> a = hom(F, G, V)
F -> G
e[1] -> y*e[1]
e[2] -> x*e[1] + y*e[2]
e[3] -> z*e[2]
Graded module homomorphism of degree [1]
julia> is_graded(a)
true
```

`is_homogeneous`

— Method`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"]);
julia> F = graded_free_module(R, 3)
Graded free module R^3([0]) of rank 3 over R
julia> G = graded_free_module(R, 2)
Graded free module R^2([0]) of rank 2 over R
julia> V = [y*G[1], x*G[1]+y*G[2], z*G[2]]
3-element Vector{FreeModElem{MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}}}:
y*e[1]
x*e[1] + y*e[2]
z*e[2]
julia> a = hom(F, G, V)
F -> G
e[1] -> y*e[1]
e[2] -> x*e[1] + y*e[2]
e[3] -> z*e[2]
Graded module homomorphism of degree [1]
julia> is_homogeneous(a)
false
```

In the graded case, we additionally have:

`degree`

— Method`degree(a::FreeModuleHom; check::Bool=true)`

If `a`

is graded, return the degree of `a`

.

**Examples**

```
julia> R, (x, y, z) = graded_polynomial_ring(QQ, ["x", "y", "z"]);
julia> F = graded_free_module(R, 3)
Graded free module R^3([0]) of rank 3 over R
julia> G = graded_free_module(R, 2)
Graded free module R^2([0]) of rank 2 over R
julia> V = [y*G[1], x*G[1]+y*G[2], z*G[2]]
3-element Vector{FreeModElem{MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}}}:
y*e[1]
x*e[1] + y*e[2]
z*e[2]
julia> a = hom(F, G, V)
F -> G
e[1] -> y*e[1]
e[2] -> x*e[1] + y*e[2]
e[3] -> z*e[2]
Graded module homomorphism of degree [1]
julia> degree(a)
[1]
```

`grading_group`

— Method`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"]);
julia> F = graded_free_module(R, 3)
Graded free module R^3([0]) of rank 3 over R
julia> G = graded_free_module(R, 2)
Graded free module R^2([0]) of rank 2 over R
julia> V = [y*G[1], x*G[1]+y*G[2], z*G[2]]
3-element Vector{FreeModElem{MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}}}:
y*e[1]
x*e[1] + y*e[2]
z*e[2]
julia> a = hom(F, G, V)
F -> G
e[1] -> y*e[1]
e[2] -> x*e[1] + y*e[2]
e[3] -> z*e[2]
Graded module homomorphism of degree [1]
julia> is_graded(a)
true
julia> grading_group(a)
Z
```