Alternating forms on free modules#

Given a free module \(M\) of finite rank over a commutative ring \(R\) and a positive integer \(p\), an alternating form of degree \(p\) on \(M\) is a map

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

that (i) is multilinear and (ii) vanishes whenever any of two of its arguments are equal. An alternating form of degree \(p\) is a tensor on \(M\) of type \((0,p)\).

Alternating forms are implemented via the class FreeModuleAltForm, which is a subclass of the generic tensor class FreeModuleTensor.

AUTHORS:

  • Eric Gourgoulhon, Michal Bejger (2014-2015): initial version

REFERENCES:

class sage.tensor.modules.free_module_alt_form.FreeModuleAltForm(fmodule, degree, name=None, latex_name=None)[source]#

Bases: FreeModuleTensor

Alternating form on a free module of finite rank over a commutative ring.

This is a Sage element class, the corresponding parent class being ExtPowerDualFreeModule.

INPUT:

  • fmodule – free module \(M\) of finite rank over a commutative ring \(R\), as an instance of FiniteRankFreeModule

  • degree – positive integer; the degree \(p\) 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, name is used

EXAMPLES:

Alternating form of degree 2 on a rank-3 free module:

sage: M = FiniteRankFreeModule(ZZ, 3, name='M', start_index=1)
sage: e = M.basis('e')
sage: a = M.alternating_form(2, name='a') ; a
Alternating form a of degree 2 on the
 Rank-3 free module M over the Integer Ring
sage: type(a)
<class 'sage.tensor.modules.ext_pow_free_module.ExtPowerDualFreeModule_with_category.element_class'>
sage: a.parent()
2nd exterior power of the dual of the Rank-3 free module M over the Integer Ring
sage: a[1,2], a[2,3] = 4, -3
sage: a.display(e)
a = 4 e^1∧e^2 - 3 e^2∧e^3
>>> from sage.all import *
>>> M = FiniteRankFreeModule(ZZ, Integer(3), name='M', start_index=Integer(1))
>>> e = M.basis('e')
>>> a = M.alternating_form(Integer(2), name='a') ; a
Alternating form a of degree 2 on the
 Rank-3 free module M over the Integer Ring
>>> type(a)
<class 'sage.tensor.modules.ext_pow_free_module.ExtPowerDualFreeModule_with_category.element_class'>
>>> a.parent()
2nd exterior power of the dual of the Rank-3 free module M over the Integer Ring
>>> a[Integer(1),Integer(2)], a[Integer(2),Integer(3)] = Integer(4), -Integer(3)
>>> a.display(e)
a = 4 e^1∧e^2 - 3 e^2∧e^3

The alternating form acting on the basis elements:

sage: a(e[1],e[2])
4
sage: a(e[1],e[3])
0
sage: a(e[2],e[3])
-3
sage: a(e[2],e[1])
-4
>>> from sage.all import *
>>> a(e[Integer(1)],e[Integer(2)])
4
>>> a(e[Integer(1)],e[Integer(3)])
0
>>> a(e[Integer(2)],e[Integer(3)])
-3
>>> a(e[Integer(2)],e[Integer(1)])
-4

An alternating form of degree 1 is a linear form:

sage: b = M.linear_form('b') ; b
Linear form b on the Rank-3 free module M over the Integer Ring
sage: b[:] = [2,-1,3]  # components w.r.t. the module's default basis (e)
>>> from sage.all import *
>>> b = M.linear_form('b') ; b
Linear form b on the Rank-3 free module M over the Integer Ring
>>> b[:] = [Integer(2),-Integer(1),Integer(3)]  # components w.r.t. the module's default basis (e)

A linear form is a tensor of type \((0,1)\):

sage: b.tensor_type()
(0, 1)
>>> from sage.all import *
>>> b.tensor_type()
(0, 1)

It is an element of the dual module:

sage: b.parent()
Dual of the Rank-3 free module M over the Integer Ring
sage: b.parent() is M.dual()
True
>>> from sage.all import *
>>> b.parent()
Dual of the Rank-3 free module M over the Integer Ring
>>> b.parent() is M.dual()
True

The members of a dual basis are linear forms:

sage: e.dual_basis()[1]
Linear form e^1 on the Rank-3 free module M over the Integer Ring
sage: e.dual_basis()[2]
Linear form e^2 on the Rank-3 free module M over the Integer Ring
sage: e.dual_basis()[3]
Linear form e^3 on the Rank-3 free module M over the Integer Ring
>>> from sage.all import *
>>> e.dual_basis()[Integer(1)]
Linear form e^1 on the Rank-3 free module M over the Integer Ring
>>> e.dual_basis()[Integer(2)]
Linear form e^2 on the Rank-3 free module M over the Integer Ring
>>> e.dual_basis()[Integer(3)]
Linear form e^3 on the Rank-3 free module M over the Integer Ring

