next | previous | forward | backward | up | top | index | toc | Macaulay2 website
Macaulay2Doc > basic commutative algebra > modules in Macaulay2

modules in Macaulay2

In this tutorial, we describe how to work with modules in Macaulay2.

A. Making modules from matrices

First, let's define a ring.

i1 : R = QQ[a..f];
i2 : m = matrix{{a,b,d,e},{b,c,e,f}}

o2 = | a b d e |
     | b c e f |

             2       4
o2 : Matrix R  <--- R

Use standard notation for cokernels, images and kernels (coker, cokernel, image, ker, kernel).

i3 : M = coker m

o3 = cokernel | a b d e |
              | b c e f |

                            2
o3 : R-module, quotient of R
i4 : N = image m

o4 = image | a b d e |
           | b c e f |

                             2
o4 : R-module, submodule of R
i5 : K = kernel m
-- ker (2) called with OptionTable: OptionTable{SubringLimit => infinity}
-- ker (2) returned CacheFunction: -*a cache function*-
-- ker (2) called with Matrix: | a b d e |
--                             | b c e f |
-- ker (2) returned Module: image {1} | cd-be  0      e2-df  ce-bf  |
--                                {1} | -bd+ae e2-df  0      -be+af |
--                                {1} | b2-ac  -ce+bf -be+af 0      |
--                                {1} | 0      cd-be  bd-ae  b2-ac  |
assert( ker(map(R^2,R^{{-1}, {-1}, {-1}, {-1}},{{a,b,d,e}, {b,c,e,f}})) === (image(map(R^{{-1}, {-1}, {-1}, {-1}},R^{{-3}, {-3}, {-3}, {-3}},{{c*d-b*e,0,e^2-d*f,c*e-b*f}, {-b*d+a*e,e^2-d*f,0,-b*e+a*f}, {b^2-a*c,-c*e+b*f,-b*e+a*f,0}, {0,c*d-b*e,b*d-a*e,b^2-a*c}}))))

o5 = image {1} | cd-be  0      e2-df  ce-bf  |
           {1} | -bd+ae e2-df  0      -be+af |
           {1} | b2-ac  -ce+bf -be+af 0      |
           {1} | 0      cd-be  bd-ae  b2-ac  |

                             4
o5 : R-module, submodule of R

Given a module, one can find its presentation matrix.

i6 : presentation M -- this is just the original matrix

o6 = | a b d e |
     | b c e f |

             2       4
o6 : Matrix R  <--- R
i7 : presentation N -- this one requires computation

o7 = {1} | cd-be  0      e2-df  ce-bf  |
     {1} | -bd+ae e2-df  0      -be+af |
     {1} | b2-ac  -ce+bf -be+af 0      |
     {1} | 0      cd-be  bd-ae  b2-ac  |

             4       4
o7 : Matrix R  <--- R

B. Submodules and quotients

To define a submodule $IN$ of a module $N$, where $I$ is an ideal, use

i8 : ideal(a,b)*N

o8 = image | a2 ab ad ae ab b2 bd be |
           | ab ac ae af b2 bc be bf |

                             2
o8 : R-module, submodule of R
i9 : a*N + b*N

o9 = image | a2 ab ad ae ab b2 bd be |
           | ab ac ae af b2 bc be bf |

                             2
o9 : R-module, submodule of R

In order to define a submodule of N generated by some elements of N, one way is the following.

i10 : N0 = image (a**N_{1}|N_{2}-N_{3})

o10 = image | ab d-e |
            | ac e-f |

                              2
o10 : R-module, submodule of R

To understand what Macaulay2 is doing here, let's break this down. N_{i} defines a matrix $R^1 \to N$, which maps 1 to the i th generator of N. (See Section XX below for more information about module homomorphisms).

i11 : N_{1}

o11 = {1} | 0 |
      {1} | 1 |
      {1} | 0 |
      {1} | 0 |

o11 : Matrix

One could use a*N_{1}, but it turns out that a ** N_{1} works better:

i12 : a ** N_{1}

