Morphisms of free modules#

AUTHORS:
  • William Stein: initial version

  • Miguel Marco (2010-06-19): added eigenvalues, eigenvectors and minpoly functions

class sage.modules.free_module_morphism.BaseIsomorphism1D[source]#

Bases: Morphism

An isomorphism between a ring and a free rank-1 module over the ring.

EXAMPLES:

sage: R.<x,y> = QQ[]
sage: V, from_V, to_V = R.free_module(R)
sage: from_V
Isomorphism morphism:
  From: Ambient free module of rank 1 over the integral domain
        Multivariate Polynomial Ring in x, y over Rational Field
  To:   Multivariate Polynomial Ring in x, y over Rational Field
>>> from sage.all import *
>>> R = QQ['x, y']; (x, y,) = R._first_ngens(2)
>>> V, from_V, to_V = R.free_module(R)
>>> from_V
Isomorphism morphism:
  From: Ambient free module of rank 1 over the integral domain
        Multivariate Polynomial Ring in x, y over Rational Field
  To:   Multivariate Polynomial Ring in x, y over Rational Field
is_injective()[source]#

EXAMPLES:

sage: R.<x,y> = QQ[]
sage: V, from_V, to_V = R.free_module(R)
sage: from_V.is_injective()
True
>>> from sage.all import *
>>> R = QQ['x, y']; (x, y,) = R._first_ngens(2)
>>> V, from_V, to_V = R.free_module(R)
>>> from_V.is_injective()
True
is_surjective()[source]#

EXAMPLES:

sage: R.<x,y> = QQ[]
sage: V, from_V, to_V = R.free_module(R)
sage: from_V.is_surjective()
True
>>> from sage.all import *
>>> R = QQ['x, y']; (x, y,) = R._first_ngens(2)
>>> V, from_V, to_V = R.free_module(R)
>>> from_V.is_surjective()
True
class sage.modules.free_module_morphism.BaseIsomorphism1D_from_FM(parent, basis=None)[source]#

Bases: BaseIsomorphism1D

An isomorphism to a ring from its 1-dimensional free module

INPUT:

  • parent – the homset

  • basis – (default 1) an invertible element of the ring

EXAMPLES:

sage: R.<x> = QQ[[]]
sage: V, from_V, to_V = R.free_module(R)
sage: v = to_V(1+x); v
(1 + x)
sage: from_V(v)
1 + x
sage: W, from_W, to_W = R.free_module(R, basis=(1-x))
sage: W is V
True
sage: w = to_W(1+x); w
(1 - x^2)
sage: from_W(w)
1 + x + O(x^20)
>>> from sage.all import *
>>> R = QQ[['x']]; (x,) = R._first_ngens(1)
>>> V, from_V, to_V = R.free_module(R)
>>> v = to_V(Integer(1)+x); v
(1 + x)
>>> from_V(v)
1 + x
>>> W, from_W, to_W = R.free_module(R, basis=(Integer(1)-x))
>>> W is V
True
>>> w = to_W(Integer(1)+x); w
(1 - x^2)
>>> from_W(w)
1 + x + O(x^20)

The basis vector has to be a unit so that the map is an isomorphism:

sage: W, from_W, to_W = R.free_module(R, basis=x)
Traceback (most recent call last):
...
ValueError: basis element must be a unit
>>> from sage.all import *
>>> W, from_W, to_W = R.free_module(R, basis=x)
Traceback (most recent call last):
...
ValueError: basis element must be a unit
class sage.modules.free_module_morphism.BaseIsomorphism1D_to_FM(parent, basis=None)[source]#

Bases: BaseIsomorphism1D

An isomorphism from a ring to its 1-dimensional free module

INPUT:

  • parent – the homset

  • basis – (default 1) an invertible element of the ring

EXAMPLES:

sage: R = Zmod(8)
sage: V, from_V, to_V = R.free_module(R)
sage: v = to_V(2); v
(2)
sage: from_V(v)
2
sage: W, from_W, to_W = R.free_module(R, basis=3)
sage: W is V
True
sage: w = to_W(2); w
(6)
sage: from_W(w)
2
>>> from sage.all import *
>>> R = Zmod(Integer(8))
>>> V, from_V, to_V = R.free_module(R)
>>> v = to_V(Integer(2)); v
(2)
>>> from_V(v)
2
>>> W, from_W, to_W = R.free_module(R, basis=Integer(3))
>>> W is V
True
>>> w = to_W(Integer(2)); w
(6)
>>> from_W(w)
2

The basis vector has to be a unit so that the map is an isomorphism:

sage: W, from_W, to_W = R.free_module(R, basis=4)
Traceback (most recent call last):
...
ValueError: basis element must be a unit
>>> from sage.all import *
>>> W, from_W, to_W = R.free_module(R, basis=Integer(4))
Traceback (most recent call last):
...
ValueError: basis element must be a unit
class sage.modules.free_module_morphism.FreeModuleMorphism(parent, A, side='left')[source]#

Bases: MatrixMorphism

INPUT:

  • parent – a homspace in a (sub) category of free modules

  • A – matrix

  • side – side of the vectors acted on by the matrix (default: "left")

EXAMPLES:

sage: V = ZZ^3; W = span([[1,2,3], [-1,2,8]], ZZ)
sage: phi = V.hom(matrix(ZZ, 3, [1..9]))
sage: type(phi)
<class 'sage.modules.free_module_morphism.FreeModuleMorphism'>
>>> from sage.all import *
>>> V = ZZ**Integer(3); W = span([[Integer(1),Integer(2),Integer(3)], [-Integer(1),Integer(2),Integer(8)]], ZZ)
>>> phi = V.hom(matrix(ZZ, Integer(3), (ellipsis_range(Integer(1),Ellipsis,Integer(9)))))
>>> type(phi)
<class 'sage.modules.free_module_morphism.FreeModuleMorphism'>
change_ring(R)[source]#

Change the ring over which this morphism is defined.

This changes the ring of the domain, codomain, and underlying matrix.

EXAMPLES:

sage: V0 = span([[0,0,1],[0,2,0]], ZZ); V1 = span([[1/2,0],[0,2]], ZZ)
sage: W = span([[1,0],[0,6]], ZZ)
sage: h = V0.hom([-3*V1.0 - 3*V1.1, -3*V1.0 - 3*V1.1])
sage: h.base_ring()
Integer Ring
sage: h
Free module morphism defined by the matrix
[-3 -3]
[-3 -3]...
sage: h.change_ring(QQ).base_ring()
Rational Field
sage: f = h.change_ring(QQ); f
Vector space morphism represented by the matrix:
[-3 -3]
[-3 -3]
Domain:   Vector space of degree 3 and dimension 2 over Rational Field
          Basis matrix:
          [0 1 0]
          [0 0 1]
Codomain: Vector space of degree 2 and dimension 2 over Rational Field
          Basis matrix:
          [1 0]
          [0 1]
sage: f = h.change_ring(GF(7)); f
Vector space morphism represented by the matrix:
[4 4]
[4 4]
Domain:   Vector space of degree 3 and dimension 2 over Finite Field of size 7
          Basis matrix:
          [0 1 0]
          [0 0 1]
Codomain: Vector space of degree 2 and dimension 2 over Finite Field of size 7
          Basis matrix:
          [1 0]
          [0 1]
>>> from sage.all import *
>>> V0 = span([[Integer(0),Integer(0),Integer(1)],[Integer(0),Integer(2),Integer(0)]], ZZ); V1 = span([[Integer(1)/Integer(2),Integer(0)],[Integer(0),Integer(2)]], ZZ)
>>> W = span([[Integer(1),Integer(0)],[Integer(0),Integer(6)]], ZZ)
>>> h = V0.hom([-Integer(3)*V1.gen(0) - Integer(3)*V1.gen(1), -Integer(3)*V1.gen(0) - Integer(3)*V1.gen(1)])
>>> h.base_ring()
Integer Ring
>>> h
Free module morphism defined by the matrix
[-3 -3]
[-3 -3]...
>>> h.change_ring(QQ).base_ring()
Rational Field
>>> f = h.change_ring(QQ); f
Vector space morphism represented by the matrix:
[-3 -3]
[-3 -3]
Domain:   Vector space of degree 3 and dimension 2 over Rational Field
          Basis matrix:
          [0 1 0]
          [0 0 1]
Codomain: Vector space of degree 2 and dimension 2 over Rational Field
          Basis matrix:
          [1 0]
          [0 1]
>>> f = h.change_ring(GF(Integer(7))); f
Vector space morphism represented by the matrix:
[4 4]
[4 4]
Domain:   Vector space of degree 3 and dimension 2 over Finite Field of size 7
          Basis matrix:
          [0 1 0]
          [0 0 1]
Codomain: Vector space of degree 2 and dimension 2 over Finite Field of size 7
          Basis matrix:
          [1 0]
          [0 1]
eigenspaces(extend=True)[source]#

Compute a list of subspaces formed by eigenvectors of self.

INPUT:

  • extend – (default: True) determines if field extensions should be considered

OUTPUT:

  • a list of pairs (eigenvalue, eigenspace)

EXAMPLES:

sage: V = QQ^3
sage: h = V.hom([[1,0,0], [0,0,1], [0,-1,0]], V)
sage: h.eigenspaces()                                                       # needs sage.rings.number_field
[(1,    Vector space of degree 3 and dimension 1 over Rational Field
         Basis matrix:
         [1 0 0]),
 (-1*I, Vector space of degree 3 and dimension 1 over Algebraic Field
         Basis matrix:
         [  0   1 1*I]),
 (1*I,  Vector space of degree 3 and dimension 1 over Algebraic Field
         Basis matrix:
         [   0    1 -1*I])]

sage: h.eigenspaces(extend=False)                                           # needs sage.rings.number_field
[(1,
  Vector space of degree 3 and dimension 1 over Rational Field
  Basis matrix:
  [1 0 0])]

sage: h = V.hom([[2,1,0], [0,2,0], [0,0,-1]], V)
sage: h.eigenspaces()                                                       # needs sage.rings.number_field
[(-1, Vector space of degree 3 and dimension 1 over Rational Field
       Basis matrix:
       [0 0 1]),
 (2, Vector space of degree 3 and dimension 1 over Rational Field
      Basis matrix:
      [0 1 0])]

sage: h = V.hom([[2,1,0], [0,2,0], [0,0,2]], V)
sage: h.eigenspaces()                                                       # needs sage.rings.number_field
[(2, Vector space of degree 3 and dimension 2 over Rational Field
      Basis matrix:
      [0 1 0]
      [0 0 1])]
>>> from sage.all import *
>>> V = QQ**Integer(3)
>>> h = V.hom([[Integer(1),Integer(0),Integer(0)], [Integer(0),Integer(0),Integer(1)], [Integer(0),-Integer(1),Integer(0)]], V)
>>> h.eigenspaces()                                                       # needs sage.rings.number_field
[(1,    Vector space of degree 3 and dimension 1 over Rational Field
         Basis matrix:
         [1 0 0]),
 (-1*I, Vector space of degree 3 and dimension 1 over Algebraic Field
         Basis matrix:
         [  0   1 1*I]),
 (1*I,  Vector space of degree 3 and dimension 1 over Algebraic Field
         Basis matrix:
         [   0    1 -1*I])]

>>> h.eigenspaces(extend=False)                                           # needs sage.rings.number_field
[(1,
  Vector space of degree 3 and dimension 1 over Rational Field
  Basis matrix:
  [1 0 0])]

>>> h = V.hom([[Integer(2),Integer(1),Integer(0)], [Integer(0),Integer(2),Integer(0)], [Integer(0),Integer(0),-Integer(1)]], V)
>>> h.eigenspaces()                                                       # needs sage.rings.number_field
[(-1, Vector space of degree 3 and dimension 1 over Rational Field
       Basis matrix:
       [0 0 1]),
 (2, Vector space of degree 3 and dimension 1 over Rational Field
      Basis matrix:
      [0 1 0])]

>>> h = V.hom([[Integer(2),Integer(1),Integer(0)], [Integer(0),Integer(2),Integer(0)], [Integer(0),Integer(0),Integer(2)]], V)
>>> h.eigenspaces()                                                       # needs sage.rings.number_field
[(2, Vector space of degree 3 and dimension 2 over Rational Field
      Basis matrix:
      [0 1 0]
      [0 0 1])]
sage: V = QQ^2; m = matrix(2, [1, 1, 0, 1])
sage: V.hom(m, side="right").eigenspaces()                                  # needs sage.rings.number_field
[(1, Vector space of degree 2 and dimension 1 over Rational Field
      Basis matrix:
      [1 0])]
sage: V.hom(m).eigenspaces()                                                # needs sage.rings.number_field
[(1, Vector space of degree 2 and dimension 1 over Rational Field
      Basis matrix:
      [0 1])]
>>> from sage.all import *
>>> V = QQ**Integer(2); m = matrix(Integer(2), [Integer(1), Integer(1), Integer(0), Integer(1)])
>>> V.hom(m, side="right").eigenspaces()                                  # needs sage.rings.number_field
[(1, Vector space of degree 2 and dimension 1 over Rational Field
      Basis matrix:
      [1 0])]
>>> V.hom(m).eigenspaces()                                                # needs sage.rings.number_field
[(1, Vector space of degree 2 and dimension 1 over Rational Field
      Basis matrix:
      [0 1])]
eigenvalues(extend=True)[source]#

Returns a list with the eigenvalues of the endomorphism of vector spaces.

INPUT:

  • extend – boolean (default: True) decides if base field extensions should be considered or not.

EXAMPLES:

We compute the eigenvalues of an endomorphism of \(\QQ^3\):