Any linear form is expanded onto them:

sage: b.display(e)
b = 2 e^1 - e^2 + 3 e^3
>>> from sage.all import *
>>> b.display(e)
b = 2 e^1 - e^2 + 3 e^3

In the above example, an equivalent writing would have been b.display(), since the basis e is the module’s default basis. A linear form maps module elements to ring elements:

sage: v = M([1,1,1])
sage: b(v)
4
sage: b(v) in M.base_ring()
True
>>> from sage.all import *
>>> v = M([Integer(1),Integer(1),Integer(1)])
>>> b(v)
4
>>> b(v) in M.base_ring()
True

Test of linearity:

sage: u = M([-5,-2,7])
sage: b(3*u - 4*v) == 3*b(u) - 4*b(v)
True
>>> from sage.all import *
>>> u = M([-Integer(5),-Integer(2),Integer(7)])
>>> b(Integer(3)*u - Integer(4)*v) == Integer(3)*b(u) - Integer(4)*b(v)
True

The standard tensor operations apply to alternating forms, like the extraction of components with respect to a given basis:

sage: a[e,1,2]
4
sage: a[1,2]  # since e is the module's default basis
4
sage: all( a[i,j] == - a[j,i] for i in {1,2,3} for j in {1,2,3} )
True
>>> from sage.all import *
>>> a[e,Integer(1),Integer(2)]
4
>>> a[Integer(1),Integer(2)]  # since e is the module's default basis
4
>>> all( a[i,j] == - a[j,i] for i in {Integer(1),Integer(2),Integer(3)} for j in {Integer(1),Integer(2),Integer(3)} )
True

the tensor product:

sage: c = b*b ; c
Symmetric bilinear form  b⊗b on the Rank-3 free module M over the
 Integer Ring
sage: c.parent()
Free module of type-(0,2) tensors on the Rank-3 free module M over the
 Integer Ring
sage: c.display(e)
b⊗b = 4 e^1⊗e^1 - 2 e^1⊗e^2 + 6 e^1⊗e^3 - 2 e^2⊗e^1 + e^2⊗e^2
 - 3 e^2⊗e^3 + 6 e^3⊗e^1 - 3 e^3⊗e^2 + 9 e^3⊗e^3
>>> from sage.all import *
>>> c = b*b ; c
Symmetric bilinear form  b⊗b on the Rank-3 free module M over the
 Integer Ring
>>> c.parent()
Free module of type-(0,2) tensors on the Rank-3 free module M over the
 Integer Ring
>>> c.display(e)
b⊗b = 4 e^1⊗e^1 - 2 e^1⊗e^2 + 6 e^1⊗e^3 - 2 e^2⊗e^1 + e^2⊗e^2
 - 3 e^2⊗e^3 + 6 e^3⊗e^1 - 3 e^3⊗e^2 + 9 e^3⊗e^3

the contractions:

sage: s = a.contract(v) ; s
Linear form on the Rank-3 free module M over the Integer Ring
sage: s.parent()
Dual of the Rank-3 free module M over the Integer Ring
sage: s.display(e)
4 e^1 - 7 e^2 + 3 e^3
>>> from sage.all import *
>>> s = a.contract(v) ; s
Linear form on the Rank-3 free module M over the Integer Ring
>>> s.parent()
Dual of the Rank-3 free module M over the Integer Ring
>>> s.display(e)
4 e^1 - 7 e^2 + 3 e^3

or tensor arithmetics:

sage: s = 3*a + c ; s
Type-(0,2) tensor on the Rank-3 free module M over the Integer Ring
sage: s.parent()
Free module of type-(0,2) tensors on the Rank-3 free module M over the
 Integer Ring
sage: s.display(e)
4 e^1⊗e^1 + 10 e^1⊗e^2 + 6 e^1⊗e^3 - 14 e^2⊗e^1 + e^2⊗e^2
 - 12 e^2⊗e^3 + 6 e^3⊗e^1 + 6 e^3⊗e^2 + 9 e^3⊗e^3
>>> from sage.all import *
>>> s = Integer(3)*a + c ; s
Type-(0,2) tensor on the Rank-3 free module M over the Integer Ring
>>> s.parent()
Free module of type-(0,2) tensors on the Rank-3 free module M over the
 Integer Ring
>>> s.display(e)
4 e^1⊗e^1 + 10 e^1⊗e^2 + 6 e^1⊗e^3 - 14 e^2⊗e^1 + e^2⊗e^2
 - 12 e^2⊗e^3 + 6 e^3⊗e^1 + 6 e^3⊗e^2 + 9 e^3⊗e^3

Note that tensor arithmetics preserves the alternating character if both operands are alternating:

sage: s = a - 2*a ; s
Alternating form of degree 2 on the Rank-3 free module M over the
 Integer Ring