o12 = {1} | 0 |
      {1} | a |
      {1} | 0 |
      {1} | 0 |

o12 : Matrix

Next, remember that the vertical bar concatenates matrices.

i13 : a ** N_{1} | N_{2}-N_{3}

o13 = {1} | 0 0  |
      {1} | a 0  |
      {1} | 0 1  |
      {1} | 0 -1 |

o13 : Matrix

Now take the image of this matrix

i14 : N0 = image(a ** N_{1} | N_{2}-N_{3})

o14 = image | ab d-e |
            | ac e-f |

                              2
o14 : R-module, submodule of R

The main advantage for using ** rather than * is that ** preservers homogeneity if possible.

i15 : isHomogeneous N0

o15 = true

Quotients are defined using standard mathematical notation.

i16 : Nbar = N/N0

o16 = subquotient (| a b d e |, | ab d-e |)
                   | b c e f |  | ac e-f |

                                2
o16 : R-module, subquotient of R

Notice that this returns a subquotient module. We treat these later. Ideals and modules are treated differently in Macaulay2 (and in commutative algebra in general). For example, asking for the dimension of an ideal I in a ring R gives the dimension of the quotient R/I, but the dimension of the module I gives a potentially very different answer. Use ideal and module to move between the two.

i17 : I = ideal(a^2, a*b, c^2)

              2        2
o17 = ideal (a , a*b, c )

o17 : Ideal of R
i18 : J = module I

o18 = image | a2 ab c2 |

                              1
o18 : R-module, submodule of R
i19 : I == ideal J

o19 = true
i20 : codim I

o20 = 2
i21 : codim J

o21 = 0

C. Syzygies and free resolutions

Create a free resolution of an ideal (or module) using res.

i22 : C = res I

       1      3      3      1
o22 = R  <-- R  <-- R  <-- R  <-- 0
                                   
      0      1      2      3      4

o22 : ChainComplex

View the differential

i23 : C.dd

           1                    3
o23 = 0 : R  <---------------- R  : 1
                | a2 ab c2 |

           3                          3
      1 : R  <---------------------- R  : 2
                {2} | -b -c2 0   |
                {2} | a  0   -c2 |
                {2} | 0  a2  ab  |

           3                  1
      2 : R  <-------------- R  : 3
                {3} | c2 |
                {4} | -b |
                {4} | a  |

           1
      3 : R  <----- 0 : 4
                0

o23 : ChainComplexMap

The (graded) betti numbers

i24 : betti C

             0 1 2 3
o24 = total: 1 3 3 1
          0: 1 . . .
          1: . 3 1 .
          2: . . 2 1

o24 : BettiTally

Use help (betti,GradedModule) for a detailed description of what this display means. Basically, it says that I has three generators of degree 2, one syzygy of degree 3, 2 syzygies of degree 4, and one second syzygy of degree 5. The free resolution of a module that is not a cokernel:

i25 : C = res Nbar

       4      6      2
o25 = R  <-- R  <-- R  <-- 0
                            
      0      1      2      3

o25 : ChainComplex
i26 : betti C

             0 1 2
o26 = total: 4 6 2
          0: . 1 .
          1: 4 1 .
          2: . 4 2

o26 : BettiTally
i27 : C.dd

           4                                                               6
o27 = 0 : R  <----------------------------------------------------------- R  : 1
                {1} | 0  0 ce-bf -cd+be+ce-bf e2-df       0           |
                {1} | 0  a -be   bd-be        0           e2-df       |
                {1} | -1 0 b2-ac 0            bd-ae-be+af cd-be-ce+bf |
                {1} | 1  0 0     0            0           0           |

           6                         2
      1 : R  <--------------------- R  : 2
                {1} | 0     0   |
                {2} | e2-df 0   |
                {3} | -d+e  e-f |
                {3} | -e    f   |
                {3} | b     -c  |
                {3} | -a    b   |

           2
      2 : R  <----- 0 : 3
                0

o27 : ChainComplexMap