sage: V = QQ^3
sage: H = V.endomorphism_ring()([[1,-1,0], [-1,1,1], [0,3,1]])
sage: H.eigenvalues()                                                       # needs sage.rings.number_field
[3, 1, -1]
>>> from sage.all import *
>>> V = QQ**Integer(3)
>>> H = V.endomorphism_ring()([[Integer(1),-Integer(1),Integer(0)], [-Integer(1),Integer(1),Integer(1)], [Integer(0),Integer(3),Integer(1)]])
>>> H.eigenvalues()                                                       # needs sage.rings.number_field
[3, 1, -1]

Note the effect of the extend option:

sage: V = QQ^2
sage: H = V.endomorphism_ring()([[0,-1], [1,0]])
sage: H.eigenvalues()                                                       # needs sage.rings.number_field
[-1*I, 1*I]
sage: H.eigenvalues(extend=False)                                           # needs sage.libs.pari
[]
>>> from sage.all import *
>>> V = QQ**Integer(2)
>>> H = V.endomorphism_ring()([[Integer(0),-Integer(1)], [Integer(1),Integer(0)]])
>>> H.eigenvalues()                                                       # needs sage.rings.number_field
[-1*I, 1*I]
>>> H.eigenvalues(extend=False)                                           # needs sage.libs.pari
[]
eigenvectors(extend=True)[source]#

Computes the subspace of eigenvectors of a given eigenvalue.

INPUT:

  • extend – boolean (default: True) decides if base field extensions should be considered or not.

OUTPUT:

A sequence of tuples. Each tuple contains an eigenvalue, a sequence with a basis of the corresponding subspace of eigenvectors, and the algebraic multiplicity of the eigenvalue.

EXAMPLES:

sage: # needs sage.rings.number_field
sage: V = (QQ^4).subspace([[0,2,1,4], [1,2,5,0], [1,1,1,1]])
sage: H = (V.Hom(V))(matrix(QQ, [[0,1,0], [-1,0,0], [0,0,3]]))
sage: H.eigenvectors()
[(3,    [ (0, 0, 1, -6/7) ], 1),
 (-1*I, [ (1,  1*I, 0, -0.571428571428572? + 2.428571428571429?*I) ], 1),
 (1*I,  [ (1, -1*I, 0, -0.571428571428572? - 2.428571428571429?*I) ], 1)]
sage: H.eigenvectors(extend=False)
[(3, [ (0, 0, 1, -6/7) ], 1)]
sage: H1 = (V.Hom(V))(matrix(QQ, [[2,1,0],[0,2,0],[0,0,3]]))
sage: H1.eigenvectors()
[(3, [ (0, 0, 1, -6/7) ], 1),
 (2, [ (0, 1, 0, 17/7) ], 2)]
sage: H1.eigenvectors(extend=False)
[(3, [ (0, 0, 1, -6/7) ], 1),
 (2, [ (0, 1, 0, 17/7) ], 2)]
>>> from sage.all import *
>>> # needs sage.rings.number_field
>>> V = (QQ**Integer(4)).subspace([[Integer(0),Integer(2),Integer(1),Integer(4)], [Integer(1),Integer(2),Integer(5),Integer(0)], [Integer(1),Integer(1),Integer(1),Integer(1)]])
>>> H = (V.Hom(V))(matrix(QQ, [[Integer(0),Integer(1),Integer(0)], [-Integer(1),Integer(0),Integer(0)], [Integer(0),Integer(0),Integer(3)]]))
>>> H.eigenvectors()
[(3,    [ (0, 0, 1, -6/7) ], 1),
 (-1*I, [ (1,  1*I, 0, -0.571428571428572? + 2.428571428571429?*I) ], 1),
 (1*I,  [ (1, -1*I, 0, -0.571428571428572? - 2.428571428571429?*I) ], 1)]
>>> H.eigenvectors(extend=False)
[(3, [ (0, 0, 1, -6/7) ], 1)]
>>> H1 = (V.Hom(V))(matrix(QQ, [[Integer(2),Integer(1),Integer(0)],[Integer(0),Integer(2),Integer(0)],[Integer(0),Integer(0),Integer(3)]]))
>>> H1.eigenvectors()
[(3, [ (0, 0, 1, -6/7) ], 1),
 (2, [ (0, 1, 0, 17/7) ], 2)]
>>> H1.eigenvectors(extend=False)
[(3, [ (0, 0, 1, -6/7) ], 1),
 (2, [ (0, 1, 0, 17/7) ], 2)]