sage: s.parent() # note the difference with s = 3*a + c above
2nd exterior power of the dual of the Rank-3 free module M over the
 Integer Ring
sage: s == -a
True
>>> from sage.all import *
>>> s = a - Integer(2)*a ; s
Alternating form of degree 2 on the Rank-3 free module M over the
 Integer Ring
>>> s.parent() # note the difference with s = 3*a + c above
2nd exterior power of the dual of the Rank-3 free module M over the
 Integer Ring
>>> s == -a
True

An operation specific to alternating forms is of course the exterior product:

sage: s = a.wedge(b) ; s
Alternating form a∧b of degree 3 on the Rank-3 free module M over the
 Integer Ring
sage: s.parent()
3rd exterior power of the dual of the Rank-3 free module M over the
 Integer Ring
sage: s.display(e)
a∧b = 6 e^1∧e^2∧e^3
sage: s[1,2,3] == a[1,2]*b[3] + a[2,3]*b[1] + a[3,1]*b[2]
True
>>> from sage.all import *
>>> s = a.wedge(b) ; s
Alternating form a∧b of degree 3 on the Rank-3 free module M over the
 Integer Ring
>>> s.parent()
3rd exterior power of the dual of the Rank-3 free module M over the
 Integer Ring
>>> s.display(e)
a∧b = 6 e^1∧e^2∧e^3
>>> s[Integer(1),Integer(2),Integer(3)] == a[Integer(1),Integer(2)]*b[Integer(3)] + a[Integer(2),Integer(3)]*b[Integer(1)] + a[Integer(3),Integer(1)]*b[Integer(2)]
True

The exterior product is nilpotent on linear forms:

sage: s = b.wedge(b) ; s
Alternating form zero of degree 2 on the Rank-3 free module M over the
 Integer Ring
sage: s.display(e)
zero = 0
>>> from sage.all import *
>>> s = b.wedge(b) ; s
Alternating form zero of degree 2 on the Rank-3 free module M over the
 Integer Ring
>>> s.display(e)
zero = 0
degree()[source]#

Return the degree of self.

EXAMPLES:

sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: a = M.alternating_form(2, name='a')
sage: a.degree()
2
>>> from sage.all import *
>>> M = FiniteRankFreeModule(ZZ, Integer(3), name='M')
>>> a = M.alternating_form(Integer(2), name='a')
>>> a.degree()
2
disp(basis=None, format_spec=None)[source]#

Display the alternating form self in terms of its expansion w.r.t. a given module basis.

The expansion is actually performed onto exterior products of elements of the cobasis (dual basis) associated with basis (see examples below). The output is either text-formatted (console mode) or LaTeX-formatted (notebook mode).

INPUT:

  • basis – (default: None) basis of the free module with respect to which the alternating form is expanded; if none is provided, the module’s default basis is assumed

  • format_spec – (default: None) format specification passed to self._fmodule._output_formatter to format the output

EXAMPLES:

Display of an alternating form of degree 1 (linear form) on a rank-3 free module:

sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: e = M.basis('e')
sage: e.dual_basis()
Dual basis (e^0,e^1,e^2) on the Rank-3 free module M over the Integer Ring
sage: a = M.linear_form('a', latex_name=r'\alpha')
sage: a[:] = [1,-3,4]
sage: a.display(e)
a = e^0 - 3 e^1 + 4 e^2
sage: a.display()  # a shortcut since e is M's default basis
a = e^0 - 3 e^1 + 4 e^2
sage: latex(a.display())  # display in the notebook
\alpha = e^{0} -3 e^{1} + 4 e^{2}
>>> from sage.all import *
>>> M = FiniteRankFreeModule(ZZ, Integer(3), name='M')
>>> e = M.basis('e')
>>> e.dual_basis()
Dual basis (e^0,e^1,e^2) on the Rank-3 free module M over the Integer Ring
>>> a = M.linear_form('a', latex_name=r'\alpha')
>>> a[:] = [Integer(1),-Integer(3),Integer(4)]
>>> a.display(e)
a = e^0 - 3 e^1 + 4 e^2
>>> a.display()  # a shortcut since e is M's default basis
a = e^0 - 3 e^1 + 4 e^2
>>> latex(a.display())  # display in the notebook
\alpha = e^{0} -3 e^{1} + 4 e^{2}

A shortcut is disp():

sage: a.disp()
a = e^0 - 3 e^1 + 4 e^2
>>> from sage.all import *
>>> a.disp()
a = e^0 - 3 e^1 + 4 e^2

Display of an alternating form of degree 2 on a rank-3 free module:

sage: b = M.alternating_form(2, 'b', latex_name=r'\beta')
sage: b[0,1], b[0,2], b[1,2] = 3, 2, -1
sage: b.display()
b = 3 e^0∧e^1 + 2 e^0∧e^2 - e^1∧e^2
sage: latex(b.display())  # display in the notebook
\beta = 3 e^{0}\wedge e^{1} + 2 e^{0}\wedge e^{2} -e^{1}\wedge e^{2}
>>> from sage.all import *
>>> b = M.alternating_form(Integer(2), 'b', latex_name=r'\beta')
>>> b[Integer(0),Integer(1)], b[Integer(0),Integer(2)], b[Integer(1),Integer(2)] = Integer(3), Integer(2), -Integer(1)
>>> b.display()
b = 3 e^0∧e^1 + 2 e^0∧e^2 - e^1∧e^2
>>> latex(b.display())  # display in the notebook
\beta = 3 e^{0}\wedge e^{1} + 2 e^{0}\wedge e^{2} -e^{1}\wedge e^{2}

Display of an alternating form of degree 3 on a rank-3 free module:

sage: c = M.alternating_form(3, 'c')
sage: c[0,1,2] = 4
sage: c.display()
c = 4 e^0∧e^1∧e^2
sage: latex(c.display())
c = 4 e^{0}\wedge e^{1}\wedge e^{2}
>>> from sage.all import *
>>> c = M.alternating_form(Integer(3), 'c')
>>> c[Integer(0),Integer(1),Integer(2)] = Integer(4)
>>> c.display()
c = 4 e^0∧e^1∧e^2
>>> latex(c.display())
c = 4 e^{0}\wedge e^{1}\wedge e^{2}

Display of a vanishing alternating form:

sage: c[0,1,2] = 0  # the only independent component set to zero
sage: c.is_zero()
True
sage: c.display()
c = 0
sage: latex(c.display())
c = 0
sage: c[0,1,2] = 4  # value restored for what follows
>>> from sage.all import *
>>> c[Integer(0),Integer(1),Integer(2)] = Integer(0)  # the only independent component set to zero
>>> c.is_zero()
True
>>> c.display()
c = 0
>>> latex(c.display())
c = 0
>>> c[Integer(0),Integer(1),Integer(2)] = Integer(4)  # value restored for what follows

Display in a basis which is not the default one:

sage: aut = M.automorphism(matrix=[[0,1,0], [0,0,-1], [1,0,0]],
....:                      basis=e)
sage: f = e.new_basis(aut, 'f')
sage: a.display(f)
a = 4 f^0 + f^1 + 3 f^2
sage: a.disp(f)     # shortcut notation
a = 4 f^0 + f^1 + 3 f^2
sage: b.display(f)
b = -2 f^0∧f^1 - f^0∧f^2 - 3 f^1∧f^2
sage: c.display(f)
c = -4 f^0∧f^1∧f^2
>>> from sage.all import *
>>> aut = M.automorphism(matrix=[[Integer(0),Integer(1),Integer(0)], [Integer(0),Integer(0),-Integer(1)], [Integer(1),Integer(0),Integer(0)]],
...                      basis=e)
>>> f = e.new_basis(aut, 'f')
>>> a.display(f)
a = 4 f^0 + f^1 + 3 f^2
>>> a.disp(f)     # shortcut notation
a = 4 f^0 + f^1 + 3 f^2
>>> b.display(f)
b = -2 f^0∧f^1 - f^0∧f^2 - 3 f^1∧f^2
>>> c.display(f)
c = -4 f^0∧f^1∧f^2

The output format can be set via the argument output_formatter passed at the module construction:

sage: N = FiniteRankFreeModule(QQ, 3, name='N', start_index=1,
....:                   output_formatter=Rational.numerical_approx)
sage: e = N.basis('e')
sage: b = N.alternating_form(2, 'b')
sage: b[1,2], b[1,3], b[2,3] = 1/3, 5/2, 4
sage: b.display()  # default format (53 bits of precision)
b = 0.333333333333333 e^1∧e^2 + 2.50000000000000 e^1∧e^3
 + 4.00000000000000 e^2∧e^3
>>> from sage.all import *
>>> N = FiniteRankFreeModule(QQ, Integer(3), name='N', start_index=Integer(1),
...                   output_formatter=Rational.numerical_approx)
>>> e = N.basis('e')
>>> b = N.alternating_form(Integer(2), 'b')
>>> b[Integer(1),Integer(2)], b[Integer(1),Integer(3)], b[Integer(2),Integer(3)] = Integer(1)/Integer(3), Integer(5)/Integer(2), Integer(4)
>>> b.display()  # default format (53 bits of precision)
b = 0.333333333333333 e^1∧e^2 + 2.50000000000000 e^1∧e^3
 + 4.00000000000000 e^2∧e^3

The output format is then controlled by the argument format_spec of the method display():

sage: b.display(format_spec=10)  # 10 bits of precision
b = 0.33 e^1∧e^2 + 2.5 e^1∧e^3 + 4.0 e^2∧e^3
>>> from sage.all import *
>>> b.display(format_spec=Integer(10))  # 10 bits of precision
b = 0.33 e^1∧e^2 + 2.5 e^1∧e^3 + 4.0 e^2∧e^3