Here is a problem to experiment with. What different betti diagrams are possible with an ideal generated by 3 homogeneous quadric polynomials, in a polynomial ring in any number of variables? Here is one to get you started.

i28 : R = QQ[a..h];
i29 : J = ideal(a*c+b*d,a*e+b*f,a*g+b*h)

o29 = ideal (a*c + b*d, a*e + b*f, a*g + b*h)

o29 : Ideal of R
i30 : betti res J

             0 1 2 3
o30 = total: 1 3 4 2
          0: 1 . . .
          1: . 3 . .
          2: . . 4 2

o30 : BettiTally

After that, try ideals generated by 4 quadrics.

D. Subquotients

Recall that the module N/N0 above displayed as something called a subquotient module. As Macaulay2 often returns such objects, it is useful to understand and be able to manipulate them. P The most common modules are quotients of free modules, or submodules of free modules. A useful generalization, which covers both of these types, are subquotients: submodules of quotients of free modules. P A subquotient module is determined by two matrices $f : R^m \to R^n$ and $g : R^p \to R^n$. The subquotient module with generators f, relations g is by definition the module M = (image f) + (image g) / (image g). Thus, if f is the identity map, M = coker g, and if g = 0, then M = image f.

i31 : use ring M

o31 = QQ[a..f]

o31 : PolynomialRing
i32 : M

o32 = cokernel | a b d e |
               | b c e f |

                                             2
o32 : QQ[a..f]-module, quotient of (QQ[a..f])
i33 : N = a*M

o33 = subquotient (| a 0 |, | a b d e |)
                   | 0 a |  | b c e f |

                                                2
o33 : QQ[a..f]-module, subquotient of (QQ[a..f])
i34 : M/N

o34 = cokernel | a 0 a b d e |
               | 0 a b c e f |

                                             2
o34 : QQ[a..f]-module, quotient of (QQ[a..f])

The two matrices f and g mentioned above are recovered using the routines: generators, relations.

i35 : generators N

o35 = | a 0 |
      | 0 a |

                       2                2
o35 : Matrix (QQ[a..f])  <--- (QQ[a..f])
i36 : relations N

o36 = | a b d e |
      | b c e f |

                       2                4
o36 : Matrix (QQ[a..f])  <--- (QQ[a..f])

It is often necessary to find a presentation matrix for such modules.

i37 : presentation N

o37 = {1} | e d b a |
      {1} | f e c b |

                       2                4
o37 : Matrix (QQ[a..f])  <--- (QQ[a..f])

Often the given representation of a module is not very efficient. Use trim to keep the module as a subquotient of the same ambient free module, but change the generators and relations to be minimal, or in the nonlocal or non-graded case, at least more efficient.

i38 : trim N

o38 = subquotient (| a 0 |, | e d b a |)
                   | 0 a |  | f e c b |

                                                2
o38 : QQ[a..f]-module, subquotient of (QQ[a..f])

Use minimalPresentation to also allow the ambient free module to be improved. This returns a quotient of a free module, but in the future might not do that.

i39 : minimalPresentation N

o39 = cokernel {1} | e d b a |
               {1} | f e c b |

                                             2
o39 : QQ[a..f]-module, quotient of (QQ[a..f])

prune is a synonym for minimalPresentation N

i40 : prune N

o40 = cokernel {1} | e d b a |
               {1} | f e c b |

                                             2
o40 : QQ[a..f]-module, quotient of (QQ[a..f])

Given a subquotient module N, there are several useful modules associated to N. The free module of which N is a subquotient is obtained using ambient.

i41 : ambient N

                2
o41 = (QQ[a..f])

o41 : QQ[a..f]-module, free

This is the same as the target of either the generator or relation matrix.

i42 : ambient N == target generators N

o42 = true
i43 : ambient N == target relations N

o43 = true

N is a submodule of a quotient module $R^n/image(g)$. The routine super returns this quotient module

i44 : super N

o44 = cokernel | a b d e |
               | b c e f |

                                             2
o44 : QQ[a..f]-module, quotient of (QQ[a..f])

