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

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


The alternating form acting on the basis elements:

sage: a(e,e)
4
sage: a(e,e)
0
sage: a(e,e)
-3
sage: a(e,e)
-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)


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

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


The members of a dual basis are linear forms:

sage: e.dual_basis()
Linear form e^1 on the Rank-3 free module M over the Integer Ring
sage: e.dual_basis()
Linear form e^2 on the Rank-3 free module M over the Integer Ring
sage: e.dual_basis()
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


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


Test of linearity:

sage: u = M([-5,-2,7])
sage: b(3*u - 4*v) == 3*b(u) - 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


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


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


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


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


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 + a[2,3]*b + a[3,1]*b
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

degree()

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

disp(basis=None, format_spec=None)

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}


A shortcut is disp():

sage: 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}


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}


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


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


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


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


Check that the bug reported in trac ticket #22520 is fixed:

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

display(basis=None, format_spec=None)

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}


A shortcut is disp():

sage: 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}


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}


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


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


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


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


Check that the bug reported in trac ticket #22520 is fixed:

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

interior_product(alt_tensor)

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:

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


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


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


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


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


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


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

wedge(other)

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}


Test of the computation:

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


Test of the computation:

sage: s[0,1,2] == d*c[1,2] + d*c[2,0] + d*c[0,1]
True


Let us check that the exterior product is associative:

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