Check that the bug reported in Issue #22520 is fixed:

sage: # needs sage.symbolic
sage: M = FiniteRankFreeModule(SR, 2, name='M')
sage: e = M.basis('e')
sage: a = M.alternating_form(2)
sage: a[0,1] = SR.var('t', domain='real')
sage: a.display()
t e^0∧e^1
>>> from sage.all import *
>>> # needs sage.symbolic
>>> M = FiniteRankFreeModule(SR, Integer(2), name='M')
>>> e = M.basis('e')
>>> a = M.alternating_form(Integer(2))
>>> a[Integer(0),Integer(1)] = SR.var('t', domain='real')
>>> a.display()
t e^0∧e^1
display(basis=None, format_spec=None)[source]#

Display the alternating form self in terms of its expansion w.r.t. a given module basis.

The expansion is actually performed onto exterior products of elements of the cobasis (dual basis) associated with basis (see examples below). The output is either text-formatted (console mode) or LaTeX-formatted (notebook mode).

INPUT:

  • basis – (default: None) basis of the free module with respect to which the alternating form is expanded; if none is provided, the module’s default basis is assumed

  • format_spec – (default: None) format specification passed to self._fmodule._output_formatter to format the output

EXAMPLES:

Display of an alternating form of degree 1 (linear form) on a rank-3 free module:

sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: e = M.basis('e')
sage: e.dual_basis()
Dual basis (e^0,e^1,e^2) on the Rank-3 free module M over the Integer Ring
sage: a = M.linear_form('a', latex_name=r'\alpha')
sage: a[:] = [1,-3,4]
sage: a.display(e)
a = e^0 - 3 e^1 + 4 e^2
sage: a.display()  # a shortcut since e is M's default basis
a = e^0 - 3 e^1 + 4 e^2
sage: latex(a.display())  # display in the notebook
\alpha = e^{0} -3 e^{1} + 4 e^{2}
>>> from sage.all import *
>>> M = FiniteRankFreeModule(ZZ, Integer(3), name='M')
>>> e = M.basis('e')
>>> e.dual_basis()
Dual basis (e^0,e^1,e^2) on the Rank-3 free module M over the Integer Ring
>>> a = M.linear_form('a', latex_name=r'\alpha')
>>> a[:] = [Integer(1),-Integer(3),Integer(4)]
>>> a.display(e)
a = e^0 - 3 e^1 + 4 e^2
>>> a.display()  # a shortcut since e is M's default basis
a = e^0 - 3 e^1 + 4 e^2
>>> latex(a.display())  # display in the notebook
\alpha = e^{0} -3 e^{1} + 4 e^{2}

A shortcut is disp():

sage: a.disp()
a = e^0 - 3 e^1 + 4 e^2
>>> from sage.all import *
>>> a.disp()
a = e^0 - 3 e^1 + 4 e^2

Display of an alternating form of degree 2 on a rank-3 free module:

sage: b = M.alternating_form(2, 'b', latex_name=r'\beta')
sage: b[0,1], b[0,2], b[1,2] = 3, 2, -1
sage: b.display()
b = 3 e^0∧e^1 + 2 e^0∧e^2 - e^1∧e^2
sage: latex(b.display())  # display in the notebook
\beta = 3 e^{0}\wedge e^{1} + 2 e^{0}\wedge e^{2} -e^{1}\wedge e^{2}
>>> from sage.all import *
>>> b = M.alternating_form(Integer(2), 'b', latex_name=r'\beta')
>>> b[Integer(0),Integer(1)], b[Integer(0),Integer(2)], b[Integer(1),Integer(2)] = Integer(3), Integer(2), -Integer(1)
>>> b.display()
b = 3 e^0∧e^1 + 2 e^0∧e^2 - e^1∧e^2
>>> latex(b.display())  # display in the notebook
\beta = 3 e^{0}\wedge e^{1} + 2 e^{0}\wedge e^{2} -e^{1}\wedge e^{2}

Display of an alternating form of degree 3 on a rank-3 free module:

sage: c = M.alternating_form(3, 'c')
sage: c[0,1,2] = 4
sage: c.display()
c = 4 e^0∧e^1∧e^2
sage: latex(c.display())
c = 4 e^{0}\wedge e^{1}\wedge e^{2}
>>> from sage.all import *
>>> c = M.alternating_form(Integer(3), 'c')
>>> c[Integer(0),Integer(1),Integer(2)] = Integer(4)
>>> c.display()
c = 4 e^0∧e^1∧e^2
>>> latex(c.display())
c = 4 e^{0}\wedge e^{1}\wedge e^{2}

Display of a vanishing alternating form:

sage: c[0,1,2] = 0  # the only independent component set to zero
sage: c.is_zero()
True
sage: c.display()
c = 0
sage: latex(c.display())
c = 0
sage: c[0,1,2] = 4  # value restored for what follows
>>> from sage.all import *
>>> c[Integer(0),Integer(1),Integer(2)] = Integer(0)  # the only independent component set to zero
>>> c.is_zero()
True
>>> c.display()
c = 0
>>> latex(c.display())
c = 0
>>> c[Integer(0),Integer(1),Integer(2)] = Integer(4)  # value restored for what follows

Display in a basis which is not the default one:

sage: aut = M.automorphism(matrix=[[0,1,0], [0,0,-1], [1,0,0]],
....:                      basis=e)
sage: f = e.new_basis(aut, 'f')
sage: a.display(f)
a = 4 f^0 + f^1 + 3 f^2
sage: a.disp(f)     # shortcut notation
a = 4 f^0 + f^1 + 3 f^2
sage: b.display(f)
b = -2 f^0∧f^1 - f^0∧f^2 - 3 f^1∧f^2
sage: c.display(f)
c = -4 f^0∧f^1∧f^2
>>> from sage.all import *
>>> aut = M.automorphism(matrix=[[Integer(0),Integer(1),Integer(0)], [Integer(0),Integer(0),-Integer(1)], [Integer(1),Integer(0),Integer(0)]],
...                      basis=e)
>>> f = e.new_basis(aut, 'f')
>>> a.display(f)
a = 4 f^0 + f^1 + 3 f^2
>>> a.disp(f)     # shortcut notation
a = 4 f^0 + f^1 + 3 f^2
>>> b.display(f)
b = -2 f^0∧f^1 - f^0∧f^2 - 3 f^1∧f^2
>>> c.display(f)
c = -4 f^0∧f^1∧f^2

The output format can be set via the argument output_formatter passed at the module construction:

sage: N = FiniteRankFreeModule(QQ, 3, name='N', start_index=1,
....:                   output_formatter=Rational.numerical_approx)
sage: e = N.basis('e')
sage: b = N.alternating_form(2, 'b')
sage: b[1,2], b[1,3], b[2,3] = 1/3, 5/2, 4
sage: b.display()  # default format (53 bits of precision)
b = 0.333333333333333 e^1∧e^2 + 2.50000000000000 e^1∧e^3
 + 4.00000000000000 e^2∧e^3
>>> from sage.all import *
>>> N = FiniteRankFreeModule(QQ, Integer(3), name='N', start_index=Integer(1),
...                   output_formatter=Rational.numerical_approx)
>>> e = N.basis('e')
>>> b = N.alternating_form(Integer(2), 'b')
>>> b[Integer(1),Integer(2)], b[Integer(1),Integer(3)], b[Integer(2),Integer(3)] = Integer(1)/Integer(3), Integer(5)/Integer(2), Integer(4)
>>> b.display()  # default format (53 bits of precision)
b = 0.333333333333333 e^1∧e^2 + 2.50000000000000 e^1∧e^3
 + 4.00000000000000 e^2∧e^3

The output format is then controlled by the argument format_spec of the method display():

sage: b.display(format_spec=10)  # 10 bits of precision
b = 0.33 e^1∧e^2 + 2.5 e^1∧e^3 + 4.0 e^2∧e^3
>>> from sage.all import *
>>> b.display(format_spec=Integer(10))  # 10 bits of precision
b = 0.33 e^1∧e^2 + 2.5 e^1∧e^3 + 4.0 e^2∧e^3

Check that the bug reported in Issue #22520 is fixed:

sage: # needs sage.symbolic
sage: M = FiniteRankFreeModule(SR, 2, name='M')
sage: e = M.basis('e')
sage: a = M.alternating_form(2)
sage: a[0,1] = SR.var('t', domain='real')
sage: a.display()
t e^0∧e^1
>>> from sage.all import *
>>> # needs sage.symbolic
>>> M = FiniteRankFreeModule(SR, Integer(2), name='M')
>>> e = M.basis('e')
>>> a = M.alternating_form(Integer(2))
>>> a[Integer(0),Integer(1)] = SR.var('t', domain='real')
>>> a.display()
t e^0∧e^1
interior_product(alt_tensor)[source]#

Interior product with an alternating contravariant tensor.

If self is an alternating form \(A\) of degree \(p\) and \(B\) is an alternating contravariant tensor of degree \(q\geq p\) on the same free module, the interior product of \(A\) by \(B\) is the alternating contravariant tensor \(\iota_A B\) of degree \(q-p\) defined by

\[(\iota_A B)^{i_1\ldots i_{q-p}} = A_{k_1\ldots k_p} B^{k_1\ldots k_p i_1\ldots i_{q-p}}\]

Note