This is the same as

i45 : super N == coker relations N

o45 = true

The cover of N is basically the source of the matrix of generators.

i46 : cover N

                2
o46 = (QQ[a..f])

o46 : QQ[a..f]-module, free, degrees {2:1}
i47 : cover N == source generators N

o47 = true

E. Homomorphisms between modules

A homomorphism $f : M \to N$ is represented as a matrix from the generators of M to the generators of N.

i48 : A = QQ[x,y]/(y^2-x^3)

o48 = A

o48 : QuotientRing
i49 : M = module ideal(x,y)

o49 = image | x y |

                              1
o49 : A-module, submodule of A

One homomorphism $F : M \to A$ is $x \mapsto y, y \mapsto x^2$ (multiplication by y/x) We write this as:

i50 : F = map(A^1,M,matrix{{y,x^2}})

o50 = | y x2 |

o50 : Matrix

Notice that as is usual in Macaulay2, the target comes before the source.

i51 : source F == M

o51 = true
i52 : target F == A^1

o52 = true
i53 : matrix F

o53 = | y x2 |

              1       2
o53 : Matrix A  <--- A

The image of F lies in the submodule M of $A^1$. To obtain the map $M \to M$, we use //. But first we need the inclusion map of M into $A^1$: Later we explain this, but for now, we just write down this map:

i54 : inducedMap(A^1,M)

o54 = | x y |

o54 : Matrix

Now we use // to lift $F : M \to A$ along $M \to A^1$, to get $M \to M$:

i55 : G = F // inducedMap(A^1,M)

o55 = {1} | 0 x |
      {1} | 1 0 |

o55 : Matrix
i56 : source G

o56 = image | x y |

                              1
o56 : A-module, submodule of A
i57 : target G

o57 = image | x y |

                              1
o57 : A-module, submodule of A

G is now a map from $M \to M$.

i58 : isWellDefined G

o58 = true

F. Canonical maps associated with modules

Let's start with a module M, and a submodule N.

i59 : R = QQ[x,y,z,w]

o59 = R

o59 : PolynomialRing
i60 : M = ideal(x,y,z)/ideal(x^2,y^2,z*w)

o60 = subquotient (| x y z |, | x2 y2 zw |)

                                1
o60 : R-module, subquotient of R
i61 : N = z*M

o61 = subquotient (| xz yz z2 |, | x2 y2 zw |)

                                1
o61 : R-module, subquotient of R
i62 : M/N

o62 = subquotient (| x y z |, | xz yz z2 x2 y2 zw |)

                                1
o62 : R-module, subquotient of R

If two modules have the same ambient free module, then there is often a canonical map between them. Some modules having the same ambient free module:

i63 : M

o63 = subquotient (| x y z |, | x2 y2 zw |)

                                1
o63 : R-module, subquotient of R
i64 : ambient M

       1
o64 = R

o64 : R-module, free
i65 : N = z*M

o65 = subquotient (| xz yz z2 |, | x2 y2 zw |)

                                1
o65 : R-module, subquotient of R
i66 : ambient(M/N)

       1
o66 = R

o66 : R-module, free
i67 : super M

o67 = cokernel | x2 y2 zw |

                             1
o67 : R-module, quotient of R
i68 : super N

o68 = cokernel | x2 y2 zw |

                             1
o68 : R-module, quotient of R
i69 : image generators M

o69 = image | x y z |

                              1
o69 : R-module, submodule of R

If two modules M and N have the same ambient module $R^n$, then inducedMap(M,N) makes the canonical map $N \to M$ between them, if one exists. If a map doesn't exist, the returned map might not be a homomorphism.

i70 : inducedMap(M,M) == id_M

o70 = true
i71 : inducedMap(super M,M) == map(super id_M) -- the map $(P+Q)/Q \to R^n/Q$, where $M=(P+Q)/Q$.

o71 = true
i72 : inducedMap(super M,ambient M) -- the quotient map $R^n \to R^n/Q$

o72 = | 1 |