sage: V = QQ^2
sage: m = matrix(2, [1, 1, 0, 1])
sage: V.hom(m, side="right").eigenvectors()                                 # needs sage.rings.number_field
[(1, [ (1, 0) ], 2)]
sage: V.hom(m).eigenvectors()                                               # needs sage.rings.number_field
[(1, [ (0, 1) ], 2)]
>>> from sage.all import *
>>> V = QQ**Integer(2)
>>> m = matrix(Integer(2), [Integer(1), Integer(1), Integer(0), Integer(1)])
>>> V.hom(m, side="right").eigenvectors()                                 # needs sage.rings.number_field
[(1, [ (1, 0) ], 2)]
>>> V.hom(m).eigenvectors()                                               # needs sage.rings.number_field
[(1, [ (0, 1) ], 2)]
inverse_image(V)[source]#

Given a submodule V of the codomain of self, return the inverse image of V under self, i.e., the biggest submodule of the domain of self that maps into V.

EXAMPLES:

We test computing inverse images over a field:

sage: V = QQ^3; W = span([[1,2,3], [-1,2,5/3]], QQ)
sage: phi = V.hom(matrix(QQ, 3, [1..9]))
sage: phi.rank()
2
sage: I = phi.inverse_image(W); I
Vector space of degree 3 and dimension 2 over Rational Field
Basis matrix:
[   1    0    0]
[   0    1 -1/2]
sage: phi(I.0) in W
True
sage: phi(I.1) in W
True
sage: W = phi.image()
sage: phi.inverse_image(W) == V
True
>>> from sage.all import *
>>> V = QQ**Integer(3); W = span([[Integer(1),Integer(2),Integer(3)], [-Integer(1),Integer(2),Integer(5)/Integer(3)]], QQ)
>>> phi = V.hom(matrix(QQ, Integer(3), (ellipsis_range(Integer(1),Ellipsis,Integer(9)))))
>>> phi.rank()
2
>>> I = phi.inverse_image(W); I
Vector space of degree 3 and dimension 2 over Rational Field
Basis matrix:
[   1    0    0]
[   0    1 -1/2]
>>> phi(I.gen(0)) in W
True
>>> phi(I.gen(1)) in W
True
>>> W = phi.image()
>>> phi.inverse_image(W) == V
True

We test computing inverse images between two spaces embedded in different ambient spaces.:

sage: V0 = span([[0,0,1],[0,2,0]],ZZ); V1 = span([[1/2,0],[0,2]],ZZ)
sage: W = span([[1,0],[0,6]],ZZ)
sage: h = V0.hom([-3*V1.0 - 3*V1.1, -3*V1.0 - 3*V1.1])
sage: h.inverse_image(W)
Free module of degree 3 and rank 2 over Integer Ring
Echelon basis matrix:
[0 2 1]
[0 0 2]
sage: h(h.inverse_image(W)).is_submodule(W)
True
sage: h(h.inverse_image(W)).index_in(W)
+Infinity
sage: h(h.inverse_image(W))
Free module of degree 2 and rank 1 over Integer Ring
Echelon basis matrix:
[ 3 12]
>>> from sage.all import *
>>> V0 = span([[Integer(0),Integer(0),Integer(1)],[Integer(0),Integer(2),Integer(0)]],ZZ); V1 = span([[Integer(1)/Integer(2),Integer(0)],[Integer(0),Integer(2)]],ZZ)
>>> W = span([[Integer(1),Integer(0)],[Integer(0),Integer(6)]],ZZ)
>>> h = V0.hom([-Integer(3)*V1.gen(0) - Integer(3)*V1.gen(1), -Integer(3)*V1.gen(0) - Integer(3)*V1.gen(1)])
>>> h.inverse_image(W)
Free module of degree 3 and rank 2 over Integer Ring
Echelon basis matrix:
[0 2 1]
[0 0 2]
>>> h(h.inverse_image(W)).is_submodule(W)
True
>>> h(h.inverse_image(W)).index_in(W)
+Infinity
>>> h(h.inverse_image(W))
Free module of degree 2 and rank 1 over Integer Ring
Echelon basis matrix:
[ 3 12]

We test computing inverse images over the integers:

sage: V = QQ^3; W = V.span_of_basis([[2,2,3],[-1,2,5/3]], ZZ)
sage: phi = W.hom([W.0, W.0 - W.1])
sage: Z = W.span([2*W.1]); Z
Free module of degree 3 and rank 1 over Integer Ring
Echelon basis matrix:
[    2    -4 -10/3]
sage: Y = phi.inverse_image(Z); Y
Free module of degree 3 and rank 1 over Integer Ring
Echelon basis matrix:
[  6   0 8/3]
sage: phi(Y) == Z
True
>>> from sage.all import *
>>> V = QQ**Integer(3); W = V.span_of_basis([[Integer(2),Integer(2),Integer(3)],[-Integer(1),Integer(2),Integer(5)/Integer(3)]], ZZ)
>>> phi = W.hom([W.gen(0), W.gen(0) - W.gen(1)])
>>> Z = W.span([Integer(2)*W.gen(1)]); Z
Free module of degree 3 and rank 1 over Integer Ring
Echelon basis matrix:
[    2    -4 -10/3]
>>> Y = phi.inverse_image(Z); Y
Free module of degree 3 and rank 1 over Integer Ring
Echelon basis matrix:
[  6   0 8/3]
>>> phi(Y) == Z
True