A.interior_product(B) yields the same result as A.contract(0,..., p-1, B, 0,..., p-1) (cf. contract()), but interior_product is more efficient, the alternating character of \(A\) being not used to reduce the computation in contract()

INPUT:

  • alt_tensor – alternating contravariant tensor \(B\) (instance of AlternatingContrTensor); the degree of \(B\) must be at least equal to the degree of self

OUTPUT:

  • element of the base ring (case \(p=q\)) or AlternatingContrTensor (case \(p<q\)) representing the interior product \(\iota_A B\), where \(A\) is self

See also

interior_product() for the interior product of an alternating contravariant tensor by an alternating form

EXAMPLES:

Let us consider a rank-3 free module:

sage: M = FiniteRankFreeModule(ZZ, 3, name='M', start_index=1)
sage: e = M.basis('e')
>>> from sage.all import *
>>> M = FiniteRankFreeModule(ZZ, Integer(3), name='M', start_index=Integer(1))
>>> e = M.basis('e')

and various interior products on it, starting with a linear form (p=1) and a module element (q=1):

sage: a = M.linear_form(name='A')
sage: a[:] = [-2, 4, 3]
sage: b = M([3, 1, 5], basis=e, name='B')
sage: c = a.interior_product(b); c
13
sage: c == a.contract(b)
True
>>> from sage.all import *
>>> a = M.linear_form(name='A')
>>> a[:] = [-Integer(2), Integer(4), Integer(3)]
>>> b = M([Integer(3), Integer(1), Integer(5)], basis=e, name='B')
>>> c = a.interior_product(b); c
13
>>> c == a.contract(b)
True

Case p=1 and q=2:

sage: b = M.alternating_contravariant_tensor(2, name='B')
sage: b[1,2], b[1,3], b[2,3] = 5, 2, 3
sage: c = a.interior_product(b); c
Element i_A B of the Rank-3 free module M over the Integer Ring
sage: c.display()
i_A B = -26 e_1 - 19 e_2 + 8 e_3
sage: latex(c)
\iota_{A} B
sage: c == a.contract(b)
True
>>> from sage.all import *
>>> b = M.alternating_contravariant_tensor(Integer(2), name='B')
>>> b[Integer(1),Integer(2)], b[Integer(1),Integer(3)], b[Integer(2),Integer(3)] = Integer(5), Integer(2), Integer(3)
>>> c = a.interior_product(b); c
Element i_A B of the Rank-3 free module M over the Integer Ring
>>> c.display()
i_A B = -26 e_1 - 19 e_2 + 8 e_3
>>> latex(c)
\iota_{A} B
>>> c == a.contract(b)
True

Case p=1 and q=3:

sage: b = M.alternating_contravariant_tensor(3, name='B')
sage: b[1,2,3] = 5
sage: c = a.interior_product(b); c
Alternating contravariant tensor i_A B of degree 2 on the Rank-3 free module M over the Integer Ring
sage: c.display()
i_A B = 15 e_1∧e_2 - 20 e_1∧e_3 - 10 e_2∧e_3
sage: c == a.contract(b)
True
>>> from sage.all import *
>>> b = M.alternating_contravariant_tensor(Integer(3), name='B')
>>> b[Integer(1),Integer(2),Integer(3)] = Integer(5)
>>> c = a.interior_product(b); c
Alternating contravariant tensor i_A B of degree 2 on the Rank-3 free module M over the Integer Ring
>>> c.display()
i_A B = 15 e_1∧e_2 - 20 e_1∧e_3 - 10 e_2∧e_3
>>> c == a.contract(b)
True

Case p=2 and q=2:

sage: a = M.alternating_form(2, name='A')
sage: a[1,2], a[1,3], a[2,3] = 2, -3, 1
sage: b = M.alternating_contravariant_tensor(2, name='B')
sage: b[1,2], b[1,3], b[2,3] = 5, 2, 3
sage: c = a.interior_product(b); c
14
sage: c == a.contract(0, 1, b, 0, 1)   # contraction on all indices of a
True
>>> from sage.all import *
>>> a = M.alternating_form(Integer(2), name='A')
>>> a[Integer(1),Integer(2)], a[Integer(1),Integer(3)], a[Integer(2),Integer(3)] = Integer(2), -Integer(3), Integer(1)
>>> b = M.alternating_contravariant_tensor(Integer(2), name='B')
>>> b[Integer(1),Integer(2)], b[Integer(1),Integer(3)], b[Integer(2),Integer(3)] = Integer(5), Integer(2), Integer(3)
>>> c = a.interior_product(b); c
14
>>> c == a.contract(Integer(0), Integer(1), b, Integer(0), Integer(1))   # contraction on all indices of a
True

Case p=2 and q=3:

sage: b = M.alternating_contravariant_tensor(3, name='B')
sage: b[1,2,3] = 5
sage: c = a.interior_product(b); c
Element i_A B of the Rank-3 free module M over the Integer Ring
sage: c.display()
i_A B = 10 e_1 + 30 e_2 + 20 e_3
sage: c == a.contract(0, 1, b, 0, 1)
True
>>> from sage.all import *
>>> b = M.alternating_contravariant_tensor(Integer(3), name='B')
>>> b[Integer(1),Integer(2),Integer(3)] = Integer(5)
>>> c = a.interior_product(b); c
Element i_A B of the Rank-3 free module M over the Integer Ring
>>> c.display()
i_A B = 10 e_1 + 30 e_2 + 20 e_3
>>> c == a.contract(Integer(0), Integer(1), b, Integer(0), Integer(1))
True

Case p=3 and q=3:

sage: a = M.alternating_form(3, name='A')
sage: a[1,2,3] = -2
sage: c = a.interior_product(b); c
-60
sage: c  == a.contract(0, 1, 2, b, 0, 1, 2)
True
>>> from sage.all import *
>>> a = M.alternating_form(Integer(3), name='A')
>>> a[Integer(1),Integer(2),Integer(3)] = -Integer(2)
>>> c = a.interior_product(b); c
-60
>>> c  == a.contract(Integer(0), Integer(1), Integer(2), b, Integer(0), Integer(1), Integer(2))
True
wedge(other)[source]#

Exterior product of self with the alternating form other.

INPUT:

  • other – an alternating form

OUTPUT:

EXAMPLES:

Exterior product of two linear forms:

sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
sage: e = M.basis('e')
sage: a = M.linear_form('A')
sage: a[:] = [1,-3,4]
sage: b = M.linear_form('B')
sage: b[:] = [2,-1,2]
sage: c = a.wedge(b) ; c
Alternating form A∧B of degree 2 on the Rank-3 free module M
 over the Integer Ring
sage: c.display()
A∧B = 5 e^0∧e^1 - 6 e^0∧e^2 - 2 e^1∧e^2
sage: latex(c)
A\wedge B
sage: latex(c.display())
A\wedge B = 5 e^{0}\wedge e^{1} -6 e^{0}\wedge e^{2} -2 e^{1}\wedge e^{2}
>>> from sage.all import *
>>> M = FiniteRankFreeModule(ZZ, Integer(3), name='M')
>>> e = M.basis('e')
>>> a = M.linear_form('A')
>>> a[:] = [Integer(1),-Integer(3),Integer(4)]
>>> b = M.linear_form('B')
>>> b[:] = [Integer(2),-Integer(1),Integer(2)]
>>> c = a.wedge(b) ; c
Alternating form A∧B of degree 2 on the Rank-3 free module M
 over the Integer Ring
>>> c.display()
A∧B = 5 e^0∧e^1 - 6 e^0∧e^2 - 2 e^1∧e^2
>>> latex(c)
A\wedge B
>>> latex(c.display())
A\wedge B = 5 e^{0}\wedge e^{1} -6 e^{0}\wedge e^{2} -2 e^{1}\wedge e^{2}

Test of the computation:

sage: a.wedge(b) == a*b - b*a
True
>>> from sage.all import *
>>> a.wedge(b) == a*b - b*a
True

Exterior product of a linear form and an alternating form of degree 2:

sage: d = M.linear_form('D')
sage: d[:] = [-1,2,4]
sage: s = d.wedge(c) ; s
Alternating form D∧A∧B of degree 3 on the Rank-3 free module M
 over the Integer Ring
sage: s.display()
D∧A∧B = 34 e^0∧e^1∧e^2
>>> from sage.all import *
>>> d = M.linear_form('D')
>>> d[:] = [-Integer(1),Integer(2),Integer(4)]
>>> s = d.wedge(c) ; s
Alternating form D∧A∧B of degree 3 on the Rank-3 free module M
 over the Integer Ring
>>> s.display()
D∧A∧B = 34 e^0∧e^1∧e^2

Test of the computation:

sage: s[0,1,2] == d[0]*c[1,2] + d[1]*c[2,0] + d[2]*c[0,1]
True
>>> from sage.all import *
>>> s[Integer(0),Integer(1),Integer(2)] == d[Integer(0)]*c[Integer(1),Integer(2)] + d[Integer(1)]*c[Integer(2),Integer(0)] + d[Integer(2)]*c[Integer(0),Integer(1)]
True

Let us check that the exterior product is associative:

sage: d.wedge(a.wedge(b)) == (d.wedge(a)).wedge(b)
True
>>> from sage.all import *
>>> d.wedge(a.wedge(b)) == (d.wedge(a)).wedge(b)
True

and that it is graded anticommutative:

sage: a.wedge(b) == - b.wedge(a)
True
sage: d.wedge(c) == c.wedge(d)
True
>>> from sage.all import *
>>> a.wedge(b) == - b.wedge(a)
True
>>> d.wedge(c) == c.wedge(d)
True