Free modules of finite rank

The class FiniteRankFreeModule implements free modules of finite rank over a commutative ring.

A free module of finite rank over a commutative ring \(R\) is a module \(M\) over \(R\) that admits a finite basis, i.e. a finite familly of linearly independent generators. Since \(R\) is commutative, it has the invariant basis number property, so that the rank of the free module \(M\) is defined uniquely, as the cardinality of any basis of \(M\).

No distinguished basis of \(M\) is assumed. On the contrary, many bases can be introduced on the free module along with change-of-basis rules (as module automorphisms). Each module element has then various representations over the various bases.

Note

The class FiniteRankFreeModule does not inherit from class FreeModule_generic nor from class CombinatorialFreeModule, since both classes deal with modules with a distinguished basis (see details below). Accordingly, the class FiniteRankFreeModule inherits directly from the generic class Parent with the category set to Modules (and not to ModulesWithBasis).

Todo

  • implement submodules
  • create a FreeModules category (cf. the TODO statement in the documentation of Modules: Implement a ``FreeModules(R)`` category, when so prompted by a concrete use case)

AUTHORS:

  • Eric Gourgoulhon, Michal Bejger (2014-2015): initial version
  • Travis Scrimshaw (2016): category set to Modules(ring).FiniteDimensional() (trac ticket #20770)

REFERENCES:

  • Chap. 10 of R. Godement : Algebra, Hermann (Paris) / Houghton Mifflin (Boston) (1968)
  • Chap. 3 of S. Lang : Algebra, 3rd ed., Springer (New York) (2002)

EXAMPLES:

Let us define a free module of rank 2 over \(\ZZ\):

sage: M = FiniteRankFreeModule(ZZ, 2, name='M') ; M
Rank-2 free module M over the Integer Ring
sage: M.category()
Category of finite dimensional modules over Integer Ring

We introduce a first basis on M:

sage: e = M.basis('e') ; e
Basis (e_0,e_1) on the Rank-2 free module M over the Integer Ring

The elements of the basis are of course module elements:

sage: e[0]
Element e_0 of the Rank-2 free module M over the Integer Ring
sage: e[1]
Element e_1 of the Rank-2 free module M over the Integer Ring
sage: e[0].parent()
Rank-2 free module M over the Integer Ring

We define a module element by its components w.r.t. basis e:

sage: u = M([2,-3], basis=e, name='u')
sage: u.display(e)
u = 2 e_0 - 3 e_1

Module elements can be also be created by arithmetic expressions:

sage: v = -2*u + 4*e[0] ; v
Element of the Rank-2 free module M over the Integer Ring
sage: v.display(e)
6 e_1
sage: u == 2*e[0] - 3*e[1]
True

We define a second basis on M from a family of linearly independent elements:

sage: f = M.basis('f', from_family=(e[0]-e[1], -2*e[0]+3*e[1])) ; f
Basis (f_0,f_1) on the Rank-2 free module M over the Integer Ring
sage: f[0].display(e)
f_0 = e_0 - e_1
sage: f[1].display(e)
f_1 = -2 e_0 + 3 e_1

We may of course express the elements of basis e in terms of basis f:

sage: e[0].display(f)
e_0 = 3 f_0 + f_1
sage: e[1].display(f)
e_1 = 2 f_0 + f_1

as well as any module element:

sage: u.display(f)
u = -f_1
sage: v.display(f)
12 f_0 + 6 f_1

The two bases are related by a module automorphism:

sage: a = M.change_of_basis(e,f) ; a
Automorphism of the Rank-2 free module M over the Integer Ring
sage: a.parent()
General linear group of the Rank-2 free module M over the Integer Ring
sage: a.matrix(e)
[ 1 -2]
[-1  3]

Let us check that basis f is indeed the image of basis e by a:

sage: f[0] == a(e[0])
True
sage: f[1] == a(e[1])
True

The reverse change of basis is of course the inverse automorphism:

sage: M.change_of_basis(f,e) == a^(-1)
True

We introduce a new module element via its components w.r.t. basis f:

sage: v = M([2,4], basis=f, name='v')
sage: v.display(f)
v = 2 f_0 + 4 f_1

The sum of the two module elements u and v can be performed even if they have been defined on different bases, thanks to the known relation between the two bases:

sage: s = u + v ; s
Element u+v of the Rank-2 free module M over the Integer Ring

We can display the result in either basis:

sage: s.display(e)
u+v = -4 e_0 + 7 e_1
sage: s.display(f)
u+v = 2 f_0 + 3 f_1

Tensor products of elements are implemented:

sage: t = u*v ; t
Type-(2,0) tensor u*v on the Rank-2 free module M over the Integer Ring
sage: t.parent()
Free module of type-(2,0) tensors on the
 Rank-2 free module M over the Integer Ring
sage: t.display(e)
u*v = -12 e_0*e_0 + 20 e_0*e_1 + 18 e_1*e_0 - 30 e_1*e_1
sage: t.display(f)
u*v = -2 f_1*f_0 - 4 f_1*f_1

We can access to tensor components w.r.t. to a given basis via the square bracket operator:

sage: t[e,0,1]
20
sage: t[f,1,0]
-2
sage: u[e,0]
2
sage: u[e,:]
[2, -3]
sage: u[f,:]
[0, -1]

The parent of the automorphism a is the group \(\mathrm{GL}(M)\), but a can also be considered as a tensor of type \((1,1)\) on M:

sage: a.parent()
General linear group of the Rank-2 free module M over the Integer Ring
sage: a.tensor_type()
(1, 1)
sage: a.display(e)
e_0*e^0 - 2 e_0*e^1 - e_1*e^0 + 3 e_1*e^1
sage: a.display(f)
f_0*f^0 - 2 f_0*f^1 - f_1*f^0 + 3 f_1*f^1

As such, we can form its tensor product with t, yielding a tensor of type \((3,1)\):

sage: t*a
Type-(3,1) tensor on the Rank-2 free module M over the Integer Ring
sage: (t*a).display(e)
-12 e_0*e_0*e_0*e^0 + 24 e_0*e_0*e_0*e^1 + 12 e_0*e_0*e_1*e^0
 - 36 e_0*e_0*e_1*e^1 + 20 e_0*e_1*e_0*e^0 - 40 e_0*e_1*e_0*e^1
 - 20 e_0*e_1*e_1*e^0 + 60 e_0*e_1*e_1*e^1 + 18 e_1*e_0*e_0*e^0
 - 36 e_1*e_0*e_0*e^1 - 18 e_1*e_0*e_1*e^0 + 54 e_1*e_0*e_1*e^1
 - 30 e_1*e_1*e_0*e^0 + 60 e_1*e_1*e_0*e^1 + 30 e_1*e_1*e_1*e^0
 - 90 e_1*e_1*e_1*e^1

The parent of \(t\otimes a\) is itself a free module of finite rank over \(\ZZ\):

sage: T = (t*a).parent() ; T
Free module of type-(3,1) tensors on the Rank-2 free module M over the
 Integer Ring
sage: T.base_ring()
Integer Ring
sage: T.rank()
16

Differences between FiniteRankFreeModule and FreeModule (or VectorSpace)

To illustrate the differences, let us create two free modules of rank 3 over \(\ZZ\), one with FiniteRankFreeModule and the other one with FreeModule:

sage: M = FiniteRankFreeModule(ZZ, 3, name='M') ; M
Rank-3 free module M over the Integer Ring
sage: N = FreeModule(ZZ, 3) ; N
Ambient free module of rank 3 over the principal ideal domain Integer Ring

The main difference is that FreeModule returns a free module with a distinguished basis, while FiniteRankFreeModule does not:

sage: N.basis()
[
(1, 0, 0),
(0, 1, 0),
(0, 0, 1)
]
sage: M.bases()
[]
sage: M.print_bases()
No basis has been defined on the Rank-3 free module M over the Integer Ring

This is also revealed by the category of each module:

sage: M.category()
Category of finite dimensional modules over Integer Ring
sage: N.category()
Category of finite dimensional modules with basis over
 (euclidean domains and infinite enumerated sets and metric spaces)

In other words, the module created by FreeModule is actually \(\ZZ^3\), while, in the absence of any distinguished basis, no canonical isomorphism relates the module created by FiniteRankFreeModule to \(\ZZ^3\):

sage: N is ZZ^3
True
sage: M is ZZ^3
False
sage: M == ZZ^3
False

Because it is \(\ZZ^3\), N is unique, while there may be various modules of the same rank over the same ring created by FiniteRankFreeModule; they are then distinguished by their names (actually by the complete sequence of arguments of FiniteRankFreeModule):

sage: N1 = FreeModule(ZZ, 3) ; N1
Ambient free module of rank 3 over the principal ideal domain Integer Ring
sage: N1 is N  # FreeModule(ZZ, 3) is unique
True
sage: M1 = FiniteRankFreeModule(ZZ, 3, name='M_1') ; M1
Rank-3 free module M_1 over the Integer Ring
sage: M1 is M  # M1 and M are different rank-3 modules over ZZ
False
sage: M1b = FiniteRankFreeModule(ZZ, 3, name='M_1') ; M1b
Rank-3 free module M_1 over the Integer Ring
sage: M1b is M1  # because M1b and M1 have the same name
True

As illustrated above, various bases can be introduced on the module created by FiniteRankFreeModule:

sage: e = M.basis('e') ; e
Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring
sage: f = M.basis('f', from_family=(-e[0], e[1]-e[2], -2*e[1]+3*e[2])) ; f
Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring
sage: M.bases()
[Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring,
 Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring]

Each element of a basis is accessible via its index:

sage: e[0]
Element e_0 of the Rank-3 free module M over the Integer Ring
sage: e[0].parent()
Rank-3 free module M over the Integer Ring
sage: f[1]
Element f_1 of the Rank-3 free module M over the Integer Ring
sage: f[1].parent()
Rank-3 free module M over the Integer Ring

while on module N, the element of the (unique) basis is accessible directly from the module symbol:

sage: N.0
(1, 0, 0)
sage: N.1
(0, 1, 0)
sage: N.0.parent()
Ambient free module of rank 3 over the principal ideal domain Integer Ring

The arithmetic of elements is similar; the difference lies in the display: a basis has to be specified for elements of M, while elements of N are displayed directly as elements of \(\ZZ^3\):

sage: u = 2*e[0] - 3*e[2] ; u
Element of the Rank-3 free module M over the Integer Ring
sage: u.display(e)
2 e_0 - 3 e_2
sage: u.display(f)
-2 f_0 - 6 f_1 - 3 f_2
sage: u[e,:]
[2, 0, -3]
sage: u[f,:]
[-2, -6, -3]
sage: v = 2*N.0 - 3*N.2 ; v
(2, 0, -3)

For the case of M, in order to avoid to specify the basis if the user is always working with the same basis (e.g. only one basis has been defined), the concept of default basis has been introduced:

sage: M.default_basis()
Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring
sage: M.print_bases()
Bases defined on the Rank-3 free module M over the Integer Ring:
 - (e_0,e_1,e_2) (default basis)
 - (f_0,f_1,f_2)

This is different from the distinguished basis of N: it simply means that the mention of the basis can be omitted in function arguments:

sage: u.display()  # equivalent to u.display(e)
2 e_0 - 3 e_2
sage: u[:]         # equivalent to u[e,:]
[2, 0, -3]

At any time, the default basis can be changed:

sage: M.set_default_basis(f)
sage: u.display()
-2 f_0 - 6 f_1 - 3 f_2

Another difference between FiniteRankFreeModule and FreeModule is that for the former the range of indices can be specified (by default, it starts from 0):

sage: M = FiniteRankFreeModule(ZZ, 3, name='M', start_index=1) ; M
Rank-3 free module M over the Integer Ring
sage: e = M.basis('e') ; e  # compare with (e_0,e_1,e_2) above
Basis (e_1,e_2,e_3) on the Rank-3 free module M over the Integer Ring
sage: e[1], e[2], e[3]
(Element e_1 of the Rank-3 free module M over the Integer Ring,
 Element e_2 of the Rank-3 free module M over the Integer Ring,
 Element e_3 of the Rank-3 free module M over the Integer Ring)

All the above holds for VectorSpace instead of FreeModule: the object created by VectorSpace is actually a Cartesian power of the base field:

sage: V = VectorSpace(QQ,3) ; V
Vector space of dimension 3 over Rational Field
sage: V.category()
Category of finite dimensional vector spaces with basis
 over (quotient fields and metric spaces)
sage: V is QQ^3
True
sage: V.basis()
[
(1, 0, 0),
(0, 1, 0),
(0, 0, 1)
]

To create a vector space without any distinguished basis, one has to use FiniteRankFreeModule:

sage: V = FiniteRankFreeModule(QQ, 3, name='V') ; V
3-dimensional vector space V over the Rational Field
sage: V.category()
Category of finite dimensional vector spaces over Rational Field
sage: V.bases()
[]
sage: V.print_bases()
No basis has been defined on the 3-dimensional vector space V over the
 Rational Field

The class FiniteRankFreeModule has been created for the needs of the SageManifolds project, where free modules do not have any distinguished basis. Too kinds of free modules occur in the context of differentiable manifolds (see here for more details):

  • the tangent vector space at any point of the manifold
  • the set of vector fields on a parallelizable open subset \(U\) of the manifold, which is a free module over the algebra of scalar fields on \(U\).

For instance, without any specific coordinate choice, no basis can be distinguished in a tangent space.

On the other side, the modules created by FreeModule have much more algebraic functionalities than those created by FiniteRankFreeModule. In particular, submodules have not been implemented yet in FiniteRankFreeModule. Moreover, modules resulting from FreeModule are tailored to the specific kind of their base ring:

  • free module over a commutative ring that is not an integral domain (\(\ZZ/6\ZZ\)):

    sage: R = IntegerModRing(6) ; R
    Ring of integers modulo 6
    sage: FreeModule(R, 3)
    Ambient free module of rank 3 over Ring of integers modulo 6
    sage: type(FreeModule(R, 3))
    <class 'sage.modules.free_module.FreeModule_ambient_with_category'>
    
  • free module over an integral domain that is not principal (\(\ZZ[X]\)):

    sage: R.<X> = ZZ[] ; R
    Univariate Polynomial Ring in X over Integer Ring
    sage: FreeModule(R, 3)
    Ambient free module of rank 3 over the integral domain Univariate
     Polynomial Ring in X over Integer Ring
    sage: type(FreeModule(R, 3))
    <class 'sage.modules.free_module.FreeModule_ambient_domain_with_category'>
    
  • free module over a principal ideal domain (\(\ZZ\)):

    sage: R = ZZ ; R
    Integer Ring
    sage: FreeModule(R,3)
    Ambient free module of rank 3 over the principal ideal domain Integer Ring
    sage: type(FreeModule(R, 3))
    <class 'sage.modules.free_module.FreeModule_ambient_pid_with_category'>
    

On the contrary, all objects constructed with FiniteRankFreeModule belong to the same class:

sage: R = IntegerModRing(6)
sage: type(FiniteRankFreeModule(R, 3))
<class 'sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule_with_category'>
sage: R.<X> = ZZ[]
sage: type(FiniteRankFreeModule(R, 3))
<class 'sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule_with_category'>
sage: R = ZZ
sage: type(FiniteRankFreeModule(R, 3))
<class 'sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule_with_category'>

Differences between FiniteRankFreeModule and CombinatorialFreeModule

An alternative to construct free modules in Sage is CombinatorialFreeModule. However, as FreeModule, it leads to a module with a distinguished basis:

sage: N = CombinatorialFreeModule(ZZ, [1,2,3]) ; N
Free module generated by {1, 2, 3} over Integer Ring
sage: N.category()
Category of finite dimensional modules with basis over Integer Ring

The distinguished basis is returned by the method basis():

sage: b = N.basis() ; b
Finite family {1: B[1], 2: B[2], 3: B[3]}
sage: b[1]
B[1]
sage: b[1].parent()
Free module generated by {1, 2, 3} over Integer Ring

For the free module M created above with FiniteRankFreeModule, the method basis has at least one argument: the symbol string that specifies which basis is required:

sage: e = M.basis('e') ; e
Basis (e_1,e_2,e_3) on the Rank-3 free module M over the Integer Ring
sage: e[1]
Element e_1 of the Rank-3 free module M over the Integer Ring
sage: e[1].parent()
Rank-3 free module M over the Integer Ring

The arithmetic of elements is similar:

sage: u = 2*e[1] - 5*e[3] ; u
Element of the Rank-3 free module M over the Integer Ring
sage: v = 2*b[1] - 5*b[3] ; v
2*B[1] - 5*B[3]

One notices that elements of N are displayed directly in terms of their expansions on the distinguished basis. For elements of M, one has to use the method display() in order to specify the basis:

sage: u.display(e)
2 e_1 - 5 e_3

The components on the basis are returned by the square bracket operator for M and by the method coefficient for N:

sage: [u[e,i] for i in {1,2,3}]
[2, 0, -5]
sage: u[e,:]  # a shortcut for the above
[2, 0, -5]
sage: [v.coefficient(i) for i in {1,2,3}]
[2, 0, -5]
class sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule(ring, rank, name=None, latex_name=None, start_index=0, output_formatter=None, category=None)

Bases: sage.structure.unique_representation.UniqueRepresentation, sage.structure.parent.Parent

Free module of finite rank over a commutative ring.

A free module of finite rank over a commutative ring \(R\) is a module \(M\) over \(R\) that admits a finite basis, i.e. a finite familly of linearly independent generators. Since \(R\) is commutative, it has the invariant basis number property, so that the rank of the free module \(M\) is defined uniquely, as the cardinality of any basis of \(M\).

No distinguished basis of \(M\) is assumed. On the contrary, many bases can be introduced on the free module along with change-of-basis rules (as module automorphisms). Each module element has then various representations over the various bases.

Note

The class FiniteRankFreeModule does not inherit from class FreeModule_generic nor from class CombinatorialFreeModule, since both classes deal with modules with a distinguished basis (see details above). Moreover, following the recommendation exposed in trac ticket #16427 the class FiniteRankFreeModule inherits directly from Parent (with the category set to Modules) and not from the Cython class Module.

The class FiniteRankFreeModule is a Sage parent class, the corresponding element class being FiniteRankFreeModuleElement.

INPUT:

  • ring – commutative ring \(R\) over which the free module is constructed
  • rank – positive integer; rank of the free module
  • name – (default: None) string; name given to the free module
  • latex_name – (default: None) string; LaTeX symbol to denote the freemodule; if none is provided, it is set to name
  • start_index – (default: 0) integer; lower bound of the range of indices in bases defined on the free module
  • output_formatter – (default: None) function or unbound method called to format the output of the tensor components; output_formatter must take 1 or 2 arguments: the first argument must be an element of the ring \(R\) and the second one, if any, some format specification

EXAMPLES:

Free module of rank 3 over \(\ZZ\):

sage: FiniteRankFreeModule._clear_cache_() # for doctests only
sage: M = FiniteRankFreeModule(ZZ, 3) ; M
Rank-3 free module over the Integer Ring
sage: M = FiniteRankFreeModule(ZZ, 3, name='M') ; M  # declaration with a name
Rank-3 free module M over the Integer Ring
sage: M.category()
Category of finite dimensional modules over Integer Ring
sage: M.base_ring()
Integer Ring
sage: M.rank()
3

If the base ring is a field, the free module is in the category of vector spaces:

sage: V = FiniteRankFreeModule(QQ, 3, name='V') ; V
3-dimensional vector space V over the Rational Field
sage: V.category()
Category of finite dimensional vector spaces over Rational Field

The LaTeX output is adjusted via the parameter latex_name:

sage: latex(M)  # the default is the symbol provided in the string ``name``
M
sage: M = FiniteRankFreeModule(ZZ, 3, name='M', latex_name=r'\mathcal{M}')
sage: latex(M)
\mathcal{M}

The free module M has no distinguished basis:

sage: M in ModulesWithBasis(ZZ)
False
sage: M in Modules(ZZ)
True

In particular, no basis is initialized at the module construction:

sage: M.print_bases()
No basis has been defined on the Rank-3 free module M over the Integer Ring
sage: M.bases()
[]

Bases have to be introduced by means of the method basis(), the first defined basis being considered as the default basis, meaning it can be skipped in function arguments required a basis (this can be changed by means of the method set_default_basis()):

sage: e = M.basis('e') ; e
Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring
sage: M.default_basis()
Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring

A second basis can be created from a family of linearly independent elements expressed in terms of basis e:

sage: f = M.basis('f', from_family=(-e[0], e[1]+e[2], 2*e[1]+3*e[2]))
sage: f
Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring
sage: M.print_bases()
Bases defined on the Rank-3 free module M over the Integer Ring:
 - (e_0,e_1,e_2) (default basis)
 - (f_0,f_1,f_2)
sage: M.bases()
[Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring,
 Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring]

M is a parent object, whose elements are instances of FiniteRankFreeModuleElement (actually a dynamically generated subclass of it):

sage: v = M.an_element() ; v
Element of the Rank-3 free module M over the Integer Ring
sage: from sage.tensor.modules.free_module_tensor import FiniteRankFreeModuleElement
sage: isinstance(v, FiniteRankFreeModuleElement)
True
sage: v in M
True
sage: M.is_parent_of(v)
True
sage: v.display() # expansion w.r.t. the default basis (e)
e_0 + e_1 + e_2
sage: v.display(f)
-f_0 + f_1

The test suite of the category of modules is passed:

sage: TestSuite(M).run()

Constructing an element of M from (the integer) 0 yields the zero element of M:

sage: M(0)
Element zero of the Rank-3 free module M over the Integer Ring
sage: M(0) is M.zero()
True

Non-zero elements are constructed by providing their components in a given basis:

sage: v = M([-1,0,3]) ; v  # components in the default basis (e)
Element of the Rank-3 free module M over the Integer Ring
sage: v.display() # expansion w.r.t. the default basis (e)
-e_0 + 3 e_2
sage: v.display(f)
f_0 - 6 f_1 + 3 f_2
sage: v = M([-1,0,3], basis=f) ; v  # components in a specific basis
Element of the Rank-3 free module M over the Integer Ring
sage: v.display(f)
-f_0 + 3 f_2
sage: v.display()
e_0 + 6 e_1 + 9 e_2
sage: v = M([-1,0,3], basis=f, name='v') ; v
Element v of the Rank-3 free module M over the Integer Ring
sage: v.display(f)
v = -f_0 + 3 f_2
sage: v.display()
v = e_0 + 6 e_1 + 9 e_2

An alternative is to construct the element from an empty list of componentsand to set the nonzero components afterwards:

sage: v = M([], name='v')
sage: v[e,0] = -1
sage: v[e,2] = 3
sage: v.display(e)
v = -e_0 + 3 e_2

Indices on the free module, such as indices labelling the element of a basis, are provided by the generator method irange(). By default, they range from 0 to the module’s rank minus one:

sage: list(M.irange())
[0, 1, 2]

This can be changed via the parameter start_index in the module construction:

sage: M1 = FiniteRankFreeModule(ZZ, 3, name='M', start_index=1)
sage: list(M1.irange())
[1, 2, 3]

The parameter output_formatter in the constructor of the free module is used to set the output format of tensor components:

sage: N = FiniteRankFreeModule(QQ, 3, output_formatter=Rational.numerical_approx)
sage: e = N.basis('e')
sage: v = N([1/3, 0, -2], basis=e)
sage: v[e,:]
[0.333333333333333, 0.000000000000000, -2.00000000000000]
sage: v.display(e)  # default format (53 bits of precision)
0.333333333333333 e_0 - 2.00000000000000 e_2
sage: v.display(e, format_spec=10)  # 10 bits of precision
0.33 e_0 - 2.0 e_2
Element

alias of FiniteRankFreeModuleElement

alternating_form(degree, name=None, latex_name=None)

Construct an alternating form on the free module.

INPUT:

  • degree – the degree of the alternating form (i.e. its tensor rank)
  • name – (default: None) string; name given to the alternating form
  • latex_name – (default: None) string; LaTeX symbol to denote the alternating form; if none is provided, the LaTeX symbol is set to name

OUTPUT:

EXAMPLES:

Alternating forms on a rank-3 module:

sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: a = M.alternating_form(2, 'a') ; a
Alternating form a of degree 2 on the
 Rank-3 free module M over the Integer Ring

The nonzero components in a given basis have to be set in a second step, thereby fully specifying the alternating form:

sage: e = M.basis('e') ; e
Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring
sage: a.set_comp(e)[0,1] = 2
sage: a.set_comp(e)[1,2] = -3
sage: a.display(e)
a = 2 e^0/\e^1 - 3 e^1/\e^2

An alternating form of degree 1 is a linear form:

sage: a = M.alternating_form(1, 'a') ; a
Linear form a on the Rank-3 free module M over the Integer Ring

To construct such a form, it is preferable to call the method linear_form() instead:

sage: a = M.linear_form('a') ; a
Linear form a on the Rank-3 free module M over the Integer Ring

See FreeModuleAltForm for more documentation.

automorphism(matrix=None, basis=None, name=None, latex_name=None)

Construct a module automorphism of self.

Denoting self by \(M\), an automorphism of self is an element of the general linear group \(\mathrm{GL}(M)\).

INPUT:

  • matrix – (default: None) matrix of size rank(M)*rank(M) representing the automorphism with respect to basis; this entry can actually be any material from which a matrix of elements of self base ring can be constructed; the columns of matrix must be the components w.r.t. basis of the images of the elements of basis. If matrix is None, the automorphism has to be initialized afterwards by method set_comp() or via the operator [].
  • basis – (default: None) basis of self defining the matrix representation; if None the default basis of self is assumed.
  • name – (default: None) string; name given to the automorphism
  • latex_name – (default: None) string; LaTeX symbol to denote the automorphism; if none is provided, the LaTeX symbol is set to name

OUTPUT:

EXAMPLES:

Automorphism of a rank-2 free \(\ZZ\)-module:

sage: M = FiniteRankFreeModule(ZZ, 2, name='M')
sage: e = M.basis('e')
sage: a = M.automorphism(matrix=[[1,2],[1,3]], basis=e, name='a') ; a
Automorphism a of the Rank-2 free module M over the Integer Ring
sage: a.parent()
General linear group of the Rank-2 free module M over the Integer Ring
sage: a.matrix(e)
[1 2]
[1 3]

An automorphism is a tensor of type (1,1):

sage: a.tensor_type()
(1, 1)
sage: a.display(e)
a = e_0*e^0 + 2 e_0*e^1 + e_1*e^0 + 3 e_1*e^1

The automorphism components can be specified in a second step, as components of a type-(1,1) tensor:

sage: a1 = M.automorphism(name='a')
sage: a1[e,:] = [[1,2],[1,3]]
sage: a1.matrix(e)
[1 2]
[1 3]
sage: a1 == a
True

Component by component specification:

sage: a2 = M.automorphism(name='a')
sage: a2[0,0] = 1  # component set in the module's default basis (e)
sage: a2[0,1] = 2
sage: a2[1,0] = 1
sage: a2[1,1] = 3
sage: a2.matrix(e)
[1 2]
[1 3]
sage: a2 == a
True

See FreeModuleAutomorphism for more documentation.

bases()

Return the list of bases that have been defined on the free module self.

Use the method print_bases() to get a formatted output with more information.

OUTPUT:

EXAMPLES:

Bases on a rank-3 free module:

sage: M = FiniteRankFreeModule(ZZ, 3, name='M_3', start_index=1)
sage: M.bases()
[]
sage: e = M.basis('e')
sage: M.bases()
[Basis (e_1,e_2,e_3) on the Rank-3 free module M_3 over the Integer Ring]
sage: f = M.basis('f')
sage: M.bases()
[Basis (e_1,e_2,e_3) on the Rank-3 free module M_3 over the Integer Ring,
 Basis (f_1,f_2,f_3) on the Rank-3 free module M_3 over the Integer Ring]
basis(symbol, latex_symbol=None, from_family=None)

Define or return a basis of the free module self.

Let \(M\) denotes the free module self and \(n\) its rank.

The basis can be defined from a set of \(n\) linearly independent elements of \(M\) by means of the argument from_family. If from_family is not specified, the basis is created from scratch and, at this stage, is unrelated to bases that could have been defined previously on \(M\). It can be related afterwards by means of the method set_change_of_basis().

If the basis specified by the given symbol already exists, it is simply returned, whatever the value of the arguments latex_symbol or from_family.

Note that another way to construct a basis of self is to use the method new_basis() on an existing basis, with the automorphism relating the two bases as an argument.

INPUT:

  • symbol – string; a letter (of a few letters) to denote a generic element of the basis
  • latex_symbol – (default: None) string; symbol to denote a generic element of the basis; if None, the value of symbol is used
  • from_family – (default: None) a tuple of \(n\) linearly independent elements of the free module self (\(n\) being the rank of self)

OUTPUT:

EXAMPLES:

Bases on a rank-3 free module:

sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: e = M.basis('e') ; e
Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring
sage: e[0]
Element e_0 of the Rank-3 free module M over the Integer Ring
sage: latex(e)
\left(e_0,e_1,e_2\right)

The LaTeX symbol can be set explicitely, as the second argument of basis():

sage: eps = M.basis('eps', r'\epsilon') ; eps
Basis (eps_0,eps_1,eps_2) on the Rank-3 free module M
 over the Integer Ring
sage: latex(eps)
\left(\epsilon_0,\epsilon_1,\epsilon_2\right)

If the provided symbol is that of an already defined basis, the latter is returned (no new basis is created):

sage: M.basis('e') is e
True
sage: M.basis('eps') is eps
True

The individual elements of the basis are labelled according the parameter start_index provided at the free module construction:

sage: M = FiniteRankFreeModule(ZZ, 3, name='M', start_index=1)
sage: e = M.basis('e') ; e
Basis (e_1,e_2,e_3) on the Rank-3 free module M over the Integer Ring
sage: e[1]
Element e_1 of the Rank-3 free module M over the Integer Ring

Construction of a basis from a family of linearly independent module elements:

sage: f1 = -e[2]
sage: f2 = 4*e[1] + 3*e[3]
sage: f3 = 7*e[1] + 5*e[3]
sage: f = M.basis('f', from_family=(f1,f2,f3))
sage: f[1].display()
f_1 = -e_2
sage: f[2].display()
f_2 = 4 e_1 + 3 e_3
sage: f[3].display()
f_3 = 7 e_1 + 5 e_3

The change-of-basis automorphisms have been registered:

sage: M.change_of_basis(e,f).matrix(e)
[ 0  4  7]
[-1  0  0]
[ 0  3  5]
sage: M.change_of_basis(f,e).matrix(e)
[ 0 -1  0]
[-5  0  7]
[ 3  0 -4]
sage: M.change_of_basis(f,e) == M.change_of_basis(e,f).inverse()
True

Check of the change-of-basis e –> f:

sage: a = M.change_of_basis(e,f) ; a
Automorphism of the Rank-3 free module M over the Integer Ring
sage: all( f[i] == a(e[i]) for i in M.irange() )
True

For more documentation on bases see FreeModuleBasis.

change_of_basis(basis1, basis2)

Return a module automorphism linking two bases defined on the free module self.

If the automorphism has not been recorded yet (in the internal dictionary self._basis_changes), it is computed by transitivity, i.e. by performing products of recorded changes of basis.

INPUT:

  • basis1 – a basis of self, denoted \((e_i)\) below
  • basis2 – a basis of self, denoted \((f_i)\) below

OUTPUT:

  • instance of FreeModuleAutomorphism describing the automorphism \(P\) that relates the basis \((e_i)\) to the basis \((f_i)\) according to \(f_i = P(e_i)\)

EXAMPLES:

Changes of basis on a rank-2 free module:

sage: FiniteRankFreeModule._clear_cache_() # for doctests only
sage: M = FiniteRankFreeModule(ZZ, 2, name='M', start_index=1)
sage: e = M.basis('e')
sage: f = M.basis('f', from_family=(e[1]+2*e[2], e[1]+3*e[2]))
sage: P = M.change_of_basis(e,f) ; P
Automorphism of the Rank-2 free module M over the Integer Ring
sage: P.matrix(e)
[1 1]
[2 3]

Note that the columns of this matrix contain the components of the elements of basis f w.r.t. to basis e:

sage: f[1].display(e)
f_1 = e_1 + 2 e_2
sage: f[2].display(e)
f_2 = e_1 + 3 e_2

The change of basis is cached:

sage: P is M.change_of_basis(e,f)
True

Check of the change-of-basis automorphism:

sage: f[1] == P(e[1])
True
sage: f[2] == P(e[2])
True

Check of the reverse change of basis:

sage: M.change_of_basis(f,e) == P^(-1)
True

We have of course:

sage: M.change_of_basis(e,e)
Identity map of the Rank-2 free module M over the Integer Ring
sage: M.change_of_basis(e,e) is M.identity_map()
True

Let us introduce a third basis on M:

sage: h = M.basis('h', from_family=(3*e[1]+4*e[2], 5*e[1]+7*e[2]))

The change of basis e –> h has been recorded directly from the definition of h:

sage: Q = M.change_of_basis(e,h) ; Q.matrix(e)
[3 5]
[4 7]

The change of basis f –> h is computed by transitivity, i.e. from the changes of basis f –> e and e –> h:

sage: R = M.change_of_basis(f,h) ; R
Automorphism of the Rank-2 free module M over the Integer Ring
sage: R.matrix(e)
[-1  2]
[-2  3]
sage: R.matrix(f)
[ 5  8]
[-2 -3]

Let us check that R is indeed the change of basis f –> h:

sage: h[1] == R(f[1])
True
sage: h[2] == R(f[2])
True

A related check is:

sage: R == Q*P^(-1)
True
default_basis()

Return the default basis of the free module self.

The default basis is simply a basis whose name can be skipped in methods requiring a basis as an argument. By default, it is the first basis introduced on the module. It can be changed by the method set_default_basis().

OUTPUT:

EXAMPLES:

At the module construction, no default basis is assumed:

sage: M = FiniteRankFreeModule(ZZ, 2, name='M', start_index=1)
sage: M.default_basis()
No default basis has been defined on the
 Rank-2 free module M over the Integer Ring

The first defined basis becomes the default one:

sage: e = M.basis('e') ; e
Basis (e_1,e_2) on the Rank-2 free module M over the Integer Ring
sage: M.default_basis()
Basis (e_1,e_2) on the Rank-2 free module M over the Integer Ring
sage: f =  M.basis('f') ; f
Basis (f_1,f_2) on the Rank-2 free module M over the Integer Ring
sage: M.default_basis()
Basis (e_1,e_2) on the Rank-2 free module M over the Integer Ring
dual()

Return the dual module of self.

EXAMPLE:

Dual of a free module over \(\ZZ\):

sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: M.dual()
Dual of the Rank-3 free module M over the Integer Ring
sage: latex(M.dual())
M^*

The dual is a free module of the same rank as M:

sage: isinstance(M.dual(), FiniteRankFreeModule)
True
sage: M.dual().rank()
3

It is formed by alternating forms of degree 1, i.e. linear forms:

sage: M.dual() is M.dual_exterior_power(1)
True
sage: M.dual().an_element()
Linear form on the Rank-3 free module M over the Integer Ring
sage: a = M.linear_form()
sage: a in M.dual()
True

The elements of a dual basis belong of course to the dual module:

sage: e = M.basis('e')
sage: e.dual_basis()[0] in M.dual()
True
dual_exterior_power(p)

Return the \(p\)-th exterior power of the dual of self.

If \(M\) stands for the free module self, the p-th exterior power of the dual of \(M\) is the set \(\Lambda^p(M^*)\) of all alternating forms of degree \(p\) on \(M\), i.e. of all multilinear maps

\[\underbrace{M\times\cdots\times M}_{p\ \; \mbox{times}} \longrightarrow R\]

that vanish whenever any of two of their arguments are equal. \(\Lambda^p(M^*)\) is a free module of rank \(\binom{n}{p}\) over the same ring as \(M\), where \(n\) is the rank of \(M\).

INPUT:

  • p – non-negative integer

OUTPUT:

  • for \(p\geq 1\), instance of ExtPowerFreeModule representing the free module \(\Lambda^p(M^*)\); for \(p=0\), the base ring \(R\) is returned instead

EXAMPLES:

Exterior powers of the dual of a free \(\ZZ\)-module of rank 3:

sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: e = M.basis('e')
sage: M.dual_exterior_power(0)  # return the base ring
Integer Ring
sage: M.dual_exterior_power(1)  # return the dual module
Dual of the Rank-3 free module M over the Integer Ring
sage: M.dual_exterior_power(1) is M.dual()
True
sage: M.dual_exterior_power(2)
2nd exterior power of the dual of the Rank-3 free module M over the Integer Ring
sage: M.dual_exterior_power(2).an_element()
Alternating form of degree 2 on the Rank-3 free module M over the Integer Ring
sage: M.dual_exterior_power(2).an_element().display()
e^0/\e^1
sage: M.dual_exterior_power(3)
3rd exterior power of the dual of the Rank-3 free module M over the Integer Ring
sage: M.dual_exterior_power(3).an_element()
Alternating form of degree 3 on the Rank-3 free module M over the Integer Ring
sage: M.dual_exterior_power(3).an_element().display()
e^0/\e^1/\e^2

See ExtPowerFreeModule for more documentation.

endomorphism(matrix_rep, basis=None, name=None, latex_name=None)

Contruct an endomorphism of the free module self.

The returned object is a module morphism \(\phi: M \rightarrow M\), where \(M\) is self.

INPUT:

  • matrix_rep – matrix of size rank(M)*rank(M) representing the endomorphism with respect to basis; this entry can actually be any material from which a matrix of elements of self base ring can be constructed; the columns of matrix_rep must be the components w.r.t. basis of the images of the elements of basis.
  • basis – (default: None) basis of self defining the matrix representation; if None the default basis of self is assumed.
  • name – (default: None) string; name given to the endomorphism
  • latex_name – (default: None) string; LaTeX symbol to denote the endomorphism; if none is provided, name will be used.

OUTPUT:

EXAMPLES:

Construction of an endomorphism with minimal data (module’s default basis and no name):

sage: M = FiniteRankFreeModule(ZZ, 2, name='M')
sage: e = M.basis('e')
sage: phi = M.endomorphism([[1,-2], [-3,4]]) ; phi
Generic endomorphism of Rank-2 free module M over the Integer Ring
sage: phi.matrix()  # matrix w.r.t the default basis
[ 1 -2]
[-3  4]

Construction with full list of arguments (matrix given a basis different from the default one):

sage: a = M.automorphism() ; a[0,1], a[1,0] = 1, -1
sage: ep = e.new_basis(a, 'ep', latex_symbol="e'")
sage: phi = M.endomorphism([[1,-2], [-3,4]], basis=ep, name='phi',
....:                      latex_name=r'\phi')
sage: phi
Generic endomorphism of Rank-2 free module M over the Integer Ring
sage: phi.matrix(ep)  # the input matrix
[ 1 -2]
[-3  4]
sage: phi.matrix()  # matrix w.r.t the default basis
[4 3]
[2 1]

See FiniteRankFreeModuleMorphism for more documentation.

general_linear_group()

Return the general linear group of self.

If self is the free module \(M\), the general linear group is the group \(\mathrm{GL}(M)\) of automorphisms of \(M\).

OUTPUT:

EXAMPLES:

The general linear group of a rank-3 free module:

sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: e = M.basis('e')
sage: GL = M.general_linear_group() ; GL
General linear group of the Rank-3 free module M over the Integer Ring
sage: GL.category()
Category of groups
sage: type(GL)
<class 'sage.tensor.modules.free_module_linear_group.FreeModuleLinearGroup_with_category'>

There is a unique instance of the general linear group:

sage: M.general_linear_group() is GL
True

The group identity element:

sage: GL.one()
Identity map of the Rank-3 free module M over the Integer Ring
sage: GL.one().matrix(e)
[1 0 0]
[0 1 0]
[0 0 1]

An element:

sage: GL.an_element()
Automorphism of the Rank-3 free module M over the Integer Ring
sage: GL.an_element().matrix(e)
[ 1  0  0]
[ 0 -1  0]
[ 0  0  1]

See FreeModuleLinearGroup for more documentation.

hom(codomain, matrix_rep, bases=None, name=None, latex_name=None)

Homomorphism from self to a free module.

Define a module homomorphism

\[\phi:\ M \longrightarrow N,\]

where \(M\) is self and \(N\) is a free module of finite rank over the same ring \(R\) as self.

Note

This method is a redefinition of sage.structure.parent.Parent.hom() because the latter assumes that self has some privileged generators, while an instance of FiniteRankFreeModule has no privileged basis.

INPUT:

  • codomain – the target module \(N\)
  • matrix_rep – matrix of size rank(N)*rank(M) representing the homomorphism with respect to the pair of bases defined by bases; this entry can actually be any material from which a matrix of elements of \(R\) can be constructed; the columns of matrix_rep must be the components w.r.t. basis_N of the images of the elements of basis_M.
  • bases – (default: None) pair (basis_M, basis_N) defining the matrix representation, basis_M being a basis of self and basis_N a basis of module \(N\) ; if None the pair formed by the default bases of each module is assumed.
  • name – (default: None) string; name given to the homomorphism
  • latex_name – (default: None) string; LaTeX symbol to denote the homomorphism; if None, name will be used.

OUTPUT:

EXAMPLES:

Homomorphism between two free modules over \(\ZZ\):

sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: N = FiniteRankFreeModule(ZZ, 2, name='N')
sage: e = M.basis('e')
sage: f = N.basis('f')
sage: phi = M.hom(N, [[-1,2,0], [5,1,2]]) ; phi
Generic morphism:
  From: Rank-3 free module M over the Integer Ring
  To:   Rank-2 free module N over the Integer Ring

Homomorphism defined by a matrix w.r.t. bases that are not the default ones:

sage: ep = M.basis('ep', latex_symbol=r"e'")
sage: fp = N.basis('fp', latex_symbol=r"f'")
sage: phi = M.hom(N, [[3,2,1], [1,2,3]], bases=(ep, fp)) ; phi
Generic morphism:
  From: Rank-3 free module M over the Integer Ring
  To:   Rank-2 free module N over the Integer Ring

Call with all arguments specified:

sage: phi = M.hom(N, [[3,2,1], [1,2,3]], bases=(ep, fp),
....:             name='phi', latex_name=r'\phi')

The parent:

sage: phi.parent() is Hom(M,N)
True

See class FiniteRankFreeModuleMorphism for more documentation.

identity_map(name='Id', latex_name=None)

Return the identity map of the free module self.

INPUT:

  • name – (string; default: ‘Id’) name given to the identity identity map
  • latex_name – (string; default: None) LaTeX symbol to denote the identity map; if none is provided, the LaTeX symbol is set to ‘mathrm{Id}’ if name is ‘Id’ and to name otherwise

OUTPUT:

EXAMPLES:

Identity map of a rank-3 \(\ZZ\)-module:

sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: e = M.basis('e')
sage: Id = M.identity_map() ; Id
Identity map of the Rank-3 free module M over the Integer Ring
sage: Id.parent()
General linear group of the Rank-3 free module M over the Integer Ring
sage: Id.matrix(e)
[1 0 0]
[0 1 0]
[0 0 1]

The default LaTeX symbol:

sage: latex(Id)
\mathrm{Id}

It can be changed by means of the method set_name():

sage: Id.set_name(latex_name=r'\mathrm{1}_M')
sage: latex(Id)
\mathrm{1}_M

The identity map is actually the identity element of GL(M):

sage: Id is M.general_linear_group().one()
True

It is also a tensor of type-(1,1) on M:

sage: Id.tensor_type()
(1, 1)
sage: Id.comp(e)
Kronecker delta of size 3x3
sage: Id[:]
[1 0 0]
[0 1 0]
[0 0 1]

Example with a LaTeX symbol different from the default one and set at the creation of the object:

sage: N = FiniteRankFreeModule(ZZ, 3, name='N')
sage: f = N.basis('f')
sage: Id = N.identity_map(name='Id_N', latex_name=r'\mathrm{Id}_N')
sage: Id
Identity map of the Rank-3 free module N over the Integer Ring
sage: latex(Id)
\mathrm{Id}_N
irange(start=None)

Single index generator, labelling the elements of a basis of self.

INPUT:

  • start – (default: None) integer; initial value of the index; if none is provided, self._sindex is assumed

OUTPUT:

  • an iterable index, starting from start and ending at self._sindex + self.rank() - 1

EXAMPLES:

Index range on a rank-3 module:

sage: M = FiniteRankFreeModule(ZZ, 3)
sage: list(M.irange())
[0, 1, 2]
sage: list(M.irange(start=1))
[1, 2]

The default starting value corresponds to the parameter start_index provided at the module construction (the default value being 0):

sage: M1 = FiniteRankFreeModule(ZZ, 3, start_index=1)
sage: list(M1.irange())
[1, 2, 3]
sage: M2 = FiniteRankFreeModule(ZZ, 3, start_index=-4)
sage: list(M2.irange())
[-4, -3, -2]
linear_form(name=None, latex_name=None)

Construct a linear form on the free module self.

A linear form on a free module \(M\) over a ring \(R\) is a map \(M \rightarrow R\) that is linear. It can be viewed as a tensor of type \((0,1)\) on \(M\).

INPUT:

  • name – (default: None) string; name given to the linear form
  • latex_name – (default: None) string; LaTeX symbol to denote the linear form; if none is provided, the LaTeX symbol is set to name

OUTPUT:

EXAMPLES:

Linear form on a rank-3 free module:

sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: e = M.basis('e')
sage: a = M.linear_form('A') ; a
Linear form A on the Rank-3 free module M over the Integer Ring
sage: a[:] = [2,-1,3]  # components w.r.t. the module's default basis (e)
sage: a.display()
A = 2 e^0 - e^1 + 3 e^2

A linear form maps module elements to ring elements:

sage: v = M([1,1,1])
sage: a(v)
4

Test of linearity:

sage: u = M([-5,-2,7])
sage: a(3*u - 4*v) == 3*a(u) - 4*a(v)
True

See FreeModuleAltForm for more documentation.

print_bases()

Display the bases that have been defined on the free module self.

Use the method bases() to get the raw list of bases.

EXAMPLES:

Bases on a rank-4 free module:

sage: M = FiniteRankFreeModule(ZZ, 4, name='M', start_index=1)
sage: M.print_bases()
No basis has been defined on the
 Rank-4 free module M over the Integer Ring
sage: e = M.basis('e')
sage: M.print_bases()
Bases defined on the Rank-4 free module M over the Integer Ring:
 - (e_1,e_2,e_3,e_4) (default basis)
sage: f = M.basis('f')
sage: M.print_bases()
Bases defined on the Rank-4 free module M over the Integer Ring:
 - (e_1,e_2,e_3,e_4) (default basis)
 - (f_1,f_2,f_3,f_4)
sage: M.set_default_basis(f)
sage: M.print_bases()
Bases defined on the Rank-4 free module M over the Integer Ring:
 - (e_1,e_2,e_3,e_4)
 - (f_1,f_2,f_3,f_4) (default basis)
rank()

Return the rank of the free module self.

Since the ring over which self is built is assumed to be commutative (and hence has the invariant basis number property), the rank is defined uniquely, as the cardinality of any basis of self.

EXAMPLES:

Rank of free modules over \(\ZZ\):

sage: M = FiniteRankFreeModule(ZZ, 3)
sage: M.rank()
3
sage: M.tensor_module(0,1).rank()
3
sage: M.tensor_module(0,2).rank()
9
sage: M.tensor_module(1,0).rank()
3
sage: M.tensor_module(1,1).rank()
9
sage: M.tensor_module(1,2).rank()
27
sage: M.tensor_module(2,2).rank()
81
set_change_of_basis(basis1, basis2, change_of_basis, compute_inverse=True)

Relates two bases by an automorphism of self.

This updates the internal dictionary self._basis_changes.

INPUT:

  • basis1 – basis 1, denoted \((e_i)\) below
  • basis2 – basis 2, denoted \((f_i)\) below
  • change_of_basis – instance of class FreeModuleAutomorphism describing the automorphism \(P\) that relates the basis \((e_i)\) to the basis \((f_i)\) according to \(f_i = P(e_i)\)
  • compute_inverse (default: True) – if set to True, the inverse automorphism is computed and the change from basis \((f_i)\) to \((e_i)\) is set to it in the internal dictionary self._basis_changes

EXAMPLES:

Defining a change of basis on a rank-2 free module:

sage: M = FiniteRankFreeModule(QQ, 2, name='M')
sage: e = M.basis('e')
sage: f = M.basis('f')
sage: a = M.automorphism()
sage: a[:] = [[1, 2], [-1, 3]]
sage: M.set_change_of_basis(e, f, a)

The change of basis and its inverse have been recorded:

sage: M.change_of_basis(e,f).matrix(e)
[ 1  2]
[-1  3]
sage: M.change_of_basis(f,e).matrix(e)
[ 3/5 -2/5]
[ 1/5  1/5]

and are effective:

sage: f[0].display(e)
f_0 = e_0 - e_1
sage: e[0].display(f)
e_0 = 3/5 f_0 + 1/5 f_1
set_default_basis(basis)

Sets the default basis of self.

The default basis is simply a basis whose name can be skipped in methods requiring a basis as an argument. By default, it is the first basis introduced on the module.

INPUT:

EXAMPLES:

Changing the default basis on a rank-3 free module:

sage: M = FiniteRankFreeModule(ZZ, 3, name='M', start_index=1)
sage: e = M.basis('e') ; e
Basis (e_1,e_2,e_3) on the Rank-3 free module M over the Integer Ring
sage: f =  M.basis('f') ; f
Basis (f_1,f_2,f_3) on the Rank-3 free module M over the Integer Ring
sage: M.default_basis()
Basis (e_1,e_2,e_3) on the Rank-3 free module M over the Integer Ring
sage: M.set_default_basis(f)
sage: M.default_basis()
Basis (f_1,f_2,f_3) on the Rank-3 free module M over the Integer Ring
sym_bilinear_form(name=None, latex_name=None)

Construct a symmetric bilinear form on the free module self.

INPUT:

  • name – (default: None) string; name given to the symmetric bilinear form
  • latex_name – (default: None) string; LaTeX symbol to denote the symmetric bilinear form; if none is provided, the LaTeX symbol is set to name

OUTPUT:

EXAMPLES:

Symmetric bilinear form on a rank-3 free module:

sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: a = M.sym_bilinear_form('A') ; a
Symmetric bilinear form A on the
 Rank-3 free module M over the Integer Ring

A symmetric bilinear form is a type-(0,2) tensor that is symmetric:

sage: a.parent()
Free module of type-(0,2) tensors on the
 Rank-3 free module M over the Integer Ring
sage: a.tensor_type()
(0, 2)
sage: a.tensor_rank()
2
sage: a.symmetries()
symmetry: (0, 1);  no antisymmetry

Components with respect to a given basis:

sage: e = M.basis('e')
sage: a[0,0], a[0,1], a[0,2] = 1, 2, 3
sage: a[1,1], a[1,2] = 4, 5
sage: a[2,2] = 6

Only independent components have been set; the other ones are deduced by symmetry:

sage: a[1,0], a[2,0], a[2,1]
(2, 3, 5)
sage: a[:]
[1 2 3]
[2 4 5]
[3 5 6]

A symmetric bilinear form acts on pairs of module elements:

sage: u = M([2,-1,3]) ; v = M([-2,4,1])
sage: a(u,v)
61
sage: a(v,u) == a(u,v)
True

The sum of two symmetric bilinear forms is another symmetric bilinear form:

sage: b = M.sym_bilinear_form('B')
sage: b[0,0], b[0,1], b[1,2] = -2, 1, -3
sage: s = a + b ; s
Symmetric bilinear form A+B on the
 Rank-3 free module M over the Integer Ring
sage: a[:], b[:], s[:]
(
[1 2 3]  [-2  1  0]  [-1  3  3]
[2 4 5]  [ 1  0 -3]  [ 3  4  2]
[3 5 6], [ 0 -3  0], [ 3  2  6]
)

Adding a symmetric bilinear from with a non-symmetric one results in a generic type-\((0,2)\) tensor:

sage: c = M.tensor((0,2), name='C')
sage: c[0,1] = 4
sage: s = a + c ; s
Type-(0,2) tensor A+C on the Rank-3 free module M over the Integer Ring
sage: s.symmetries()
no symmetry;  no antisymmetry
sage: s[:]
[1 6 3]
[2 4 5]
[3 5 6]

See FreeModuleTensor for more documentation.

tensor(tensor_type, name=None, latex_name=None, sym=None, antisym=None)

Construct a tensor on the free module self.

INPUT:

  • tensor_type – pair (k, l) with k being the contravariant rank and l the covariant rank
  • name – (default: None) string; name given to the tensor
  • latex_name – (default: None) string; LaTeX symbol to denote the tensor; if none is provided, the LaTeX symbol is set to name
  • sym – (default: None) a symmetry or a list of symmetries among the tensor arguments: each symmetry is described by a tuple containing the positions of the involved arguments, with the convention position = 0 for the first argument. For instance:
    • sym = (0,1) for a symmetry between the 1st and 2nd arguments
    • sym = [(0,2), (1,3,4)] for a symmetry between the 1st and 3rd arguments and a symmetry between the 2nd, 4th and 5th arguments.
  • antisym – (default: None) antisymmetry or list of antisymmetries among the arguments, with the same convention as for sym

OUTPUT:

  • instance of FreeModuleTensor representing the tensor defined on self with the provided characteristics

EXAMPLES:

Tensors on a rank-3 free module:

sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: t = M.tensor((1,0), name='t') ; t
Element t of the Rank-3 free module M over the Integer Ring
sage: t = M.tensor((0,1), name='t') ; t
Linear form t on the Rank-3 free module M over the Integer Ring
sage: t = M.tensor((1,1), name='t') ; t
Type-(1,1) tensor t on the Rank-3 free module M over the Integer Ring
sage: t = M.tensor((0,2), name='t', sym=(0,1)) ; t
Symmetric bilinear form t on the
 Rank-3 free module M over the Integer Ring
sage: t = M.tensor((0,2), name='t', antisym=(0,1)) ; t
Alternating form t of degree 2 on the
 Rank-3 free module M over the Integer Ring
sage: t = M.tensor((1,2), name='t') ; t
Type-(1,2) tensor t on the Rank-3 free module M over the Integer Ring

See FreeModuleTensor for more examples and documentation.

tensor_from_comp(tensor_type, comp, name=None, latex_name=None)

Construct a tensor on self from a set of components.

The tensor symmetries are deduced from those of the components.

INPUT:

  • tensor_type – pair (k, l) with k being the contravariant rank and l the covariant rank
  • comp – instance of Components representing the tensor components in a given basis
  • name – (default: None) string; name given to the tensor
  • latex_name – (default: None) string; LaTeX symbol to denote the tensor; if none is provided, the LaTeX symbol is set to name

OUTPUT:

  • instance of FreeModuleTensor representing the tensor defined on self with the provided characteristics.

EXAMPLES:

Construction of a tensor of rank 1:

sage: from sage.tensor.modules.comp import Components, CompWithSym, CompFullySym, CompFullyAntiSym
sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: e = M.basis('e') ; e
Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring
sage: c = Components(ZZ, e, 1)
sage: c[:]
[0, 0, 0]
sage: c[:] = [-1,4,2]
sage: t = M.tensor_from_comp((1,0), c)
sage: t
Element of the Rank-3 free module M over the Integer Ring
sage: t.display(e)
-e_0 + 4 e_1 + 2 e_2
sage: t = M.tensor_from_comp((0,1), c) ; t
Linear form on the Rank-3 free module M over the Integer Ring
sage: t.display(e)
-e^0 + 4 e^1 + 2 e^2

Construction of a tensor of rank 2:

sage: c = CompFullySym(ZZ, e, 2)
sage: c[0,0], c[1,2] = 4, 5
sage: t = M.tensor_from_comp((0,2), c) ; t
Symmetric bilinear form on the
 Rank-3 free module M over the Integer Ring
sage: t.symmetries()
symmetry: (0, 1);  no antisymmetry
sage: t.display(e)
4 e^0*e^0 + 5 e^1*e^2 + 5 e^2*e^1
sage: c = CompFullyAntiSym(ZZ, e, 2)
sage: c[0,1], c[1,2] = 4, 5
sage: t = M.tensor_from_comp((0,2), c) ; t
Alternating form of degree 2 on the
 Rank-3 free module M over the Integer Ring
sage: t.display(e)
4 e^0/\e^1 + 5 e^1/\e^2
tensor_module(k, l)

Return the free module of all tensors of type \((k, l)\) defined on self.

INPUT:

  • k – non-negative integer; the contravariant rank, the tensor type being \((k, l)\)
  • l – non-negative integer; the covariant rank, the tensor type being \((k, l)\)

OUTPUT:

  • instance of TensorFreeModule representing the free module \(T^{(k,l)}(M)\) of type-\((k,l)\) tensors on the free module self

EXAMPLES:

Tensor modules over a free module over \(\ZZ\):

sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: T = M.tensor_module(1,2) ; T
Free module of type-(1,2) tensors on the Rank-3 free module M
 over the Integer Ring
sage: T.an_element()
Type-(1,2) tensor on the Rank-3 free module M over the Integer Ring

Tensor modules are unique:

sage: M.tensor_module(1,2) is T
True

The base module is itself the module of all type-\((1,0)\) tensors:

sage: M.tensor_module(1,0) is M
True

See TensorFreeModule for more documentation.

zero()

Return the zero element of self.

EXAMPLES:

Zero elements of free modules over \(\ZZ\):

sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: M.zero()
Element zero of the Rank-3 free module M over the Integer Ring
sage: M.zero().parent() is M
True
sage: M.zero() is M(0)
True
sage: T = M.tensor_module(1,1)
sage: T.zero()
Type-(1,1) tensor zero on the Rank-3 free module M over the Integer Ring
sage: T.zero().parent() is T
True
sage: T.zero() is T(0)
True

Components of the zero element with respect to some basis:

sage: e = M.basis('e')
sage: M.zero()[e,:]
[0, 0, 0]
sage: all(M.zero()[e,i] == M.base_ring().zero() for i in M.irange())
True
sage: T.zero()[e,:]
[0 0 0]
[0 0 0]
[0 0 0]
sage: M.tensor_module(1,2).zero()[e,:]
[[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
 [[0, 0, 0], [0, 0, 0], [0, 0, 0]],
 [[0, 0, 0], [0, 0, 0], [0, 0, 0]]]