o72 : Matrix
i73 : inducedMap(M,N) -- the inclusion map

o73 = {1} | z 0 0 |
      {1} | 0 z 0 |
      {1} | 0 0 z |

o73 : Matrix

The projection map $M \to M/N$

i74 : inducedMap(M/N,M) -- the projection map

o74 = {1} | 1 0 0 |
      {1} | 0 1 0 |
      {1} | 0 0 1 |

o74 : Matrix

The projection map $N \to M/N$, which is the zero map

i75 : inducedMap(M/N,N) -- the zero map

o75 = 0

o75 : Matrix

Not all such maps can be defined. The functions 'inducedMap' normally checks that the result is a well-defined homomorphism. The option 'Verify' controls that behavior.

i76 : inducedMap(M,M/N,Verify => false)

o76 = {1} | 1 0 0 |
      {1} | 0 1 0 |
      {1} | 0 0 1 |

o76 : Matrix
i77 : inducedMap(M/N,x*M)

o77 = {1} | 0 y 0 |
      {1} | 0 0 0 |
      {1} | 0 0 0 |

o77 : Matrix
i78 : inducedMap(M/N,M) * inducedMap(M,x*M) == inducedMap(M/N,x*M)

o78 = true

Before doing interesting homomorphisms, let's see how to write down some canonical homomorphisms associated to M. exercises: 1. isomorphism theorems. Given submodules M and N of a module P, (a) find $(M+N)/M$ (b) find $N/(M \cap N)$ (c) find in Macaulay2, an isomorphism between them.

2. Given a homomorphism $M \to A$. Suppose that the image lies in M (M is a submodule of $A^1$). Find the map $M \to M$.

G. Homomorphisms and Hom

i79 : A = QQ[x,y,Degrees=>{2,3}]/(y^2-x^3)

o79 = A

o79 : QuotientRing
i80 : M = module ideal(x,y)

o80 = image | x y |

                              1
o80 : A-module, submodule of A
i81 : H = Hom(M,M)
-- ker (3) called with OptionTable: OptionTable{SubringLimit => infinity}
-- ker (3) returned CacheFunction: -*a cache function*-
-- ker (3) called with Matrix: {-3} | 0 0  -x 0  |
--                             {-2} | x y  0  -x |
--                             {-4} | 0 0  0  0  |
--                             {-3} | y x2 -x -y |
-- ker (3) returned Module: image {-2} | x y  x2 0 |
--                                {-3} | y x2 xy 0 |
assert( ker(map(image(map(A^{{5}, {6}},A^{{3}, {2}, {4}, {3}},{{x,y,0,0}, {0,0,x,y}})),image(map(A^{{2}, {3}},A^{{0}, {-1}, {1}, {0}},{{x,y,0,0}, {0,0,x,y}})),{{0,0,-x,0}, {x,y,0,-x}, {0,0,0,0}, {y,x^2,-x,-y}})) === (image(map(A^{{2}, {3}},A^{{0}, {-1}, {-2}, {-3}},{{x,y,x^2,0}, {y,x^2,x*y,0}}))))

o81 = image {-2} | x y  |
            {-3} | y x2 |

                              2
o81 : A-module, submodule of A

The elements of H correspond to homomorphisms $M \to A$. The homomorphism associated to elements of H may be obtained using the routine homomorphism.

i82 : F = homomorphism(H_{0})

o82 = {2} | 1 0 |
      {3} | 0 1 |

o82 : Matrix
i83 : G = homomorphism(H_{1})

o83 = {2} | 0 x |
      {3} | 1 0 |

o83 : Matrix
i84 : source F == M

o84 = true
i85 : target F == M

o85 = true
i86 : ker F
-- ker (4) called with OptionTable: OptionTable{SubringLimit => infinity}
-- ker (4) returned CacheFunction: -*a cache function*-
-- ker (4) called with Matrix: {2} | 1 0 |
--                             {3} | 0 1 |
-- ker (4) returned Module: image 0
assert( ker(map(image(map(A^1,A^{{-2}, {-3}},{{x,y}})),image(map(A^1,A^{{-2}, {-3}},{{x,y}})),{{1,0}, {0,1}})) === (image(map(A^1,A^{{-5}, {-6}},0))))