We test that Issue #24590 is resolved:

sage: A = FreeQuadraticModule(ZZ, 1, matrix([2]))
sage: f = A.Hom(A).an_element()
sage: f.inverse_image(A)
Free module of degree 1 and rank 1 over Integer Ring
Echelon basis matrix:
[1]
>>> from sage.all import *
>>> A = FreeQuadraticModule(ZZ, Integer(1), matrix([Integer(2)]))
>>> f = A.Hom(A).an_element()
>>> f.inverse_image(A)
Free module of degree 1 and rank 1 over Integer Ring
Echelon basis matrix:
[1]

We test that it respects the side:

sage: V = ZZ^2
sage: m = matrix(2, [1, 1, 0, 1])
sage: h = V.hom(m, side="right")
sage: h
Free module morphism defined as left-multiplication by the matrix
[1 1]
[0 1]...
sage: SV = V.span([V.0])
sage: h.inverse_image(SV)
Free module of degree 2 and rank 1 over Integer Ring
Echelon basis matrix:
[1 0]
sage: V.hom(m).inverse_image(SV)
Free module of degree 2 and rank 1 over Integer Ring
Echelon basis matrix:
[ 1 -1]
>>> from sage.all import *
>>> V = ZZ**Integer(2)
>>> m = matrix(Integer(2), [Integer(1), Integer(1), Integer(0), Integer(1)])
>>> h = V.hom(m, side="right")
>>> h
Free module morphism defined as left-multiplication by the matrix
[1 1]
[0 1]...
>>> SV = V.span([V.gen(0)])
>>> h.inverse_image(SV)
Free module of degree 2 and rank 1 over Integer Ring
Echelon basis matrix:
[1 0]
>>> V.hom(m).inverse_image(SV)
Free module of degree 2 and rank 1 over Integer Ring
Echelon basis matrix:
[ 1 -1]
lift(x)[source]#

Given an element of the image, return an element of the codomain that maps onto it.

Note that lift and preimage_representative are equivalent names for this method, with the latter suggesting that the return value is a coset representative of the domain modulo the kernel of the morphism.

EXAMPLES:

sage: X = QQ**2
sage: V = X.span([[2, 0], [0, 8]], ZZ)
sage: W = (QQ**1).span([[1/12]], ZZ)
sage: f = V.hom([W([1/3]), W([1/2])], W)
sage: l=f.lift([1/3]); l  # random
(8, -16)
sage: f(l)
(1/3)
sage: f(f.lift([1/2]))
(1/2)
sage: f(f.lift([1/6]))
(1/6)
sage: f.lift([1/12])
Traceback (most recent call last):
...
ValueError: element is not in the image
sage: f.lift([1/24])
Traceback (most recent call last):
...
TypeError: element [1/24] is not in free module
>>> from sage.all import *
>>> X = QQ**Integer(2)
>>> V = X.span([[Integer(2), Integer(0)], [Integer(0), Integer(8)]], ZZ)
>>> W = (QQ**Integer(1)).span([[Integer(1)/Integer(12)]], ZZ)
>>> f = V.hom([W([Integer(1)/Integer(3)]), W([Integer(1)/Integer(2)])], W)
>>> l=f.lift([Integer(1)/Integer(3)]); l  # random
(8, -16)
>>> f(l)
(1/3)
>>> f(f.lift([Integer(1)/Integer(2)]))
(1/2)
>>> f(f.lift([Integer(1)/Integer(6)]))
(1/6)
>>> f.lift([Integer(1)/Integer(12)])
Traceback (most recent call last):
...
ValueError: element is not in the image
>>> f.lift([Integer(1)/Integer(24)])
Traceback (most recent call last):
...
TypeError: element [1/24] is not in free module

This works for vector spaces, too:

sage: V = VectorSpace(GF(3), 2)
sage: W = VectorSpace(GF(3), 3)
sage: f = V.hom([W.1, W.1 - W.0])
sage: f.lift(W.1)
(1, 0)
sage: f.lift(W.2)
Traceback (most recent call last):
...
ValueError: element is not in the image
sage: w = W((17, -2, 0))
sage: f(f.lift(w)) == w
True
>>> from sage.all import *
>>> V = VectorSpace(GF(Integer(3)), Integer(2))
>>> W = VectorSpace(GF(Integer(3)), Integer(3))
>>> f = V.hom([W.gen(1), W.gen(1) - W.gen(0)])
>>> f.lift(W.gen(1))
(1, 0)
>>> f.lift(W.gen(2))
Traceback (most recent call last):
...
ValueError: element is not in the image
>>> w = W((Integer(17), -Integer(2), Integer(0)))
>>> f(f.lift(w)) == w
True

This example illustrates the use of the preimage_representative as an equivalent name for this method.

sage: V = ZZ^3
sage: W = ZZ^2
sage: w = vector(ZZ, [1,2])
sage: f = V.hom([w, w, w], W)
sage: f.preimage_representative(vector(ZZ, [10, 20]))
(0, 0, 10)
>>> from sage.all import *
>>> V = ZZ**Integer(3)
>>> W = ZZ**Integer(2)
>>> w = vector(ZZ, [Integer(1),Integer(2)])
>>> f = V.hom([w, w, w], W)
>>> f.preimage_representative(vector(ZZ, [Integer(10), Integer(20)]))
(0, 0, 10)
sage: V = QQ^2; m = matrix(2, [1, 1, 0, 1])
sage: V.hom(m, side="right").lift(V.0 + V.1)
(0, 1)
sage: V.hom(m).lift(V.0 + V.1)
(1, 0)
>>> from sage.all import *
>>> V = QQ**Integer(2); m = matrix(Integer(2), [Integer(1), Integer(1), Integer(0), Integer(1)])
>>> V.hom(m, side="right").lift(V.gen(0) + V.gen(1))
(0, 1)
>>> V.hom(m).lift(V.gen(0) + V.gen(1))
(1, 0)
preimage_representative(x)[source]#

Given an element of the image, return an element of the codomain that maps onto it.

Note that lift and preimage_representative are equivalent names for this method, with the latter suggesting that the return value is a coset representative of the domain modulo the kernel of the morphism.

EXAMPLES:

sage: X = QQ**2
sage: V = X.span([[2, 0], [0, 8]], ZZ)
sage: W = (QQ**1).span([[1/12]], ZZ)
sage: f = V.hom([W([1/3]), W([1/2])], W)
sage: l=f.lift([1/3]); l  # random
(8, -16)
sage: f(l)
(1/3)
sage: f(f.lift([1/2]))
(1/2)
sage: f(f.lift([1/6]))
(1/6)
sage: f.lift([1/12])
Traceback (most recent call last):
...
ValueError: element is not in the image
sage: f.lift([1/24])
Traceback (most recent call last):
...
TypeError: element [1/24] is not in free module
>>> from sage.all import *
>>> X = QQ**Integer(2)
>>> V = X.span([[Integer(2), Integer(0)], [Integer(0), Integer(8)]], ZZ)
>>> W = (QQ**Integer(1)).span([[Integer(1)/Integer(12)]], ZZ)
>>> f = V.hom([W([Integer(1)/Integer(3)]), W([Integer(1)/Integer(2)])], W)
>>> l=f.lift([Integer(1)/Integer(3)]); l  # random
(8, -16)
>>> f(l)
(1/3)
>>> f(f.lift([Integer(1)/Integer(2)]))
(1/2)
>>> f(f.lift([Integer(1)/Integer(6)]))
(1/6)
>>> f.lift([Integer(1)/Integer(12)])
Traceback (most recent call last):
...
ValueError: element is not in the image
>>> f.lift([Integer(1)/Integer(24)])
Traceback (most recent call last):
...
TypeError: element [1/24] is not in free module

This works for vector spaces, too:

sage: V = VectorSpace(GF(3), 2)
sage: W = VectorSpace(GF(3), 3)
sage: f = V.hom([W.1, W.1 - W.0])
sage: f.lift(W.1)
(1, 0)
sage: f.lift(W.2)
Traceback (most recent call last):
...
ValueError: element is not in the image
sage: w = W((17, -2, 0))
sage: f(f.lift(w)) == w
True
>>> from sage.all import *
>>> V = VectorSpace(GF(Integer(3)), Integer(2))
>>> W = VectorSpace(GF(Integer(3)), Integer(3))
>>> f = V.hom([W.gen(1), W.gen(1) - W.gen(0)])
>>> f.lift(W.gen(1))
(1, 0)
>>> f.lift(W.gen(2))
Traceback (most recent call last):
...
ValueError: element is not in the image
>>> w = W((Integer(17), -Integer(2), Integer(0)))
>>> f(f.lift(w)) == w
True

This example illustrates the use of the preimage_representative as an equivalent name for this method.

sage: V = ZZ^3
sage: W = ZZ^2
sage: w = vector(ZZ, [1,2])
sage: f = V.hom([w, w, w], W)
sage: f.preimage_representative(vector(ZZ, [10, 20]))
(0, 0, 10)
>>> from sage.all import *
>>> V = ZZ**Integer(3)
>>> W = ZZ**Integer(2)
>>> w = vector(ZZ, [Integer(1),Integer(2)])
>>> f = V.hom([w, w, w], W)
>>> f.preimage_representative(vector(ZZ, [Integer(10), Integer(20)]))
(0, 0, 10)
sage: V = QQ^2; m = matrix(2, [1, 1, 0, 1])
sage: V.hom(m, side="right").lift(V.0 + V.1)
(0, 1)
sage: V.hom(m).lift(V.0 + V.1)
(1, 0)
>>> from sage.all import *
>>> V = QQ**Integer(2); m = matrix(Integer(2), [Integer(1), Integer(1), Integer(0), Integer(1)])
>>> V.hom(m, side="right").lift(V.gen(0) + V.gen(1))
(0, 1)
>>> V.hom(m).lift(V.gen(0) + V.gen(1))
(1, 0)
pushforward(x)[source]#

Compute the image of a sub-module of the domain.

EXAMPLES:

sage: V = QQ^3; W = span([[1,2,3], [-1,2,5/3]], QQ)
sage: phi = V.hom(matrix(QQ, 3, [1..9]))
sage: phi.rank()
2
sage: phi(V)   #indirect doctest
Vector space of degree 3 and dimension 2 over Rational Field
Basis matrix:
[ 1  0 -1]
[ 0  1  2]
>>> from sage.all import *
>>> V = QQ**Integer(3); W = span([[Integer(1),Integer(2),Integer(3)], [-Integer(1),Integer(2),Integer(5)/Integer(3)]], QQ)
>>> phi = V.hom(matrix(QQ, Integer(3), (ellipsis_range(Integer(1),Ellipsis,Integer(9)))))
>>> phi.rank()
2
>>> phi(V)   #indirect doctest
Vector space of degree 3 and dimension 2 over Rational Field
Basis matrix:
[ 1  0 -1]
[ 0  1  2]

We compute the image of a submodule of a ZZ-module embedded in a rational vector space:

sage: V = QQ^3; W = V.span_of_basis([[2,2,3], [-1,2,5/3]], ZZ)
sage: phi = W.hom([W.0, W.0 - W.1]); phi
Free module morphism defined by the matrix
[ 1  0]
[ 1 -1]...
sage: phi(span([2*W.1], ZZ))
Free module of degree 3 and rank 1 over Integer Ring
Echelon basis matrix:
[  6   0 8/3]
sage: phi(2*W.1)
(6, 0, 8/3)
>>> from sage.all import *
>>> V = QQ**Integer(3); W = V.span_of_basis([[Integer(2),Integer(2),Integer(3)], [-Integer(1),Integer(2),Integer(5)/Integer(3)]], ZZ)
>>> phi = W.hom([W.gen(0), W.gen(0) - W.gen(1)]); phi
Free module morphism defined by the matrix
[ 1  0]
[ 1 -1]...
>>> phi(span([Integer(2)*W.gen(1)], ZZ))
Free module of degree 3 and rank 1 over Integer Ring
Echelon basis matrix:
[  6   0 8/3]
>>> phi(Integer(2)*W.gen(1))
(6, 0, 8/3)
sage.modules.free_module_morphism.is_FreeModuleMorphism(x)[source]#

This function is deprecated.

EXAMPLES:

sage: V = ZZ^2; f = V.hom([V.1, -2*V.0])
sage: sage.modules.free_module_morphism.is_FreeModuleMorphism(f)
doctest:warning...
DeprecationWarning: is_FreeModuleMorphism is deprecated;
use isinstance(..., FreeModuleMorphism) or categories instead
See https://github.com/sagemath/sage/issues/37731 for details.
True
sage: sage.modules.free_module_morphism.is_FreeModuleMorphism(0)
False
>>> from sage.all import *
>>> V = ZZ**Integer(2); f = V.hom([V.gen(1), -Integer(2)*V.gen(0)])
>>> sage.modules.free_module_morphism.is_FreeModuleMorphism(f)
doctest:warning...
DeprecationWarning: is_FreeModuleMorphism is deprecated;
use isinstance(..., FreeModuleMorphism) or categories instead
See https://github.com/sagemath/sage/issues/37731 for details.
True
>>> sage.modules.free_module_morphism.is_FreeModuleMorphism(Integer(0))
False