o86 = image 0

                              1
o86 : A-module, submodule of A
i87 : coker F

o87 = subquotient (| x y |, | x y |)

                                1
o87 : A-module, subquotient of A
i88 : m = matrix{{x,y},{y,x}}

o88 = | x y |
      | y x |

              2       2
o88 : Matrix A  <--- A
i89 : Hom(m,A^2)
-- ker (5) called with OptionTable: OptionTable{SubringLimit => infinity}
-- ker (5) returned CacheFunction: -*a cache function*-
-- ker (5) called with Matrix: 0
--                           4
-- ker (5) returned Module: A
assert( ker(map(A^0,A^{{3}, {3}, {3}, {3}},0)) === (A^{{3}, {3}, {3}, {3}}))
-- ker (6) called with OptionTable: OptionTable{SubringLimit => infinity}
-- ker (6) returned CacheFunction: -*a cache function*-
-- ker (6) called with Matrix: 0
--                           4
-- ker (6) returned Module: A
assert( ker(map(A^0,A^4,0)) === (A^4))

o89 = {-3} | x 0 y 0 |
      {-3} | 0 x 0 y |
      {-3} | y 0 x 0 |
      {-3} | 0 y 0 x |

              4       4
o89 : Matrix A  <--- A
i90 : Hom(A^2,m)
-- ker (7) called with OptionTable: OptionTable{SubringLimit => infinity}
-- ker (7) returned CacheFunction: -*a cache function*-
-- ker (7) called with Matrix: 0
--                           4
-- ker (7) returned Module: A
assert( ker(map(A^0,A^4,0)) === (A^4))
-- ker (8) called with OptionTable: OptionTable{SubringLimit => infinity}
-- ker (8) returned CacheFunction: -*a cache function*-
-- ker (8) called with Matrix: 0
--                           4
-- ker (8) returned Module: A
assert( ker(map(A^0,A^{{-3}, {-3}, {-3}, {-3}},0)) === (A^{{-3}, {-3}, {-3}, {-3}}))

o90 = | x y 0 0 |
      | y x 0 0 |
      | 0 0 x y |
      | 0 0 y x |

              4       4
o90 : Matrix A  <--- A

H. Tensor products

In Macaulay2, ** denotes the tensor product operator.

i91 : m ** m

o91 = | x2 xy xy y2 |
      | xy x2 y2 xy |
      | xy y2 x2 xy |
      | y2 xy xy x2 |

              4       4
o91 : Matrix A  <--- A
i92 : (coker m) ** (coker m)

o92 = cokernel | x y 0 0 x y 0 0 |
               | y x 0 0 0 0 x y |
               | 0 0 x y y x 0 0 |
               | 0 0 y x 0 0 y x |

                             4
o92 : A-module, quotient of A

Notice that tensor products of matrices and of modules are very different.

i93 : M = coker m

o93 = cokernel | x y |
               | y x |

                             2
o93 : A-module, quotient of A
i94 : M2 = prune(M ** M)

o94 = cokernel | 0  -x y x x 0 |
               | -x 0  x y 0 x |
               | x  0  0 0 y 0 |
               | 0  x  0 0 0 y |

                             4
o94 : A-module, quotient of A
i95 : A = QQ[a,b,c]

o95 = A

o95 : PolynomialRing
i96 : A ** A

o96 = QQ[2:a..c]

o96 : PolynomialRing

Oops! Macaulay2 doesn't know what a should be!

i97 : B = oo

o97 = B

o97 : PolynomialRing
i98 : a == B_3

o98 = true
i99 : a == B_0

o99 = false

To remedy this, one can give the variables as an option to tensor.

i100 : tensor(A,A,Variables=>{a,b,c,d,e,f})

o100 = QQ[a..f]

o100 : PolynomialRing