---
title: "Handbook of Magma Functions, Part VIII: Modules"
version: "2.30-1"
canonical: "https://docs.magma-maths.org/Modules/index-modules.html"
---

# Modules

- [Introduction to Modules](https://docs.magma-maths.org/Modules/IntroductionToModules/index-introduction-to-modules.md): Overview, definitions, and presentations of modules.
- [Free Modules](https://docs.magma-maths.org/Modules/FreeModules/index-free-modules.md): Free modules, bases, and rank.
- [Modules over Dedekind Domains](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/index-modules-over-dedekind-domains.md): Creation, arithmetic, basis, and homomorphisms of modules over Dedekind domains.
- [Chain Complexes](https://docs.magma-maths.org/Modules/ChainComplexes/index-chain-complexes.md): Ext, Tor, and projective resolutions.
- [Multilinear Algebra](https://docs.magma-maths.org/Modules/MultilinearAlgebra/index-multilinear-algebra.md): Tensors, tensor spaces, and multilinear invariants.

## Introduction to Modules

- [Overview](https://docs.magma-maths.org/Modules/IntroductionToModules/overview.md)
- [General Modules](https://docs.magma-maths.org/Modules/IntroductionToModules/definition.md)
- [The Presentation of Submodules](https://docs.magma-maths.org/Modules/IntroductionToModules/presentation.md)

### Overview

This section of the Handbook describes the Magma facilities for linear algebra and module theory. Since this topic is absolutely fundamental for much of algebra, it is important that the reader understand how linear algebra is presented in Magma. The structures covered under this heading include:

**(i)**
Vector spaces;

**(ii)**
Inner product spaces;

**(iii)**
Modules defined over any ring or algebra

**(iv)**
$R[G]$-modules, where $R$ is a ring and $G$ is a group;

**(v)**
Linear transformations and $R$-module homomorphisms.

Although vector spaces are, of course, subsumed under general modules, we present a separate treatment of them, firstly because of their importance and secondly because their theory is somewhat cleaner than that of a general module. Magma users who are unfamiliar with the language of module theory will find a self-contained treatment of the vector space machinery in Chapter [Vector Spaces](https://docs.magma-maths.org/MatricesLinearAlgebra/VectorSpaces/index-vector-spaces.md#chapvectspace). In the Magma universe, rectangular matrices are regarded as forming a module (actually a bimodule). We shall regard a rectangular matrix as the concrete realization of a linear transformation or $R$-module homomorphism. Thus, an $m \times n$ matrix over a ring $R$ is considered to be an element of the module ${\operatorname{Hom}}_R(M, N)$. Reflecting the dual nature of matrices, the ${\operatorname{Hom}}_R(M, N)$ operations include the standard module-theoretic operations as well as operations that interpret an element of ${\operatorname{Hom}}_R(M, N)$ as a homomorphism.

### General Modules

A module $M$ is always regarded as a submodule or quotient module of the free module $S^{(n)}$, for some ring or algebra $S$. The types of module that are definable in the system fall into three classes:

**(a)**
**Abstract Modules**: Given a ring $R$, a set $M$, and a mapping $\phi : R \times M \ar M$, the pair $(M, \phi)$ will be referred to as an *abstract* $R$-module. Because of the very general nature of this construction, only the basic arithmetic operations may be applied to modules of this type.

**(b)**
**Modules with Scalar Action**: Given a general ring $R$, an $R$-module with *scalar action* is a submodule or quotient module of the free $R$-module $R^{(n)}$, where the action is that of ring multiplication in $R$.

**(c)**
**Modules with Matrix Action**: Let $R$ be a PIR and suppose $S$ is a $R$-algebra. Thus there exists a ring homomorphism $\phi : R \rightarrow S$, and so $S$ is a (left) $R$-module with the $R$-action defined by $r*s = \phi(r)*s$. Indeed, any $S$-module $M$ is a (left) $S$-module with action defined by $r*m$ = $\phi(r)*m$. Furthermore, if $\phi(R)$ lies in the centre of $S$, then $S$ acts on $M$ as a ring of $R$-module endomorphisms. Consequently, $M$ is an $S$-module. We take $M$ to be the free $R$-module $R^{(n)}$, and so the action of $S$ on $M$ is given by the action of a subring of $M_n(R)$ on $M$. Thus, given an $R$-algebra $S$, an $S$-module of the form $M$ = $R^{(n)}$ may be specified by giving $M$ together with a homomorphism of $S$ into $M_n(R)$.

### The Presentation of Submodules

Let $N$ be a submodule of the module $M = R^{(m)}$. For simplicity, assume that $N$ is free, and has dimension $n$ where $n < m$. There are two ways in which $N$ may be viewed:

**(a)**
As a submodule embedded in $M$. Thus, though $N$ is a module of dimension $n$, its elements are regarded as elements of $M$.

**(b)**
As the module $R^{(n)}$ represented on a reduced basis, together with a morphism $\phi$ defining the inclusion of $N$ into $M$.

The presentation (a) is the usual way submodules are regarded in elementary linear algebra. However, this presentation is inconvenient for more advanced applications. For example, many of the major functions available for studying an $R[G]$-module $N$ expect that $N$ is given relative to a reduced basis. We shall refer to a submodule presentation (a) as the *embedded presentation*, and (b) as the *reduced presentation*. To provide the user with the maximum flexibility, Magma supports both forms of submodule presentation for the important classes of modules. Usually, a module calculation commences with the definition of one or two modules from which further modules are created by the operations of forming submodules, quotient modules, and extensions. Let us call these latter modules *descendants* of the original module. Magma provides parallel creation functions which allow the user to choose the form of submodule presentation. Once that choice has been made, all descendants of the initial module(s) will follow the same presentation convention. The module creation functions that select the embedded form are usually of the form *Qualifier*`Space`, while those that adopt the standard form are usually of the form *Qualifier*`Module`. Thus in the case of vector spaces the function `KSpace(K, n)` constructs the $n$-dimensional vector space over the field $K$, where submodules are to be presented in embedded form. On the other hand, `RModule(K, n)` constructs the $n$-dimensional vector space over the field $K$, where submodules are to be presented in reduced form.

<a id="general"></a>
<a id="chapmodrng"></a>
## Free Modules

- [Introduction](https://docs.magma-maths.org/Modules/FreeModules/introduction.md)
  - [Free Modules](https://docs.magma-maths.org/Modules/FreeModules/introduction.md#free-modules)
  - [Module Categories](https://docs.magma-maths.org/Modules/FreeModules/introduction.md#module-categories)
  - [Presentation of Submodules](https://docs.magma-maths.org/Modules/FreeModules/introduction.md#presentation-of-submodules)
  - [Notation](https://docs.magma-maths.org/Modules/FreeModules/introduction.md#notation)
- [Definition of a Module](https://docs.magma-maths.org/Modules/FreeModules/creation-module.md)
  - [Construction of Modules of $n$-tuples](https://docs.magma-maths.org/Modules/FreeModules/creation-module.md#construction-of-modules-of-n-tuples)
    - [`RSpace(R, n): Rng, RngIntElt → ModTupRng`](https://docs.magma-maths.org/Modules/FreeModules/creation-module.md#function-modrng-rspace)
    - [`RModule(R, n): Rng, RngIntElt → ModRng`](https://docs.magma-maths.org/Modules/FreeModules/creation-module.md#function-modrng-rmodule)
    - [`RSpace(R, n, F): Rng, RngIntElt, Mtrx → ModTupRng`](https://docs.magma-maths.org/Modules/FreeModules/creation-module.md#function-rspace-rng-rngintelt-mtrx)
    - [Example: Module of 6-Tuples over the Integers](https://docs.magma-maths.org/Modules/FreeModules/creation-module.md#example-ex-d42492)
  - [Construction of Modules of $m \times n$ Matrices](https://docs.magma-maths.org/Modules/FreeModules/creation-module.md#construction-of-modules-of-m-times-n-matrices)
    - [`RMatrixSpace(R, m, n): Rng, RngIntElt, RngIntElt → ModMatRng`](https://docs.magma-maths.org/Modules/FreeModules/creation-module.md#function-rmatrixspace-rng-rngintelt-rngintelt)
  - [Construction of a Module with Specified Basis](https://docs.magma-maths.org/Modules/FreeModules/creation-module.md#construction-of-a-module-with-specified-basis)
    - [`RModuleWithBasis(Q): [ModFldElt] → ModFld`](https://docs.magma-maths.org/Modules/FreeModules/creation-module.md#function-rmodulewithbasis-modfldelt)
    - [`RSpaceWithBasis(Q): [ModTupRngElt] → ModTupRng`](https://docs.magma-maths.org/Modules/FreeModules/creation-module.md#function-rspacewithbasis-modtuprngelt)
    - [`RSpaceWithBasis(a): AlgMatElt → ModTupRng`](https://docs.magma-maths.org/Modules/FreeModules/creation-module.md#function-rspacewithbasis-algmatelt)
    - [`RSpaceWithBasis(a): ModMatRngElt → ModTupRng`](https://docs.magma-maths.org/Modules/FreeModules/creation-module.md#function-rspacewithbasis-modmatrngelt)
    - [`RMatrixSpaceWithBasis(Q): [ModTupRngElt] → ModMatRng`](https://docs.magma-maths.org/Modules/FreeModules/creation-module.md#function-rmatrixspacewithbasis-modtuprngelt)
- [Accessing Module Information](https://docs.magma-maths.org/Modules/FreeModules/access.md)
  - [`M . i: ModTupRng, RngIntElt → ModElt`](https://docs.magma-maths.org/Modules/FreeModules/access.md#operation-operation-modtuprng-rngintelt-modelt)
  - [`CoefficientRing(M): ModTupRng → Rng`](https://docs.magma-maths.org/Modules/FreeModules/access.md#function-coefficientring-modtuprng)
  - [`BaseRing(M): ModTupRng → Rng`](https://docs.magma-maths.org/Modules/FreeModules/access.md#function-basering-modtuprng)
  - [`CoefficientRing(M): ModRng → Rng`](https://docs.magma-maths.org/Modules/FreeModules/access.md#function-coefficientring-modrng)
  - [`BaseRing(M): ModRng → Rng`](https://docs.magma-maths.org/Modules/FreeModules/access.md#function-basering-modrng)
  - [`CoefficientField(M): ModFld → Fld`](https://docs.magma-maths.org/Modules/FreeModules/access.md#function-coefficientfield-modfld)
  - [`BaseField(M): ModFld → Fld`](https://docs.magma-maths.org/Modules/FreeModules/access.md#function-basefield-modfld)
  - [`Generators(M): ModTupRng → { ModTupRngElt }`](https://docs.magma-maths.org/Modules/FreeModules/access.md#function-generators-modtuprng)
  - [`OverDimension(M): ModTupRng → RngIntElt`](https://docs.magma-maths.org/Modules/FreeModules/access.md#function-overdimension-modtuprng)
  - [`OverDimension(u): ModTupRngElt → RngIntElt`](https://docs.magma-maths.org/Modules/FreeModules/access.md#function-overdimension-modtuprngelt)
  - [`Moduli(M): ModTupRng → [ RngElt ]`](https://docs.magma-maths.org/Modules/FreeModules/access.md#function-moduli-modtuprng)
  - [`Parent(u): ModTupRngElt → ModRng`](https://docs.magma-maths.org/Modules/FreeModules/access.md#function-parent-modtuprngelt)
  - [`Generic(M): ModRng → ModRng`](https://docs.magma-maths.org/Modules/FreeModules/access.md#function-generic-modrng)
- [Standard Constructions](https://docs.magma-maths.org/Modules/FreeModules/operation.md)
  - [Changing the Coefficient Ring](https://docs.magma-maths.org/Modules/FreeModules/operation.md#changing-the-coefficient-ring)
    - [`ChangeRing(M, S): ModRng, Rng → ModRng, Map`](https://docs.magma-maths.org/Modules/FreeModules/operation.md#function-changering-modrng-rng)
    - [`ChangeRing(M, S, f): ModRng, Rng, Map → ModRng, Map`](https://docs.magma-maths.org/Modules/FreeModules/operation.md#function-changering-modrng-rng-map)
    - [`ChangeUniverse(~x, R): ModTupRngElt, Rng → ModRng, Map`](https://docs.magma-maths.org/Modules/FreeModules/operation.md#function-changeuniverse-modtuprngelt-rng-ref)
  - [Direct Sums](https://docs.magma-maths.org/Modules/FreeModules/operation.md#direct-sums)
    - [`DirectSum(M, N): ModRng, ModRng → ModRng, Map, Map, Map, Map`](https://docs.magma-maths.org/Modules/FreeModules/operation.md#function-directsum-modrng-modrng)
    - [`DirectSum(Q): [ ModRng ] → [ ModRng ], [ Map ], [ Map ]`](https://docs.magma-maths.org/Modules/FreeModules/operation.md#function-directsum-modrng)
- [Construction of Elements](https://docs.magma-maths.org/Modules/FreeModules/creation.md)
  - [`elt< M | a₁, ..., aₙ >: ModTupRng, List → ModTupRngElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#constructor-constructor-elt-modtuprng-list-modtuprngelt)
  - [`M ! Q: ModTupRng, [RngElt] → ModTupRngElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#operation-op-modtuprng-rngelt)
  - [`CharacteristicVector(M, S): ModRng, { RngIntElt } → ModRngElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#function-characteristicvector-modrng-rngintelt)
  - [`Zero(M): ModRng → ModRngElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#function-zero-modrng)
  - [`M ! 0: ModRng, RngIntElt → ModRngElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#operation-op-modrng-rngintelt)
  - [`Random(M): ModRng → ModRngElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#function-random-modrng)
  - [Example: Elements of a Free Module over Z\[x\]](https://docs.magma-maths.org/Modules/FreeModules/creation.md#example-ex-cd5034)
  - [Deconstruction of Elements](https://docs.magma-maths.org/Modules/FreeModules/creation.md#deconstruction-of-elements)
    - [`ElementToSequence(u): ModTupRngElt → [RngElt]`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#function-elementtosequence-modtuprngelt)
    - [`Eltseq(u): ModTupRngElt → [RngElt]`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#function-eltseq-modtuprngelt)
  - [Operations on Module Elements](https://docs.magma-maths.org/Modules/FreeModules/creation.md#operations-on-module-elements)
    - [Arithmetic](https://docs.magma-maths.org/Modules/FreeModules/creation.md#arithmetic)
      - [`u + v: ModTupRngElt, ModTupRngElt → ModTupRngElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#operation-op-plus-modtuprngelt-modtuprngelt)
      - [`- u: ModTupRngElt → ModTupRngElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#operation-operation-modtuprngelt-modtuprngelt)
      - [`u - v: ModTupRngElt, ModTupRngElt → ModTupRngElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#operation-op-minus-modtuprngelt-modtuprngelt)
      - [`x * u: RngElt, ModTupRngElt → ModTupRngElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#operation-op-times-rngelt-modtuprngelt)
      - [`u * x: ModTupRngElt, RngElt → ModTupRngElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#operation-op-times-modtuprngelt-rngelt)
      - [`u / x: ModTupRngElt, RngElt → ModTupRngElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#operation-op-div-modtuprngelt-rngelt)
    - [Indexing](https://docs.magma-maths.org/Modules/FreeModules/creation.md#indexing)
      - [`u[i]: ModTupRngElt, RngIntElt → RngElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#indexed-indexed-u-modtuprngelt-rngintelt-rngelt)
      - [`u[i] := x: ModTupRngElt, RngIntElt, RngElt → ModTupRngElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#literal-literal-u-i-x-modtuprngelt-rngintelt-rngelt-modtuprngelt)
    - [Normalization](https://docs.magma-maths.org/Modules/FreeModules/creation.md#normalization)
      - [`Normalize(u): ModTupRngElt → ModTupRngElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#function-normalize-modtuprngelt)
      - [`Normalise(u): ModTupRngElt → ModTupRngElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#function-normalise-modtuprngelt)
      - [`Rotate(u, k): ModTupRngElt, RngIntElt → ModTupRngElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#function-rotate-modtuprngelt-rngintelt)
      - [`Rotate(~u, k): ModTupRngElt, RngIntElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#procedure-rotate-modtuprngelt-rngintelt-ref)
      - [Example: Arithmetic on Module Elements](https://docs.magma-maths.org/Modules/FreeModules/creation.md#example-ex-8a5f2c)
  - [Properties of Vectors](https://docs.magma-maths.org/Modules/FreeModules/creation.md#properties-of-vectors)
    - [`IsZero(u): ModTupRngElt → BoolElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#function-iszero-modtuprngelt)
    - [`Depth(v): ModTupRngElt → RngIntElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#function-depth-modtuprngelt)
    - [`Support(u): ModTupRngElt → { RngElt }`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#function-support-modtuprngelt)
    - [`Weight(u): ModTupRngElt → RngIntElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#function-weight-modtuprngelt)
  - [Inner Products](https://docs.magma-maths.org/Modules/FreeModules/creation.md#inner-products)
    - [`(u, v): ModTupRngElt, ModTupRngElt → RngElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#literal-literal-u-v-modtuprngelt-modtuprngelt-rngelt)
    - [`InnerProduct(u, v): ModTupRngElt, ModTupRngElt → RngElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#function-innerproduct-modtuprngelt-modtuprngelt)
    - [`Norm(u): ModTupRngElt → RngElt`](https://docs.magma-maths.org/Modules/FreeModules/creation.md#function-norm-modtuprngelt)
- [Bases](https://docs.magma-maths.org/Modules/FreeModules/basis.md)
  - [`Basis(M): ModTupRng → [ModTupRngElt]`](https://docs.magma-maths.org/Modules/FreeModules/basis.md#function-basis-modtuprng)
  - [`Rank(M): ModTupRng → RngIntElt`](https://docs.magma-maths.org/Modules/FreeModules/basis.md#function-rank-modtuprng)
  - [`Coordinates(M, u): ModTupRng, ModTupRngElt → [RngElt]`](https://docs.magma-maths.org/Modules/FreeModules/basis.md#function-coordinates-modtuprng-modtuprngelt)
- [Submodules](https://docs.magma-maths.org/Modules/FreeModules/submodule.md)
  - [Construction of Submodules](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#construction-of-submodules)
    - [`sub<M | L>: ModTupRng, List → ModTupRng`](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#constructor-constructor-sub-modtuprng-list-modtuprng)
    - [`sub<M | L>: ModMatRng, List → ModMatRng`](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#constructor-constructor-sub-modmatrng-list-modmatrng)
    - [Example: Submodule over a Rational Function Field](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#example-ex-e4a021)
  - [Operations on Submodules](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#operations-on-submodules)
  - [Membership and Equality](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#membership-and-equality)
    - [`u in M: ModTupRngElt, ModTupRng → BoolElt`](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#operation-op-in-modtuprngelt-modtuprng)
    - [`u in M: ModMatRngElt, ModMatRng → BoolElt`](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#operation-op-in-modmatrngelt-modmatrng)
    - [`u notin M: ModTupRngElt, ModTupRng → BoolElt`](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#operation-op-notin-modtuprngelt-modtuprng)
    - [`u notin M: ModMatRngElt, ModMatRng → BoolElt`](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#operation-op-notin-modmatrngelt-modmatrng)
    - [`N subset M: ModTupRng, ModTupRng → BoolElt`](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#operation-op-subset-modtuprng-modtuprng)
    - [`N subset M: ModMatRng, ModMatRng → BoolElt`](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#operation-op-subset-modmatrng-modmatrng)
    - [`N notsubset M: ModTupRng, ModTupRng → BoolElt`](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#operation-operation-notsubset-modtuprng-modtuprng-boolelt)
    - [`N notsubset M: ModMatRng, ModMatRng → BoolElt`](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#operation-operation-notsubset-modmatrng-modmatrng-boolelt)
    - [`N eq M: ModTupRng, ModTupRng → BoolElt`](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#operation-op-eq-modtuprng-modtuprng)
    - [`M eq N: ModMatRng, ModMatRng → BoolElt`](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#operation-op-eq-modmatrng-modmatrng)
    - [`N ne M: ModTupRng, ModTupRng → BoolElt`](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#operation-op-ne-modtuprng-modtuprng)
    - [`M ne N: ModMatRng, ModMatRng → BoolElt`](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#operation-op-ne-modmatrng-modmatrng)
  - [Operations on Submodules](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#id1)
    - [`M + N: ModTupRng, ModTupRng → ModTupRng`](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#operation-op-plus-modtuprng-modtuprng)
    - [`M + N: ModMatRng, ModMatRng → ModMatRng`](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#operation-op-plus-modmatrng-modmatrng)
    - [`M meet N: ModTupRng, ModTupRng → ModTupRng`](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#operation-op-meet-modtuprng-modtuprng)
    - [`M meet N: ModMatRng, ModMatRng → ModMatRng`](https://docs.magma-maths.org/Modules/FreeModules/submodule.md#operation-op-meet-modmatrng-modmatrng)
- [Quotient Modules](https://docs.magma-maths.org/Modules/FreeModules/quotient.md)
  - [Construction of Quotient Modules](https://docs.magma-maths.org/Modules/FreeModules/quotient.md#construction-of-quotient-modules)
    - [`quo<M | L>: ModTupRng, List → ModTupRng`](https://docs.magma-maths.org/Modules/FreeModules/quotient.md#constructor-constructor-quo-modtuprng-list-modtuprng)
    - [`quo<M | L>: ModMatRng, List → ModMatRng`](https://docs.magma-maths.org/Modules/FreeModules/quotient.md#constructor-constructor-quo-modmatrng-list-modmatrng)
- [Homomorphisms](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md)
  - [${\operatorname{Hom}}_{R}(M, N)$ for $R$-modules](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#operatorname-hom-r-m-n-for-r-modules)
    - [`Hom(M, N): ModTupRng, ModTupRng → ModMatRng`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#function-hom-modtuprng-modtuprng)
    - [`RMatrixSpace(R, m, n): Rng, RngIntElt, RngIntElt → ModMatRng`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#function-rmatrixspace-rng-rngintelt-rngintelt-2)
    - [Example: Module of Homomorphisms of Vector Spaces](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#example-ex-bf6e98)
  - [${\operatorname{Hom}}_{R}(M, N)$ for Matrix Modules](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#operatorname-hom-r-m-n-for-matrix-modules)
    - [`Hom(M, N, "right"): ModMatRng, ModMatRng, MonStgElt → ModMatRng`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#function-hom-modmatrng-modmatrng-monstgelt-right)
    - [`Hom(M, N, "left"): ModMatRng, ModMatRng, MonStgElt → ModMatRng`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#function-hom-modmatrng-modmatrng-monstgelt-left)
    - [Example: Homomorphisms Between Homomorphism Modules](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#example-ex-e3a29e)
  - [Modules ${\operatorname{Hom}}_{R}(M, N)$ with Given Basis](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#modules-operatorname-hom-r-m-n-with-given-basis)
    - [`RMatrixSpaceWithBasis(Q): [ ModMatRngElt ] → ModMatRng`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#function-rmatrixspacewithbasis-modmatrngelt)
    - [`KMatrixSpaceWithBasis(Q): [ ModMatRngElt ] → ModMatRng`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#function-kmatrixspacewithbasis-modmatrngelt)
  - [The Endomorphism Ring](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#the-endomorphism-ring)
    - [`EndomorphismAlgebra(M): ModTupRng → AlgMat`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#function-endomorphismalgebra-modtuprng)
    - [Example: Endomorphism Ring of a Vector Space](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#example-ex-7acde1)
  - [The Reduced Form of a Matrix Module](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#the-reduced-form-of-a-matrix-module)
    - [`Reduce(H): ModMatRng → ModMatRng, Map`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#function-reduce-modmatrng)
    - [Example: Reduced Form for Maps Between Vector Spaces](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#example-ex-ecaba6)
    - [Example: Reduced Form for Maps Between Hom Modules](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#example-ex-4c472d)
  - [Construction of a Matrix](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#construction-of-a-matrix)
    - [`M ! Q: ModMatRng, [RngElt] → ModMatRngElt`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#operation-op-modmatrng-rngelt)
    - [Example: Hilbert Matrix as an Endomorphism](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#example-ex-9b8959)
  - [Element Operations](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#element-operations)
    - [`u * a: ModTupRngElt, ModMatRngElt → ModTupRngElt`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#operation-op-times-modtuprngelt-modmatrngelt)
    - [`a(u): ModTupRngElt, ModMatRngElt → ModTupRngElt`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#literal-a-modtuprngelt-modmatrngelt)
    - [`a * b: ModMatRngElt, ModMatRngElt → ModMatRngElt`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#operation-op-times-modmatrngelt-modmatrngelt)
    - [`a ^ -1: ModMatRngElt, RngIntElt → ModMatRngElt`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#operation-op-pow-modmatrngelt-rngintelt)
    - [`Codomain(S): ModMatRng → ModTupRng`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#function-codomain-modmatrng)
    - [`Codomain(a): ModMatRngElt → ModTupRng`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#function-codomain-modmatrngelt)
    - [`Cokernel(a): ModMatRngElt → ModTupRng`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#function-cokernel-modmatrngelt)
    - [`Domain(S): ModMatRng → ModTupRng`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#function-domain-modmatrng)
    - [`Domain(a): ModMatRngElt → ModTupRng`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#function-domain-modmatrngelt)
    - [`Image(a): ModMatRngElt → ModTupRng`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#function-image-modmatrngelt)
    - [`Kernel(a): ModMatRngElt → ModTupRng`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#function-kernel-modmatrngelt)
    - [`NullSpace(a): ModMatRngElt → ModTupRng`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#function-nullspace-modmatrngelt)
    - [`Morphism(M, N): ModTupRng, ModTupRng → ModMatRngElt`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#function-morphism-modtuprng-modtuprng)
    - [`Rank(a): ModMatRngElt → RngIntElt`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#function-rank-modmatrngelt)
    - [`IsBijective(a): ModMatRngElt → BoolElt`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#function-isbijective-modmatrngelt)
    - [`IsInjective(a): ModMatRngElt → BoolElt`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#function-isinjective-modmatrngelt)
    - [`IsSurjective(a): ModMatRngElt → BoolElt`](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#function-issurjective-modmatrngelt)
    - [Example: Operations in a Homomorphism Module](https://docs.magma-maths.org/Modules/FreeModules/homomorphisms.md#example-ex-85af3b)

### Introduction

#### Free Modules

This chapter describes the facilities provided for modules in the following representations:

**•**
*Tuple Modules:* Modules whose elements are $n$-tuples over a fixed ring $R$, i.e., modules $R^{(n)}$;

**•**
*Matrix Modules:* Modules whose elements are homomorphisms of modules, i.e., $Hom_R(M, N)$. The elements of these modules are $m \times n$ matrices over the ring $R$;

The ring $R$ acts on the right of the module element by scalar multiplication. If $R$ is not an Euclidean Domain then, currently, only arithmetic with vectors is supported. In particular, the ability to work with submodules and quotient modules is restricted to situations where $R$ is either a field or Euclidean Domain.

In the first part of the chapter we describe the operations that apply to modules generally, while in the second half we describe the creation of modules $Hom_R(M, N)$ together with the operations that are specific to them. Insofar as elementary module-theoretic operations are concerned, there is no real difference between tuple modules and matrix modules except for the input and display of elements. Many special operations provided for matrices are described in the chapter on matrices.

The reader is referred to the chapter on vector spaces for descriptions of the extensive functionality provided for modules over fields.

#### Module Categories

The family of all finitely generated modules over a given ring $R$ forms a category, while the set of all finitely generated modules forms a family of categories indexed by the ring $R$. In this family of categories, objects are modules and the morphisms are module homomorphisms. The category name for modules is `ModRng`. We distinguish the following subcategories of `ModRng`:

**•**
`ModTupFld` - the category of modules of $n$-tuples over a field;

**•**
`ModMatFld` - the category of modules of $m \times n$ matrices over a field;

**•**
`ModTupEd` - the category of modules of $n$-tuples over an euclidean domain.

**•**
`ModTupRng` - the category of modules of $n$-tuples over a ring;

**•**
`ModMatRng` - the category of modules of $m \times n$ matrices over a ring;

#### Presentation of Submodules

Let $N$ be a free submodule of the $R$-module $M$. We have two alternative ways of presenting $N$. Firstly, we can present it on a set of generators that are elements of $M$; we call such a presentation an *embedded presentation*. Alternatively, given that $N$ has rank $r$, we can present it as the module $S^{(r)}$, with appropriate action induced from the action of $R$ on $M$. We call this presentation of $N$ a *reduced presentation*. The user can control the method of submodule presentation at the time of creation of an initial module through selection of the appropriate creation function. Thus, the function `RModule` will create a module with the convention that it and all its submodules and quotient modules will have their submodules presented in reduced form. The use of `RSpace`, on the other hand, signifies that submodules are to be presented in embedded form.

#### Notation

Throughout this chapter, $R$ will denote a ring (possibly a field) while $K$ will denote a field. The letters $M$ and $N$ will denote modules, while $U$ and $V$ will denote vector spaces.

### Definition of a Module

#### Construction of Modules of $n$-tuples

<a id="function-modrng-rspace"></a>
##### `RSpace(R, n): Rng, RngIntElt -> ModTupRng`

<a id="function-modrng-rmodule"></a>
##### `RModule(R, n): Rng, RngIntElt -> ModRng`

Given a ring $R$ and a non-negative integer $n$, create the free right $R$-module $R^{(n)}$, consisting of all $n$-tuples over $R$. The module is created with the standard basis, $e_1, \ldots, e_n$, where $e_i$ $(i = 1, \ldots, n)$ is the vector containing a $1$ in the $i$-th position and zeros elsewhere. The function `RModule` creates a module in reduced mode while `RSpace` creates a module in embedded mode.

<a id="function-rspace-rng-rngintelt-mtrx"></a>
##### `RSpace(R, n, F): Rng, RngIntElt, Mtrx -> ModTupRng`

Given a ring $R$, a non-negative integer $n$, and a square $n \times n$ symmetric matrix $F$, create the free right $R$-module $R^{(n)}$ (in embedded form), with inner product matrix $F$. This is the same as `RSpace(R, n)`, except that the functions `Norm` and `InnerProduct` (see below) will be with respect to the inner product matrix $F$.

<a id="example-ex-d42492"></a>
##### `Example: Module of 6-Tuples over the Integers (ex-d42492)`

We construct the module consisting of $6$-tuples over the integers.

```magma
> Z := IntegerRing();
> M := RModule(Z, 6);
> M;
RModule M of dimension 6 with base ring Integer Ring
```

#### Construction of Modules of $m \times n$ Matrices

<a id="function-rmatrixspace-rng-rngintelt-rngintelt"></a>
##### `RMatrixSpace(R, m, n): Rng, RngIntElt, RngIntElt -> ModMatRng`

The module comprising all $m \times n$ matrices over the ring $R$.

#### Construction of a Module with Specified Basis

<a id="function-rmodulewithbasis-modfldelt"></a>
##### `RModuleWithBasis(Q): [ModFldElt] -> ModFld`

<a id="function-rspacewithbasis-modtuprngelt"></a>
##### `RSpaceWithBasis(Q): [ModTupRngElt] -> ModTupRng`

<a id="function-rspacewithbasis-algmatelt"></a>
##### `RSpaceWithBasis(a): AlgMatElt -> ModTupRng`

<a id="function-rspacewithbasis-modmatrngelt"></a>
##### `RSpaceWithBasis(a): ModMatRngElt -> ModTupRng`

Given a sequence $Q$ (or matrix $a$) of $k$ independent vectors each lying in a module $M$, construct the submodule of $M$ of dimension $k$ whose basis is $Q$ (or the rows of $a$). The basis is echelonized internally but all functions which depend on the basis of the space (e.g. `Coordinates`) will use the given basis.

<a id="function-rmatrixspacewithbasis-modtuprngelt"></a>
##### `RMatrixSpaceWithBasis(Q): [ModTupRngElt] -> ModMatRng`

The module of $m \times n$ matrices whose basis is given by the linearly independent matrices of the sequence $Q$.

### Accessing Module Information

<a id="operation-operation-modtuprng-rngintelt-modelt"></a>
#### `M . i: ModTupRng, RngIntElt -> ModElt`

Given an $R$-module $M$ and a positive integer $i$, return the $i$-th generator of $M$. The integer $i$ must lie in the range $[1, r]$, where $r$ is the number of generators for $M$.

<a id="function-coefficientring-modtuprng"></a>
#### `CoefficientRing(M): ModTupRng -> Rng`

<a id="function-basering-modtuprng"></a>
#### `BaseRing(M): ModTupRng -> Rng`

<a id="function-coefficientring-modrng"></a>
#### `CoefficientRing(M): ModRng -> Rng`

<a id="function-basering-modrng"></a>
#### `BaseRing(M): ModRng -> Rng`

<a id="function-coefficientfield-modfld"></a>
#### `CoefficientField(M): ModFld -> Fld`

<a id="function-basefield-modfld"></a>
#### `BaseField(M): ModFld -> Fld`

Given an $R$-module $M$ which is defined as a submodule of $S^{(n)}$, return the ring $S$.

<a id="function-generators-modtuprng"></a>
#### `Generators(M): ModTupRng -> { ModTupRngElt }`

The generators for the $R$-module $M$, returned as a set.

<a id="function-overdimension-modtuprng"></a>
#### `OverDimension(M): ModTupRng -> RngIntElt`

Given an $R$-module $M$ which is an embedded submodule of the module $S^{(n)}$, return $n$.

<a id="function-overdimension-modtuprngelt"></a>
#### `OverDimension(u): ModTupRngElt -> RngIntElt`

Given an element $u$ of an embedded submodule of the module $S^{(n)}$, return $n$.

<a id="function-moduli-modtuprng"></a>
#### `Moduli(M): ModTupRng -> [ RngElt ]`

The column moduli of the module $M$ over a euclidean domain.

<a id="function-parent-modtuprngelt"></a>
#### `Parent(u): ModTupRngElt -> ModRng`

Given an element $u$ belonging to the $R$-module $M$, return $M$.

<a id="function-generic-modrng"></a>
#### `Generic(M): ModRng -> ModRng`

Given an $R$-module $M$ which is a submodule of the module $R^{(n)}$, return the module $R^{(n)}$ as an $R$-module.

<a id="modules-standard-constructions"></a>
### Standard Constructions

Given one or more existing modules, various standard constructions are available to construct new modules.

#### Changing the Coefficient Ring

<a id="function-changering-modrng-rng"></a>
##### `ChangeRing(M, S): ModRng, Rng -> ModRng, Map`

Given a module $M$ with base ring $R$, together with a ring $S$, construct the module $N$ with base ring $S$ obtained by coercing the components of elements of $M$ into $N$, together with the homomorphism from $M$ to $N$.

<a id="function-changering-modrng-rng-map"></a>
##### `ChangeRing(M, S, f): ModRng, Rng, Map -> ModRng, Map`

Given a module $M$ with base ring $R$, together with a ring $S$, and a homomorphism $f: R \rightarrow S$, construct the module $N$ with base ring $S$ obtained by mapping the components of elements of $M$ into $N$ by $f$, together with the homomorphism from $M$ to $N$.

<a id="function-changeuniverse-modtuprngelt-rng-ref"></a>
##### `ChangeUniverse(~x, R): ModTupRngElt, Rng -> ModRng, Map`

Change the coefficient ring of $x$ to be $R$.

#### Direct Sums

<a id="function-directsum-modrng-modrng"></a>
##### `DirectSum(M, N): ModRng, ModRng -> ModRng, Map, Map, Map, Map`

Given $R$-modules $M$ and $N$, construct the direct sum $D$ of $M$ and $N$ as an $R$-module. The embedding maps from $M$ into $D$ and from $N$ into $D$ respectively, and the projection maps from $D$ onto $M$ and from $D$ onto $N$ respectively are also returned.

<a id="function-directsum-modrng"></a>
##### `DirectSum(Q): [ ModRng ] -> [ ModRng ], [ Map ], [ Map ]`

Given a sequence $Q$ of $R$-modules, construct the direct sum $D$ of these modules. The embedding maps from each of the elements of $Q$ into $D$ and the projection maps from $D$ onto each of the elements of $Q$ are also returned.

### Construction of Elements

<a id="constructor-constructor-elt-modtuprng-list-modtuprngelt"></a>
#### `elt< M | a₁, ..., aₙ >: ModTupRng, List -> ModTupRngElt`

Given a module $M$ with base module $S^{(n)}$, and elements $a_1, \ldots, a_n$ belonging to $S$, construct the element $m = (a_1, \ldots, a_n)$ of $M$. Note that if $m$ is not an element of $M$, an error will result.

<a id="operation-op-modtuprng-rngelt"></a>
#### `M ! Q: ModTupRng, [RngElt] -> ModTupRngElt`

Given the module $M$ with base module $S^{(n)}$, and elements $a_1, \ldots, a_n$ belonging to $S$, construct the element $m = (a_1, \ldots, a_n)$ of $M$. Note that if $m$ is not an element of $M$, an error will result.

<a id="function-characteristicvector-modrng-rngintelt"></a>
#### `CharacteristicVector(M, S): ModRng, { RngIntElt } -> ModRngElt`

Given a submodule $M$ of the module $R^{(n)}$ together with a set $S$ of integers lying in the interval $[1, n]$, return the characteristic number of $S$ as a vector of $R$.

<a id="function-zero-modrng"></a>
#### `Zero(M): ModRng -> ModRngElt`

<a id="operation-op-modrng-rngintelt"></a>
#### `M ! 0: ModRng, RngIntElt -> ModRngElt`

The zero element for the $R$-module $M$.

<a id="function-random-modrng"></a>
#### `Random(M): ModRng -> ModRngElt`

Given a module $M$ defined over a finite ring or field, return a random vector.

<a id="example-ex-cd5034"></a>
#### `Example: Elements of a Free Module over Z[x] (ex-cd5034)`

We create the module of $4$-tuples over the polynomial ring ${\mathbb{Z}}[x]$ and define various elements.

```magma
> P<x> := PolynomialRing(IntegerRing());
> M := RModule(P, 4);
> a := elt< M | 1+x, -x, 2+x, 0 >;
> a;
(x + 1    -x x + 2     0)
> b := M ! [ 1+x+x^2, 0, 1-x^7, 2*x ];
> b;
(x^2 + x + 1           0    -x^7 + 1         2*x)
> zero := M ! 0;
> zero;
(0 0 0 0)
```

#### Deconstruction of Elements

<a id="function-elementtosequence-modtuprngelt"></a>
##### `ElementToSequence(u): ModTupRngElt -> [RngElt]`

<a id="function-eltseq-modtuprngelt"></a>
##### `Eltseq(u): ModTupRngElt -> [RngElt]`

Given an element $u$ belonging to the $R$-module $M$, return $u$ in the form of a sequence $Q$ of elements of $R$. Thus, if $u$ is an element of $R^{(n)}$, then $Q[i] = u[i], 1 \leq i \leq n$, while if $u$ is an element of $R^{(m \times n)}$, then $Q[(i-1)n +j] = u[i,j], 1 \leq i \leq m, 1 \leq j \leq n$.

#### Operations on Module Elements

##### Arithmetic

<a id="operation-op-plus-modtuprngelt-modtuprngelt"></a>
###### `u + v: ModTupRngElt, ModTupRngElt -> ModTupRngElt`

Sum of the elements $u$ and $v$, where $u$ and $v$ lie in the same $R$-module $M$.

<a id="operation-operation-modtuprngelt-modtuprngelt"></a>
###### `- u: ModTupRngElt -> ModTupRngElt`

Additive inverse of the element $u$.

<a id="operation-op-minus-modtuprngelt-modtuprngelt"></a>
###### `u - v: ModTupRngElt, ModTupRngElt -> ModTupRngElt`

Difference of the elements $u$ and $v$, where $u$ and $v$ lie in the same $R$-module $M$.

<a id="operation-op-times-rngelt-modtuprngelt"></a>
###### `x * u: RngElt, ModTupRngElt -> ModTupRngElt`

Given an element $x$ belonging to a ring $R$, and an element $u$ belonging to the left $R$-module $M$, return the (left) scalar product $x * u$ as an element of $M$.

<a id="operation-op-times-modtuprngelt-rngelt"></a>
###### `u * x: ModTupRngElt, RngElt -> ModTupRngElt`

Given an element $x$ belonging to a ring $R$, and an element $u$ belonging to the right $R$-module $M$, return the (right) scalar product $u * x$ as an element of $M$.

<a id="operation-op-div-modtuprngelt-rngelt"></a>
###### `u / x: ModTupRngElt, RngElt -> ModTupRngElt`

Given a non-zero element $x$ belonging to a field $K$, and an element $u$ belonging to the right $K$-module $M$, return the scalar product $u * (1/x)$ as an element of $M$.

##### Indexing

<a id="indexed-indexed-u-modtuprngelt-rngintelt-rngelt"></a>
###### `u[i]: ModTupRngElt, RngIntElt -> RngElt`

Given an element $u$ belonging to a submodule $M$ of the $R$-module $R^{(n)}$ and a positive integer $i$, $1 \leq i\leq n$, return the $i$-th component of $u$ (as an element of the ring $R$).

<a id="literal-literal-u-i-x-modtuprngelt-rngintelt-rngelt-modtuprngelt"></a>
###### `u[i] := x: ModTupRngElt, RngIntElt, RngElt -> ModTupRngElt`

Given an element $u$ belonging to a submodule $M$ of the $R$-module $T = R^{(n)}$, a positive integer $i$, $1 \leq i\leq n$, and an element $x$ of the ring $R$, redefine the $i$-th component of $u$ to be $x$. The parent of $u$ is changed to $T$ (since the modified element $u$ need not lie in $M$).

##### Normalization

<a id="function-normalize-modtuprngelt"></a>
###### `Normalize(u): ModTupRngElt -> ModTupRngElt`

<a id="function-normalise-modtuprngelt"></a>
###### `Normalise(u): ModTupRngElt -> ModTupRngElt`

The element $u$ must belong to an $R$-module, where $R$ is either a field, the ring of integers, or a univariate polynomial ring over a field. Assume that the vector $u$ is non-zero. If $R$ is a field then `Normalize` returns ${1\over a}*u$, where $a$ is the first non-zero component of $u$. If $R$ is the ring of integers, `Normalize` returns $\epsilon*u$, where $\epsilon$ is $+1$ if the first non-zero component of $u$ is positive, and $-1$ otherwise. If $R$ is the polynomial ring $K[x]$, $K$ a field, then `Normalize` returns ${1\over a}*u$, where $a$ is the leading coefficient of the first non-zero (polynomial) component of $u$. If $u$ is the zero vector, it is returned as the value of this function.

<a id="function-rotate-modtuprngelt-rngintelt"></a>
###### `Rotate(u, k): ModTupRngElt, RngIntElt -> ModTupRngElt`

Given a vector $u$, return the vector obtained from $u$ by rotating by $k$ coordinate positions.

<a id="procedure-rotate-modtuprngelt-rngintelt-ref"></a>
###### `Rotate(~u, k): ModTupRngElt, RngIntElt`

Given a vector $u$, destructively rotate $u$ by $k$ coordinate positions.

<a id="example-ex-8a5f2c"></a>
###### `Example: Arithmetic on Module Elements (ex-8a5f2c)`

We illustrate the use of the arithmetic operators for module elements by applying them to elements of the module of $4$-tuples over the polynomial ring ${\mathbb{Z}}[x]$.

```magma
> P<x> := PolynomialRing(IntegerRing());
> M := RModule(P, 4);
> a :=  M ! [ 1+x, -x, 2+x, 0 ];
> b := M ! [ 1+x+x^2, 0, 1-x^7, 2*x ];
> a + b;
(x^2 + 2*x + 2    -x    -x^7 + x + 3    2*x)
> -a;
(-x - 1      x -x - 2      0)
> a - b;
(       -x^2          -x x^7 + x + 1        -2*x)
> (1-x + x^2)*a;
(x^3 + 1    -x^3 + x^2 - x    x^3 + x^2 - x + 2    0)
> a*(1-x);
(    -x^2 + 1      x^2 - x -x^2 - x + 2            0)
> a[3];
x + 2
> a[3] := x - 2;
> a;
(x + 1    -x x - 2     0)
> ElementToSequence(a - b);
[
    -x^2,
    -x,
    x^7 + x - 3,
    -2*x
]
> Support(a);
{ 1, 2, 3 }
```

#### Properties of Vectors

<a id="function-iszero-modtuprngelt"></a>
##### `IsZero(u): ModTupRngElt -> BoolElt`

Returns `true` if the element $u$ of the $R$-module $M$ is the zero element.

<a id="function-depth-modtuprngelt"></a>
##### `Depth(v): ModTupRngElt -> RngIntElt`

The index of the first non-zero entry of the vector $v$ (0 if none such).

<a id="function-support-modtuprngelt"></a>
##### `Support(u): ModTupRngElt -> { RngElt }`

A set of integers giving the positions of the non-zero components of the vector $u$.

<a id="function-weight-modtuprngelt"></a>
##### `Weight(u): ModTupRngElt -> RngIntElt`

The number of non-zero components of the vector $u$.

#### Inner Products

<a id="literal-literal-u-v-modtuprngelt-modtuprngelt-rngelt"></a>
##### `(u, v): ModTupRngElt, ModTupRngElt -> RngElt`

<a id="function-innerproduct-modtuprngelt-modtuprngelt"></a>
##### `InnerProduct(u, v): ModTupRngElt, ModTupRngElt -> RngElt`

Return the inner product of the vectors $u$ and $v$ with respect to the inner product defined on the space. If an inner product matrix $F$ is given when the space is created, then this is defined to be $u\cdot F\cdot v^{tr}$. Otherwise, this is simply $u\cdot v^{tr}$.

<a id="function-norm-modtuprngelt"></a>
##### `Norm(u): ModTupRngElt -> RngElt`

Return the norm product of the vector $u$ with respect to the inner product defined on the space. If an inner product matrix $F$ is given when the space is created, then this is defined to be $u\cdot F\cdot u^{tr}$. Otherwise, this is simply $u\cdot u^{tr}$.

### Bases

The application of the functions in this section is restricted either to vector spaces or to torsion-free modules over a Euclidean Domain. For a full description of the basis functions for a module defined over a field, the reader is referred to the chapter on vector spaces.

<a id="function-basis-modtuprng"></a>
#### `Basis(M): ModTupRng -> [ModTupRngElt]`

The current basis for the free $R$-module $M$, $R$ an ED, returned as a sequence of module elements.

<a id="function-rank-modtuprng"></a>
#### `Rank(M): ModTupRng -> RngIntElt`

The rank of the free $R$-module $M$.

<a id="function-coordinates-modtuprng-modtuprngelt"></a>
#### `Coordinates(M, u): ModTupRng, ModTupRngElt -> [RngElt]`

Given a vector $u$ belonging to the rank $r$ free $R$-module $M$, $R$ an Euclidean Domain, with basis $u_1, \ldots, u_r$, return a sequence $[a_1, \ldots, a_r]$ giving the coordinates of $u$ relative to the $M$-basis: $u = a_1*u_1 + \cdots +a_r*u_r$.

### Submodules

#### Construction of Submodules

Submodules may be defined for any type of module. However, functions that depend upon membership testing are only implemented for modules over Euclidean Domains (EDs). The conventions defining the presentations of submodules are as follows:

**•**
If $M$ has been created using the function `RSpace`, then every submodule of $M$ is given in terms of a generating set consisting of elements of $M$, i.e. by means of an embedded generating set.

**•**
If $M$ has been created using the function `RModule`, then every submodule of $M$ is given in terms of a reduced basis.

<a id="constructor-constructor-sub-modtuprng-list-modtuprng"></a>
##### `sub<M | L>: ModTupRng, List -> ModTupRng`

<a id="constructor-constructor-sub-modmatrng-list-modmatrng"></a>
##### `sub<M | L>: ModMatRng, List -> ModMatRng`

Given an $R$-module $M$, construct the submodule $N$ generated by the elements of $M$ specified by the list $L$. Each term $L_i$ of the list $L$ must be an expression defining an object of one of the following types:

**(a)**
A sequence of $n$ elements of $R$ defining an element of $M$;

**(b)**
A set or sequence whose terms are elements of $M$;

**(c)**
A submodule of $M$;

**(d)**
A set or sequence whose terms are submodules of $M$.

The generators stored for $N$ consist of the elements specified by terms $L_i$ together with the stored generators for submodules specified by terms of $L_i$. Repetitions of an element and occurrences of the zero element are removed (unless $N$ is trivial).

The constructor returns the submodule $N$ and the inclusion homomorphism $f : N \rightarrow M$.

<a id="example-ex-e4a021"></a>
##### `Example: Submodule over a Rational Function Field (ex-e4a021)`

We construct a submodule of the $4$-dimensional vector space over the field of rational function $F[x]$, where $F$ is ${\bf F}_{5}$.

```magma
> P := PolynomialRing(GF(5));
> R<x> := FieldOfFractions(P);
> M := RSpace(R, 4);
> N := sub< M | [1, x, 1-x, 0], [1+2*x-x^2, 2*x, 0, 1-x^4 ] >;
> N;
Vector space of degree 4, dimension 2 over Field of Fractions in x over
Univariate Polynomial Algebra over GF(5)
Generators:
(1    x    4*x + 1    0)
(4*x^2 + 2*x + 1    2*x    0    4*x^4 + 1)
Echelonized basis:
(1  0  3/(x + 4)  (x^3 + x^2 + x + 1) / (x + 4))
(0  1  (4*x^2 + 2*x + 1) / (x^2 + 4*x)  (4*x^3 + 4*x^2 + 4*x + 4) / (x^2 + 4*x))
```

#### Operations on Submodules

#### Membership and Equality

The following operations are only available for submodules of $R^{(n)}$, $\Hom_R(M, N)$, and $R[G]$, where $R$ is a Euclidean Domain. If the modules involved are $R[G]$-modules, the operators refer to the underlying $R$-module.

<a id="operation-op-in-modtuprngelt-modtuprng"></a>
##### `u in M: ModTupRngElt, ModTupRng -> BoolElt`

<a id="operation-op-in-modmatrngelt-modmatrng"></a>
##### `u in M: ModMatRngElt, ModMatRng -> BoolElt`

Returns `true` if the element $u$ lies in the $R$-module $M$, where $u$ and $M$ belong to the same $R$-module.

<a id="operation-op-notin-modtuprngelt-modtuprng"></a>
##### `u notin M: ModTupRngElt, ModTupRng -> BoolElt`

<a id="operation-op-notin-modmatrngelt-modmatrng"></a>
##### `u notin M: ModMatRngElt, ModMatRng -> BoolElt`

Returns `true` if the element $u$ does not lie in the $R$-module $M$, where $u$ and $M$ belong to the same $R$-module.

<a id="operation-op-subset-modtuprng-modtuprng"></a>
##### `N subset M: ModTupRng, ModTupRng -> BoolElt`

<a id="operation-op-subset-modmatrng-modmatrng"></a>
##### `N subset M: ModMatRng, ModMatRng -> BoolElt`

Returns `true` if the $R$-module $N$ is contained in the $R$-module $M$, where $M$ and $N$ belong to a common $R$-module.

<a id="operation-operation-notsubset-modtuprng-modtuprng-boolelt"></a>
##### `N notsubset M: ModTupRng, ModTupRng -> BoolElt`

<a id="operation-operation-notsubset-modmatrng-modmatrng-boolelt"></a>
##### `N notsubset M: ModMatRng, ModMatRng -> BoolElt`

Returns `true` if the $R$-module $N$ is not contained in the $R$-module $M$, where $M$ and $N$ belong to a common $R$-module.

<a id="operation-op-eq-modtuprng-modtuprng"></a>
##### `N eq M: ModTupRng, ModTupRng -> BoolElt`

<a id="operation-op-eq-modmatrng-modmatrng"></a>
##### `M eq N: ModMatRng, ModMatRng -> BoolElt`

Returns `true` if the $R$-modules $N$ and $M$ are equal, where $N$ and $M$ belong to a common $R$-module.

<a id="operation-op-ne-modtuprng-modtuprng"></a>
##### `N ne M: ModTupRng, ModTupRng -> BoolElt`

<a id="operation-op-ne-modmatrng-modmatrng"></a>
##### `M ne N: ModMatRng, ModMatRng -> BoolElt`

Returns `true` if the $R$-modules $N$ and $M$ are not equal, where $N$ and $M$ belong to a common $R$-module.

<a id="id1"></a>
#### Operations on Submodules

The following operations are only available for submodules of $R^{(n)}$, $\Hom_R(M, N)$, and $R[G]$, where $R$ is a Euclidean Domain. If the modules involved are $R[G]$-modules, the operators refer to the underlying $R$-module.

<a id="operation-op-plus-modtuprng-modtuprng"></a>
##### `M + N: ModTupRng, ModTupRng -> ModTupRng`

<a id="operation-op-plus-modmatrng-modmatrng"></a>
##### `M + N: ModMatRng, ModMatRng -> ModMatRng`

Sum of the submodules $M$ and $N$, where $M$ and $N$ belong to a common $R$-module.

<a id="operation-op-meet-modtuprng-modtuprng"></a>
##### `M meet N: ModTupRng, ModTupRng -> ModTupRng`

<a id="operation-op-meet-modmatrng-modmatrng"></a>
##### `M meet N: ModMatRng, ModMatRng -> ModMatRng`

Intersection of the submodules $M$ and $N$, where $M$ and $N$ belong to a common $R$-module.

### Quotient Modules

#### Construction of Quotient Modules

<a id="constructor-constructor-quo-modtuprng-list-modtuprng"></a>
##### `quo<M | L>: ModTupRng, List -> ModTupRng`

<a id="constructor-constructor-quo-modmatrng-list-modmatrng"></a>
##### `quo<M | L>: ModMatRng, List -> ModMatRng`

Given an $R$-module $M$, construct the quotient module $P = M/N$, where $N$ is the submodule generated by the elements of $M$ specified by the list $L$. Each term $L_i$ of the list $L$ must be an expression defining an object of one of the following types:

**(a)**
A sequence of $n$ elements of $R$ defining an element of $M$;

**(b)**
A set or sequence whose terms are elements of $M$;

**(c)**
A submodule of $M$;

**(d)**
A set or sequence whose terms are submodules of $M$.

The generators constructed for $N$ consist of the elements specified by terms $L_i$ together with the stored generators for submodules specified by terms of $L_i$.

The constructor returns the quotient module $P$ and the natural homomorphism $f : M \rightarrow P$.

### Homomorphisms

Throughout this part of the chapter, when discussing the set of all $R$-homomorphisms from the $R$-module $M$ into the $R$-module $N$, it will be assumed that $R$ is a **commutative** ring. We further assume that $M$ and $N$ are free $R$-modules and that bases for these modules are present. The module ${\operatorname{Hom}}_{R}(M, N)$ will be identified with the module of $m \times n$ matrices over $R$. Thus, an element of ${\operatorname{Hom}}_{R}(M, N)$ is represented as a matrix relative to the bases of the generic modules corresponding to $M$ and $N$. For this reason, we will refer to these modules as *matrix modules*. We remind the reader that submodules of ${\operatorname{Hom}}_{R}(M, N)$ are always presented in embedded form. If the user wishes to have submodules presented in reduced form then he/she should use the natural isomorphism between $R^{(m \times n)}$ and $R^{(mn)}$.

It should be noted that essentially operation defined for tuple modules, their elements, and submodules applies to matrix modules. Thus, all of the operations discussed earlier in this chapter apply to matrix modules. The modules $M$ and $N$ may themselves be matrix modules. In this case, the resulting matrix module has either a right or left action and an element belonging to it transforms a (homomorphism) element of $M$ into a (homomorphism) element of $N$. The function `Reduce` may be used to construct for a matrix module $H$ the matrix module $H'$ equivalent to $H$ whose elements are with respect to the actual bases of the domain and codomain of elements of $H$ (not the generic bases of the domain and codomain).

<a id="operatorname-hom-r-m-n-for-r-modules"></a>
#### ${\operatorname{Hom}}_{R}(M, N)$ for $R$-modules

<a id="function-hom-modtuprng-modtuprng"></a>
##### `Hom(M, N): ModTupRng, ModTupRng -> ModMatRng`

If $M$ is the tuple module $R^{(m)}$ and $N$ is the tuple module $R^{(n)}$, create the module ${\operatorname{Hom}}_{R}(M, N)$ as the $(R, R)$-bimodule $R^{(m \times n)}$, represented as the set of all $m \times n$ matrices over $R$. The module is created with the standard basis, $\{E_{ij}\  |\  i = 1 \ldots, m, j = 1 \ldots, n\}$, where $E_{ij}$ is the matrix having a $1$ in the ($i, j$)-th position and zeros elsewhere.

<a id="function-rmatrixspace-rng-rngintelt-rngintelt-2"></a>
##### `RMatrixSpace(R, m, n): Rng, RngIntElt, RngIntElt -> ModMatRng`

Given a ring $R$ and positive integers $m$ and $n$, construct $H = {\operatorname{Hom}}(M, N)$, where $M = R^{(m)}$ and $N = R^{(n)}$, as the free $(R, R)$-bimodule $R^{(m \times n)}$, consisting of all $m \times n$ matrices over $R$. The module is created with the standard basis, $\{E_{ij}\  |\  i = 1 \ldots, m, j = 1 \ldots, m\}$. Note that the modules $M$ and $N$ are created by this function and may be accessed as `Domain(H)` and `Codomain(H)`, respectively.

<a id="example-ex-bf6e98"></a>
##### `Example: Module of Homomorphisms of Vector Spaces (ex-bf6e98)`

We construct the vector spaces $V$ and $W$ of dimensions $3$ and $4$, respectively, over the field of two elements and then define M to be the module of homomorphisms from $V$ into $W$.

```magma
> F2 := GaloisField(2);
> V  := VectorSpace(F2, 3);
> W  := VectorSpace(F2, 4);
> M  := Hom(V, W);
> M;
Full KMatrixSpace of 3 by 4 matrices over GF(2)
```

<a id="operatorname-hom-r-m-n-for-matrix-modules"></a>
#### ${\operatorname{Hom}}_{R}(M, N)$ for Matrix Modules

<a id="function-hom-modmatrng-modmatrng-monstgelt-right"></a>
##### `Hom(M, N, "right"): ModMatRng, ModMatRng, MonStgElt -> ModMatRng`

Suppose $M$ is a matrix module over the coefficient ring $R$ whose elements are $a$ by $b$ matrices and have domain $D$ and codomain $C$. Suppose also that $N$ is a matrix module over the coefficient ring $R$ whose elements are $a$ by $c$ matrices and have domain $D$ and codomain $C'$. Then the homomorphism module $H = {\operatorname{Hom}}(M, N)$ with right multiplication action exists and consists of all $b$ by $c$ matrices over $R$ which multiply an element of $M$ on the right to yield an element of $N$. This function constructs $H$ explicitly. The domain of elements of $H$ is then $M$ and the codomain of elements of $H$ is $N$ and the elements are $b$ by $c$ matrices over $R$ which multiply an element of $M$ on the right to yield an element of $N$. Note that if $M$ and $N$ are proper submodules of their respective generic modules, then $H$ may be a proper submodule of its generic module, and the correct basis of $H$ will be explicitly constructed.

<a id="function-hom-modmatrng-modmatrng-monstgelt-left"></a>
##### `Hom(M, N, "left"): ModMatRng, ModMatRng, MonStgElt -> ModMatRng`

Suppose $M$ is a matrix module over the coefficient ring $R$ whose elements are $a$ by $c$ matrices and have domain $D$ and codomain $C$. Suppose also that $N$ is a matrix module over the coefficient ring $R$ whose elements are $b$ by $c$ and have domain $D'$ and codomain $C$. Then the homomorphism module $H = {\operatorname{Hom}}(M, N)$ with left multiplication action exists and consists of all $b$ by $a$ matrices over $R$ which multiply an element of $M$ on the left to yield an element of $N$. This function constructs $H$ explicitly. The domain of elements of $H$ is then $M$ and the codomain of elements of $H$ is $N$ and the elements are $b$ by $a$ matrices over $R$ which multiply an element of $M$ on the right to yield an element of $N$. Note that if $M$ and $N$ are proper submodules of their respective generic modules, then $H$ may be a proper submodule of its generic module, and the correct basis of $H$ will be explicitly constructed.

<a id="example-ex-e3a29e"></a>
##### `Example: Homomorphisms Between Homomorphism Modules (ex-e3a29e)`

We construct two homomorphism modules $H_1$ and $H_2$ over ${\mathbb{Q}}$ and then the homomorphism module $H = {\operatorname{Hom}}(H_1, H_2)$ with right matrix action.

```magma
> Q := RationalField();
> H1 := sub<RMatrixSpace(Q, 2, 3) | [1,2,3, 4,5,6], [0,0,1, 1,3,3]>;
> H2 := sub<RMatrixSpace(Q, 2, 4) | [6,5,7,1, 15,14,16,4], [0,0,0,0, 1,2,3,4]>;
> H := Hom(H1, H2, "right");
> H: Maximal;
KMatrixSpace of 3 by 4 matrices and dimension 1 over Rational Field
Echelonized basis:

[   1    2    3    4]
[-1/2   -1 -3/2   -2]
[   0    0    0    0]

> H1.1 * H.1;
[  0   0   0   0]
[3/2   3 9/2   6]
> H1.1 * H.1 in H2;
true
> Image(H.1): Maximal;
KMatrixSpace of 2 by 4 matrices and dimension 1 over Rational Field
Echelonized basis:

[0 0 0 0]
[1 2 3 4]

> Kernel(H.1): Maximal;
KMatrixSpace of 2 by 3 matrices and dimension 1 over Rational Field
Echelonized basis:

[ 1  2  6]
[ 7 14 15]

> H1 := sub<RMatrixSpace(Q,2,3) | [1,2,3, 4,5,6]>;
> H2 := sub<RMatrixSpace(Q,3,3) | [1,2,3, 5,7,9, 4,5,6]>;
> H := Hom(H1, H2, "left");
> H: Maximal;
KMatrixSpace of 3 by 2 matrices and dimension 1 over Rational Field
Echelonized basis:

[1 0]
[1 1]
[0 1]
> Image(H.1);
KMatrixSpace of 3 by 3 matrices and dimension 1 over Rational Field
> Kernel(H.1);
KMatrixSpace of 2 by 3 matrices and dimension 0 over Rational Field
```

<a id="modules-operatorname-hom-r-m-n-with-given-basis"></a>
#### Modules ${\operatorname{Hom}}_{R}(M, N)$ with Given Basis

<a id="function-rmatrixspacewithbasis-modmatrngelt"></a>
##### `RMatrixSpaceWithBasis(Q): [ ModMatRngElt ] -> ModMatRng`

Given a sequence $Q$ of $k$ independent matrices each lying in a matrix space $H = {\operatorname{Hom}}(M, N)$, where $M = R^{(m)}$ and $N = R^{(n)}$, construct the subspace of $H$ of dimension $k$ whose basis is $Q$. The basis is echelonized internally but all functions which depend on the basis of the matrix space (e.g. `Coordinates`) will use the given basis $Q$.

<a id="function-kmatrixspacewithbasis-modmatrngelt"></a>
##### `KMatrixSpaceWithBasis(Q): [ ModMatRngElt ] -> ModMatRng`

Given a sequence $Q$ of $k$ independent matrices each lying in a matrix space $H = {\operatorname{Hom}}(M, N)$, where $M = K^{(m)}$ and $N = K^{(n)}$, with $K$ a field, construct the subspace of $H$ of dimension $k$ whose basis is $Q$. The basis is echelonized internally but all functions which depend on the basis of the matrix space (e.g. `Coordinates`) will use the given basis $Q$.

#### The Endomorphism Ring

<a id="function-endomorphismalgebra-modtuprng"></a>
##### `EndomorphismAlgebra(M): ModTupRng -> AlgMat`

If $M$ is the free R-module $R^{(m)}$, create the matrix algebra ${\operatorname{Mat}}_m(R)$. The algebra is created with the standard basis, $\{E_{ij}\  |\  i = 1 \ldots, m, j = 1 \ldots, m\}$, where $E_{ij}$ is the matrix having a $1$ in the ($i, j$)-th position and zeros elsewhere.

<a id="example-ex-7acde1"></a>
##### `Example: Endomorphism Ring of a Vector Space (ex-7acde1)`

We construct the endomorphism ring of the $4$-dimensional vector space over the rational field.

```magma
> Q  := RationalField();
> R4 := RModule(Q, 4);
> M  := EndomorphismAlgebra(R4);
> M;
Full Matrix Algebra of degree 4 over Rational Field
```

#### The Reduced Form of a Matrix Module

<a id="function-reduce-modmatrng"></a>
##### `Reduce(H): ModMatRng -> ModMatRng, Map`

Suppose $H$ is a matrix module whose elements have domain $A$ and codomain $B$. Suppose first that $A$ and $B$ are tuple modules ($R$-spaces, $R$-modules, or $RG$-modules) and that $A$ has degree $a$ and dimension $d$ while $B$ has degree $b$ and dimension $e$. (For the reduced cases ($R$-modules or $RG$-modules), $a$ equals $d$ and $b$ equals $e$). The elements of $H$ have the natural representation with respect to the standard embedded basis of the generic modules of $A$ and $B$. Thus $H$ has degree $a$ by $b$. So one can multiply a 1 by $a$ vector of $A$ directly by an element $h$ of $H$ (in the natural matrix way) to get a 1 by $b$ vector of $B$. Now suppose $A$ and $B$ are in the embedded form ($R$-space) and $h$ is in $H$. Then $h$ is an $a$ by $b$ matrix but there is a corresponding $d$ by $e$ matrix $h'$ which gives the same transformation of $h$ from $A$ to $B$ but is *with respect to the bases of* $A$ *and* $B$. We call $h'$ the *reduced* form of $h$. Also, there is the *reduced module* $H'$ corresponding to $H$. This function constructs the reduced module $H'$ corresponding to $H$, together with the epimorphism $f$ from $H$ onto $H'$. Note that if $A$ and $B$ are in reduced form, then $H'$ is the same as $H$. Suppose secondly that $A$ and $B$ are matrix modules themselves. Suppose $A = {\operatorname{Hom}}(D_1, C_1)$, $B = {\operatorname{Hom}}(D_1, C_2)$, and $H = {\operatorname{Hom}}(A, B)$ with the right multiplication action. Suppose also that $A$ has degree $r$ by $s$ and dimension $d$ while $B$ has degree $r$ by $t$, and dimension $e$. Then $H$ would have degree $s$ by $t$ so an element $h$ of $H$ would be $s$ by $t$ and would multiply a $r$ by $s$ element of $A$ on the right to yield an $r$ by $t$ element of $B$. Then the reduced matrix $h'$ corresponding to a matrix $h$ of $H$ would be a $d$ by $e$ matrix corresponding to the bases of $A$ and $B$. This function similarly constructs the reduced module $H'$ corresponding to $H$, together with the epimorphism $f$ from $H$ onto $H'$. Note also that in this case the domain and codomains of $H'$ are the generic $R$-spaces (tuple modules) corresponding to $A$ (of dimension $d$) and $B$ (of dimension $e$). Similarly, for the left multiplication action there is the corresponding reduced module constructed in the obvious way. Note also that the kernel of the epimorphism $f$ is the submodule of $H$ which consists of all matrices which transform all elements of $A$ to the zero element of $B$.

<a id="example-ex-ecaba6"></a>
##### `Example: Reduced Form for Maps Between Vector Spaces (ex-ecaba6)`

We demonstrate the function `Reduce` for a homomorphism module from one vector space to another.

```magma
> V1 := sub<VectorSpace(GF(3), 3) | [1,0,1], [0,1,2]>;
> V2 := sub<VectorSpace(GF(3), 4) | [1,1,0,2], [0,0,1,2]>;
> H := Hom(V1, V2);
> H;
KMatrixSpace of 3 by 4 matrices and dimension 8 over GF(3)
> R, f := Reduce(H);
> R;
Full KMatrixSpace of 2 by 2 matrices over GF(3)
> H.1;
[1 0 0 0]
[0 1 0 2]
[0 1 0 2]
> f(H.1);
[1 0]
[0 0]
> V1.1;
(1 0 1)
> V1.1 * H.1;
(1 1 0 2)
> Coordinates(V2, V1.1 * H.1);
[ 1, 0 ]
> Coordinates(V2, V1.2 * H.1);
[ 0, 0 ]
> Kernel(f): Maximal;
KMatrixSpace of 3 by 4 matrices and dimension 4 over GF(3)
Echelonized basis:

[1 0 0 0]
[2 0 0 0]
[2 0 0 0]

[0 1 0 0]
[0 2 0 0]
[0 2 0 0]

[0 0 1 0]
[0 0 2 0]
[0 0 2 0]

[0 0 0 1]
[0 0 0 2]
[0 0 0 2]
> R.1@@f;
[1 0 0 0]
[0 1 0 2]
[0 1 0 2]
```

<a id="example-ex-4c472d"></a>
##### `Example: Reduced Form for Maps Between Hom Modules (ex-4c472d)`

We demonstrate the function `Reduce` for a homomorphism module from one homomorphism module to another. Note that the reduced module has the same dimension as the original module but larger degrees!

```magma
> V1 := VectorSpace(GF(3), 2);
> V2 := VectorSpace(GF(3), 3);
> V3 := VectorSpace(GF(3), 4);
> H1 := Hom(V1, V2);
> H2 := Hom(V1, V3);
> H := Hom(H1, H2, "right");
> H1;
Full KMatrixSpace of 2 by 3 matrices over GF(3)
> H2;
Full KMatrixSpace of 2 by 4 matrices over GF(3)
> H;
Full KMatrixSpace of 3 by 4 matrices over GF(3)
> R,f := Reduce(H);
> R;
KMatrixSpace of 6 by 8 matrices and dimension 12 over GF(3)
> X := H.1;
> X;
[1 0 0 0]
[0 0 0 0]
[0 0 0 0]
> f(X);
[1 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 1 0 0 0]
[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]
> Domain(X);
Full KMatrixSpace of 2 by 3 matrices over GF(3)
> Domain(f(X));
Full Vector space of degree 6 over GF(3)
> Image(X): Maximal;
KMatrixSpace of 2 by 4 matrices and dimension 2 over GF(3)
Echelonized basis:

[1 0 0 0]
[0 0 0 0]

[0 0 0 0]
[1 0 0 0]

> Image(f(X));
Vector space of degree 8, dimension 2 over GF(3)
Echelonized basis:
(1 0 0 0 0 0 0 0)
(0 0 0 0 1 0 0 0)
> Kernel(X): Maximal;
KMatrixSpace of 2 by 3 matrices and dimension 4 over GF(3)
Echelonized basis:

[0 1 0]
[0 0 0]

[0 0 1]
[0 0 0]

[0 0 0]
[0 1 0]

[0 0 0]
[0 0 1]

> Kernel(f(X)): Maximal;
Vector space of degree 6, dimension 4 over GF(3)
Echelonized basis:
(0 1 0 0 0 0)
(0 0 1 0 0 0)
(0 0 0 0 1 0)
(0 0 0 0 0 1)
```

#### Construction of a Matrix

<a id="operation-op-modmatrng-rngelt"></a>
##### `M ! Q: ModMatRng, [RngElt] -> ModMatRngElt`

Given the matrix bimodule $M$ over the ring $R$, and the sequence $Q = [a_{11}$, $\ldots$, $a_{1n}$, $a_{21}$, $\ldots$, $a_{2n}$, $\ldots$, $a_{m1}$, $\ldots$, $a_{mn}]$ whose terms are elements of the ring $R$, construct the $m \times n$ matrix

$$
\begin{pmatrix}a_{11}&a_{12}&\ldots&a_{1n}\\ a_{21}&a_{22}&\ldots&a_{2n}\\ \vdots&\vdots&\ddots&\vdots\\ a_{m1}&a_{m2}&\ldots&a_{mn}\end{pmatrix}
$$

as an element of $M$. In the context of the `sub` or `quo` constructors the coercion clause `M !` may be omitted.

<a id="example-ex-9b8959"></a>
##### `Example: Hilbert Matrix as an Endomorphism (ex-9b8959)`

We create the $4 \times 4$ Hilbert matrix $h4$ as an element of the endomorphism ring of the $4$-dimensional vector space over the rational field.

```magma
> Q  := RationalField();
> R4 := RModule(Q, 4);
> M  := EndomorphismAlgebra(R4);
> h4 := M ! [ 1/i :  i in [1 .. 16 ] ];
> h4;
[   1  1/2  1/3  1/4]
[ 1/5  1/6  1/7  1/8]
[ 1/9 1/10 1/11 1/12]
[1/13 1/14 1/15 1/16]
```

#### Element Operations

All operations that apply to elements of tuple modules also apply to elements of matrix modules. Here, we confine our discussion to those operations which are special to matrix modules. Throughout this section, $M$ is a submodule of $R^{(m)}$, $N$ is a submodule of $R^{(n)}$ and $a$ is a homomorphism belonging to ${\operatorname{Hom}}_{R}(M, N)$, where $R$ is a Euclidean Domain. See also the chapter on general matrices for many other functions applicable to matrices (e.g., `EchelonForm)`.

<a id="operation-op-times-modtuprngelt-modmatrngelt"></a>
##### `u * a: ModTupRngElt, ModMatRngElt -> ModTupRngElt`

<a id="literal-a-modtuprngelt-modmatrngelt"></a>
##### `a(u): ModTupRngElt, ModMatRngElt -> ModTupRngElt`

Given an element $u$ belonging to the module $M$, return the image of $u$ under the homomorphism $a$ as an element of the module $N$.

<a id="operation-op-times-modmatrngelt-modmatrngelt"></a>
##### `a * b: ModMatRngElt, ModMatRngElt -> ModMatRngElt`

Given a homomorphism $a$ belonging to a submodule of ${\operatorname{Hom}}(M, N)$, and a homomorphism $b$ belonging to a submodule of ${\operatorname{Hom}}(N, P)$, return the composition of the homomorphisms $a$ and $b$ as an element of ${\operatorname{Hom}}(M, P)$. Note that if ${\operatorname{Hom}}(M, P)$ does not already exist, it will be created.

<a id="operation-op-pow-modmatrngelt-rngintelt"></a>
##### `a ^ -1: ModMatRngElt, RngIntElt -> ModMatRngElt`

Given a homomorphism $a$ belonging to a submodule of ${\operatorname{Hom}}(M, N)$ with $M$ and $N$ having the same dimension, return the inverse of $a$ as an element of ${\operatorname{Hom}}(N, M)$.

<a id="function-codomain-modmatrng"></a>
##### `Codomain(S): ModMatRng -> ModTupRng`

Given a submodule $S$ of the module ${\operatorname{Hom}}(M, N)$, return the module $N$.

<a id="function-codomain-modmatrngelt"></a>
##### `Codomain(a): ModMatRngElt -> ModTupRng`

The codomain $N$ of the homomorphism $a$ belonging to ${\operatorname{Hom}}(M, N)$.

<a id="function-cokernel-modmatrngelt"></a>
##### `Cokernel(a): ModMatRngElt -> ModTupRng`

The cokernel for the homomorphism $a$ belonging to the module ${\operatorname{Hom}}(M, N)$.

<a id="function-domain-modmatrng"></a>
##### `Domain(S): ModMatRng -> ModTupRng`

The domain $M$ of the submodule $S$ belonging to the module ${\operatorname{Hom}}(M, N)$.

<a id="function-domain-modmatrngelt"></a>
##### `Domain(a): ModMatRngElt -> ModTupRng`

The domain $M$ of the homomorphism $a$ belonging to the module ${\operatorname{Hom}}(M, N)$.

<a id="function-image-modmatrngelt"></a>
##### `Image(a): ModMatRngElt -> ModTupRng`

The image of the homomorphism $a$ belonging to the module $H ={\operatorname{Hom}}(M, N)$, returned as a submodule of $N$. Note that if the domain and codomain of $a$ are matrix modules themselves, the image will be with respect to the appropriate action (right or left).

<a id="function-kernel-modmatrngelt"></a>
##### `Kernel(a): ModMatRngElt -> ModTupRng`

<a id="function-nullspace-modmatrngelt"></a>
##### `NullSpace(a): ModMatRngElt -> ModTupRng`

The kernel of the homomorphism $a$ belonging to the module ${\operatorname{Hom}}(M, N)$, returned as a submodule of $M$. Note that if the domain and codomain of $a$ are matrix modules themselves, the kernel will be with respect to the appropriate action (right or left).

<a id="function-morphism-modtuprng-modtuprng"></a>
##### `Morphism(M, N): ModTupRng, ModTupRng -> ModMatRngElt`

Assuming the $R$-module $M$ was created as a submodule of the module $N$, return the matrix defining the inclusion homomorphism $\phi : M \rightarrow N$ as an element of ${\operatorname{Hom}}_R(M, N)$. Thus $\phi$ gives the correspondence between elements of $M$ (represented with respect to the standard basis of $M$) and elements for $N$.

<a id="function-rank-modmatrngelt"></a>
##### `Rank(a): ModMatRngElt -> RngIntElt`

The dimension of the image of the homomorphism $a$, i.e. the rank of $a$.

<a id="function-isbijective-modmatrngelt"></a>
##### `IsBijective(a): ModMatRngElt -> BoolElt`

Returns `true` if the homomorphism $a$ belonging to the module ${\operatorname{Hom}}(M, N)$ is a bijective mapping.

<a id="function-isinjective-modmatrngelt"></a>
##### `IsInjective(a): ModMatRngElt -> BoolElt`

Returns `true` if the homomorphism $a$ belonging to the module ${\operatorname{Hom}}(M, N)$ is an injective mapping.

<a id="function-issurjective-modmatrngelt"></a>
##### `IsSurjective(a): ModMatRngElt -> BoolElt`

Returns `true` if the homomorphism $a$ belonging to the module ${\operatorname{Hom}}_R(M, N)$ is a surjective mapping.

<a id="example-ex-85af3b"></a>
##### `Example: Operations in a Homomorphism Module (ex-85af3b)`

We illustrate some of these operations in the context of the module ${\operatorname{Hom}}_R(M, N)$, where $M$ and $N$ are, respectively, the $4$-dimensional and $3$-dimensional vector spaces over $GF(8)$.

```magma
> K<w> := GaloisField(8);
> V3 := VectorSpace(K, 3);
> V4 := VectorSpace(K, 4);
> M := Hom(V4, V3);
> A := M ! [1, w, w^5, 0,  w^3, w^4, w, 1,  w^6, w^3, 1, w^4 ];
> A;
[  1   w w^5]
[  0 w^3 w^4]
[  w   1 w^6]
[w^3   1 w^4]
> Rank(A);
3
> Image(A);
Full Vector space of degree 3 over GF(2^3)
> Kernel(A);
Vector space of degree 4, dimension 1 over GF(2^3)
Echelonized basis:
(  1 w^5   1   1)
> Cokernel(A);
Vector space of degree 3, dimension 0 over GF(2^3)
```

<a id="dedekind-modules"></a>
<a id="modded-chapter"></a>
## Modules over Dedekind Domains

- [Introduction](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/introduction.md)
- [Creation of Modules](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/creation.md)
  - [`Module(O, n): RngOrd, RngIntElt → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/creation.md#function-module-rngord-rngintelt)
  - [`Module(O, n): RngFunOrd, RngIntElt → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/creation.md#function-module-rngfunord-rngintelt)
  - [`Module(O): RngOrd → ModDed, Map`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/creation.md#function-module-rngord)
  - [`Module(O): RngFunOrd → ModDed, Map`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/creation.md#function-module-rngfunord)
  - [`Module(I): RngOrdFracIdl → ModDed, Map`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/creation.md#function-module-rngordfracidl)
  - [`Module(I): RngFunOrdIdl → ModDed, Map`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/creation.md#function-module-rngfunordidl)
  - [`Module(S): SeqEnum[Tup] → ModDed, Map`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/creation.md#function-module-seqenum-tup)
  - [`Module(S): SeqEnum[RngOrdFracIdl] → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/creation.md#function-module-seqenum-rngordfracidl)
  - [`Module(S): SeqEnum[RngFunOrdIdl] → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/creation.md#function-module-seqenum-rngfunordidl)
  - [`Module(S): SeqEnum[ModElt] → ModDed, Map`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/creation.md#function-module-seqenum-modelt)
  - [Example: Creating Modules over Dedekind Domains](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/creation.md#example-ex-5637aa)
  - [`sub<M | m>: ModDed, SeqEnum[ModDedElt] → ModDed, Map`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/creation.md#constructor-constructor-sub-modded-seqenum-moddedelt-modded-map)
  - [`sub<M | m1, .., mn>: ModDed, ModDedElt, ..., ModDedElt → ModDed, Map`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/creation.md#constructor-constructor-sub-modded-moddedelt-moddedelt-modded-map)
  - [`quo<M | S>: ModDed, ModDed → ModDed, Map`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/creation.md#constructor-constructor-quo-modded-modded-modded-map)
  - [`quo<M | m>: ModDed, SeqEnum[ModDedElt] → ModDed, Map`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/creation.md#constructor-constructor-quo-modded-seqenum-moddedelt-modded-map)
  - [`quo<M | m1, .., mn>: ModDed, ModDedElt, ..., ModDedElt → ModDed, Map`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/creation.md#constructor-constructor-quo-modded-moddedelt-moddedelt-modded-map)
  - [Example: Submodules and Quotient Modules](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/creation.md#example-ex-90c9d8)
- [Elementary Functions](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elementary-functions.md)
  - [`BaseRing(M): ModDed → Rng`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elementary-functions.md#function-basering-modded)
  - [`CoefficientRing(M): ModDed → Rng`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elementary-functions.md#function-coefficientring-modded)
  - [`Degree(M): ModDed → RngIntElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elementary-functions.md#function-degree-modded)
  - [`Ngens(M): ModDed → RngIntElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elementary-functions.md#function-ngens-modded)
  - [`NumberOfGenerators(M): ModDed → RngIntElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elementary-functions.md#function-numberofgenerators-modded)
  - [`M . i: ModDed, RngIntElt → ModTupRngElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elementary-functions.md#operation-operation-modded-rngintelt-modtuprngelt)
  - [`Determinant(M): ModDed → RngOrdIdl`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elementary-functions.md#function-determinant-modded)
  - [`Determinant(M): ModDed → RngFunOrdIdl`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elementary-functions.md#function-determinant-modded-2)
  - [`Dimension(M): ModDed → RngIntElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elementary-functions.md#function-dimension-modded)
  - [`Contents(M): ModDed → RngOrdFracIdl`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elementary-functions.md#function-contents-modded)
  - [`Simplify(M): ModDed → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elementary-functions.md#function-simplify-modded)
  - [`EmbeddingSpace(M): ModDed → Mod`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elementary-functions.md#function-embeddingspace-modded)
  - [Example: Elementary Functions on a Module](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elementary-functions.md#example-ex-5e5c19)
- [Predicates on Modules](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/ops.md)
  - [`M eq N: ModDed, ModDed → BoolElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/ops.md#operation-op-eq-modded-modded)
  - [`x in M: Any, ModDed → BoolElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/ops.md#operation-op-in-any-modded)
  - [`M subset N: ModDed, ModDed → BoolElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/ops.md#operation-op-subset-modded-modded)
  - [`IsFree(M): ModDed → BoolElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/ops.md#function-isfree-modded)
- [Arithmetic with Modules](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/module-arith.md)
  - [`I * M: RngOrdIdl, ModDed → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/module-arith.md#operation-op-times-rngordidl-modded)
  - [`I * M: RngFunOrdIdl, ModDed → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/module-arith.md#operation-op-times-rngfunordidl-modded)
  - [`M * I: ModDed, RngOrdIdl → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/module-arith.md#operation-op-times-modded-rngordidl)
  - [`M * I: ModDed, RngFunOrdIdl → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/module-arith.md#operation-op-times-modded-rngfunordidl)
  - [`M1 + M2: ModDed, ModDed → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/module-arith.md#operation-op-plus-modded-modded)
  - [`DirectSum(M1, M2): ModDed, ModDed → ModDed, Map, Map, Map, Map`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/module-arith.md#function-directsum-modded-modded)
  - [`DirectSum(S): [ModDed] → ModDed, [Map], [Map]`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/module-arith.md#function-directsum-modded)
  - [`u * I: ModDedElt, RngOrdIdl → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/module-arith.md#operation-op-times-moddedelt-rngordidl)
  - [`u * I: ModDedElt, RngFunOrdIdl → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/module-arith.md#operation-op-times-moddedelt-rngfunordidl)
  - [`I * u: RngOrdIdl, ModDedElt → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/module-arith.md#operation-op-times-rngordidl-moddedelt)
  - [`I * u: RngFunOrdIdl, ModDedElt → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/module-arith.md#operation-op-times-rngfunordidl-moddedelt)
  - [Example: Module Arithmetic and Predicates](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/module-arith.md#example-ex-79759b)
- [Basis of a Module](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/basis.md)
  - [`Basis(M): ModDed → SeqEnum`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/basis.md#function-basis-modded)
  - [`PseudoBasis(M): ModDed → SeqEnum`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/basis.md#function-modded-pseudobasis)
  - [`PseudoGenerators(M): ModDed → SeqEnum`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/basis.md#function-pseudogenerators-modded)
  - [`LocalBasis(M, p): ModDed, RngOrdIdl → [ ModTupFldElt ]`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/basis.md#function-localbasis-modded-rngordidl)
- [Other Functions on Modules](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/other.md)
  - [`M1 meet M2: ModDed, ModDed → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/other.md#operation-op-meet-modded-modded)
  - [`Dual(M): ModDed → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/other.md#function-dual-modded)
  - [`ElementaryDivisors(M, N): ModDed, ModDed → SeqEnum`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/other.md#function-elementarydivisors-modded-modded)
  - [`SteinitzClass(M): ModDed → RngOrdIdl`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/other.md#function-steinitzclass-modded)
  - [`SteinitzForm(M): ModDed → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/other.md#function-steinitzform-modded)
  - [Example: Bases and Other Module Functions](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/other.md#example-ex-69678f)
- [Homomorphisms between Modules](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/homomorphisms.md)
  - [`hom<M -> N | T>: ModDed, ModDed, Map → Map`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/homomorphisms.md#constructor-constructor-hom-modded-modded-map-map)
  - [`hom<M -> N | T>: ModDed, ModDed, SeqEnum[ModTupRngElt] → Map`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/homomorphisms.md#constructor-constructor-hom-modded-modded-seqenum-modtuprngelt-map)
  - [`hom<M -> N | T>: ModDed, ModDed, MtrxSpcElt → Map`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/homomorphisms.md#constructor-constructor-hom-modded-modded-mtrxspcelt-map)
  - [`Hom(M, N): ModDed, ModDed → ModDed, Map`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/homomorphisms.md#function-hom-modded-modded)
  - [`IsSubmodule(M, N): ModDed, ModDed → BoolElt, Map`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/homomorphisms.md#function-issubmodule-modded-modded)
  - [`Morphism(M, N): ModDed, ModDed → Map`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/homomorphisms.md#function-morphism-modded-modded)
  - [Example: Homomorphisms Between Modules over Dedekind Domains](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/homomorphisms.md#example-ex-f6bf14)
- [Elements of Modules](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elements.md)
  - [Creation of Elements](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elements.md#creation-of-elements)
    - [`M ! v: ModDed, SeqEnum → ModDedElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elements.md#operation-op-modded-seqenum)
    - [`M ! v: ModDed, ModDedElt → ModDedElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elements.md#operation-op-modded-moddedelt)
    - [`M ! v: ModDed, ModElt → ModDedElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elements.md#operation-op-modded-modelt)
    - [Example: Coercion into Quotient Modules](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elements.md#example-ex-2c7014)
  - [Arithmetic with Elements](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elements.md#arithmetic-with-elements)
    - [`x + y: ModDedElt, ModDedElt → ModDedElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elements.md#operation-op-plus-moddedelt-moddedelt)
    - [`x - y: ModDedElt, ModDedElt → ModDedElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elements.md#operation-op-minus-moddedelt-moddedelt)
    - [`u * c: ModDedElt, RngElt → ModDedElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elements.md#operation-op-times-moddedelt-rngelt)
    - [`c * u: RngElt, ModDedElt → ModDedElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elements.md#operation-op-times-rngelt-moddedelt)
    - [`u / c: ModDedElt, RngElt → ModDedElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elements.md#operation-op-div-moddedelt-rngelt)
    - [`I * u: RngOrdIdl, ModDedElt → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elements.md#operation-op-times-rngordidl-moddedelt-2)
    - [`I * u: RngFunOrdIdl, ModDedElt → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elements.md#operation-op-times-rngfunordidl-moddedelt-2)
    - [`u * I: ModDedElt, RngOrdIdl → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elements.md#operation-op-times-moddedelt-rngordidl-2)
    - [`u * I: ModDedElt, RngFunOrdIdl → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elements.md#operation-op-times-moddedelt-rngfunordidl-2)
  - [Other Functions on Elements](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elements.md#other-functions-on-elements)
    - [`x eq y: ModDedElt, ModDedElt → Bool`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elements.md#operation-op-eq-moddedelt-moddedelt)
    - [`IsZero(a): ModDedElt → BoolElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elements.md#function-iszero-moddedelt)
    - [`ElementToSequence(a): ModDedElt → SeqEnum`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elements.md#function-elementtosequence-moddedelt)
    - [`Eltseq(a): ModDedElt → SeqEnum`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/elements.md#function-eltseq-moddedelt)
- [Pseudo Matrices](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md)
  - [Construction of a Pseudo Matrix](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#construction-of-a-pseudo-matrix)
    - [`PseudoMatrix(I, m): [RngOrdFracIdl], MtrxSpcElt → PMat`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#function-pseudomatrix-rngordfracidl-mtrxspcelt)
    - [`PseudoMatrix(I, m): [RngFunOrdIdl], MtrxSpcElt → PMat`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#function-pseudomatrix-rngfunordidl-mtrxspcelt)
    - [`PseudoMatrix(m): Mtrx[FldOrd] → PMat`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#function-pseudomatrix-mtrx-fldord)
    - [`PseudoMatrix(m): Mtrx[RngOrd] → PMat`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#function-pseudomatrix-mtrx-rngord)
    - [`PseudoMatrix(m): Mtrx[FldFunOrd] → PMat`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#function-pseudomatrix-mtrx-fldfunord)
    - [`PseudoMatrix(m): Mtrx[RngFunOrd] → PMat`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#function-pseudomatrix-mtrx-rngfunord)
    - [`PseudoMatrix(M): ModDed → PMat`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#function-pseudomatrix-modded)
    - [`AbsoluteBasis(M): ModDed → SeqEnum`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#function-absolutebasis-modded)
  - [Elementary Functions](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#elementary-functions)
    - [`CoefficientIdeals(P): PMat → SeqEnum`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#function-coefficientideals-pmat)
    - [`Matrix(P): PMat → Mtrx`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#function-matrix-pmat)
    - [`Order(pm): PMat → Rng`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#function-order-pmat)
    - [`Dimension(pm): PMat → RngIntElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#function-dimension-pmat)
    - [`Length(pm): PMat → RngIntElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#function-length-pmat)
  - [Basis of a Pseudo Matrix](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#basis-of-a-pseudo-matrix)
    - [`Basis(P): PMat → SeqEnum`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#function-basis-pmat)
  - [Predicates](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#predicates)
    - [`p1 eq p2: PMat, PMat → BoolElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#operation-op-eq-pmat-pmat)
  - [Operations with Pseudo Matrices](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#operations-with-pseudo-matrices)
    - [`Transpose(P): PMat → PMat`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#function-transpose-pmat)
    - [`HermiteForm(X): PMat → PMat, AlgMatElt`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#function-hermiteform-pmat)
    - [`VerticalJoin(X, Y): PMat, PMat → PMat`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#function-verticaljoin-pmat-pmat)
    - [`X meet Y: PMat, PMat → PMat`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#operation-op-meet-pmat-pmat)
    - [`Module(X): PMat → ModDed`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#function-module-pmat)
    - [`I * X: RngOrdFracIdl, PMat → PMat`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#operation-op-times-rngordfracidl-pmat)
    - [`I * X: RngFunOrdIdl, PMat → PMat`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#operation-op-times-rngfunordidl-pmat)
    - [`X * I: PMat, RngOrdFracIdl → PMat`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#operation-op-times-pmat-rngordfracidl)
    - [`X * I: PMat, RngFunOrdIdl → PMat`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/pmat.md#operation-op-times-pmat-rngfunordidl)

### Introduction

Since the structure theory for modules over arbitrary orders (which are in general not Dedekind domains) is very unsatisfactory, modules over orders in Magma are always modules over some maximal order of a number field or function field, they form a magma of type `ModDed`.

Let $k$ be a number field or function field and ${\cal O}_k$ its ring of integers. Since ${\cal O}_k$ is a Dedekind domain, every finitely generated torsion free module $M$ over ${\cal O}_k$ has a representation as a direct sum

$$
M = \sum_{i=1}^m {{\cal A}_i} \alpha_i =
   \{ \sum_{i=1}^m a_i\alpha_i \mid a_i \in {\cal A}_i\}
$$

with (fractional) ideals ${{\cal A}_i}$ and elements $\alpha_i \in kM \cong k^r$.

A (not necessarily direct) sum $\sum _{i=1}^m {{\cal A}_i}\alpha_i$ will be represented as a pseudo–matrix $({{\cal A}}|A)$ where ${{\cal A}} = ({{\cal A}_1}, \ldots, {{\cal A}_m})^t$ is a column vector of ideals and $A = (\alpha_1, \ldots, \alpha_m)^t \in k^{m\times r}$ is a matrix. The ideals ${{\cal A}_i}$ are called coefficient ideals.

This pseudo–matrix is called a pseudo–basis iff the sum is direct. A pseudo–matrix $({{\cal A}}| A)$ is in Hermite normal form iff there are $s\leq m$, $1\leq i_1 < i_2< \cdots < i_s$ such that $A_{j, l} = 0$ ($1\leq l<i_j$), $A_{j, i_j} = 1$ and $A_{j, l}$ is reduced modulo ${{\cal A}_j}{{\cal A}_l}^{-1}$. For $j>s$ we have $A_{j,l} = 0$.

This normal form is unique if a suitable reduction is used.

As a consequence of this normalisation, usually $\alpha_i\not\in M$. To be precise: $\alpha_i\in M$ iff $1\in {{\cal A}_i}$.

All modules are in Hermite normal form, i.e. every module is represented by a pseudo–basis in Hermite normal form.

General (non torsion free) modules are represented as quotients of a torsion free module $M$ and a submodule $S$. Elements of $Q := M/S$ are represented as elements of $M$, arithmetic in $Q$ is reduced to arithmetic in $M$ followed by a reduction modulo the pseudo–basis of $S$.

### Creation of Modules

Modules over Dedekind domains can be created from orders of number fields and function fields and combinations of ideals and vector space elements. Submodules and quotient modules by submodules can also be created.

<a id="function-module-rngord-rngintelt"></a>
#### `Module(O, n): RngOrd, RngIntElt -> ModDed`

<a id="function-module-rngfunord-rngintelt"></a>
#### `Module(O, n): RngFunOrd, RngIntElt -> ModDed`

Create the free module $O^n$ where $O$ is a Dedekind domain.

<a id="function-module-rngord"></a>
#### `Module(O): RngOrd -> ModDed, Map`

<a id="function-module-rngfunord"></a>
#### `Module(O): RngFunOrd -> ModDed, Map`

Create the relative order $O$ as a module over its coefficient ring. Also returns the map from the resulting module into $O$.

<a id="function-module-rngordfracidl"></a>
#### `Module(I): RngOrdFracIdl -> ModDed, Map`

<a id="function-module-rngfunordidl"></a>
#### `Module(I): RngFunOrdIdl -> ModDed, Map`

Create the ideal $I$ of a relative order $O$ as a module over the coefficient ring of the order. Also returns the map from the module into $O$.

<a id="function-module-seqenum-tup"></a>
#### `Module(S): SeqEnum[Tup] -> ModDed, Map`

Create a module from the sequence of tuples of ideals of a Dedekind domain and `ModElt`s with entries in the Dedekind domain or its field of fractions. The elements of the resulting module will be the sum of products of an element of an ideal and the corresponding `ModElt`. Also returns the map from the vector space into the module.

<a id="function-module-seqenum-rngordfracidl"></a>
#### `Module(S): SeqEnum[RngOrdFracIdl] -> ModDed`

<a id="function-module-seqenum-rngfunordidl"></a>
#### `Module(S): SeqEnum[RngFunOrdIdl] -> ModDed`

Create the module which is equal to the direct sum of the ideals in the sequence.

<a id="function-module-seqenum-modelt"></a>
#### `Module(S): SeqEnum[ModElt] -> ModDed, Map`

Create the module which is freely generated by the elements of the sequence $S$. The elements of the sequence must be `ModElt`s with entries in a Dedekind domain or field of fractions of a Dedekind domain. Also returns the map from the vector space into the module.

<a id="example-ex-5637aa"></a>
#### `Example: Creating Modules over Dedekind Domains (ex-5637aa)`

The creation of some simple modules is shown.

```magma
> x := ext<Integers()|>.1;
> M := MaximalOrder(x^2 + 5);
> Module(M, 5);
Module over Maximal Equation Order with defining polynomial x^2 + 5 over Z
 generated by: (in echelon form)
Principal Ideal of M
Generator:
    M.1 * ( M.1 0 0 0 0 )
Principal Ideal of M
Generator:
    M.1 * ( 0 M.1 0 0 0 )
Principal Ideal of M
Generator:
    M.1 * ( 0 0 M.1 0 0 )
Principal Ideal of M
Generator:
    M.1 * ( 0 0 0 M.1 0 )
Principal Ideal of M
Generator:
    M.1 * ( 0 0 0 0 M.1 )
> I := 1/5*M;
> Module([I, I^3, I^8]);
Module over Maximal Equation Order with defining polynomial x^2 + 5 over Z
 generated by: (in echelon form)
Fractional Principal Ideal of M
Generator:
    1/5*M.1 * ( M.1 0 0 )
Fractional Principal Ideal of M
Generator:
    1/125*M.1 * ( 0 M.1 0 )
Fractional Principal Ideal of M
Generator:
    1/390625*M.1 * ( 0 0 M.1 )
> V := RModule(M, 3);
> Module([<I, V![0, 1, 0]>, <I^4, V![2, 3, 5]>]);
Module over Maximal Equation Order with defining polynomial x^2 + 5 over Z
Fractional Principal Ideal of M
Generator:
    1/5*M.1 car Fractional Principal Ideal of M
Generator:
    1/125*M.1
```

The same can be done using orders of function fields.

```magma
> P<x> := PolynomialRing(Rationals());
> P<y> := PolynomialRing(P);
> F<c> := FunctionField(x^2 - y);
> M := MaximalOrderFinite(F);
> Module(M, 5);
Module over Maximal Equation Order of F over Univariate Polynomial Ring in x over
Rational Field
 generated by: (in echelon form)
Ideal of M
Generator:
1 * ( 1 0 0 0 0 )
Ideal of M
Generator:
1 * ( 0 1 0 0 0 )
Ideal of M
Generator:
1 * ( 0 0 1 0 0 )
Ideal of M
Generator:
1 * ( 0 0 0 1 0 )
Ideal of M
Generator:
1 * ( 0 0 0 0 1 )
> I := 1/5*M;
> Module([I, I^3, I^8]);
Module over Maximal Equation Order of F over Univariate Polynomial Ring in x over
Rational Field
 generated by: (in echelon form)
Ideal of M
Generator:
1/5 * ( 1 0 0 )
Ideal of M
Generator:
1/125 * ( 0 1 0 )
Ideal of M
Generator:
1/390625 * ( 0 0 1 )
> V := RModule(M, 3);
> Module([<I, V![0, 1, 0]>, <I^4, V![2, 3, 5]>]);
Integral Module over Maximal Equation Order of F over Univariate Polynomial Ring
in x over Rational
Field
Ideal of M
Generator:
1/5 car Ideal of M
Generator:
1/125
```

<a id="constructor-constructor-sub-modded-seqenum-moddedelt-modded-map"></a>
#### `sub<M | m>: ModDed, SeqEnum[ModDedElt] -> ModDed, Map`

<a id="constructor-constructor-sub-modded-moddedelt-moddedelt-modded-map"></a>
#### `sub<M | m1, .., mn>: ModDed, ModDedElt, ..., ModDedElt -> ModDed, Map`

Construct the submodule of the module $M$ generated by the elements in the sequence or list of elements $m$. Also returns the inclusion map of the submodule into $M$.

<a id="constructor-constructor-quo-modded-modded-modded-map"></a>
#### `quo<M | S>: ModDed, ModDed -> ModDed, Map`

<a id="constructor-constructor-quo-modded-seqenum-moddedelt-modded-map"></a>
#### `quo<M | m>: ModDed, SeqEnum[ModDedElt] -> ModDed, Map`

<a id="constructor-constructor-quo-modded-moddedelt-moddedelt-modded-map"></a>
#### `quo<M | m1, .., mn>: ModDed, ModDedElt, ..., ModDedElt -> ModDed, Map`

Construct the quotient of the module $M$ by the submodule $S$ or the submodule generated by the elements of the sequence or list of elements $m$. Also returns the inclusion map of the quotient module into $M$.

<a id="example-ex-90c9d8"></a>
#### `Example: Submodules and Quotient Modules (ex-90c9d8)`

Use of the `sub` and `quo` constructors is illustrated below. Let $M$ and $V$ be as above when they were referring to number fields.

```magma
> Mod := Module([V|[0,1,0], [4,4,0]]);
> S1 := sub<Mod | >;
> S1;
Integral Module over Maximal Equation Order with defining polynomial x^2 + 5
over Z
(0)
> Q1 := quo<Mod | Mod>;
> Q1;
Quotient of Module over Maximal Equation Order with defining polynomial x^2 + 5
over Z
Principal Ideal of M
Generator:
    4/1*M.1 car Principal Ideal of M
Generator:
    M.1
by Integral Module over Maximal Equation Order with defining polynomial
x^2 + 5 over Z
Principal Ideal of M
Generator:
    4/1*M.1 car Principal Ideal of M
Generator:
    M.1
> S2 := sub<Mod | Mod.2>;
> S2;
Integral Module over Maximal Equation Order with defining polynomial x^2 + 5
over Z
Principal Ideal of M
Generator:
    M.1
> Q2 := quo<Mod | Mod.2>;
> Q2;
Quotient of Module over Maximal Equation Order with defining polynomial x^2 + 5
over Z
Principal Ideal of M
Generator:
    4/1*M.1 car Principal Ideal of M
Generator:
    M.1
by Integral Module over Maximal Equation Order with defining polynomial
x^2 + 5 over Z
Principal Ideal of M
Generator:
    M.1
> S3 := sub<Mod | 4*Mod.1, Mod.2>;
> S3;
Integral Module over Maximal Equation Order with defining polynomial x^2 + 5
over Z
Principal Ideal of M
Generator:
    4/1*M.1 car Principal Ideal of M
Generator:
    M.1
> Q3 := quo<Mod | >;
> Q3;
Integral Module over Maximal Equation Order with defining polynomial x^2 + 5
over Z
Principal Ideal of M
Generator:
    4/1*M.1 car Principal Ideal of M
Generator:
    M.1
> Q4 := quo<Mod | S1>;
> Q4;
Quotient of Module over Maximal Equation Order with defining polynomial x^2 + 5
over Z
Principal Ideal of M
Generator:
    4/1*M.1 car Principal Ideal of M
Generator:
    M.1
by Integral Module over Maximal Equation Order with defining polynomial
x^2 + 5 over Z
(0)
```

### Elementary Functions

Various simple properties of a module can be retrieved using the following functions.

<a id="function-basering-modded"></a>
#### `BaseRing(M): ModDed -> Rng`

<a id="function-coefficientring-modded"></a>
#### `CoefficientRing(M): ModDed -> Rng`

The Dedekind domain which $M$ is a module over.

<a id="function-degree-modded"></a>
#### `Degree(M): ModDed -> RngIntElt`

The dimension of the vector space the module $M$ embeds into.

<a id="function-ngens-modded"></a>
#### `Ngens(M): ModDed -> RngIntElt`

<a id="function-numberofgenerators-modded"></a>
#### `NumberOfGenerators(M): ModDed -> RngIntElt`

The minimum number of vectors and ideals which generate the module $M$.

<a id="operation-operation-modded-rngintelt-modtuprngelt"></a>
#### `M . i: ModDed, RngIntElt -> ModTupRngElt`

The vector of the $ith$ vector and ideal pair generating the module $M$.

<a id="function-determinant-modded"></a>
#### `Determinant(M): ModDed -> RngOrdIdl`

<a id="function-determinant-modded-2"></a>
#### `Determinant(M): ModDed -> RngFunOrdIdl`

The determinant of the module $M$.

<a id="function-dimension-modded"></a>
#### `Dimension(M): ModDed -> RngIntElt`

The dimension of the vector space spanned by the module $M$ over its coefficient ring. This is the same as the number of generators of a pseudo basis of $M$.

<a id="function-contents-modded"></a>
#### `Contents(M): ModDed -> RngOrdFracIdl`

```magma
UseBasis: BoolElt                    Default: false
```

The contents of the module $M$, ie. the gcd of the ideals obtained by multiplying the coefficient ideals by the ideal generated by the coefficients in the corresponding generators. The parameter `UseBasis` decides whether a pseudo basis or pseudo generators are used.

<a id="function-simplify-modded"></a>
#### `Simplify(M): ModDed -> ModDed`

```magma
UseBasis: BoolElt                    Default: false
```

Computes a module of contents $1$ by scaling each coefficient ideal by the inverse of the contents of the module $M$. The parameter `UseBasis` determines if the operations are performed on the pseudo generators or the pseudo basis of $M$.

<a id="function-embeddingspace-modded"></a>
#### `EmbeddingSpace(M): ModDed -> Mod`

The canonical vector space containing the module $M$, ie.. $M$ tensored with the field of fractions of the coefficient ring.

<a id="example-ex-5e5c19"></a>
#### `Example: Elementary Functions on a Module (ex-5e5c19)`

The use of some elementary functions on a module is shown below.

```magma
> P<x> := PolynomialRing(Rationals());
> P<y> := PolynomialRing(P);
> F<c> := FunctionField(x^2 - y);
> M := MaximalOrderFinite(F);
> Vs := RModule(M, 2);
> s := [Vs | [1, 3], [2, 3]];
> Mods := Module(s);
> CoefficientRing(Mods);
Maximal Equation Order of F over Univariate Polynomial Ring in x over Rational
Field
> Mods.1;
(1 0)
> Determinant(Mods);
Ideal of M
Generator:
-3
> Vs := RSpace(M, 2);
> s := [Vs | [1, 3], [2, 3]];
> Mods := Module(s);
> sMods := sub<Mods | Mods!Vs![1, 3]>;
> qMods := quo<Mods | sMods>;
> Degree(Mods);
2
> Ngens(Mods);
2
> Ngens(sMods);
1
> Degree(sMods);
2
> Degree(qMods);
2
> Ngens(qMods);
2
> Determinant(Mods);
Ideal of M
Basis:
[1]
> Determinant(sMods);
>>   Determinant(sMods);
               ^
Runtime error in `Determinant': Module must be square
> Determinant(qMods);
Ideal of M
Basis:
[1]
```

### Predicates on Modules

Modules and potential elements can be tested against each other for a few properties.

<a id="operation-op-eq-modded-modded"></a>
#### `M eq N: ModDed, ModDed -> BoolElt`

Return `true` if $M$ and $N$ are equal as modules.

<a id="operation-op-in-any-modded"></a>
#### `x in M: Any, ModDed -> BoolElt`

Return `true` if $x$ can be coerced into the module $M$.

<a id="operation-op-subset-modded-modded"></a>
#### `M subset N: ModDed, ModDed -> BoolElt`

Return `true` if $M$ is a submodule of $N$. An embedding map of $M$ in $N$ can be returned by `IsSubmodule(M, N)`.

<a id="function-isfree-modded"></a>
#### `IsFree(M): ModDed -> BoolElt`

Return `true` if $M$ is a free module.

### Arithmetic with Modules

Some arithmetic operations can be carried out involving modules and their elements and compatible ideals to gain more modules.

<a id="operation-op-times-rngordidl-modded"></a>
#### `I * M: RngOrdIdl, ModDed -> ModDed`

<a id="operation-op-times-rngfunordidl-modded"></a>
#### `I * M: RngFunOrdIdl, ModDed -> ModDed`

<a id="operation-op-times-modded-rngordidl"></a>
#### `M * I: ModDed, RngOrdIdl -> ModDed`

<a id="operation-op-times-modded-rngfunordidl"></a>
#### `M * I: ModDed, RngFunOrdIdl -> ModDed`

The module generated by the products of the ideals of the module $M$ with $I$.

<a id="operation-op-plus-modded-modded"></a>
#### `M1 + M2: ModDed, ModDed -> ModDed`

The union of the modules $M1$ and $M2$.

<a id="function-directsum-modded-modded"></a>
#### `DirectSum(M1, M2): ModDed, ModDed -> ModDed, Map, Map, Map, Map`

<a id="function-directsum-modded"></a>
#### `DirectSum(S): [ModDed] -> ModDed, [Map], [Map]`

The direct sum $D$ of the modules $M1$ and $M2$ or the modules in the sequence $S$ together with the embedding maps $M1 \rightarrow D, M2 \rightarrow D, \ldots$ and the projection maps $D \rightarrow M1, D \rightarrow M2, \ldots$ returned in sequences only when a sequence $S$ is input.

<a id="operation-op-times-moddedelt-rngordidl"></a>
#### `u * I: ModDedElt, RngOrdIdl -> ModDed`

<a id="operation-op-times-moddedelt-rngfunordidl"></a>
#### `u * I: ModDedElt, RngFunOrdIdl -> ModDed`

<a id="operation-op-times-rngordidl-moddedelt"></a>
#### `I * u: RngOrdIdl, ModDedElt -> ModDed`

<a id="operation-op-times-rngfunordidl-moddedelt"></a>
#### `I * u: RngFunOrdIdl, ModDedElt -> ModDed`

The module containing elements which are products of the Dedekind module element $u$ and an element lying in the ideal $I$.

<a id="example-ex-79759b"></a>
#### `Example: Module Arithmetic and Predicates (ex-79759b)`

Some module predicates and arithmetic are shown below.

```magma
> P<x> := PolynomialRing(Integers());
> K :=  NumberField([x^5 + 3, x^2 + 2]);
> M := MaximalOrder(K);
> Vs := RModule(M, 2);
> s := [Vs | [1, 3], [2, 3]];
> Mods := Module(s);
> sMods := sub<Mods | Mods!Vs![1, 3]>;
> Mods eq sMods;
false
> [1, 0] in Mods;
true
> [1, 0] in sMods;
false
> sMods subset Mods;
true
> Vs := RSpace(M, 2);
> s := [Vs | [Random(M, 3), 3], [2, Random(M, 2)]];
> Mods := Module(s);
> sMods := sub<Mods | Mods!s[1]>;
> (7*M + 11*K.1*M)*sMods;
Module over Maximal Equation Order with defining polynomial x^5 + [3, 0] over
its ground order
 generated by:
Ideal of M
Two element generators:
    7/1*$.1*M.1
    11/1*$.1*M.2 * ( M.1 + (-$.1 - 2/1*$.2)*M.2 + $.2*M.3 + (2/1*$.1 +
2/1*$.2)*M.5 3/1*$.1*M.1 )
 in echelon form:
Ideal of M
Two element generators:
    21/1*$.1*M.1
    33/1*$.1*M.2 * ( 1/3*$.1*M.1 + (-1/3*$.1 - 2/3*$.2)*M.2 + 1/3*$.2*M.3 +
(2/3*$.1 + 2/3*$.2)*M.5 M.1 )
> Mods + sMods;
Module over Maximal Equation Order with defining polynomial x^5 + [3, 0] over
its ground order
 generated by: (in echelon form)
Ideal of M
Two element generators:
    148919257164/1*$.1*M.1
    (148919257048/1*$.1 + 26/1*$.2)*M.1 + (32/1*$.1 + 148919257015/1*$.2)*M.2 +
    (196/1*$.1 + 148919257117/1*$.2)*M.3 + (148919257163/1*$.1 + 76/1*$.2)*M.4 +
    (148919257077/1*$.1 + 148919257116/1*$.2)*M.5 * ( M.1 0 )
Ideal of M
Two element generators:
    3/1*$.1*M.1
    ($.1 - $.2)*M.1 + -M.3 + M.4 + ($.1 + $.2)*M.5 * ( (-19866460521/1*$.1 -
33/1*$.2)*M.1 + (1/3*$.1 + 1/3*$.2)*M.4 + (1/3*$.1 + 1/3*$.2)*M.5 M.1 )
> 4*sMods;
Module over Maximal Equation Order with defining polynomial x^5 + [3, 0] over
its ground order
 generated by:
Principal Ideal of M
Generator:
    4/1*$.1*M.1 * ( (2/1*$.1 - 2/1*$.2)*M.1 + ($.1 + 2/1*$.2)*M.2 + (2/1*$.1 +
2/1*$.2)*M.3 + (2/1*$.1 - $.2)*M.5 3/1*$.1*M.1 )
 in echelon form:
Principal Ideal of M
Generator:
    12/1*$.1*M.1 * ( (2/3*$.1 - 2/3*$.2)*M.1 + (1/3*$.1 + 2/3*$.2)*M.2 +
(2/3*$.1 + 2/3*$.2)*M.3 + (2/3*$.1 - 1/3*$.2)*M.5 M.1 )
```

### Basis of a Module

The basis of a module is given by vectors. However, more complete information can be supplied which includes the ideals.

<a id="function-basis-modded"></a>
#### `Basis(M): ModDed -> SeqEnum`

A sequence of vectors which correspond to a pseudo basis of the module $M$.

<a id="function-modded-pseudobasis"></a>
#### `PseudoBasis(M): ModDed -> SeqEnum`

A sequence of tuples containing ideals and vectors which generate the module $M$. The vectors are guaranteed to be linearly independent.

<a id="function-pseudogenerators-modded"></a>
#### `PseudoGenerators(M): ModDed -> SeqEnum`

A sequence of tuples containing ideals and vectors which generate the module $M$. This will return the data used to define the module, so that in contrast to [`PseudoBasis`](https://docs.magma-maths.org/Modules/ModulesOverDedekindDomains/basis.md#function-modded-pseudobasis) the vectors will in general not be independent.

<a id="function-localbasis-modded-rngordidl"></a>
#### `LocalBasis(M, p): ModDed, RngOrdIdl -> [ ModTupFldElt ]`

```magma
Type: MonStgElt                    Default: ""
```

Returns a basis of a free module $F$ that agrees with $M$ at the completion at $p$. If `Type` is specified, it must either be `"Submodule"` or `"Supermodule"`. In which case $F$ is either a sub- or supermodule of $M$.

### Other Functions on Modules

Intersections of modules can taken. Several other functions are also available.

<a id="operation-op-meet-modded-modded"></a>
#### `M1 meet M2: ModDed, ModDed -> ModDed`

Return the intersection of the modules $M1$ and $M2$.

<a id="function-dual-modded"></a>
#### `Dual(M): ModDed -> ModDed`

The module dual to $M$.

<a id="function-elementarydivisors-modded-modded"></a>
#### `ElementaryDivisors(M, N): ModDed, ModDed -> SeqEnum`

The elementary divisors (ideals) of the torsion part of the quotient $R$-module $M/N$: For $N\subseteq M$ we get

$$
T(M/N) \cong \oplus_{i=1}^n R/{{\cal A}_i}
$$

The ${{\cal A}_i}$ are unique if we require $R\subseteq {{\cal A}_1} \subseteq \cdots \subseteq {{\cal A}_n}$. The ${{\cal A}_i}$ are called the elementary divisors (or elementary ideals) of $M/N$. This corresponds to the Smith normal form for integral matrices.

<a id="function-steinitzclass-modded"></a>
#### `SteinitzClass(M): ModDed -> RngOrdIdl`

The Steinitz class of the module $M$.

<a id="function-steinitzform-modded"></a>
#### `SteinitzForm(M): ModDed -> ModDed`

The Steinitz (almost–free) form of the module $M$.

<a id="example-ex-69678f"></a>
#### `Example: Bases and Other Module Functions (ex-69678f)`

Some bases and other functions are demonstrated below.

```magma
> P<x> := PolynomialRing(Rationals());
> P<y> := PolynomialRing(P);
> F<c> := FunctionField(y^3 - x^3*y^2 + y - x^7);
> M := MaximalOrderFinite(F);
> Vs := RSpace(M, 2);
> s := [Vs | [1, Random(M, 3)], [Random(M, 3), 3]];
> Mods := Module(s);
> qMods := quo<Mods | Mods!s[2]>;
> Basis(Mods);
[
    ([ 1, 0, 0 ] [ 2*x^2 - 3*x + 1/2, -2/3*x^2 - x + 1/3, 2/3*x^2 - 2*x + 1/2
        ]),
    ([ -x^2 + x + 2/3, -1/3*x^2 - 1, -3/2*x^2 - 2/3*x + 1 ] [ 3, 0, 0 ])
]
> Basis(qMods);
[
    ([ 1, 0, 0 ] [ 2*x^2 - 3*x + 1/2, -2/3*x^2 - x + 1/3, 2/3*x^2 - 2*x + 1/2
        ]),
    ([ -x^2 + x + 2/3, -1/3*x^2 - 1, -3/2*x^2 - 2/3*x + 1 ] [ 3, 0, 0 ])
]
> PseudoBasis(Mods) eq PseudoBasis(qMods);
> Vs := RModule(M, 2);
> s := [Vs | [Random(M, 3), Random(M, 3)], [2, 3]];
> Mods := Module(s);
> sMods := sub<Mods | Mods!s[1]>;
> Mods meet sMods;
Module over Maximal Equation Order of F over Univariate Polynomial Ring in x
over Rational Field
Ideal of M
Generator:
(x + 1)*c^2 + (-3/2*x^2 - 3/2*x)*c + 1/2*x^2 + 2/3*x + 1/2
> ElementaryDivisors(Mods, sMods);
[ Ideal of M
Basis:
[1 0 0]
[0 1 0]
[0 0 1], Ideal of M
Generator:
0 ]
> Dual(Mods);
Module over Maximal Equation Order of F over Univariate Polynomial Ring in x
over Rational Field
Fractional ideal of M
Generator:
(-3*x^4 + 21*x^3 + 20*x^2 + 80*x - 387)/(x^17 - 24*x^16 + 192*x^15 - 510*x^14 -
    94/3*x^13 + 304/3*x^12 + 902/3*x^11 - 3109/3*x^10 - 389/9*x^9 + 664/9*x^8 +
    1094/3*x^7 - 1540/3*x^6 - 101/9*x^5 + 128/3*x^4 + 2000/27*x^3 - 4361/9*x^2 -
    427*x + 2056)*c^2 + (-3*x^9 + 48*x^8 - 189*x^7 - 24*x^6 + 3*x^5 - 48*x^4 +
    195*x^3 - 3*x^2 - x + 24)/(x^17 - 24*x^16 + 192*x^15 - 510*x^14 - 94/3*x^13
    + 304/3*x^12 + 902/3*x^11 - 3109/3*x^10 - 389/9*x^9 + 664/9*x^8 + 1094/3*x^7
    - 1540/3*x^6 - 101/9*x^5 + 128/3*x^4 + 2000/27*x^3 - 4361/9*x^2 - 427*x +
    2056)*c + (3*x^12 - 48*x^11 + 192*x^10 + 3*x^9 - 20*x^8 - 56*x^7 + 192*x^6 +
    3*x^5 - 5*x^4 - 8*x^3 + 272/3*x^2 + 128*x - 771)/(x^17 - 24*x^16 + 192*x^15
    - 510*x^14 - 94/3*x^13 + 304/3*x^12 + 902/3*x^11 - 3109/3*x^10 - 389/9*x^9 +
    664/9*x^8 + 1094/3*x^7 - 1540/3*x^6 - 101/9*x^5 + 128/3*x^4 + 2000/27*x^3 -
    4361/9*x^2 - 427*x + 2056) car Ideal of M
Generator:
1/3
> Dual(sMods);
Module over Maximal Equation Order of F over Univariate Polynomial Ring in x
over Rational Field
Fractional ideal of M
Generator:
(3/2*x^6 + 3*x^5 - 3/4*x^4 - 4*x^3 - 25/12*x^2 - 5/6*x - 1/2)/(x^17 + 3*x^16 +
    21/4*x^15 + 27/4*x^14 + 1/24*x^13 - 247/24*x^12 - 173/24*x^11 + 61/24*x^10 +
    305/72*x^9 + 17/72*x^8 - 4*x^7 - 53/12*x^6 - 1/8*x^5 + 23/6*x^4 +
    377/108*x^3 + 23/18*x^2 + 1/3*x + 1/8)*c^2 + (-5/2*x^9 - 5*x^8 - 1/4*x^7 +
    9/2*x^6 + 13/4*x^5 + 5/4*x^4 - 3/4*x^3 - 7/4*x^2 - 3/4*x)/(x^17 + 3*x^16 +
    21/4*x^15 + 27/4*x^14 + 1/24*x^13 - 247/24*x^12 - 173/24*x^11 + 61/24*x^10 +
    305/72*x^9 + 17/72*x^8 - 4*x^7 - 53/12*x^6 - 1/8*x^5 + 23/6*x^4 +
    377/108*x^3 + 23/18*x^2 + 1/3*x + 1/8)*c + (x^12 + 2*x^11 - 1/2*x^10 -
    7/2*x^9 - 8/3*x^8 - 5/12*x^7 + 11/4*x^6 + 19/4*x^5 - 1/4*x^4 - 25/6*x^3 -
    67/36*x^2 - 1/3*x - 1/4)/(x^17 + 3*x^16 + 21/4*x^15 + 27/4*x^14 + 1/24*x^13
    - 247/24*x^12 - 173/24*x^11 + 61/24*x^10 + 305/72*x^9 + 17/72*x^8 - 4*x^7 -
    53/12*x^6 - 1/8*x^5 + 23/6*x^4 + 377/108*x^3 + 23/18*x^2 + 1/3*x + 1/8)
> SteinitzClass(Mods) eq SteinitzClass(sMods);
false
> SteinitzForm(Mods);
Module over Maximal Equation Order of F over Univariate Polynomial Ring in x
over Rational Field
Ideal of M
Generator:
3 car Ideal of M
Generator:
1
> SteinitzForm(sMods);
Module over Maximal Equation Order of F over Univariate Polynomial Ring in x
over Rational Field
Ideal of M
Generator:
1
```

### Homomorphisms between Modules

It is possible to create a homomorphism between two modules, take the image and kernel of such and verify that these are submodules of the codomain and domain respectively. The Hom–module can also be created as a module of a Dedekind domain.

<a id="constructor-constructor-hom-modded-modded-map-map"></a>
#### `hom<M -> N | T>: ModDed, ModDed, Map -> Map`

<a id="constructor-constructor-hom-modded-modded-seqenum-modtuprngelt-map"></a>
#### `hom<M -> N | T>: ModDed, ModDed, SeqEnum[ModTupRngElt] -> Map`

<a id="constructor-constructor-hom-modded-modded-mtrxspcelt-map"></a>
#### `hom<M -> N | T>: ModDed, ModDed, MtrxSpcElt -> Map`

```magma
ModuleBasis: BoolElt                    Default: true
```

Return a homomorphism from the module $M$ into the module $N$ as specified by $T$ from which the images of the generators can be inferred. $T$ may be a map between the vector spaces of same degree as $M$ and $N$, a matrix over the field of fractions or a sequence of vectors. If `ModuleBasis` is `true` then the matrix will be taken to be a transformation between the modules and as such will be expected to have size `Dimension(M)`$*$`Dimension(N)` otherwise it will be interpreted as a transformation between the corresponding vector spaces and will be expected to have size `Degree(M)`$*$`Degree(N)`.

<a id="function-hom-modded-modded"></a>
#### `Hom(M, N): ModDed, ModDed -> ModDed, Map`

The module of homomorphisms between the module $M$ and the module $N$ and the map from the hom–module to the collection of maps from $M$ to $N$, (such that given an element of the hom–module a homomorphism from $M$ to $N$ is returned). The module is over the same Dedekind domain as $M$ and $N$.

<a id="function-issubmodule-modded-modded"></a>
#### `IsSubmodule(M, N): ModDed, ModDed -> BoolElt, Map`

Return `true` if $M$ is a submodule of $N$ and the map embedding $M$ into $N$.

<a id="function-morphism-modded-modded"></a>
#### `Morphism(M, N): ModDed, ModDed -> Map`

The map giving the morphism from the module $M$ to the module $N$. Either $M$ is a submodule of $N$, in which case the embedding of $M$ into $N$ is returned, or $N$ is a quotient module of $M$, in which case the natural epimorphism from $M$ onto $N$ is returned.

<a id="example-ex-f6bf14"></a>
#### `Example: Homomorphisms Between Modules over Dedekind Domains (ex-f6bf14)`

This example demonstrates the use of homomorphisms between modules over Dedekind domains. Let `M` and `V` be as above referring to function fields.

```magma
> S := [V|[0,1,0], [4,4,0]];
> Mod := Module(S);
> W := KModule(FieldOfFractions(M), 4);
> S := [W|[3, 2, 1, 0]];
> N := Module(S);
> h := hom<Mod -> N | >;
>> h := hom<Mod -> N | >;
           ^
Runtime error in map< ... >: No images given
> h := hom<Mod -> N | V.1, V.2, V.3>;

>> h := hom<Mod -> N | V.1, V.2, V.3>;
           ^
Runtime error in map< ... >: An image for each generator is required
> h := hom<Mod -> N | W![3, 2, 1, 0], W![3*(M!F.1 + 1), 2*(M!F.1 + 1),
> M!F.1 + 1, 0] >;
> h(Mod!(4*V.1));
( 4 )
> h(Mod!V![0, 1, 0]);
( x^2 + 1 )
> I := Image(h);
> I;
Module over Maximal Equation Order of F over Univariate Polynomial Ring in x
over Rational Field
Ideal of M
Generator:
1
> K := Kernel(h);
> K;
Integral Module over Maximal Equation Order of F over Univariate Polynomial Ring
in x over Rational Field
Ideal of M
Generator:
1
> IsSubmodule(K, Mod);
true Mapping from: ModDed: K to ModDed: Mod
> H, m := Hom(Mod, N);
> H; m;
Module over Maximal Equation Order of F over Univariate Polynomial Ring in x over
Rational Field
 generated by: (in echelon form)
Ideal of M
Generator:
1/4 * ( 1 0 )
Ideal of M
Generator:
1 * ( 0 1 )
Mapping from: ModDed: H to Power Structure of Map given by a rule [no inverse]
> m(H![5, 20]);
Mapping from: ModDed: Mod to ModDed: N
using
[5]
[20]
```

### Elements of Modules

#### Creation of Elements

<a id="operation-op-modded-seqenum"></a>
##### `M ! v: ModDed, SeqEnum -> ModDedElt`

<a id="operation-op-modded-moddedelt"></a>
##### `M ! v: ModDed, ModDedElt -> ModDedElt`

<a id="operation-op-modded-modelt"></a>
##### `M ! v: ModDed, ModElt -> ModDedElt`

Coerce $v$ into an element of $M$. $v$ can be a sequence of length dimension of $M$, a module element or vector or an element of another module over a Dedekind domain which is compatible with $M$.

<a id="example-ex-2c7014"></a>
##### `Example: Coercion into Quotient Modules (ex-2c7014)`

Let `Mod` and its submodules and quotient modules be as in the sub and quotient module example above.

```magma
> m := 4*Mod.1;
> m;
(4/1*M.1 0)
> Q1!m;
( 4/1*M.1 0 )
> Q2!m;
( 4/1*M.1 0 )
> m := Mod!m;
> Q3!m;
( 4/1*M.1 0 )
> Q4!m;
( 4/1*M.1 0 )
> S1!m;
>> S1!m;
     ^
Runtime error in `!': Illegal coercion
LHS: ModDed
RHS: ModDedElt
> S1!Mod!V!0;
(  )
> S2!Mod!Mod.2;
( M.1 )
> S3!Mod!(4*Mod.1);
( 4/1*M.1 0 )
```

#### Arithmetic with Elements

Basic arithmetic can be performed with elements of a module over a Dedekind domain.

<a id="operation-op-plus-moddedelt-moddedelt"></a>
##### `x + y: ModDedElt, ModDedElt -> ModDedElt`

The sum of the module elements.

<a id="operation-op-minus-moddedelt-moddedelt"></a>
##### `x - y: ModDedElt, ModDedElt -> ModDedElt`

The difference of the module elements.

<a id="operation-op-times-moddedelt-rngelt"></a>
##### `u * c: ModDedElt, RngElt -> ModDedElt`

<a id="operation-op-times-rngelt-moddedelt"></a>
##### `c * u: RngElt, ModDedElt -> ModDedElt`

The product of the module element $u$ and the ring element $c$.

<a id="operation-op-div-moddedelt-rngelt"></a>
##### `u / c: ModDedElt, RngElt -> ModDedElt`

The product of $u$ and $1/c$ if it lies in the parent module of $u$.

<a id="operation-op-times-rngordidl-moddedelt-2"></a>
##### `I * u: RngOrdIdl, ModDedElt -> ModDed`

<a id="operation-op-times-rngfunordidl-moddedelt-2"></a>
##### `I * u: RngFunOrdIdl, ModDedElt -> ModDed`

<a id="operation-op-times-moddedelt-rngordidl-2"></a>
##### `u * I: ModDedElt, RngOrdIdl -> ModDed`

<a id="operation-op-times-moddedelt-rngfunordidl-2"></a>
##### `u * I: ModDedElt, RngFunOrdIdl -> ModDed`

The module containing elements which are products of $u$ and an element lying in $I$.

#### Other Functions on Elements

Elements of modules over a Dedekind domain can be tested for equality and represented as a sequence.

<a id="operation-op-eq-moddedelt-moddedelt"></a>
##### `x eq y: ModDedElt, ModDedElt -> Bool`

Return `true` if $x$ and $y$ are the same element of a module.

<a id="function-iszero-moddedelt"></a>
##### `IsZero(a): ModDedElt -> BoolElt`

Returns whether the module element $a$ is zero.

<a id="function-elementtosequence-moddedelt"></a>
##### `ElementToSequence(a): ModDedElt -> SeqEnum`

<a id="function-eltseq-moddedelt"></a>
##### `Eltseq(a): ModDedElt -> SeqEnum`

The module element $a$ expressed as a sequence.

<a id="pmat"></a>
<a id="secpmat"></a>
### Pseudo Matrices

A pseudo matrix, ie. an object of type `PMat`, is a sequence of ideals together with a matrix. Pseudo matrices arise naturally in the (computational) theory of finitely generated torsion free modules over Dedekind domains, they are a natural extension of ordinary matrices which should be thought of as pseudo matrices where all the ideals are generated by $1$. Pseudo matrices are generally used to represent the module that is generated by the rows of the matrix scaled by the elements of the corresponding ideal. Thus, if the matrix is regular, a linear combination of the rows lies in the module if and only if the coefficient of the $i$th row is a member of the $i$th ideal. The ideals are therefore called coefficient ideals.

#### Construction of a Pseudo Matrix

<a id="function-pseudomatrix-rngordfracidl-mtrxspcelt"></a>
##### `PseudoMatrix(I, m): [RngOrdFracIdl], MtrxSpcElt -> PMat`

<a id="function-pseudomatrix-rngfunordidl-mtrxspcelt"></a>
##### `PseudoMatrix(I, m): [RngFunOrdIdl], MtrxSpcElt -> PMat`

Construct the pseudo matrix with coefficient ideals the elements of the sequence $I$ and matrix $m$.

<a id="function-pseudomatrix-mtrx-fldord"></a>
##### `PseudoMatrix(m): Mtrx[FldOrd] -> PMat`

<a id="function-pseudomatrix-mtrx-rngord"></a>
##### `PseudoMatrix(m): Mtrx[RngOrd] -> PMat`

<a id="function-pseudomatrix-mtrx-fldfunord"></a>
##### `PseudoMatrix(m): Mtrx[FldFunOrd] -> PMat`

<a id="function-pseudomatrix-mtrx-rngfunord"></a>
##### `PseudoMatrix(m): Mtrx[RngFunOrd] -> PMat`

Construct the pseudo matrix with trivial coefficient ideals and the matrix $m$.

<a id="function-pseudomatrix-modded"></a>
##### `PseudoMatrix(M): ModDed -> PMat`

```magma
Generators: BoolElt                    Default: false
```

Construct the pseudo matrix described by the pseudo basis of the module $M$. If `Generators` is `true` the pseudo matrix described by the pseudo generators of $M$ is returned.

<a id="function-absolutebasis-modded"></a>
##### `AbsoluteBasis(M): ModDed -> SeqEnum`

Returns a basis of the module $M$ over ${\mathbb{Z}}$ or ${\mathbb{F}}_q[t]$.

#### Elementary Functions

<a id="function-coefficientideals-pmat"></a>
##### `CoefficientIdeals(P): PMat -> SeqEnum`

Return the coefficient ideals of the pseudo matrix $P$.

<a id="function-matrix-pmat"></a>
##### `Matrix(P): PMat -> Mtrx`

Return the matrix of the pseudo matrix $P$.

<a id="function-order-pmat"></a>
##### `Order(pm): PMat -> Rng`

Return the order the pseudo matrix $pm$ is over.

<a id="function-dimension-pmat"></a>
##### `Dimension(pm): PMat -> RngIntElt`

The dimension of the pseudo matrix $pm$. This is the number of columns of the matrix.

<a id="function-length-pmat"></a>
##### `Length(pm): PMat -> RngIntElt`

The length or dimension of the pseudo matrix $pm$. This is the number of coefficient ideals of $pm$.

#### Basis of a Pseudo Matrix

<a id="function-basis-pmat"></a>
##### `Basis(P): PMat -> SeqEnum`

Return a list of sequences of ring elements corresponding to the entries of each row of the matrix of the pseudo matrix $P$.

#### Predicates

<a id="operation-op-eq-pmat-pmat"></a>
##### `p1 eq p2: PMat, PMat -> BoolElt`

Return whether the pseudo matrices $p1$ and $p2$ are equal, that is, whether they have the same matrix and the same sequence of coefficient ideals.

#### Operations with Pseudo Matrices

<a id="function-transpose-pmat"></a>
##### `Transpose(P): PMat -> PMat`

Return the pseudo matrix whose coefficient ideals are the same as those of $P$ but whose matrix is the transpose of the matrix of $P$. This function requires the matrix to be square.

<a id="function-hermiteform-pmat"></a>
##### `HermiteForm(X): PMat -> PMat, AlgMatElt`

Return the Hermite normal form $H$ of the pseudo matrix $X$ together with a regular transformation matrix such that the module generated by $X$ is the same as the one generated by $H$ and such that (for the matrix parts) $H=TX$ holds.

<a id="function-verticaljoin-pmat-pmat"></a>
##### `VerticalJoin(X, Y): PMat, PMat -> PMat`

Return the pseudo matrix whose matrix is the vertical join of the matrices of the pseudo matrices $X$ and $Y$ with coefficient ideals the concatenation of those of $X$ and $Y$.

<a id="operation-op-meet-pmat-pmat"></a>
##### `X meet Y: PMat, PMat -> PMat`

Return the intersection of the pseudo matrices X and Y.

<a id="function-module-pmat"></a>
##### `Module(X): PMat -> ModDed`

Return the module $\sum C_i * m_i$ where ${C_i}$ are the coefficient ideals of the pseudo matrix $X$ and $m_i$ are the rows of the matrix of $X$.

<a id="operation-op-times-rngordfracidl-pmat"></a>
##### `I * X: RngOrdFracIdl, PMat -> PMat`

<a id="operation-op-times-rngfunordidl-pmat"></a>
##### `I * X: RngFunOrdIdl, PMat -> PMat`

<a id="operation-op-times-pmat-rngordfracidl"></a>
##### `X * I: PMat, RngOrdFracIdl -> PMat`

<a id="operation-op-times-pmat-rngfunordidl"></a>
##### `X * I: PMat, RngFunOrdIdl -> PMat`

The pseudo matrix whose coefficient ideals are those of the pseudo matrix $X$ multiplied by $I$ and whose matrix is the matrix of $X$.

<a id="complexes"></a>
<a id="chap-chain-complexes"></a>
## Chain Complexes

- [Complexes of Modules](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md)
  - [Creation](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#creation)
    - [`Complex(L, d): List, RngIntElt → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-complex-list-rngintelt)
    - [`Complex(f, d): Map, RngIntElt → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-complex-map-rngintelt)
    - [`ZeroComplex(A, m, n): AlgBas, RngIntElt, RngIntElt → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-zerocomplex-algbas-rngintelt-rngintelt)
    - [`Dual(C): ModCpx → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-dual-modcpx)
    - [`Dual(C, n): ModCpx, RngIntElt → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-dual-modcpx-rngintelt)
  - [Subcomplexes and Quotient Complexes](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#subcomplexes-and-quotient-complexes)
    - [`sub< C | Q >: ModCpx, SeqEnum[ModAlg] → ModCpx, MapChn`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#constructor-constructor-sub-modcpx-seqenum-modalg-modcpx-mapchn)
    - [`sub< C | L >: ModCpx, List → ModCpx, MapChn`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#constructor-constructor-sub-modcpx-list-modcpx-mapchn)
    - [`RandomSubcomplex(C, Q): ModCpx, SeqEnum → ModCpx, MapChn`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-randomsubcomplex-modcpx-seqenum)
    - [`quo< C | D >: ModCpx, ModCpx → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#constructor-constructor-quo-modcpx-modcpx-modcpx)
    - [`quo< C | S >: ModCpx, SeqEnum[ModAlg] → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#constructor-constructor-quo-modcpx-seqenum-modalg-modcpx)
    - [`quo< C | L >: ModCpx, List → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#constructor-constructor-quo-modcpx-list-modcpx)
  - [Access Functions](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#access-functions)
    - [`Degrees(C): ModCpx → RngIntElt`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-degrees-modcpx)
    - [`Algebra(C): ModCpx → AlgBas`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-algebra-modcpx)
    - [`BoundaryMap(C, n): ModCpx, RngIntElt → ModMatRngElt`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-boundarymap-modcpx-rngintelt)
    - [`BoundaryMaps(C): ModCpx → List`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-boundarymaps-modcpx)
    - [`DimensionsOfHomology(C): ModCpx → SeqEnum`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-dimensionsofhomology-modcpx)
    - [`DimensionOfHomology(C, n): ModCpx, RngIntElt → RngIntElt`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-dimensionofhomology-modcpx-rngintelt)
    - [`DimensionsOfTerms(C): ModCpx → SeqEnum`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-dimensionsofterms-modcpx)
    - [`Term(C, n): ModCpx, RngIntElt → ModAlg`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-term-modcpx-rngintelt)
    - [`Terms(C): ModCpx → SeqEnum`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-terms-modcpx)
  - [Elementary Operations](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#elementary-operations)
    - [`DirectSum(C, D): ModCpx, ModCpx → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-directsum-modcpx-modcpx)
    - [`Homology(C): ModCpx → SeqEnum`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-homology-modcpx)
    - [`HomologyOfChainComplex(C): ModCpx → SeqEnum`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-homologyofchaincomplex-modcpx)
    - [`Homology(C, n): ModCpx, RngIntElt → SeqEnum`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-homology-modcpx-rngintelt)
    - [`Prune(C): ModCpx → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-prune-modcpx)
    - [`Prune(C,n): ModCpx, RngIntElt → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-prune-modcpx-rngintelt)
    - [`Preprune(C): ModCpx → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-preprune-modcpx)
    - [`Preprune(C,n): ModCpx, RngIntElt → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-preprune-modcpx-rngintelt)
    - [`Shift(C, n): ModCpx, RngIntElt → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-shift-modcpx-rngintelt)
    - [`ShiftToDegreeZero(C): ModCpx → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-shifttodegreezero-modcpx)
    - [`Splice(C, D): ModCpx, ModCpx → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-splice-modcpx-modcpx)
    - [`Splice(C, D, f): ModCpx, ModCpx, ModMatRngElt → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-splice-modcpx-modcpx-modmatrngelt)
  - [Extensions](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#extensions)
    - [`LeftExactExtension(C): ModCpx → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-leftexactextension-modcpx)
    - [`RightExactExtension(C): ModCpx → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-rightexactextension-modcpx)
    - [`ExactExtension(C): ModCpx → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-exactextension-modcpx)
    - [`LeftZeroExtension(C): ModCpx → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-leftzeroextension-modcpx)
    - [`LeftZeroExtension(C, n): ModCpx, RngIntElt → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-leftzeroextension-modcpx-rngintelt)
    - [`RightZeroExtension(C): ModCpx → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-rightzeroextension-modcpx)
    - [`RightZeroExtension(C, n): ModCpx, RngIntElt → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-rightzeroextension-modcpx-rngintelt)
    - [`ZeroExtension(C): ModCpx → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-zeroextension-modcpx)
    - [`EqualizeDegrees(C, D): ModCpx, ModCpx → ModCpx, ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-equalizedegrees-modcpx-modcpx)
    - [`EqualizeDegrees(Q): SeqEnum → SeqEnum`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-equalizedegrees-seqenum)
    - [`EqualizeDegrees(C, D, n): ModCpx, ModCpx, RngIntElt → ModCpx, ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-equalizedegrees-modcpx-modcpx-rngintelt)
  - [Predicates](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#predicates)
    - [`IsExact(C): ModComplex → BoolElt`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-isexact-modcomplex)
    - [`IsShortExactSequence(C): ModCpx → BoolElt, RngIntElt`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-isshortexactsequence-modcpx)
    - [`IsExact(C, n): ModCpx, RngIntElt → BoolElt`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-isexact-modcpx-rngintelt)
    - [`IsZeroComplex(C): ModCpx → BoolElt`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-iszerocomplex-modcpx)
    - [`IsZeroMap(C, n): ModCpx, RngIntElt → BoolElt`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-iszeromap-modcpx-rngintelt)
    - [`IsZeroTerm(C, n): ModCpx, RngIntElt → BoolElt`](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#function-iszeroterm-modcpx-rngintelt)
    - [Example: Complexes over a Quiver Algebra](https://docs.magma-maths.org/Modules/ChainComplexes/complexes.md#example-ex-bb43ae)
- [Chain Maps](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md)
  - [Creation](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#creation)
    - [`ChainMap(Q, C, D, n): SeqEnum, ModCpx, ModCpx, RngIntElt → MapChn`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#function-chainmap-seqenum-modcpx-modcpx-rngintelt)
    - [`ZeroChainMap(C, D): ModCpx, ModCpx → MapChn`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#function-zerochainmap-modcpx-modcpx)
  - [Access Functions](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#access-functions)
    - [`Degree(f): MapChn → RngIntElt`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#function-degree-mapchn)
    - [`ModuleMap(f, n): MapChn, RngIntElt → ModMatRngElt`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#function-modulemap-mapchn-rngintelt)
    - [`Kernel(f): MapChn → ModCpx, MapChn`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#function-kernel-mapchn)
    - [`Cokernel(f): MapChn → ModCpx, MapChn`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#function-cokernel-mapchn)
    - [`Image(f): MapChn → ModCpx, MapChn, MapChn`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#function-image-mapchn)
  - [Elementary Operations](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#elementary-operations)
    - [`f + g: MapChn, MapChn → MapChn`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#operation-op-plus-mapchn-mapchn)
    - [`a * g: RngElt, MapChn → MapChn`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#operation-op-times-rngelt-mapchn)
    - [`f * g: MapChn, MapChn → MapChn`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#operation-op-times-mapchn-mapchn)
  - [Predicates](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#predicates)
    - [`IsSurjective(f): MapChn → BoolElt`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#function-issurjective-mapchn)
    - [`IsInjective(f): MapChn → BoolElt`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#function-isinjective-mapchn)
    - [`IsZero(f): MapChn → BoolElt`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#function-iszero-mapchn)
    - [`IsIsomorphism(f): MapChn → BoolElt`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#function-isisomorphism-mapchn)
    - [`IsShortExactSequence(f, g): MapChn, MapChn → BoolElt`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#function-isshortexactsequence-mapchn-mapchn)
    - [`IsChainMap(L, C, D, n): List, ModCpx, ModCpx, RngIntElt → BoolElt`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#function-ischainmap-list-modcpx-modcpx-rngintelt)
    - [`IsChainMap(f): MapChn → BoolElt`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#function-ischainmap-mapchn)
    - [`IsProperChainMap(f): MapChn → BoolElt`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#function-isproperchainmap-mapchn)
    - [`HasDefinedModuleMap(C,n): ModCpx, RngIntElt → BoolElt`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#function-hasdefinedmodulemap-modcpx-rngintelt)
    - [Example: Chain Maps over a Basic Algebra](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#example-ex-f4e1ae)
  - [Maps on Homology](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#maps-on-homology)
    - [`InducedMapOnHomology(f, n): MapChn, RngIntElt → ModTupFldElt`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#function-inducedmaponhomology-mapchn-rngintelt)
    - [`ConnectingHomomorphism(f, g, n): MapChn, MapChn, RngIntElt → ModMatRngElt`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#function-connectinghomomorphism-mapchn-mapchn-rngintelt)
    - [`LongExactSequenceOnHomology(f, g): MapChn, MapChn → ModCpx`](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#function-longexactsequenceonhomology-mapchn-mapchn)
    - [Example: Long Exact Sequence in Homology](https://docs.magma-maths.org/Modules/ChainComplexes/chainmaps.md#example-ex-4cd4be)

### Complexes of Modules

Complexes of modules are a fundamental object in homological algebra. Magma supports the type `ModCpx` representing a complex of modules. Conceptually, a complex is an infinite sequence of modules, indexed by integers, with maps between successive modules such that the composition of any two maps is zero. Complexes are often written

$$
\dots \smash{ \mathop{\longrightarrow}\limits^{f_{n+1}}} M_n \smash{ \mathop{\longrightarrow}\limits^{f_{n}}} M_{n-1}
\smash{ \mathop{\longrightarrow}\limits^{f_{n-1}}} M_{n-2} \smash{ \mathop{\longrightarrow}\limits^{f_{n-2}}} \dots
$$

where the map $f_n$ has domain $M_n$ and codomain $M_{n-1}$. The indices on the modules and maps decrease to the right. In practice, Magma requires all but a finite number of the modules and maps to be zero.

The homomorphism from $M_n$ to $M_{n-1}$ in the complex is the $n^{th}$ boundary map of the complex. The homology of the complex in degree $n$ is the quotient of the kernel of the $n^{th}$ boundary map by the image of the boundary map of degree $n-1$. Magma computes the homology only if both boundary maps are defined. A complex is said to be *exact* if the image of each map is equal to the kernel of the next.

Currently, there are two types of modules over which complexes are supported:

**(a)**
Modules over a basic algebra $A$ (see Chapter [Basic Algebras](https://docs.magma-maths.org/Algebras/BasicAlgebras/index-basic-algebras.md#algbas-chap));

**(b)**
Modules over a multivariate polynomial ring over a field (see Chapter [Modules over Multivariate Rings](https://docs.magma-maths.org/CommutativeAlgebra/ModulesOverMultivariateRings/index-modules-over-multivariate-rings.md#pmod-chap) and in particular the function [`FreeResolution`](https://docs.magma-maths.org/CommutativeAlgebra/ModulesOverMultivariateRings/free-resolution.md#function-pmod-freeresolution)). Most of the functions in this chapter work for either type of module but exceptions are noted.

#### Creation

<a id="function-complex-list-rngintelt"></a>
##### `Complex(L, d): List, RngIntElt -> ModCpx`

Given a list $L$ of maps between successive $A$-modules create the corresponding complex. The last term of the complex has degree $d$. This function returns an error if the maps don’t actually form a complex.

<a id="function-complex-map-rngintelt"></a>
##### `Complex(f, d): Map, RngIntElt -> ModCpx`

Given a map $f$ between $A$-modules $M$ and $N$, form the complex consisting of the two term complex whose only map is $f$. The term $N$ is in degree $d$.

<a id="function-zerocomplex-algbas-rngintelt-rngintelt"></a>
##### `ZeroComplex(A, m, n): AlgBas, RngIntElt, RngIntElt -> ModCpx`

Given a basic algebra $A$ and integers $m$ and $n$ such that $m > n$, create a complex of modules over the basic algebra $A$, starting with a term of degree $m$ and ending with a term of degree $n$, where all the modules and maps are zero.

<a id="function-dual-modcpx"></a>
##### `Dual(C): ModCpx -> ModCpx`

<a id="function-dual-modcpx-rngintelt"></a>
##### `Dual(C, n): ModCpx, RngIntElt -> ModCpx`

The dual of the complex $C$ over a basic algebra $A$ as a complex over the opposite algebra of $A$. If an integer $n$ is supplied then the last term of the dual complex is in degree $n$. Otherwise, the last term of the dual complex is in degree 0.

#### Subcomplexes and Quotient Complexes

Let $C$ be a complex of $A$-modules, $M_m, \ldots, M_n$. A subcomplex $S$ of $C$ is a complex whose terms are submodules of the terms of $C$ and whose maps are the restrictions of the maps of $C$ to the terms of $S$.

<a id="constructor-constructor-sub-modcpx-seqenum-modalg-modcpx-mapchn"></a>
##### `sub< C | Q >: ModCpx, SeqEnum[ModAlg] -> ModCpx, MapChn`

<a id="constructor-constructor-sub-modcpx-list-modcpx-mapchn"></a>
##### `sub< C | L >: ModCpx, List -> ModCpx, MapChn`

Given a complex $C$ and a sequence $Q$ of submodules of the terms of $C$, returns the smallest subcomplex whose terms contain the modules in $Q$. The input can also be a list $L$ of sequences of elements of the successive terms of $C$. In this case the submodules generated by the elements is computed. The function also returns the chain map giving the inclusion of the subcomplex in $C$.

<a id="function-randomsubcomplex-modcpx-seqenum"></a>
##### `RandomSubcomplex(C, Q): ModCpx, SeqEnum -> ModCpx, MapChn`

Given a chain complex $C$ over a basic algebra in degrees $a$ to $a-t+1$ and a sequence $Q = [q_1, \ldots, q_t]$ of natural numbers, the function creates the minimal chain complex whose term in degree $a-i+1$ is a submodule generated by $q_i$ random elements of the term in degree $a-i+1$ of $C$. The function also returns the chain map that is the inclusion of the subcomplex into $C$.

<a id="constructor-constructor-quo-modcpx-modcpx-modcpx"></a>
##### `quo< C | D >: ModCpx, ModCpx -> ModCpx`

<a id="constructor-constructor-quo-modcpx-seqenum-modalg-modcpx"></a>
##### `quo< C | S >: ModCpx, SeqEnum[ModAlg] -> ModCpx`

<a id="constructor-constructor-quo-modcpx-list-modcpx"></a>
##### `quo< C | L >: ModCpx, List -> ModCpx`

Given a complex $C$ and a subcomplex $D$ of $C$, returns the quotient complex C/D together with the natural quotient map. If given as a sequence $S$ of submodules of the terms of $C$ or a list $L$ of sequences of elements of the terms of $C$, then the submodule generated by $S$ or $L$ is created and the quotient computed. The function also returns the chain map of $C$ on the quotient.

#### Access Functions

<a id="function-degrees-modcpx"></a>
##### `Degrees(C): ModCpx -> RngIntElt`

Returns the first and last degrees of the defined terms of the complex $C$.

<a id="function-algebra-modcpx"></a>
##### `Algebra(C): ModCpx -> AlgBas`

Given a complex $C$ over a basic algebra $A$, this function returns the algebra $A$.

<a id="function-boundarymap-modcpx-rngintelt"></a>
##### `BoundaryMap(C, n): ModCpx, RngIntElt -> ModMatRngElt`

Returns the boundary map of the complex $C$ from the term of degree $n$ to the term of degree $n-1$.

<a id="function-boundarymaps-modcpx"></a>
##### `BoundaryMaps(C): ModCpx -> List`

The list of boundary maps of the complex $C$.

<a id="function-dimensionsofhomology-modcpx"></a>
##### `DimensionsOfHomology(C): ModCpx -> SeqEnum`

Returns the list of the dimensions of the homology groups of the complex $C$.

<a id="function-dimensionofhomology-modcpx-rngintelt"></a>
##### `DimensionOfHomology(C, n): ModCpx, RngIntElt -> RngIntElt`

Returns the dimension of the homology group of the complex $C$ in degree $n$.

<a id="function-dimensionsofterms-modcpx"></a>
##### `DimensionsOfTerms(C): ModCpx -> SeqEnum`

Returns the list of the dimensions of the terms of the complex $C$.

<a id="function-term-modcpx-rngintelt"></a>
##### `Term(C, n): ModCpx, RngIntElt -> ModAlg`

The module in the complex $C$ in degree $n$.

<a id="function-terms-modcpx"></a>
##### `Terms(C): ModCpx -> SeqEnum`

The sequence of terms of the complex $C$.

#### Elementary Operations

<a id="function-directsum-modcpx-modcpx"></a>
##### `DirectSum(C, D): ModCpx, ModCpx -> ModCpx`

Returns the direct sum of the complex $C$ and the complex $D$.

<a id="function-homology-modcpx"></a>
##### `Homology(C): ModCpx -> SeqEnum`

<a id="function-homologyofchaincomplex-modcpx"></a>
##### `HomologyOfChainComplex(C): ModCpx -> SeqEnum`

The sequence of homology groups of the complex $C$ as a sequence of modules.

<a id="function-homology-modcpx-rngintelt"></a>
##### `Homology(C, n): ModCpx, RngIntElt -> SeqEnum`

Returns the homology group in degree $n$ of the complex $C$, as an $A$-module.

<a id="function-prune-modcpx"></a>
##### `Prune(C): ModCpx -> ModCpx`

Returns the complex that consists of the terms of $C$ with the right end term (term of lowest degree) removed.

<a id="function-prune-modcpx-rngintelt"></a>
##### `Prune(C, n): ModCpx, RngIntElt -> ModCpx`

Returns the complex that consists of the terms of $C$ with $n$ terms removed from the right end.

<a id="function-preprune-modcpx"></a>
##### `Preprune(C): ModCpx -> ModCpx`

Returns the complex that consists of the terms of $C$ with the left end term (term of highest degree) removed.

<a id="function-preprune-modcpx-rngintelt"></a>
##### `Preprune(C, n): ModCpx, RngIntElt -> ModCpx`

Returns the complex that consists of the terms of $C$ with $n$ terms removed from the left end.

<a id="function-shift-modcpx-rngintelt"></a>
##### `Shift(C, n): ModCpx, RngIntElt -> ModCpx`

Given the complex $C$ in degrees $r$ to $s$, returns the complex in shifted degrees $r+n$ to $s+n$. The integer $n$ may be either positive or negative. The maps in the complex are all multiplied by the scalar $(-1)^n$.

<a id="function-shifttodegreezero-modcpx"></a>
##### `ShiftToDegreeZero(C): ModCpx -> ModCpx`

Given the complex $C$, returns the shift of $C$ so that the last term, the term of lowest degree, is in degree 0.

<a id="function-splice-modcpx-modcpx"></a>
##### `Splice(C, D): ModCpx, ModCpx -> ModCpx`

Given two complexes $C$ and $D$ over the same basic algebra, such that the end term of $C$ coincides with the initial term of $D$, form the complex that corresponds to the concatenation of $C$ and $D$ (as sequences of maps) This function checks that the resulting sequence of maps forms a complex. The degrees of complex $D$ remain unchanged while the degrees of the terms in complex $C$ are changed to fit.

<a id="function-splice-modcpx-modcpx-modmatrngelt"></a>
##### `Splice(C, D, f): ModCpx, ModCpx, ModMatRngElt -> ModCpx`

The splice of the complex $C$ with the complex $D$ along the map $f$ from the last term of $C$ to the first term of $D$. The degree of the last term of the splice is the same as the degree of the last term of the complex $D$.

#### Extensions

The following are elementary operations related to extending complexes

<a id="function-leftexactextension-modcpx"></a>
##### `LeftExactExtension(C): ModCpx -> ModCpx`

Given a complex $C$ of modules over a basic algebra, returns the complex of length one greater that is obtained by adjoining the inclusion map from the kernel of the boundary map in highest degree to the term of highest degree in $C$.

<a id="function-rightexactextension-modcpx"></a>
##### `RightExactExtension(C): ModCpx -> ModCpx`

Given a complex $C$ of modules over a basic algebra, returns the complex of length one greater that is obtained by adjoining the quotient map to the cokernel of the boundary map of lowest degree from the term of lowest degree in $C$.

<a id="function-exactextension-modcpx"></a>
##### `ExactExtension(C): ModCpx -> ModCpx`

Returns the left and right exact extensions of the complex $C$.

<a id="function-leftzeroextension-modcpx"></a>
##### `LeftZeroExtension(C): ModCpx -> ModCpx`

<a id="function-leftzeroextension-modcpx-rngintelt"></a>
##### `LeftZeroExtension(C, n): ModCpx, RngIntElt -> ModCpx`

Given a complex $C$ of modules over a basic algebra, returns the complex of length one greater that is obtained by adjoining the zero map from the zero module to the term of highest degree in the complex. If a natural number $n$ is included in the input then the operation is performed $n$ times.

<a id="function-rightzeroextension-modcpx"></a>
##### `RightZeroExtension(C): ModCpx -> ModCpx`

<a id="function-rightzeroextension-modcpx-rngintelt"></a>
##### `RightZeroExtension(C, n): ModCpx, RngIntElt -> ModCpx`

Given a complex $C$ of modules over a basic algebra, returns the complex of length one greater that is obtained by adjoining the zero map to the zero module from the term of lowest degree in the complex. If a natural number $n$ is included in the input then the operation is performed $n$ times.

<a id="function-zeroextension-modcpx"></a>
##### `ZeroExtension(C): ModCpx -> ModCpx`

Returns the left and right zero extensions of the complex $C$.

<a id="function-equalizedegrees-modcpx-modcpx"></a>
##### `EqualizeDegrees(C, D): ModCpx, ModCpx -> ModCpx, ModCpx`

<a id="function-equalizedegrees-seqenum"></a>
##### `EqualizeDegrees(Q): SeqEnum -> SeqEnum`

Given complexes $C$ and $D$ over the same algebra, the function returns the complexes obtained by taking zero extensions of $C$ and $D$, if necessary, so that both complexes have the same degrees. The input can also be given as a sequence $Q$ of complexes, in which case the function returns the sequence of complexes obtained by taking zero extensions of the elements of $Q$, if necessary, until all of the elements of the sequence have the same degrees.

<a id="function-equalizedegrees-modcpx-modcpx-rngintelt"></a>
##### `EqualizeDegrees(C, D, n): ModCpx, ModCpx, RngIntElt -> ModCpx, ModCpx`

The two complexes, $C$ and $D$, with zero extension sufficient that the first and the shift by degree $n$ of the second have the same degrees.

#### Predicates

The following functions return a Boolean value.

<a id="function-isexact-modcomplex"></a>
##### `IsExact(C): ModComplex -> BoolElt`

Returns `true` if and only if the complex $C$ is an exact sequence, i.e. the image of each map in $C$ is equal to the kernel of the succeeding map (with the obvious exceptions of the first and last maps of the complex). If the complex has only two terms then this is true trivially.

<a id="function-isshortexactsequence-modcpx"></a>
##### `IsShortExactSequence(C): ModCpx -> BoolElt, RngIntElt`

Returns `true` if the complex $C$ consists of a short exact sequence together with other terms that are zero. The function returns also the degrees of the complex of nonzero terms.

<a id="function-isexact-modcpx-rngintelt"></a>
##### `IsExact(C, n): ModCpx, RngIntElt -> BoolElt`

Returns `true` if and only if the complex $C$ is an exact sequence in degree $n$, i.e. the image of the map in $C$ into the term of degree $n$ is equal to the kernel of the succeeding map.

<a id="function-iszerocomplex-modcpx"></a>
##### `IsZeroComplex(C): ModCpx -> BoolElt`

Returns `true` if and only if the complex $C$ is composed entirely of zero modules and maps.

<a id="function-iszeromap-modcpx-rngintelt"></a>
##### `IsZeroMap(C, n): ModCpx, RngIntElt -> BoolElt`

Returns `true` if and only if the boundary map in degree $n$ of the complex $C$ is the zero map.

<a id="function-iszeroterm-modcpx-rngintelt"></a>
##### `IsZeroTerm(C, n): ModCpx, RngIntElt -> BoolElt`

Returns `true` if and only if the term in degree $n$ of the complex $C$ is the zero object.

<a id="example-ex-bb43ae"></a>
##### `Example: Complexes over a Quiver Algebra (ex-bb43ae)`

We construct the quiver algebra of a quiver with three nodes and three arrows going from node 1 to node 2, from 2 to 1, and 2 to 3. The relation is that $(ab)^3a =0$ where $a$ is the first arrow and $b$ is the second. Then we construct projective and injective resolutions of the first simple module.

```magma
> ff := GF(8);
> FA<e1,e2,e3,a,b,c> := FreeAlgebra(ff,6);
> rrr := [a*b*a*b*a*b*a];
> D := BasicAlgebra(FA,rrr,3,[<1,2>,<2,1>,<2,3>]);
> D;
Basic algebra of dimension 23 over GF(2^3)
Number of projective modules: 3
Number of generators: 6
> DimensionsOfProjectiveModules(D);
[ 10, 12, 1 ]
> DimensionsOfInjectiveModules(D);
[ 8, 7, 8 ]
```

Here is the opposite algebra:

```magma
> OD := OppositeAlgebra(D);
reverse trees
> OD;
Basic algebra of dimension 23 over GF(2^3)
Number of projective modules: 3
Number of generators: 6
> s1 := SimpleModule(D,1);
> P,mu := ProjectiveResolution(s1,7);
> P;
Basic algebra complex with terms of degree 7 down to 0
Dimensions of terms: 12 12 12 12 12 12 12 10
> Q,nu := InjectiveResolution(s1,7);
> Q;
Basic algebra complex with terms of degree 0 down to -7
Dimensions of terms: 8 7 0 0 0 0 0 0
```

Note that the projective and injective resolutions are complexes with the appropriate augmentation and coaugmentation maps. First we form the two term complex whose boundary map is the composition of the augmentation and coaugmentation maps.

```magma
> theta := MapToMatrix(hom<Term(P,0)-> Term(Q,0)|mu*nu>);
> E := Complex(theta,0);
```

Then we splice all of this together.

```magma
> R := Splice(P,E);
> S := Splice(R,Q);
> S;
Basic algebra complex with terms of degree 8 down to -7
Dimensions of terms: 12 12 12 12 12 12 12 10 8 7 0 0 0 0 0 0
```

### Chain Maps

A chain map from complex $C$ to complex $D$ is a sequence of homomorphisms between the terms of $C$ and the terms of $D$ such that the maps commute with the boundary homomorphisms on the two complexes. The chain map has degree zero if the map on $C_n$ has it’s image in $D_n$. Otherwise the degree of the chain map expresses the extent to which the degrees of the terms are raised or lowered by the chain map.

Chain maps do not have to be defined in every degree for which either its domain or codomain is defined. On the other hand it must be defined wherever possible, i.e. for any degree $i$ for which the term of the domain is defined and for which the term of the codomain is defined in degree $i + n$ where $n$ is the degree of the chain map.

The freedom of definition can cause problems with constructions such as the kernel or cokernel. That is, the kernel of a chain complex may not be a complex. For this reason we allow the Kernel and Cokernel functions to work only for proper chain maps where “proper” is defined as follows. Suppose $C$ is a chain complex in degrees $a$ to $b$ and $D$ is a complex in degrees $u$ to $v$. A chain map in degree $n$ from $C$ to $D$ is proper provided $u \geq a+n$ and $v \geq b+n$.

#### Creation

<a id="function-chainmap-seqenum-modcpx-modcpx-rngintelt"></a>
##### `ChainMap(Q, C, D, n): SeqEnum, ModCpx, ModCpx, RngIntElt -> MapChn`

Returns the chain map given by the sequence of maps in $Q$. Each element in $Q$ is a map from a term of the complex $C$ to a corresponding term of the complex $D$. The integer $n$ is the degree of the chain map. This means that for any $i$ the term in degree $i$ of $C$ is mapped to the term of degree $n+i$ of $D$. There should be a map defined for any degree $i$ in the range of degrees of $C$ such that there is a corresponding term in degree $n+i$ for the complex $D$.

<a id="function-zerochainmap-modcpx-modcpx"></a>
##### `ZeroChainMap(C, D): ModCpx, ModCpx -> MapChn`

Given chain complexes $C$ and $D$, construct the chain map from $C$ to $D$ all of whose terms are zero.

#### Access Functions

<a id="function-degree-mapchn"></a>
##### `Degree(f): MapChn -> RngIntElt`

Given a chain map $f$, returns the degree of $f$. Note that $f: C \rightarrow D$ has degree $n$ if it takes the term in degree $i$ of the complex $C$ to the term in degree $i+n$ of the complex $D$.

<a id="function-modulemap-mapchn-rngintelt"></a>
##### `ModuleMap(f, n): MapChn, RngIntElt -> ModMatRngElt`

Given a chain map $f:C \rightarrow D$ and an integer $n$, this function returns the map from the term in degree $n$ of the complex $C$ to the term in degree $n + \hbox{\tt Degree}(f)$ of the complex $D$.

<a id="function-kernel-mapchn"></a>
##### `Kernel(f): MapChn -> ModCpx, MapChn`

Returns the kernel complex of $f$ and the inclusion of the kernel in the domain of $f$. The function is only defined for proper chain maps. If the chain map is not defined for a certain term of the domain then that term is equal to the term of the kernel complex. That is, if $f$ is not defined on a term then the functions acts as if $f$ were the zero map on that term.

<a id="function-cokernel-mapchn"></a>
##### `Cokernel(f): MapChn -> ModCpx, MapChn`

Returns the cokernel complex of $f$ and the projection of the cokernel onto the codomain of $f$. The function is only defined for proper chain maps. If the chain map is not defined for a certain term of the codomain then that term is equal to the term of the cokernel complex. That is, if $f$ is not defined on a term then the function acts as if $f$ were the zero map on that term.

<a id="function-image-mapchn"></a>
##### `Image(f): MapChn -> ModCpx, MapChn, MapChn`

Returns the image complex of $f$ and the inclusion of the image in the codomain of $f$ and the projection of the domain of $f$ on to the image. The function is only defined for proper chain maps.

#### Elementary Operations

<a id="operation-op-plus-mapchn-mapchn"></a>
##### `f + g: MapChn, MapChn -> MapChn`

The sum of two chain maps with the same domain and codomain.

<a id="operation-op-times-rngelt-mapchn"></a>
##### `a * g: RngElt, MapChn -> MapChn`

The product of the chain map $g$ by the scalar $a$ in the base ring of the algebra.

<a id="operation-op-times-mapchn-mapchn"></a>
##### `f * g: MapChn, MapChn -> MapChn`

The composition of the two chain maps $f$ and $g$.

#### Predicates

The following functions return a Boolean value.

<a id="function-issurjective-mapchn"></a>
##### `IsSurjective(f): MapChn -> BoolElt`

Returns `true` if the chain map $f$ is a surjection in every degree, `false` otherwise.

<a id="function-isinjective-mapchn"></a>
##### `IsInjective(f): MapChn -> BoolElt`

Returns `true` if the chain map $f$ is an injection in every degree, `false` otherwise.

<a id="function-iszero-mapchn"></a>
##### `IsZero(f): MapChn -> BoolElt`

Returns `true` if the chain map $f$ is zero in every degree, `false` otherwise.

<a id="function-isisomorphism-mapchn"></a>
##### `IsIsomorphism(f): MapChn -> BoolElt`

Returns `true` if the chain map $f$ is an isomorphism of chain complexes, `false` otherwise.

<a id="function-isshortexactsequence-mapchn-mapchn"></a>
##### `IsShortExactSequence(f, g): MapChn, MapChn -> BoolElt`

Returns `true` if the sequence of chain complexes, $0 \rightarrow Domain(f) \rightarrow Domain(g) \rightarrow Codomain(g) \rightarrow 0$, where the internal maps are $f$ and $g$, is exact.

<a id="function-ischainmap-list-modcpx-modcpx-rngintelt"></a>
##### `IsChainMap(L, C, D, n): List, ModCpx, ModCpx, RngIntElt -> BoolElt`

Returns `true` if the list of maps $L$ from the terms of complex $C$ to the terms of the complex $D$ is a chain map of degree $n$, i. e. it has the right length and the diagram commutes.

<a id="function-ischainmap-mapchn"></a>
##### `IsChainMap(f): MapChn -> BoolElt`

Returns `true` if the supposed chain map $f$ really is a chain map, i. e. the diagrams commute.

<a id="function-isproperchainmap-mapchn"></a>
##### `IsProperChainMap(f): MapChn -> BoolElt`

Returns `true` if the chain map $f$ is a proper chain map, a necessary condition for taking kernel and cokernel.

<a id="function-hasdefinedmodulemap-modcpx-rngintelt"></a>
##### `HasDefinedModuleMap(C, n): ModCpx, RngIntElt -> BoolElt`

Returns `true` if the module map in degree $n$ of the complex $C$ is defined.

<a id="example-ex-f4e1ae"></a>
##### `Example: Chain Maps over a Basic Algebra (ex-f4e1ae)`

We from the basic algebra of the direct product of a cyclic group of order 3 with symmetric group on three letters over the field with three elements.

```magma
> FA<e1,e2,a,b> := FreeAlgebra(GF(3),4);
> MM:= [e1 +e2 - FA!1, a*b*a, b*a*b];
> BS3 := BasicAlgebra(FA, MM, 2, [<1,2>,<2,1>]);
> gg := CyclicGroup(3);
> BC3 := BasicAlgebra(gg,GF(3));
> A := TensorProduct(BS3,BC3);
> A;
Basic algebra of dimension 18 over GF(3)
Number of projective modules: 2
Number of generators: 6
```

Now we want the projective resolution of the second simple module as a complex. This we will manipulate and take a somewhat random complex.

```magma
> PR := ProjectiveResolution(SimpleModule(A,2),12);
> PR;
Basic algebra complex with terms of degree 12 down to 0
Dimensions of terms: 117 108 99 90 81 72 63 54 45 36 27 18 9
> PR := Prune(PR);
> PR := Prune(PR);
> PR := Prune(PR);
> PR;
Basic algebra complex with terms of degree 12 down to 3
Dimensions of terms: 117 108 99 90 81 72 63 54 45 36
> PR := Prune(PR);
> PR := Prune(PR);
> PR;
Basic algebra complex with terms of degree 12 down to 5
Dimensions of terms: 117 108 99 90 81 72 63 54
> PR := ZeroExtension(PR);
> PR;
Basic algebra complex with terms of degree 13 down to 4
Dimensions of terms: 0 117 108 99 90 81 72 63 54 0
> PR := Shift(PR,-4);
> PR;
Basic algebra complex with terms of degree 9 down to 0
Dimensions of terms: 0 117 108 99 90 81 72 63 54 0
> S := [* *];
> for i := 1 to 10 do
>    S[i] := [Random(Term(PR,10-i)),Random(Term(PR,10-i))];
> end for;
> C,mu := Subcomplex(PR,S);
> C;
Basic algebra complex with terms of degree 9 down to 0
Dimensions of terms: 0 36 67 64 62 63 58 54 51 0
> Homology(C);
[
    AModule of dimension 4 over GF(3),
    AModule of dimension 6 over GF(3),
    AModule of dimension 5 over GF(3),
    AModule of dimension 3 over GF(3),
    AModule of dimension 2 over GF(3),
    AModule of dimension 1 over GF(3),
    AModule of dimension 4 over GF(3),
    AModule of dimension 26 over GF(3)
]
[
    Mapping from: AModule of dimension 4 over GF(3) to AModule of dimension 4
    over GF(3),
    Mapping from: AModule of dimension 38 over GF(3) to AModule of dimension 6
    over GF(3),
    Mapping from: AModule of dimension 34 over GF(3) to AModule of dimension 5
    over GF(3),
    Mapping from: AModule of dimension 33 over GF(3) to AModule of dimension 3
    over GF(3),
    Mapping from: AModule of dimension 31 over GF(3) to AModule of dimension 2
    over GF(3),
    Mapping from: AModule of dimension 33 over GF(3) to AModule of dimension 1
    over GF(3),
    Mapping from: AModule of dimension 29 over GF(3) to AModule of dimension 4
    over GF(3),
    Mapping from: AModule of dimension 51 over GF(3) to AModule of dimension 26
    over GF(3)
]
> D := Cokernel(mu);
> D;
Basic algebra complex with terms of degree 9 down to 0
Dimensions of terms: 0 81 41 35 28 18 14 9 3 0
> Homology(D);
[
    AModule of dimension 64 over GF(3)
    AModule of dimension 5 over GF(3),
    AModule of dimension 3 over GF(3),
    AModule of dimension 2 over GF(3),
    AModule of dimension 1 over GF(3),
    AModule of dimension 4 over GF(3),
    AModule of dimension 3 over GF(3),
    AModule of dimension 3 over GF(3)
]
[
    Mapping from: AModule of dimension 64 over GF(3) to AModule of dimension 64
    over GF(3),
    Mapping from: AModule of dimension 22 over GF(3) to AModule of dimension 5
    over GF(3),
    Mapping from: AModule of dimension 22 over GF(3) to AModule of dimension 3
    over GF(3),
    Mapping from: AModule of dimension 15 over GF(3) to AModule of dimension 2
    over GF(3),
    Mapping from: AModule of dimension 14 over GF(3) to AModule of dimension 1
    over GF(3),
    Mapping from: AModule of dimension 8 over GF(3) to AModule of dimension 4
    over GF(3),
    Mapping from: AModule of dimension 9 over GF(3) to AModule of dimension 3
    over GF(3),
    Mapping from: AModule of dimension 3 over GF(3) to AModule of dimension 3
    over GF(3)
]
```

#### Maps on Homology

<a id="function-inducedmaponhomology-mapchn-rngintelt"></a>
##### `InducedMapOnHomology(f, n): MapChn, RngIntElt -> ModTupFldElt`

The homomorphism induced on homology by the chain map $f$ in degree $n$.

<a id="function-connectinghomomorphism-mapchn-mapchn-rngintelt"></a>
##### `ConnectingHomomorphism(f, g, n): MapChn, MapChn, RngIntElt -> ModMatRngElt`

The connecting homomorphism in degree $n$ of the short exact sequence of chain complexes given by the chain maps $f$ and $g$.

<a id="function-longexactsequenceonhomology-mapchn-mapchn"></a>
##### `LongExactSequenceOnHomology(f, g): MapChn, MapChn -> ModCpx`

The long exact sequence on homology for the exact sequence of complexes given by the chain maps $f$ and $g$ as a chain complex with the homology group in degree $i$ for the Cokernel of the complex $C$ appearing in degree $3i$.

<a id="example-ex-4cd4be"></a>
##### `Example: Long Exact Sequence in Homology (ex-4cd4be)`

We create a basic algebra with two simple modules and four nonidempotent generators. The relations are given in the sequence `rrr`.

```magma
> ff := GF(3);
> p := Characteristic(ff);
> FA<e1, e2, y, x, a, b> := FreeAlgebra(ff,6);
> rrr := [y^p,x^p,x*y+y*x,x*a*b-a*b*x,y*a*b-a*b*y,(b*a)^2,(b*a)^2];
> A := BasicAlgebra(FA,rrr,2,[<1,1>,<1,1>,<1,2>,<2,1>]);
> A;
Basic algebra of dimension 81 over GF(3)
Number of projective modules: 2
Number of generators: 6
> DimensionsOfProjectiveModules(A);
[ 45, 36 ]
```

Now we generate the simple modules and their projective covers. We want a module $PP$ that is the direct sum of two copies of each of the projective indecomposable module.

```magma
> S1 := SimpleModule(A,1);
> PP := ProjectiveModule(A,[2,2]);
```

Now we are going to create a complex all of whose terms are isomorphic to $PP$. To make it interesting we will insist that the first homomorphism have its image in the second radical layer of $PP$.

```magma
> J1 := JacobsonRadical(PP);
> theta1 := Morphism(J1,PP);
> J2 := JacobsonRadical(J1);
> theta2 := Morphism(J2,J1);
> theta := theta2*theta1;
> HomPJ := AHom(PP, J2);
> HomPJ;
KMatrixSpace of 162 by 150 matrices and dimension 300 over GF(3)
> gamma := Random(HomPJ)*theta;
> LL := [* gamma *];
```

So we now have the first boundary map of the complex. The other boundary maps are generated randomly.

```magma
> for i := 1 to 15 do
>     K, phi := Kernel(gamma);
>     HomPK := AHom(PP,K);
>     gamma := Random(HomPK)*MapToMatrix(phi);
>     LL := [* gamma *] cat LL;
> end for;
```

Now we make the list into a chain complex.

```magma
> C := Complex(LL,0);
> C;
Basic algebra complex with terms of degree 16 down to 0
Dimensions of terms: 162 162 162 162 162 162 162 162 162 162 162 162 162 162
162 162 162
> DimensionsOfHomology(C);
[ 30, 23, 34, 32, 35, 32, 35, 42, 30, 34, 32, 33, 29, 42, 21 ]

Now we will get a random subcomplex.

> a,b := Degrees(C);
> S, mu := RandomSubcomplex(C,[2: i in [1 .. a-b+1]]);
> S;
Basic algebra complex with terms of degree 16 down to 0
Dimensions of terms: 162 155 162 162 162 154 142 162 162 148 154 162 162 152
155 152 162
> DimensionsOfHomology(S);
[ 27, 27, 34, 32, 35, 33, 48, 42, 28, 44, 38, 33, 29, 48, 24 ]
```

Now take the quotient.

```magma
> Q,nu := quo<C|S>;
> Q;
Basic algebra complex with terms of degree 16 down to 0
Dimensions of terms: 0 7 0 0 0 8 20 0 0 14 8 0 0 10 7 10 0
> DimensionsOfHomology(Q);
[ 7, 0, 0, 0, 6, 18, 0, 0, 12, 6, 0, 0, 8, 5, 10 ]
```

Now we check to see if this is a short exact sequence of chain maps.

```magma
> IsShortExactSequence(mu,nu);
true
> lll := LongExactSequenceOnHomology(mu,nu);
Basic algebra complex with terms of degree 47 down to 3
Dimensions of terms: 27 30 7 27 23 0 34 34 0 32 32 0 35 35 6 33 32 18 48 35 0
42 42 0 28 30 12 44 34 6 38 32 0 33 33 0 29 29 8 48 42 5 24 21 10
> IsExact(lll);
true
```

## Multilinear Algebra

- [Introduction](https://docs.magma-maths.org/Modules/MultilinearAlgebra/intro.md)
  - [Overview](https://docs.magma-maths.org/Modules/MultilinearAlgebra/intro.md#overview)
  - [Verbose Printing](https://docs.magma-maths.org/Modules/MultilinearAlgebra/intro.md#verbose-printing)
    - [Example: Verbose Printing for Tensor Spaces](https://docs.magma-maths.org/Modules/MultilinearAlgebra/intro.md#example-ex-18db1e)
    - [`T : Magma;`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/intro.md#literal-literal-t-magma)
    - [`S : Magma;`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/intro.md#literal-literal-s-magma)
    - [`C : Magma;`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/intro.md#literal-literal-c-magma)
    - [Example: Printing Tensors to Strings](https://docs.magma-maths.org/Modules/MultilinearAlgebra/intro.md#example-ex-525a77)
- [Tensors](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md)
  - [Creating Tensors](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#creating-tensors)
    - [Black-box Tensors](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#black-box-tensors)
      - [`Tensor(S, F): SeqEnum, UserProgram → TenSpcElt, List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-tensor-seqenum-userprogram)
      - [`Tensor(S, F): List, UserProgram → TenSpcElt, List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-tensor-list-userprogram)
      - [`Tensor(S, F, Cat): SeqEnum, UserProgram, TenCat → TenSpcElt, List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-tensor-seqenum-userprogram-tencat)
      - [`Tensor(S, F, Cat): List, UserProgram, TenCat → TenSpcElt, List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-tensor-list-userprogram-tencat)
      - [Example: Black-Box Dot Product Tensor](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-cdbf81)
      - [Example: Black-Box Cross Product](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-82ef8c)
      - [`Tensor(D, C, F): SeqEnum, Any, UserProgram → TenSpcElt, List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-tensor-seqenum-any-userprogram)
      - [`Tensor(D, C, F): List, Any, UserProgram → TenSpcElt, List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-tensor-list-any-userprogram)
      - [`Tensor(D, C, F, Cat): SeqEnum, Any, UserProgram, TenCat → TenSpcElt, List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-tensor-seqenum-any-userprogram-tencat)
      - [`Tensor(D, C, F, Cat): List, Any, UserProgram, TenCat → TenSpcElt, List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-tensor-list-any-userprogram-tencat)
      - [Example: Black-Box Triple Product](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-e475ab)
    - [Tensors with Structure Constant Sequences](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#tensors-with-structure-constant-sequences)
      - [`Tensor(D, S): [RngIntElt], SeqEnum → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-tensor-rngintelt-seqenum)
      - [`Tensor(R, D, S): Rng, [RngIntElt], SeqEnum → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-tensor-rng-rngintelt-seqenum)
      - [`Tensor(D, S, Cat): [RngIntElt], SeqEnum, TenCat → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-tensor-rngintelt-seqenum-tencat)
      - [`Tensor(R, D, S, Cat): Rng, [RngIntElt], SeqEnum, TenCat → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-tensor-rng-rngintelt-seqenum-tencat)
      - [Example: Tensor from Structure Constants](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-3135bc)
      - [`StructureConstants(T): TenSpcElt → SeqEnum`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-structureconstants-tenspcelt)
      - [`Eltseq(T): TenSpcElt → SeqEnum`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-eltseq-tenspcelt)
      - [`Assign(T, ind, k): TenSpcElt, [RngIntElt], Any → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-assign-tenspcelt-rngintelt-any)
      - [`Assign(~T, ind, k): TenSpcElt, [RngIntElt], Any`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#procedure-assign-tenspcelt-rngintelt-any-ref)
      - [Example: Structure Constants from a Black-Box Tensor](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-73e82c)
      - [Example: Stored Structure Constants](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-80fd79)
    - [Bilinear Tensors](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#bilinear-tensors)
      - [`Tensor(M, s, t): [Mtrx], RngIntElt, RngIntElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-tensor-mtrx-rngintelt-rngintelt)
      - [`Tensor(M, s, t, C): [Mtrx], RngIntElt, RngIntElt, TenCat → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-tensor-mtrx-rngintelt-rngintelt-tencat)
      - [Example: Symplectic Bilinear Form](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-be1f50)
      - [`AsMatrices(T, s, t): TenSpcElt, RngIntElt, RngIntElt → SeqEnum`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-asmatrices-tenspcelt-rngintelt-rngintelt)
      - [`SystemOfForms(T): TenSpcElt → SeqEnum`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-systemofforms-tenspcelt)
      - [Example: Trilinear Tensor from Matrices](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-1d87b3)
    - [Tensors from Algebraic Objects](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#tensors-from-algebraic-objects)
      - [`Tensor(A): Alg → TenSpcElt, Map`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-tensor-alg)
      - [Example: Lie Bracket Tensor of D4(11)](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-17021d)
      - [`Tensor(Q): RngUPolRes → TenSpcElt, Map`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-tensor-rngupolres)
      - [Example: Tensor of the Witt Algebra](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-3ead54)
      - [`CommutatorTensor(A): Alg → TenSpcElt, Map`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-commutatortensor-alg)
      - [`AnticommutatorTensor(A): Alg → TenSpcElt, Map`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-anticommutatortensor-alg)
      - [Example: Commutator Tensor of a Matrix Algebra](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-ad0163)
      - [Example: Jordan Product of a Matrix Algebra](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-b964df)
      - [`AssociatorTensor(A): Alg → TenSpcElt, Map`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-associatortensor-alg)
      - [Example: Associator Tensor of the Octonions](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-4acc3b)
      - [`pCentralTensor(G, p, s, t): Grp, RngIntElt, RngIntElt, RngIntElt → TenSpcElt, List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-pcentraltensor-grp-rngintelt-rngintelt-rngintelt)
      - [`pCentralTensor(G, s, t): GrpPC, RngIntElt, RngIntElt → TenSpcElt, List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-pcentraltensor-grppc-rngintelt-rngintelt)
      - [`pCentralTensor(G, s, t): Grp, RngIntElt, RngIntElt → TenSpcElt, List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-pcentraltensor-grp-rngintelt-rngintelt)
      - [`pCentralTensor(G): Grp → TenSpcElt, List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-pcentraltensor-grp)
      - [Example: Recovering a Ring from a p-Group](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-94b48f)
      - [`MatrixTensor(K, S): Fld, [RngIntElt] → TenSpcElt, List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-matrixtensor-fld-rngintelt)
      - [`Polarisation(f): MPolElt → TenSpcElt, MPolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-polarisation-mpolelt)
      - [`Polarisation(f): RngUPolElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-polarisation-rngupolelt)
      - [`Polarization(f): MPolElt → TenSpcElt, MPolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-polarization-mpolelt)
      - [`Polarization(f): RngUPolElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-polarization-rngupolelt)
      - [Example: Polarization of a Binary Cubic Form](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-794950)
    - [New Tensors from Old](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#new-tensors-from-old)
      - [`AlternatingTensor(T): TenSpcElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-alternatingtensor-tenspcelt)
      - [`AntisymmetricTensor(T): TenSpcElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-antisymmetrictensor-tenspcelt)
      - [`SymmetricTensor(T): TenSpcElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-symmetrictensor-tenspcelt)
      - [Example: Alternating Tensor of a Lie Algebra](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-3641e3)
      - [Example: Symmetrizing a Matrix Algebra Tensor](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-73d5eb)
      - [`Shuffle(T, g): TenSpcElt, GrpPermElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-shuffle-tenspcelt-grppermelt)
      - [`Shuffle(T, g): TenSpcElt, SeqEnum → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-shuffle-tenspcelt-seqenum)
      - [Example: Transposing a Form by Shuffling](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-e67343)
      - [Example: Shuffling a Random 5-Tensor](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-ae928f)
      - [`TensorProduct(t, s): TenSpcElt, TenSpcElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-tensorproduct-tenspcelt-tenspcelt)
  - [Operations with Tensors](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operations-with-tensors)
    - [Elementary Operations](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#elementary-operations)
      - [`S + T: TenSpcElt, TenSpcElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-op-plus-tenspcelt-tenspcelt)
      - [`S - T: TenSpcElt, TenSpcElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-op-minus-tenspcelt-tenspcelt)
      - [`k * T: RngElt, TenSpcElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-op-times-rngelt-tenspcelt)
      - [`-T: TenSpcElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-operation-tenspcelt-tenspcelt)
      - [Example: Module Operations on Tensors](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-ce9931)
      - [`AssociatedForm(T): TenSpcElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-associatedform-tenspcelt)
      - [`Compress(T): TenSpcElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-compress-tenspcelt)
      - [`Compress(~T): TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#procedure-compress-tenspcelt-ref)
      - [Example: Associated Form of a Lie Algebra Tensor](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-9d2ed1)
    - [General Properties](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#general-properties)
      - [`Parent(T): TenSpcElt → TenSpc`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-parent-tenspcelt)
      - [`Domain(T): TenSpcElt → List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-domain-tenspcelt)
      - [`Codomain(T): TenSpcElt → Any`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-codomain-tenspcelt)
      - [`Valence(T): TenSpcElt → RngIntElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-valence-tenspcelt)
      - [`Frame(T): TenSpcElt → List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-frame-tenspcelt)
      - [`BaseRing(T): TenSpcElt → Rng`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-basering-tenspcelt)
      - [`BaseField(T): TenSpcElt → Fld`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-basefield-tenspcelt)
      - [Example: Basic Properties of a Tensor](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-7020de)
      - [`TensorCategory(T): TenSpcElt → TenCat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-tensorcategory-tenspcelt)
      - [`ChangeTensorCategory(T, C): TenSpcElt, TenCat → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-changetensorcategory-tenspcelt-tencat)
      - [`ChangeTensorCategory(~T, C): TenSpcElt, TenCat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#procedure-changetensorcategory-tenspcelt-tencat-ref)
      - [`IsCovariant(T): TenSpcElt → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-iscovariant-tenspcelt)
      - [`IsContravariant(T): TenSpcElt → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-iscontravariant-tenspcelt)
      - [Example: Category of a Right Module Tensor](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-bef887)
      - [`NondegenerateTensor(T): TenSpcElt → TenSpcElt, Hmtp`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-nondegeneratetensor-tenspcelt)
      - [`IsNondegenerate(T): TenSpcElt → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-isnondegenerate-tenspcelt)
      - [`IsDegenerate(T): TenSpcElt → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-isdegenerate-tenspcelt)
      - [Example: Nondegeneracy of a Tensor](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-f6f9ff)
      - [`Image(T): TenSpcElt → ModTupRng`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-image-tenspcelt)
      - [`FullyNondegenerateTensor(T): TenSpcElt → TenSpcElt, Hmtp`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-fullynondegeneratetensor-tenspcelt)
      - [`IsFullyNondegenerate(T): TenSpcElt → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-isfullynondegenerate-tenspcelt)
      - [Example: Fully Nondegenerate Tensors](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-f9b7b8)
      - [`IsAlternating(T): TenSpcElt → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-isalternating-tenspcelt)
      - [`IsAntisymmetric(T): TenSpcElt → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-isantisymmetric-tenspcelt)
      - [`IsSymmetric(T): TenSpcElt → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-issymmetric-tenspcelt)
      - [Example: Symmetric Form from a Ternary Cubic](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-6f9baa)
    - [Tensors As Multilinear Maps](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#tensors-as-multilinear-maps)
      - [`x @ T: Tup, TenSpcElt → Any`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-operation-tup-tenspcelt-any)
      - [Example: Evaluating the Jacobi Identity Tensor](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-be5d59)
      - [`T * f: TenSpcElt, Map → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-op-times-tenspcelt-map)
      - [`t * s: TenSpcElt, TenSpcElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-op-times-tenspcelt-tenspcelt)
      - [`S eq T: TenSpcElt, TenSpcElt → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-op-eq-tenspcelt-tenspcelt)
      - [Example: Composing Tensors with Linear Maps](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-0a17aa)
    - [Operations with Bilinear Maps](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operations-with-bilinear-maps)
      - [`x * T: Any, TenSpcElt → Any`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-op-times-any-tenspcelt)
      - [`T * y: TenSpcElt, Any → Any`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-op-times-tenspcelt-any)
      - [`x * T: Any, TenSpc → Any`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-op-times-any-tenspc)
      - [`T * y: TenSpc, Any → Any`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-op-times-tenspc-any)
      - [Example: Infix Notation for Bilinear Maps](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-4ade75)
      - [`x * y: BmpUElt, BmpVElt → Any`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-op-times-bmpuelt-bmpvelt)
      - [`x * y: BmpU, BmpV → Any`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-op-times-bmpu-bmpv)
      - [`x * y: BmpUElt, BmpV → Any`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-op-times-bmpuelt-bmpv)
      - [`x * y: BmpU, BmpVElt → Any`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-op-times-bmpu-bmpvelt)
      - [`LeftDomain(B): TenSpcElt → BmpU`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-leftdomain-tenspcelt)
      - [`RightDomain(B): TenSpcElt → BmpV`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-rightdomain-tenspcelt)
      - [`IsCoercible(U,x): BmpU, Any → BoolElt, BmpUElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-iscoercible-bmpu-any)
      - [`IsCoercible(V,x): BmpV, Any → BoolElt, BmpVElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-iscoercible-bmpv-any)
      - [`U ! x: BmpU, Any → BmpUElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-op-bmpu-any)
      - [`V ! x: BmpV, Any → BmpVElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-op-bmpv-any)
      - [Example: Product Notation for Bilinear Maps](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-90f3f7)
      - [`Parent(x): BmpUElt → BmpU`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-parent-bmpuelt)
      - [`Parent(x): BmpVElt → BmpV`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-parent-bmpvelt)
      - [`Parent(X): BmpU → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-parent-bmpu)
      - [`Parent(X): BmpV → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-parent-bmpv)
      - [`u1 eq u2: BmpUElt, BmpUElt → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-op-eq-bmpuelt-bmpuelt)
      - [`v1 eq v2: BmpUElt, BmpUElt → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-op-eq-bmpuelt-bmpuelt-2)
      - [`U1 eq U2: BmpU, BmpU → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-op-eq-bmpu-bmpu)
      - [`V1 eq V2: BmpV, BmpV → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#operation-op-eq-bmpv-bmpv)
      - [Example: Domains of a Bilinear Map](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-77d198)
    - [Manipulating Tensor Data](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#manipulating-tensor-data)
      - [`Slice(T, grid): TenSpcElt, [SetEnum] → SeqEnum`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-slice-tenspcelt-setenum)
      - [`InducedTensor(T, grid): TenSpcElt, [SetEnum] → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-inducedtensor-tenspcelt-setenum)
      - [Example: Slicing a Tensor](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-ff7268)
      - [`SliceAsMatrices(T, grid, a, b): TenSpcElt, [SetEnum], RngIntElt, RngIntElt → SeqEnum`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-sliceasmatrices-tenspcelt-setenum-rngintelt-rngintelt)
      - [Example: Slices as Matrices](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-436f03)
      - [`Foliation(T, i): TenSpcElt, RngIntElt → Mtrx`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-foliation-tenspcelt-rngintelt)
      - [Example: Exfoliating and Foliating a Tensor](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-c6ce4b)
      - [`AsTensorSpace(T, i): TenSpcElt, RngIntElt → TenSpc, Mtrx`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-astensorspace-tenspcelt-rngintelt)
      - [`AsCotensorSpace(T): TenSpcElt → TenSpc, Mtrx`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-ascotensorspace-tenspcelt)
      - [Example: Tensor Space at a Coordinate](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-8523ef)
      - [`AsTensor(S): TenSpc → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-astensor-tenspc)
      - [Example: Recovering a Tensor from Its Tensor Space](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-a38c03)
  - [Invariants of Tensors](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#invariants-of-tensors)
    - [`Induce(X, i): AlgMat, RngIntElt → Map, AlgMat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-induce-algmat-rngintelt)
    - [`Induce(X, i): AlgMatLie, RngIntElt → Map, AlgMatLie`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-induce-algmatlie-rngintelt)
    - [`Induce(X, i): GrpMat, RngIntElt → Map, GrpMat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-induce-grpmat-rngintelt)
    - [Example: Inducing Derivations of a Symplectic Form](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-4be7ac)
    - [`DerivedFrom(~X, t, C, RC : parameters): Any, TenSpcElt, {RngIntElt}, {RngIntElt}`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#procedure-derivedfrom-any-tenspcelt-rngintelt-rngintelt-ref)
    - [Standard Invariants](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#standard-invariants)
      - [`Radical(T, s): TenSpcElt, RngIntElt → ModTupRng`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-radical-tenspcelt-rngintelt)
      - [`Radical(T): TenSpcElt → Tup`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-radical-tenspcelt)
      - [`Coradical(T): TenSpcElt → ModTupRng, Map`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-coradical-tenspcelt)
      - [Example: Radicals of the Commutator Tensor](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-fef917)
      - [`Discriminant(B): TenSpcElt → RngMPolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-discriminant-tenspcelt)
      - [Example: Discriminant of the Octonions](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-8de961)
      - [`Pfaffian(B): TenSpcElt → RngMPolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-pfaffian-tenspcelt)
      - [Example: Pfaffians of Genus 2 Groups](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-4cc2d2)
  - [Exporting Tensors](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#exporting-tensors)
    - [`HeisenbergAlgebra(T): TenSpcElt → AlgGen`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-heisenbergalgebra-tenspcelt)
    - [Example: Heisenberg Algebras from Tensors](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-182a22)
    - [`HeisenbergLieAlgebra(T): TenSpcElt → AlgLie`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-heisenbergliealgebra-tenspcelt)
    - [Example: Lie Algebras from Tensors](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-19a3f6)
    - [`HeisenbergGroup(T): TenSpcElt → GrpMat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-heisenberggroup-tenspcelt)
    - [`HeisenbergGroupPC(T): TenSpcElt → GrpPC`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#function-heisenberggrouppc-tenspcelt)
    - [Example: p-Groups from Tensors](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-3bc793)
    - [Example: p-Groups from Non-Full Tensors](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensors.md#example-ex-ce8a17)
- [Tensor Spaces](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md)
  - [Constructions of Tensor and Cotensor Spaces](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#constructions-of-tensor-and-cotensor-spaces)
    - [Universal Tensor Spaces](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#universal-tensor-spaces)
      - [`KTensorSpace(K, S): Fld, [RngIntElt] → TenSpc`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-ktensorspace-fld-rngintelt)
      - [`KTensorSpace(K, S, C): Fld, [RngIntElt], TenCat → TenSpc`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-ktensorspace-fld-rngintelt-tencat)
      - [`RTensorSpace(R, S): Rng, [RngIntElt] → TenSpc`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-rtensorspace-rng-rngintelt)
      - [`RTensorSpace(R, S, C): Rng, [RngIntElt], TenCat → TenSpc`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-rtensorspace-rng-rngintelt-tencat)
      - [Example: Universal Tensor Space over a Field](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#example-ex-9c4d34)
      - [`TensorSpace(S): SeqEnum → TenSpc, List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-tensorspace-seqenum)
      - [`TensorSpace(S): List → TenSpc, List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-tensorspace-list)
      - [`TensorSpace(S, C): SeqEnum, TenCat → TenSpc, List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-tensorspace-seqenum-tencat)
      - [`TensorSpace(S, C): List, TenCat → TenSpc, List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-tensorspace-list-tencat)
      - [Example: Universal Tensor Space from Modules](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#example-ex-d8700c)
      - [`TensorSpace(V, p, q): ModTupFld, RngIntElt, RngIntElt → TenSpc`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-tensorspace-modtupfld-rngintelt-rngintelt)
      - [`TensorSpace(K, d, p, q): Fld, RngIntElt, RngIntElt, RngIntElt → TenSpc`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-tensorspace-fld-rngintelt-rngintelt-rngintelt)
      - [Example: Signatured Tensor Space](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#example-ex-170743)
    - [Universal Cotensor Spaces](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#universal-cotensor-spaces)
      - [`KCotensorSpace(K, S): Fld, [RngIntElt] → TenSpc`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-kcotensorspace-fld-rngintelt)
      - [`KCotensorSpace(K, S, C): Fld, [RngIntElt], TenCat → TenSpc`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-kcotensorspace-fld-rngintelt-tencat)
      - [`CotensorSpace(S): SeqEnum → TenSpc`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-cotensorspace-seqenum)
      - [`CotensorSpace(S): List → TenSpc, List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-cotensorspace-list)
      - [`CotensorSpace(S, C): SeqEnum, TenCat → TenSpc`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-cotensorspace-seqenum-tencat)
      - [`CotensorSpace(S, C): List, TenCat → TenSpc, List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-cotensorspace-list-tencat)
      - [Example: Universal Cotensor Spaces](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#example-ex-a0d0fa)
    - [Some Standard Constructions](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#some-standard-constructions)
      - [`AlternatingSpace(T): TenSpc → TenSpc, Map`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-alternatingspace-tenspc)
      - [`AntisymmetricSpace(T): TenSpc → TenSpc, Map`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-antisymmetricspace-tenspc)
      - [`SymmetricSpace(T): TenSpc → TenSpc, Map`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-symmetricspace-tenspc)
      - [Example: Standard Tensor Subspaces](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#example-ex-4fe5c3)
      - [`ExteriorCotensorSpace(V, n): ModTupFld, RngIntElt → TenSpc`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-exteriorcotensorspace-modtupfld-rngintelt)
      - [`SymmetricCotensorSpace(V, n): ModTupFld, RngIntElt → TenSpc`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-symmetriccotensorspace-modtupfld-rngintelt)
      - [Example: Standard Cotensor Subspaces](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#example-ex-cd38a4)
  - [Operations on Tensor Spaces](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#operations-on-tensor-spaces)
    - [Membership and Comparison with Tensor Spaces](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#membership-and-comparison-with-tensor-spaces)
      - [`T in TS: TenSpcElt, TenSpc → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#operation-op-in-tenspcelt-tenspc)
      - [`TS ! T: TenSpc, TenSpcElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#operation-op-tenspc-tenspcelt)
      - [`TS ! S: TenSpc, SeqEnum → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#operation-op-tenspc-seqenum)
      - [`T ! n: TenSpc, RngIntElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#operation-op-tenspc-rngintelt)
      - [`IsCoercible(TS, x): TenSpc, Any → BoolElt, TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-iscoercible-tenspc-any)
      - [Example: Coercion into a Tensor Space](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#example-ex-e939dc)
      - [`S eq T: TenSpc, TenSpc → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#operation-op-eq-tenspc-tenspc)
      - [`S subset T: TenSpc, TenSpc → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#operation-op-subset-tenspc-tenspc)
      - [`IsCoercible(T, S): TenSpc, Any → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-iscoercible-tenspc-any-2)
      - [`T ! S: TenSpc, TenSpc → TenSpc`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#operation-op-tenspc-tenspc)
      - [Example: Containment of Tensor Spaces](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#example-ex-812352)
    - [Tensor Spaces as Modules](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#tensor-spaces-as-modules)
      - [`Basis(T): TenSpc → SeqEnum`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-basis-tenspc)
      - [`Generators(T): TenSpc → SeqEnum`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-generators-tenspc)
      - [`T . i: TenSpc, RngIntElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#operation-operation-tenspc-rngintelt-tenspcelt)
      - [`NumberOfGenerators(T): TenSpc → RngIntElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-numberofgenerators-tenspc)
      - [`Ngens(T): TenSpc → RngIntElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-ngens-tenspc)
      - [`Dimension(T): TenSpc → RngIntElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-dimension-tenspc)
      - [`# T: TenSpc → RngIntElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#operation-operation-tenspc-rngintelt)
      - [Example: Module Functions on Tensor Spaces](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#example-ex-d57848)
      - [`Random(T): TenSpc → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-random-tenspc)
      - [`RandomTensor(R, S): Rng, [RngIntElt] → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-randomtensor-rng-rngintelt)
      - [`RandomTensor(R, S, C): Rng, [RngIntElt], TenCat → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-randomtensor-rng-rngintelt-tencat)
      - [`RandomCotensor(K, S): Fld, [RngIntElt] → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-randomcotensor-fld-rngintelt)
      - [Example: Random Tensors](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#example-ex-377558)
      - [`RandomAlternatingTensor(R, d, n, c): Rng, RngIntElt, RngIntElt, RngIntElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-randomalternatingtensor-rng-rngintelt-rngintelt-rngintelt)
      - [`RandomAlternatingTensor(R, S): Rng, [RngIntElt] → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-randomalternatingtensor-rng-rngintelt)
      - [`RandomAntisymmetricTensor(R, d, n, c): Rng, RngIntElt, RngIntElt, RngIntElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-randomantisymmetrictensor-rng-rngintelt-rngintelt-rngintelt)
      - [`RandomAntisymmetricTensor(R, S): Rng, [RngIntElt] → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-randomantisymmetrictensor-rng-rngintelt)
      - [`RandomSymmetricTensor(R, d, n, c): Rng, RngIntElt, RngIntElt, RngIntElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-randomsymmetrictensor-rng-rngintelt-rngintelt-rngintelt)
      - [`RandomSymmetricTensor(R, S): Rng, [RngIntElt] → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-randomsymmetrictensor-rng-rngintelt)
      - [Example: Random Symmetric Tensors](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#example-ex-f99231)
    - [Properties of Tensor Spaces](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#properties-of-tensor-spaces)
      - [`Valence(T): TenSpc → RngIntElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-valence-tenspc)
      - [`Frame(T): TenSpc → List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-frame-tenspc)
      - [`BaseRing(T): TenSpc → Rng`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-basering-tenspc)
      - [`BaseField(T): TenSpc → Fld`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-basefield-tenspc)
      - [Example: Properties of Tensor Spaces](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#example-ex-40631c)
      - [`TensorCategory(T): TenSpc → TenCat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-tensorcategory-tenspc)
      - [`IsCovariant(T): TenSpc → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-iscovariant-tenspc)
      - [`IsContravariant(T): TenSpc → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-iscontravariant-tenspc)
      - [`ChangeTensorCategory(T, C): TenSpc, TenCat → TenSpc`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-changetensorcategory-tenspc-tencat)
      - [`ChangeTensorCategory(~T, C): TenSpc, TenCat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#procedure-changetensorcategory-tenspc-tencat-ref)
      - [Example: Categories of Tensor Spaces](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#example-ex-066785)
      - [`IsAlternating(T): TenSpc → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-isalternating-tenspc)
      - [`IsAntisymmetric(T): TenSpc → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-isantisymmetric-tenspc)
      - [`IsSymmetric(T): TenSpc → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-issymmetric-tenspc)
      - [`UniversalTensorSpace(T): TenSpc → TenSpc`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-universaltensorspace-tenspc)
      - [`UniversalCotensorSpace(T): TenSpc → TenSpc`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-universalcotensorspace-tenspc)
      - [`Generic(T): TenSpc → TenSpc`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#function-generic-tenspc)
      - [Example: Subspace of Alternating Tensors](https://docs.magma-maths.org/Modules/MultilinearAlgebra/tensor_spaces.md#example-ex-c56f94)
- [Tensor Categories](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md)
  - [Constructing Tensor Categories](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#constructing-tensor-categories)
    - [`TensorCategory(A, P): [RngIntElt], {SetEnum} → TenCat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-tensorcategory-rngintelt-setenum)
    - [`TensorCategory(A, P): Map, {SetEnum} → TenCat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-tensorcategory-map-setenum)
    - [`CotensorCategory(A, P): [RngIntElt], {SetEnum} → TenCat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-cotensorcategory-rngintelt-setenum)
    - [`CotensorCategory(A, P): Map, {SetEnum} → TenCat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-cotensorcategory-map-setenum)
    - [Example: Basic Tensor Category Construction](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#example-ex-2873fe)
    - [`HomotopismCategory(v : parameters): RngIntElt → TenCat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-homotopismcategory-rngintelt)
    - [`CohomotopismCategory(v): RngIntElt → TenCat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-cohomotopismcategory-rngintelt)
    - [`AdjointCategory(v, s, t): RngIntElt, RngIntElt, RngIntElt → TenCat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-adjointcategory-rngintelt-rngintelt-rngintelt)
    - [`LinearCategory(v, s, t): RngIntElt, RngIntElt, RngIntElt → TenCat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-linearcategory-rngintelt-rngintelt-rngintelt)
    - [Example: Special Tensor Category Constructors](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#example-ex-f54041)
  - [Operations on Tensor Categories](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#operations-on-tensor-categories)
    - [`C1 eq C2: TenCat, TenCat → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#operation-op-eq-tencat-tencat)
    - [`Valence(C): TenCat → RngIntElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-valence-tencat)
    - [`Arrows(C): TenCat → SeqEnum`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-arrows-tencat)
    - [`RepeatPartition(C): TenCat → SetEnum`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-repeatpartition-tencat)
    - [`IsCovariant(C): TenCat → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-iscovariant-tencat)
    - [`IsContravariant(C): TenCat → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-iscontravariant-tencat)
    - [Example: Properties of Tensor Categories](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#example-ex-d61054)
  - [Categorical Operations](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#categorical-operations)
    - [Categorical Operations on Tensors](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#categorical-operations-on-tensors)
      - [`Subtensor(T, S): TenSpcElt, List → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-subtensor-tenspcelt-list)
      - [`Subtensor(T, S): TenSpcElt, SeqEnum → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-subtensor-tenspcelt-seqenum)
      - [`Subtensor(T, D, C): TenSpcElt, List, Any → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-subtensor-tenspcelt-list-any)
      - [`Subtensor(T, D, C): TenSpcElt, SeqEnum, Any → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-subtensor-tenspcelt-seqenum-any)
      - [`IsSubtensor(T, S): TenSpcElt, TenSpcElt → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-issubtensor-tenspcelt-tenspcelt)
      - [Example: Subtensors of Octonion Multiplication](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#example-ex-b3fa65)
      - [`LocalIdeal(T, S, I): TenSpcElt, List, {RngIntElt} → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-localideal-tenspcelt-list-rngintelt)
      - [`LocalIdeal(T, S, I): TenSpcElt, SeqEnum, {RngIntElt} → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-localideal-tenspcelt-seqenum-rngintelt)
      - [`LocalIdeal(T, D, C, I): TenSpcElt, List, Any, {RngIntElt} → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-localideal-tenspcelt-list-any-rngintelt)
      - [`LocalIdeal(T, D, C, I): TenSpcElt, SeqEnum, Any, {RngIntElt} → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-localideal-tenspcelt-seqenum-any-rngintelt)
      - [`LocalIdeal(T, S, I): TenSpcElt, TenSpcElt, {RngIntElt} → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-localideal-tenspcelt-tenspcelt-rngintelt)
      - [`IsLocalIdeal(T, S, I): TenSpcElt, TenSpcElt, {RngIntElt} → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-islocalideal-tenspcelt-tenspcelt-rngintelt)
      - [Example: Local Ideals of a Tensor](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#example-ex-96befc)
      - [`Ideal(T, S): TenSpcElt, List → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-ideal-tenspcelt-list)
      - [`Ideal(T, S): TenSpcElt, SeqEnum → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-ideal-tenspcelt-seqenum)
      - [`Ideal(T, D, C): TenSpcElt, List, Any → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-ideal-tenspcelt-list-any)
      - [`Ideal(T, D, C): TenSpcElt, SeqEnum, Any → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-ideal-tenspcelt-seqenum-any)
      - [`Ideal(T, S): TenSpcElt, TenSpcElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-ideal-tenspcelt-tenspcelt)
      - [`IsIdeal(T, S): TenSpcElt, TenSpcElt → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-isideal-tenspcelt-tenspcelt)
      - [Example: Ideals of the Tensor of an Algebra](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#example-ex-fad333)
      - [`LocalQuotient(T, S, I : parameters): TenSpcElt, TenSpcElt, {RngIntElt} → TenSpcElt, Hmtp`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-localquotient-tenspcelt-tenspcelt-rngintelt)
      - [`Quotient(T, S : parameters): TenSpcElt, TenSpcElt → TenSpcElt, Hmtp`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-quotient-tenspcelt-tenspcelt)
      - [`T / S: TenSpcElt, TenSpcElt → TenSpcElt, Hmtp`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#operation-op-div-tenspcelt-tenspcelt)
      - [Example: Fully Nondegenerate Quotient Tensor](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#example-ex-0f6850)
    - [Categorical Operations on Tensor Spaces](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#categorical-operations-on-tensor-spaces)
      - [`SubConstructor(T, L): TenSpc, Any → TenSpc, Map`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-subconstructor-tenspc-any)
      - [`sub< T | L >: TenSpc, Any → TenSpc, Map`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#constructor-constructor-sub-tenspc-any-tenspc-map)
      - [`IsSubtensorSpace(T, S): TenSpc, TenSpc → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-issubtensorspace-tenspc-tenspc)
      - [Example: Subspace of Symmetric Forms](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#example-ex-40cd43)
      - [`QuoConstructor(T, X): TenSpc, Any → TenSpc, Map`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-quoconstructor-tenspc-any)
      - [`quo< T | X >: TenSpc, Any → TenSpc, Map`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#constructor-constructor-quo-tenspc-any-tenspc-map)
      - [`T / S: TenSpc, TenSpc → TenSpc, Map`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#operation-op-div-tenspc-tenspc)
      - [Example: Quotients of Tensor Spaces](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#example-ex-87c8de)
  - [Homotopisms](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#homotopisms)
    - [Constructions of Homotopisms](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#constructions-of-homotopisms)
      - [`Homotopism(T, S, M : parameters): TenSpcElt, TenSpcElt, List → Hmtp`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-homotopism-tenspcelt-tenspcelt-list)
      - [`Homotopism(T, S, M : parameters): TenSpcElt, TenSpcElt, SeqEnum → Hmtp`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-homotopism-tenspcelt-tenspcelt-seqenum)
      - [`Homotopism(T, S, M, C : parameters): TenSpcElt, TenSpcElt, List, TenCat → Hmtp`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-homotopism-tenspcelt-tenspcelt-list-tencat)
      - [`Homotopism(T, S, M, C : parameters): TenSpcElt, TenSpcElt, SeqEnum, TenCat → Hmtp`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-homotopism-tenspcelt-tenspcelt-seqenum-tencat)
      - [`Homotopism(M, C): List, TenCat → Hmtp`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-homotopism-list-tencat)
      - [`Homotopism(M, C): SeqEnum, TenCat → Hmtp`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-homotopism-seqenum-tencat)
      - [`IsHomotopism(T, s, H): TenSpcElt, TenSpcElt, Hmtp → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-ishomotopism-tenspcelt-tenspcelt-hmtp)
      - [`IsHomotopism(T, s, M): TenSpcElt, TenSpcElt, List → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-ishomotopism-tenspcelt-tenspcelt-list)
      - [`IsHomotopism(T, s, M): TenSpcElt, TenSpcElt, SeqEnum → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-ishomotopism-tenspcelt-tenspcelt-seqenum)
      - [`IsHomotopism(T, s, M, C): TenSpcElt, TenSpcElt, List, TenCat → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-ishomotopism-tenspcelt-tenspcelt-list-tencat)
      - [`IsHomotopism(T, s, M, C): TenSpcElt, TenSpcElt, SeqEnum, TenCat → BoolElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-ishomotopism-tenspcelt-tenspcelt-seqenum-tencat)
      - [Example: Constructing Homotopisms](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#example-ex-6fd856)
      - [Example: Homotopisms from Mixed Maps](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#example-ex-d02f12)
    - [Basic Operations with Homotopisms](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#basic-operations-with-homotopisms)
      - [`H1 * H2: Hmtp, Hmtp → Hmtp`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#operation-op-times-hmtp-hmtp)
      - [`H . a: Hmtp, RngIntElt → Map`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#operation-operation-hmtp-rngintelt-map)
      - [Example: Operations with Homotopisms](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#example-ex-c4051c)
      - [`Precompose(T, f, a): TenSpcElt, Map, RngIntElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-precompose-tenspcelt-map-rngintelt)
      - [`Precompose(T, M, a): TenSpcElt, Mtrx, RngIntElt → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-precompose-tenspcelt-mtrx-rngintelt)
      - [`T @ H: TenSpcElt, Hmtp → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#operation-operation-tenspcelt-hmtp-tenspcelt)
    - [Basic Properties of Homotopisms](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#basic-properties-of-homotopisms)
      - [`Domain(H): Hmtp → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-domain-hmtp)
      - [`Codomain(H): Hmtp → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-codomain-hmtp)
      - [`Maps(H): Hmtp → List`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-maps-hmtp)
      - [`TensorCategory(H): Hmtp → TenCat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-tensorcategory-hmtp)
      - [`ChangeTensorCategory(H, C): Hmtp, TenCat → Hmtp`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-changetensorcategory-hmtp-tencat)
      - [`ChangeTensorCategory(~H, C): Hmtp, TenCat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#procedure-changetensorcategory-hmtp-tencat-ref)
      - [`Valence(H): Hmtp → RngIntElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-valence-hmtp)
      - [`Kernel(H): Hmtp → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-kernel-hmtp)
      - [`Image(H): Hmtp → TenSpcElt`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-image-hmtp)
      - [Example: Properties of Homotopisms](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#example-ex-5a1efc)
      - [`Shuffle(H, g): Hmtp, GrpPermElt → Hmtp`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-shuffle-hmtp-grppermelt)
      - [`Shuffle(H, g): Hmtp, [RngIntElt] → Hmtp`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#function-shuffle-hmtp-rngintelt)
- [Linear Invariants of Tensors](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Linear-invariants-of-tensors.md)
  - [Invariants for Bilinear Tensors](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Linear-invariants-of-tensors.md#invariants-for-bilinear-tensors)
    - [`AdjointAlgebra(B): TenSpcElt → AlgMat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Linear-invariants-of-tensors.md#function-adjointalgebra-tenspcelt)
    - [Example: Adjoint Algebra of a p-Group Tensor](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Linear-invariants-of-tensors.md#example-ex-55dbd9)
    - [`LeftNucleus(B : parameters): TenSpcElt → AlgMat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Linear-invariants-of-tensors.md#function-leftnucleus-tenspcelt)
    - [`MidNucleus(B): TenSpcElt → AlgMat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Linear-invariants-of-tensors.md#function-midnucleus-tenspcelt)
    - [`RightNucleus(B): TenSpcElt → AlgMat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Linear-invariants-of-tensors.md#function-rightnucleus-tenspcelt)
    - [Example: Nuclei Embed in the Derivation Algebra](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Linear-invariants-of-tensors.md#example-ex-75db37)
  - [Invariants of General Multilinear Maps](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Linear-invariants-of-tensors.md#invariants-of-general-multilinear-maps)
    - [`Centroid(T): TenSpcElt → AlgMat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Linear-invariants-of-tensors.md#function-centroid-tenspcelt)
    - [`Centroid(T, A): TenSpcElt, {RngIntElt} → AlgMat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Linear-invariants-of-tensors.md#function-centroid-tenspcelt-rngintelt)
    - [Example: Centroid of a Multiplication Tensor](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Linear-invariants-of-tensors.md#example-ex-71158e)
    - [`DerivationAlgebra(T): TenSpcElt → AlgMatLie`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Linear-invariants-of-tensors.md#function-derivationalgebra-tenspcelt)
    - [`DerivationAlgebra(T, A): TenSpcElt, {RngIntElt} → AlgMatLie`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Linear-invariants-of-tensors.md#function-derivationalgebra-tenspcelt-rngintelt)
    - [`Nucleus(T, a, b): TenSpcElt, RngIntElt, RngIntElt → AlgMat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Linear-invariants-of-tensors.md#function-nucleus-tenspcelt-rngintelt-rngintelt)
    - [`Nucleus(T, A): TenSpcElt, SetEnum → AlgMat`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Linear-invariants-of-tensors.md#function-nucleus-tenspcelt-setenum)
    - [Example: Restricting the Derivation Algebra](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Linear-invariants-of-tensors.md#example-ex-84e946)
    - [`SelfAdjointAlgebra(t, a, b): TenSpcElt, RngIntElt, RngIntElt → ModMatFld`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Linear-invariants-of-tensors.md#function-selfadjointalgebra-tenspcelt-rngintelt-rngintelt)
    - [`TensorOverCentroid(T): TenSpcElt → TenSpcElt, Hmtp`](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Linear-invariants-of-tensors.md#function-tensorovercentroid-tenspcelt)
    - [Example: Recovering a Field with the Centroid](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Linear-invariants-of-tensors.md#example-ex-93b5e7)
- [Some Extended Examples](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Some_examples.md)
  - [Distinguishing Groups](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Some_examples.md#distinguishing-groups)
    - [Example: Distinguishing Payne's Elation Groups](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Some_examples.md#example-ex-d908f2)
  - [Simplifying Automorphism Group Computations](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Some_examples.md#simplifying-automorphism-group-computations)
    - [Example: Automorphisms via the Adjoint Algebra](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Some_examples.md#example-ex-c87b8b)
- [Bibliography](https://docs.magma-maths.org/Modules/MultilinearAlgebra/bibliography.md)

### Introduction

This chapter discusses Magma operations with multilinear algebra. The notation follows [[FMW19](https://docs.magma-maths.org/references.md#cite-fmw-densors)] closely and can be viewed as companion literature. Wherever possible we follow the conventions in use in physics [[Wey50a](https://docs.magma-maths.org/references.md#cite-weyl), Chapter V], differential geometry [[Lee13](https://docs.magma-maths.org/references.md#cite-lee-geom), Chapter 10], and algebra [[Lan12](https://docs.magma-maths.org/references.md#cite-landsberg-tensors)]. Necessary categorical formalism is drawn largely from [[Wil13a](https://docs.magma-maths.org/references.md#cite-wilson-division)]. The package covers:

**(1)**
Tensors and multilinear functions and their associated groups and algebras.

**(2)**
Spaces of tensors.

**(3)**
Categories of tensors and tensor spaces.

**(4)**
Linear invariants of tensors.

#### Overview

We set up some notation used throughout. Define $K$ to be a commutative ring (typically a field), $\nu$ to be a nonnegative integer, and a sequence of right $K$-modules $U_0,\dots,U_{\nu}$. Set $[\nu]=\{0,\dots,\nu\}$, and for a subset $A\subset[\nu]$, let $\bar{A}=[\nu]-A$. Let $\oslash_{a\in[\nu]} U_a$ denote the set of multilinear maps $U_{\nu}\times\cdots U_1\rightarrowtail U_0$. Here, we use $\rightarrowtail$ exclusively for multilinear maps.

A *tensor space* $T$ is a $K$-module equipped with a monomorphism

$$
\langle \cdot | : T \hookrightarrow \oslash_{a\in[\nu]}U_a.
$$

*Tensors* are elements of $T$, $(U_{\nu},\dots,U_0)$ is the *frame*, and $\nu+1$ is the valence. In Dirac styled $\langle t|$ “bra t” and $|u\rangle$ “ket u” notation, we evaluate $\langle t | \in\oslash_{a\in[\nu]}U_a$ on inputs $|u\rangle=|u_{\nu},\dots, u_1\rangle\in U_{\nu}\times\cdots\times U_1$ denote $\langle t | u\rangle$ or $\langle t | u_{\nu},\dots,u_1\rangle$.

The module $U_0$ is reserved for the codomain which in turn makes reverse indexing the simplest notation. Every tensor in Magma is treated as an element of a tensor space which is, by default, a universal tensor space:

$$
\oslash_{a\in[\nu]} U_a = \hom_K(U_{\nu},\dots,\hom_K(U_1,U_0)\cdots).
$$

In Magma, the tensor space determines the associated multilinear function of a given tensor $T$. Evaluation of $T$ mimics the application of a map $U_v\times \cdots \times U_1\to U_0$, for instance,

```
> <u_v, ..., u_1> @ T;
```

Special attention is given to bilinear maps $*:U_2\times U_1\rightarrowtail U_0$ including the ability to use infix notation `u\_2 * u\_1`. Tensor spaces have type `TenSpc` and behave like modules in that they have subspaces and quotient spaces. Tensors have type `TenSpcElt` and behave in a similar way to Magma matrices.

A library of commonly used exceptional tensors is provided. These include octonion algebras and exceptional Jordan algebras.

Tensor categories, type `TenCat`, provide Magma with the information needed to interpret the contents of a tensor space. For example, one tensor category may treat a $(d\times d)$-matrix $F$ over a field $K$ as a linear map $K^d\to K^d$, while another assigns the same matrix to a bilinear form $K^d\times K^d\rightarrowtail K$. Functors are provided to change tensor categories and to define standard categories.

#### Verbose Printing

The string `"TensorSpace"` and an integer, either $0$ or $1$, is now acceptable input to `SetVerbose`. Level $0$ turns off printing, and level $1$ turns it on.

<a id="example-ex-18db1e"></a>
##### `Example: Verbose Printing for Tensor Spaces (ex-18db1e)`

We demonstrate the verbose printing. Currently, we only have verbose printing when we solve linear systems. To turn on all the printing statements, set `"TensorSpace"` to $1$.

```magma
> SetVerbose("TensorSpace", 1);
>
> t := RandomTensor(GF(2), [32, 32, 32]);
> D := DerivationAlgebra(t);
Construting a 3072 by 32768 matrix over Finite field of size 2.
Adding in possible fusion data.
Computing the nullspace of a 3072 by 32768 matrix.
```

<a id="literal-literal-t-magma"></a>
##### `T : Magma;`

<a id="literal-literal-s-magma"></a>
##### `S : Magma;`

<a id="literal-literal-c-magma"></a>
##### `C : Magma;`

Prints strings that can be executed in Magma to construct the given object. If $T$ is a black-box tensor where structure constants cannot be computed, then the printed string is the same as `print T`, which cannot be executed to construct $T$.

<a id="example-ex-525a77"></a>
##### `Example: Printing Tensors to Strings (ex-525a77)`

We first construct a tensor category, tensor space, and a tensor contained in the tensor space.

```magma
> C := TensorCategory([1, 1, 0], {{0}, {1,2}});
> C;
Tensor category of valence 3 (->,->,==) ({ 0 },{ 1, 2 })
>
> T := KTensorSpace(GF(2), [10, 10, 2], C);
> T;
Tensor space of dimension 200 over GF(2) with valence 3
U2 : Full Vector space of degree 10 over GF(2)
U1 : Full Vector space of degree 10 over GF(2)
U0 : Full Vector space of degree 2 over GF(2)
>
> t := T![1..200];
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 10 over GF(2)
U1 : Full Vector space of degree 10 over GF(2)
U0 : Full Vector space of degree 2 over GF(2)
```

Now we will print at “Magma” level each of the objects we created.

```magma
> C:Magma;
TensorCategory([ 1, 1, 0 ], { PowerSet(IntegerRing()) |
{ IntegerRing() | 0 },
{ IntegerRing() | 1, 2 }
})
>
> T:Magma;
TensorSpace([*VectorSpace(GF(2), 10), VectorSpace(GF(2), 10),
VectorSpace(GF(2),2)*], TensorCategory([ 1, 1, 0 ], {
PowerSet(IntegerRing()) |
{ IntegerRing() | 0 },
{ IntegerRing() | 1, 2 }
}))
>
> t:Magma;
Tensor(GF(2), [ 10, 10, 2 ], [ GF(2) | 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0 ], TensorCategory([ 1, 1, 0 ], { PowerSet(IntegerRing()) |
{ IntegerRing() | 0 },
{ IntegerRing() | 1, 2 }
}))
```

<a id="ch-tensors"></a>
<a id="id1"></a>
### Tensors

A tensor has the following information associated with it:-

- A commutative ring $K$ of coefficients.
- A valence ${\nu}$ indicating the number of variables to include in its associated multilinear map.
- A list $[U_{\nu},\dots, U_0]$ of $K$-modules called the *frame*.
- A function $U_{\nu}\times \cdots \times U_1\to U_0$ that is $K$-linear in each $U_i$.

Tensors have type `TenSpcElt` and are formally elements of a tensor space (type `TenSpc`). By default a tensor’s parent space is a universal tensor space:

$$
\hom_K(U_v,\dots,\hom_K(U_1,U_0)\cdots) \cong \hom_K(U_v\otimes_K\cdots \otimes_K U_1,U_0).
$$

The left hand module is primarily used because it avoids the need to work with the equivalence classes of a tensor product. Operations such as linear combinations of tensors take place within a tensor space. A tensor space has attributes such as coefficients, valence, and frame.

When necessary, the user may further direct the operations on tensors to appropriate tensor categories (type `TenCat`). For instance covariant and contravariant variables can be specified and symmetry conditions can be imposed. If no tensor category is prescribed then a default tensor category is selected based on the method of creation.

#### Creating Tensors

##### Black-box Tensors

A user can specify a tensor by a black-box function that evaluates the required multilinear map.

<a id="function-tensor-seqenum-userprogram"></a>
###### `Tensor(S, F): SeqEnum, UserProgram -> TenSpcElt, List`

<a id="function-tensor-list-userprogram"></a>
###### `Tensor(S, F): List, UserProgram -> TenSpcElt, List`

<a id="function-tensor-seqenum-userprogram-tencat"></a>
###### `Tensor(S, F, Cat): SeqEnum, UserProgram, TenCat -> TenSpcElt, List`

<a id="function-tensor-list-userprogram-tencat"></a>
###### `Tensor(S, F, Cat): List, UserProgram, TenCat -> TenSpcElt, List`

Returns a tensor $T$ and a list of maps from the given frame into vector spaces of the returned frame. Note that $T$ is a tensor over vector spaces—essentially forgetting all other structure. The last entry of $S$ is assumed to be the codomain of the multilinear map. The user-defined function $F$ should take as input a tuple of elements of the domain and return an element of the codomain. If no tensor category is provided, then Albert’s homotopism category is used.

<a id="example-ex-cdbf81"></a>
###### `Example: Black-Box Dot Product Tensor (ex-cdbf81)`

We demonstrate the black-box constructions by first constructing the dot product $\cdot : {\mathbb{Q}}^4\times {\mathbb{Q}}^4\rightarrowtail {\mathbb{Q}}$. The function used to evaluate our black-box tensor, `Dot`, must take exactly one argument. The argument will be a `Tup`, an element of the Cartesian product $U_{\nu}\times \cdots\times U_1$. Note that `x[i]` is the $i$th entry in the tuple and not the $i$th coordinate.

```magma
> Q := Rationals();
> U := VectorSpace(Q, 4);
> V := VectorSpace(Q, 4);
> W := VectorSpace(Q, 1);  // Vector space, not the field Q
> Dot := func< x | x[1]*Matrix(4, 1, Eltseq(x[2])) >;
```

Now we will construct the tensor from the data above. The first object returned is the tensor, and the second is a list of maps, mapping the given frame into the vector space frame. In this example, since the given frame consists of vector spaces, these maps are trivial. Note that the list of maps are not needed to work with the given tensor, we will demonstrate this later.

```magma
> Tensor([U, V, W], Dot);
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 4 over Rational Field
U1 : Full Vector space of degree 4 over Rational Field
U0 : Full Vector space of degree 1 over Rational Field
[*
    Mapping from: ModTupFld: U to ModTupFld: U given by a rule,
    Mapping from: ModTupFld: U to ModTupFld: U given by a rule,
    Mapping from: ModTupFld: W to ModTupFld: W given by a rule
*]
```

We will provide a tensor category for the dot product tensor, so that the returned tensor is not in the default homotopism category. We will use instead the $\{2,1\}$-adjoint category. While the returned tensor prints out the same as above, it does indeed live in a universe, see the section on Tensor Categories (`TenCat`).

```magma
> Cat := AdjointCategory(3, 2, 1);
> Cat;
Tensor category of valence 3 (<-,->,==) ({ 1 },{ 2 },{ 0 })
>
> t := Tensor([U, V, W], Dot, Cat);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 4 over Rational Field
U1 : Full Vector space of degree 4 over Rational Field
U0 : Full Vector space of degree 1 over Rational Field
>
> TensorCategory(t);
Tensor category of valence 3 (<-,->,==) ({ 1 },{ 2 },{ 0 })
```

<a id="example-ex-82ef8c"></a>
###### `Example: Black-Box Cross Product (ex-82ef8c)`

We will construct the cross product $\times : {\mathbb{R}}^3\times {\mathbb{R}}^3\rightarrowtail {\mathbb{R}}^3$ and verify that ${\bf i}\times {\bf j} = {\bf k}$. However, to do this test, we will input integer sequences (specifically `[RngIntElt]`), and we will still be able to evaluate.

```magma
> K := RealField(5);
> V := VectorSpace(K, 3);
> CP := function(x)
>   return V![x[1][2]*x[2][3] - x[1][3]*x[2][2],
>     x[1][3]*x[2][1] - x[1][1]*x[2][3],
>     x[1][1]*x[2][2] - x[1][2]*x[2][1] ];
> end function;
> t := Tensor([V, V, V], CP);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 3 over Real field of precision 5
U1 : Full Vector space of degree 3 over Real field of precision 5
U0 : Full Vector space of degree 3 over Real field of precision 5
>
> // test that i x j = k
> <[1,0,0], [0,1,0]> @ t eq V.3;
true
```

<a id="function-tensor-seqenum-any-userprogram"></a>
###### `Tensor(D, C, F): SeqEnum, Any, UserProgram -> TenSpcElt, List`

<a id="function-tensor-list-any-userprogram"></a>
###### `Tensor(D, C, F): List, Any, UserProgram -> TenSpcElt, List`

<a id="function-tensor-seqenum-any-userprogram-tencat"></a>
###### `Tensor(D, C, F, Cat): SeqEnum, Any, UserProgram, TenCat -> TenSpcElt, List`

<a id="function-tensor-list-any-userprogram-tencat"></a>
###### `Tensor(D, C, F, Cat): List, Any, UserProgram, TenCat -> TenSpcElt, List`

Returns a tensor $T$ and a list of maps from the given frame into vector spaces of the returned frame. Note that $T$ is a tensor over vector spaces—essentially forgetting all other structure. The user-defined function $F$ should take as input a tuple of elements of $D$ and return an element of $C$. If no tensor category is provided, then Albert’s homotopism category is used.

<a id="example-ex-e475ab"></a>
###### `Example: Black-Box Triple Product (ex-e475ab)`

Tensors make it easy to create algebras that do not fit into traditional categories, such as algebras with triple products. Here, we create a triple product $\langle \,\rangle : \rm{Mat}_{2\times 3}(K)\times \rm{Mat}_{2\times 3}(K)\times\rm{Mat}_{2\times 3}(K)\rightarrowtail \rm{Mat}_{2\times 3}(K)$, given by $\langle A, B, C\rangle = AB^tC$.

```magma
> K := GF(541);
> U := KMatrixSpace(K,2,3);
> my_prod := func< x | x[1]*Transpose(x[2])*x[3] >;
> t := Tensor([U,U,U,U], my_prod );
> t;
Tensor of valence 4, U3 x U2 x U1 >-> U0
U3 : Full Vector space of degree 6 over GF(541)
U2 : Full Vector space of degree 6 over GF(541)
U1 : Full Vector space of degree 6 over GF(541)
U0 : Full Vector space of degree 6 over GF(541)
```

Notice that the returned tensor is over vector spaces instead of the universe of `KMatrixSpace`. Tensors can still evaluate elements from the given frame, even though it prints out over vector spaces. However, the returned value form the tensor will be in the codomain of the tensor, so in this case, $K^6$.

```magma
> A := U![1,0,0,0,0,0];
> A;
[  1   0   0]
[  0   0   0]
> <A,A,A>@t;  // A is a generalized idempotent
(  1   0   0   0   0   0)
```

We can experiment to see if this triple product is left associative. To do this, we will construct five random matrices $\{ X_1,\dots,X_5\}\subset \rm{Mat}_{2\times 3}(K)$, and then we test if

$$
\langle \langle X_1, X_2, X_3 \rangle, X_4, X_5\rangle = \langle X_1, \langle X_4, X_3, X_2\rangle, X_5\rangle.
$$

Observe that the tuples have mixed entries, one from $K^6$ and two others from $\rm{Mat}_{2\times 3}(K)$.

```magma
> X := [Random(U) : i  in [1..5]];
> X;
[
    [485 378 385]
    [241 505 134],

    [141 531 245]
    [472 484 339],

    [377  85 170]
    [451 522 334],

    [211 340 409]
    [ 95 349 128],

    [264 372 144]
    [205  47 428]
]
>
> A := <X[1],X[2],X[3]> @ t;
> B := <X[4],X[3],X[2]> @ t;
> A, B;
(460 436 181 341 134 404)
(465 420 458 421 291 225)
>
> <A, X[4], X[5]> @ t eq <X[1], B, X[5]> @ t;
true
```

To confirm this product is left associative, we can create a new tensor for the left triple-associator and check that its image is $0$. We will create a $6$-tensor

$$
\{ \, \} : \prod_{k=1}^5 \rm{Mat}_{2\times 3}(K)\rightarrowtail \rm{Mat}_{2\times 3}(K)
$$

where

$$
\langle X_1,\dots, X_5\rangle = \langle \langle X_1, X_2, X_3 \rangle, X_4, X_5\rangle - \langle X_1, \langle X_4, X_3, X_2\rangle, X_5\rangle.
$$

Therefore, if $\operatorname{im}(\langle \, \rangle)=0$, then $\langle \,\rangle$ is left associative.

```magma
> l_asct := func< X | Eltseq(<<X[1], X[2], X[3]> @ t, X[4], X[5]> @ t
>     - <X[1], <X[4], X[3], X[2]> @ t, X[5]> @ t) >;
> Lt := Tensor([* U : i in [0..5] *], l_asct);
> Lt;
Tensor of valence 6, U5 x U4 x U3 x U2 x U1 >-> U0
U5 : Full Vector space of degree 6 over GF(541)
U4 : Full Vector space of degree 6 over GF(541)
U3 : Full Vector space of degree 6 over GF(541)
U2 : Full Vector space of degree 6 over GF(541)
U1 : Full Vector space of degree 6 over GF(541)
U0 : Full Vector space of degree 6 over GF(541)
>
> I := Image(Lt);
> I;
Vector space of degree 6, dimension 0 over GF(541)
Generators:

>
> Dimension(I);
0
```

Observe that in `lasct` the function `Eltseq` is called. This is because $t$ returns vectors in $K^6$ which is not naturally coercible into $\rm{Mat}_{2\times 3}(K)$. On the other hand, sequences can be coerced into $\rm{Mat}_{2\times 3}(K)$.

##### Tensors with Structure Constant Sequences

Most computations with tensors $T$ will be carried out using structure constants $T_{j_{\nu}\cdots j_0}\in K$. Here $T$ is framed by free $K$-modules $[U_{\nu},\dots,U_0]$ with each $U_i$ having an ordered basis ${\cal B}_i=[e_{i1},\dots,e_{id_i}]$. The interpretation of structure constants is that the associated multilinear function $[x_{\nu},\dots,x_1]$ from $U_{\nu}\times \cdots \times U_1$ into $U_0$ is determined on bases ${\cal B}_i$ as follows:

$$
[e_{{\nu}j_{\nu}},\dots,e_{1j_1} ] = \sum_{k=1}^{d_0} T_{j_{\nu} \cdots j_0} e_{0k}.
$$

Structure constants are input and stored as sequences $S$ in $K$ according to the following assignment. Set $f:{\mathbb{Z}}^{\nu+1}\to {\mathbb{Z}}$ to be:

$$
f(j_{\nu},\dots,j_0) = 1+\sum_{s=0}^{\nu} (j_s-1)\prod_{t=0}^{s-1} d_t.
$$

So $S[f(j_{\nu},\dots,j_0)]=T_{j_{\nu}\cdots j_0}$ specifies the structure constants as a sequence.

**Notes.**

- Magma does not currently support the notion of a sparse sequence of structure constants. A user can provide this functionality by specifying the multilinear function associated with a tensor by means of a user program rather than by structure constants.
- Some routines in Magma require structure constant sequences. If they are not provided, Magma may compute and store a structure constant representation with the tensor.
- Magma does not separate structure constant indices that are contravariant. Instead contravariant variables are signaled by tensor categories. So Ricci-styled tensors $T_{a_p\cdots a_1}^{b_q\cdots b_1}$ should be input as $T_{a_{p+q}\cdots a_{1+q} b_q\cdots b_1}$ and the tensor category changed to mark $\{q,\dots,1\}$ as contravariant. Intrinsics are provided to facilitate this approach. See Section [Tensor Categories](https://docs.magma-maths.org/Modules/MultilinearAlgebra/Tensor_categories.md#ch-tensor-categories) for more details on tensor categories.

<a id="function-tensor-rngintelt-seqenum"></a>
###### `Tensor(D, S): [RngIntElt], SeqEnum -> TenSpcElt`

<a id="function-tensor-rng-rngintelt-seqenum"></a>
###### `Tensor(R, D, S): Rng, [RngIntElt], SeqEnum -> TenSpcElt`

<a id="function-tensor-rngintelt-seqenum-tencat"></a>
###### `Tensor(D, S, Cat): [RngIntElt], SeqEnum, TenCat -> TenSpcElt`

<a id="function-tensor-rng-rngintelt-seqenum-tencat"></a>
###### `Tensor(R, D, S, Cat): Rng, [RngIntElt], SeqEnum, TenCat -> TenSpcElt`

Let $R$ be a commutative unital ring and $D$ a sequence $[d_v, \ldots, d_0]$ giving the dimensions of the $R$-modules $U_{v}, \ldots, U_{0}$. The intrinsic returns the tensor with frame { $U_{v}, \ldots, U_{1} \rbrace$, codomain $U_{0}$, and multilinear map defined by the structure constant sequence $S$. If $R$ is not specified then the parent ring of the first element of $S$ is used. The default tensor category $Cat$ is the homotopism category.

<a id="example-ex-3135bc"></a>
###### `Example: Tensor from Structure Constants (ex-3135bc)`

We will create structure constants sequence with all 0s and one 1 that occurs in the first entry. First, we will input this along with the dimensions of the tensor we are after, $2\times 2\times 2$. However, since we did not specify a ring, it is assumed to be the parent ring of the first entry of the structure constants sequence. In this example, the ring is ${\mathbb{Z}}$.

```magma
> sc := [ 0 : i in [1..8] ];
> sc[1] := 1;
> Tensor([2, 2, 2], sc);
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full RSpace of degree 2 over Integer Ring
U1 : Full RSpace of degree 2 over Integer Ring
U0 : Full RSpace of degree 2 over Integer Ring
```

We do not want the underlying ring to be ${\mathbb{Z}}$, so we will input the ring we want: GF$(64)$.

```magma
> K := GF(64);
> t := Tensor(K, [2, 2, 2], sc);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 2 over GF(2^6)
U1 : Full Vector space of degree 2 over GF(2^6)
U0 : Full Vector space of degree 2 over GF(2^6)
>
> Image(t);
Vector space of degree 2, dimension 1 over GF(2^6)
Generators:
(     1      0)
Echelonized basis:
(     1      0)
```

We can recover the structure constants by calling `StructureConstants` or `Eltseq`. We will also test that the tensor evaluates inputs correctly.

```magma
> StructureConstants(t);
[ 1, 0, 0, 0, 0, 0, 0, 0 ]
>
> <[1, 0], [K.1^3, 0]> @ t;
( K.1^3      0)
>
> <[K.1^29, 1], [0, K.1^2]> @ t;
(     0      0)
```

<a id="function-structureconstants-tenspcelt"></a>
###### `StructureConstants(T): TenSpcElt -> SeqEnum`

<a id="function-eltseq-tenspcelt"></a>
###### `Eltseq(T): TenSpcElt -> SeqEnum`

Returns the sequence of structure constants of the given tensor $T$.

<a id="function-assign-tenspcelt-rngintelt-any"></a>
###### `Assign(T, ind, k): TenSpcElt, [RngIntElt], Any -> TenSpcElt`

<a id="procedure-assign-tenspcelt-rngintelt-any-ref"></a>
###### `Assign(~T, ind, k): TenSpcElt, [RngIntElt], Any`

Returns the tensor $T$ where the `ind` element (viewed as a multi-dimensional array) is replaced with $k$. For example, replacing the $(a,b,c)$ entry of a $3$-tensor, set `ind`$\,=[a,b,c]$.

<a id="example-ex-73e82c"></a>
###### `Example: Structure Constants from a Black-Box Tensor (ex-73e82c)`

We will construct the natural Lie module action for $\rm{SL}_2$, but we will construct it as a *left* module. To do this, we construct a function that takes elements from $\rm{SL}_2\times V$ and returns an element that Magma can coerce into $V$. We run a quick test to make sure our function runs on the trivial example; this is the only check the intrinsic runs on black-box tensors. Since $\rm{SL}_2$ and $V$ are part of different universes in Magma, we must use the `List` environment when constructing this black-box tensor.

```magma
> SL2 := MatrixLieAlgebra("A1", GF(7));
> V := VectorSpace(GF(7), 2);
> left_action := func< x | x[2]*Transpose(Matrix(x[1])) >;
> left_action(<SL2!0, V!0>);
(0 0)
>
> SL2 := MatrixLieAlgebra("A1", GF(7));
> V := VectorSpace(GF(7), 2);
> left_action := func< x | x[2]*Transpose(Matrix(x[1])) >;
> left_action(<SL2!0, V!0>);
(0 0)
>
> t := Tensor([* SL2, V, V *], left_action);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 3 over GF(7)
U1 : Full Vector space of degree 2 over GF(7)
U0 : Full Vector space of degree 2 over GF(7)
```

Now we will extract the structure constants from this Lie module action. We will then construct a tensor with these structure constants and compare it with our first tensor above.

```magma
> StructureConstants(t);
[ 1, 0, 0, 6, 0, 0, 1, 0, 0, 1, 0, 0 ]
>
> s := Tensor([3, 2, 2], Eltseq(t));
> s;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 3 over GF(7)
U1 : Full Vector space of degree 2 over GF(7)
U0 : Full Vector space of degree 2 over GF(7)
>
> t eq s;
true
```

<a id="example-ex-80fd79"></a>
###### `Example: Stored Structure Constants (ex-80fd79)`

The structure constants are convenient data structure for nearly all the algorithms using tensors. In fact, most computations require structure constants, so we store the structure constants sequence with the tensor. This means that after the initial structure constant sequence computation, every time `StructureConstants` or `Eltseq` is called, Magma retrieves what was previously computed.

We will demonstrate this on a large black-box example, so some time is spent computing the structure constants. Of course, the exact timing will vary by machine. We will construct a product of two subalgebras of $\rm{Mat}_{20}({\bf F}_{3})$, namely $* : \rm{SL}_{20}({\bf F}_{3})\times \rm{Mat}_4({\bf F}_{3})\rightarrowtail \rm{Mat}_{20}({\bf F}_{3})$.

```magma
> SL20 := MatrixLieAlgebra("A19", GF(3));
> M4 := MatrixAlgebra(GF(3), 4);
> Prod := func< x | Matrix(x[1])*DiagonalJoin(<x[2] : i in [1..5]>) >;
> t := Tensor([* SL20, M4 *], MatrixAlgebra(GF(3), 20), Prod);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 399 over GF(3)
U1 : Full Vector space of degree 16 over GF(3)
U0 : Full Vector space of degree 400 over GF(3)
```

We record the time it takes to initially compute the structure constants sequence, and then we record the time when we call the function again.

```magma
> time sc := StructureConstants(t);
Time: 58.670
>
> time sc := StructureConstants(t);
Time: 0.000
```

##### Bilinear Tensors

In the special case of bilinear maps $U_2\times U_1\rightarrowtail U_0$, the structure constant sequences may be presented as lists $[M_1,\dots, M_a]$ of matrices. This can be considered as a left (resp. right) representation $U_2\to \hom_K(U_1,U_0)$, (resp.$U_1\to \hom_K(U_2,U_0)$). Alternatively, bilinear maps can be treated as *systems of bilinear forms* $[M_1,\dots,M_a]$ where the matrices are the Gram matrices of bilinear forms $\phi_i:U_2\times U_1\rightarrowtail K$. Here the associated bilinear map $U_2\times U_1\rightarrowtail U_0$ is specified by

$$
(u_2,u_1) \mapsto ( \phi_1(u_2,u_1),\dots, \phi_a(u_2,u_1)).
$$

<a id="function-tensor-mtrx-rngintelt-rngintelt"></a>
###### `Tensor(M, s, t): [Mtrx], RngIntElt, RngIntElt -> TenSpcElt`

<a id="function-tensor-mtrx-rngintelt-rngintelt-tencat"></a>
###### `Tensor(M, s, t, C): [Mtrx], RngIntElt, RngIntElt, TenCat -> TenSpcElt`

Given a sequence of matrices $M$, the bilinear tensor specified by $M$ is returned. The interpretation of the matrices as structure constant sequences is determined by the coordinates $s$ and $t$ which must be integers from the set $\{2,1,0\}$. Optionally a tensor category $C$ can be specified.

<a id="example-ex-be1f50"></a>
###### `Example: Symplectic Bilinear Form (ex-be1f50)`

We will construct a symplectic bilinear form on $V=K^8$. It would be cumbersome to construct this tensor as a black-box tensor or by providing the structure constants sequence. Instead, we will provide a (Gram) matrix.

```magma
> K := GF(17);
> MS := KMatrixSpace(K, 2, 2);
> J := KroneckerProduct(IdentityMatrix(K, 4), MS![0, 1, -1, 0]);
> J;
[ 0  1  0  0  0  0  0  0]
[16  0  0  0  0  0  0  0]
[ 0  0  0  1  0  0  0  0]
[ 0  0 16  0  0  0  0  0]
[ 0  0  0  0  0  1  0  0]
[ 0  0  0  0 16  0  0  0]
[ 0  0  0  0  0  0  0  1]
[ 0  0  0  0  0  0 16  0]
>
> t := Tensor(J, 2, 1);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 8 over GF(17)
U1 : Full Vector space of degree 8 over GF(17)
U0 : Full Vector space of degree 1 over GF(17)
>
> IsAlternating(t);
true
```

Now we will construct the symplectic form using the black-box construction and verify that the two tensors are the same.

```magma
> V := VectorSpace(K, 8);
> symp := func< x | x[1]*J*Matrix(8, 1, Eltseq(x[2])) >;
> s := Tensor([V, V], VectorSpace(K, 1), symp);
> s;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 8 over GF(17)
U1 : Full Vector space of degree 8 over GF(17)
U0 : Full Vector space of degree 1 over GF(17)
>
> SystemOfForms(s);
[
    [ 0  1  0  0  0  0  0  0]
    [16  0  0  0  0  0  0  0]
    [ 0  0  0  1  0  0  0  0]
    [ 0  0 16  0  0  0  0  0]
    [ 0  0  0  0  0  1  0  0]
    [ 0  0  0  0 16  0  0  0]
    [ 0  0  0  0  0  0  0  1]
    [ 0  0  0  0  0  0 16  0]
]
```

<a id="function-asmatrices-tenspcelt-rngintelt-rngintelt"></a>
###### `AsMatrices(T, s, t): TenSpcElt, RngIntElt, RngIntElt -> SeqEnum`

<a id="function-systemofforms-tenspcelt"></a>
###### `SystemOfForms(T): TenSpcElt -> SeqEnum`

For a tensor $T$ with frame $[K^{d_v},\dots,K^{d_0}]$, a list $[M_1,\dots,M_d]$, $d=(d_v\cdots d_0)/d_s d_t$, of $(d_s\times d_t)$-matrices in $K$ representing the tensor as an element of $\hom_K(K^{d_s}\otimes_K K^{d_t},K^d)$ is returned. For the intrinsic `SystemOfForms`, $T$ must have valence $2$ and the implied values are $s=2$ and $t=1$.

<a id="example-ex-1d87b3"></a>
###### `Example: Trilinear Tensor from Matrices (ex-1d87b3)`

We construct the associator of $\rm{SL}_2({\mathbb{Q}})$ where

$$
\langle \, \rangle : \prod_{k=1}^3\rm{SL}_2\rightarrowtail \rm{SL}_2
$$

given by

$$
\langle x,y,z \rangle = [[x,y],z] - [x,[y,z]].
$$

It can be hard to understand some of the features of this trilinear map by only looking at the structure constants sequence. The function `AsMatrices` slices the sequence and presents the data as a sequence of matrices.

```magma
> K := Rationals();
> L := LieAlgebra("A1", K);
> t := AssociatorTensor(L);
> t;
Tensor of valence 4, U3 x U2 x U1 >-> U0
U3 : Full Vector space of degree 3 over Rational Field
U2 : Full Vector space of degree 3 over Rational Field
U1 : Full Vector space of degree 3 over Rational Field
U0 : Full Vector space of degree 3 over Rational Field
>
> Eltseq(t);
[ 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0,
0,-2, 0, 0, 0, 0, 0, 0, 0, 2, 0, -1, 0, 0, 0, 0, 0, 0, 0, -1, 0, 2, 0, 0, 0,
0, 0, 0, 0, -2, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2,
0, 0, 0, 0, 0, 0 ]
```

Calling `AsMatrices(t, 3, 1)` returns a sequence of nine matrices, but we only show the first four. As explained in the documentation above, this sequence of matrices can be interpreted as the system of bilinear forms for the 3-tensor $\circ_{31} : V_3 \times V_1 \rightarrowtail \hom_K(V_2,V_0)$ given by

$$
x\circ_{31} z = \langle x, -,z \rangle = [[x,-],z] - [x,[-,z]].
$$

```magma
> AsMatrices(t, 3, 1)[1..4];
[
    [ 0  0  2]
    [ 0  0  0]
    [-2  0  0],

    [ 0  0  0]
    [ 0  0  2]
    [ 0 -2  0],

    [0 0 0]
    [0 0 0]
    [0 0 0],

    [ 0  1  0]
    [-1  0  0]
    [ 0  0  0]
]
```

##### Tensors from Algebraic Objects

A natural and important source of tensors come from algebraic objects with a distributive property. One main source is from algebras, where $*:A\times A\rightarrowtail A$ is given by multiplication in $A$. Like with the previous sections on tensor constructions, all tensors will be constructed over vector spaces. The user can still input elements from the original algebra, but map(s) will also be returned. Furthermore, each tensor is assigned a category relevant to its origin, see the section on tensor categories for more information.

<a id="function-tensor-alg"></a>
###### `Tensor(A): Alg -> TenSpcElt, Map`

Given an algebra $A$ with an element product that satisfies an appropriate distributive law, return the bilinear tensor given by the product in $A$.

<a id="example-ex-17021d"></a>
###### `Example: Lie Bracket Tensor of D4(11) (ex-17021d)`

We want to get the Lie bracket from $D_4(11)$. Tensors created from algebras will have a homotopism category, but with $U_2=U_1=U_0$. This forces the operators acting to be the same on all the coordinates; in other words, $\Omega=\rm{End}(U_2)$ instead of $\Omega=\rm{End}(U_2)\times\rm{End}(U_1)\times\rm{End}(U_0)$.

```magma
> L := LieAlgebra("D4", GF(11));
> t := Tensor(L);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 28 over GF(11)
U1 : Full Vector space of degree 28 over GF(11)
U0 : Full Vector space of degree 28 over GF(11)
> IsAlternating(t);
true
> TensorCategory(t);
Tensor category of valence 3 (->,->,->) ({ 0, 1, 2 })
```

If we compute the derivation algebra of $L$, our operators will act in the same way on each coordinate. This is the standard definition of the derivation algebra of a ring.

```magma
> D := DerivationAlgebra(t);
> Dimension(D);
28
> SemisimpleType(D);
D4
```

Now we will change the category to the standard homotopism category, where we do *not* fuse $U_2$, $U_1$, and $U_0$.

```magma
> ChangeTensorCategory(~t, HomotopismCategory(3));
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 28 over GF(11)
U1 : Full Vector space of degree 28 over GF(11)
U0 : Full Vector space of degree 28 over GF(11)
> TensorCategory(t);
Tensor category of valence 3 (->,->,->) ({ 1 },{ 2 },{ 0 })
```

We compare the same computation of derivation algebra. This time, the theory tells us that there will be a solvable radical. In this example, $\operatorname{Rad}(D)=K^2$.

```magma
> D := DerivationAlgebra(t);
> Dimension(D);
30
> R := SolvableRadical(D);
> SemisimpleType(D/R);
D4
```

<a id="function-tensor-rngupolres"></a>
###### `Tensor(Q): RngUPolRes -> TenSpcElt, Map`

Returns the bilinear tensor given by the product in quotient polynomial ring $Q$.

<a id="example-ex-3ead54"></a>
###### `Example: Tensor of the Witt Algebra (ex-3ead54)`

The Witt algebra, over a finite field of characteristic $p$, is isomorphic to the derivation algebra of $K[x]/(x^p)$. The Witt algebra is a simple Lie algebra with dimension $p$ and a trivial Killing form. First, we will construct the tensor from the ring ${\bf F}_{5}[x]/(x^5)$. Note that, like with algebras, the tensor category will fuse $U_2$, $U_1$, and $U_0$, so that the operators act the same way on every coordinate.

```magma
> p := 5;
> R<x> := PolynomialRing(GF(p));
> I := ideal< R | x^p >;
> Q := quo< R | I >;
> Q;
Univariate Quotient Polynomial Algebra in $.1 over Finite field of size
5 with modulus $.1^5
> t := Tensor(Q);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 5 over GF(5)
U1 : Full Vector space of degree 5 over GF(5)
U0 : Full Vector space of degree 5 over GF(5)
> TensorCategory(t);
Tensor category of valence 3 (->,->,->) ({ 0, 1, 2 })
```

Now we will construct a Lie representation of the Witt algebra from the tensor $t$.

```magma
> D := DerivationAlgebra(t);
> IsSimple(D);
true
> Dimension(D);
5
> KillingForm(D);
[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]
```

<a id="function-commutatortensor-alg"></a>
###### `CommutatorTensor(A): Alg -> TenSpcElt, Map`

<a id="function-anticommutatortensor-alg"></a>
###### `AnticommutatorTensor(A): Alg -> TenSpcElt, Map`

Given an algebra $A$ return the tensor corresponding to the bilinear commutator map $[a,b]=ab-ba$ or the anticommutator map $\langle a,b\rangle = ab+ba$ of the algebra $A$. This should not be used to get the tensor given by the Lie or Jordan product in a Lie or Jordan algebra; instead use `Tensor`.

<a id="example-ex-ad0163"></a>
###### `Example: Commutator Tensor of a Matrix Algebra (ex-ad0163)`

We will construct the commutator tensor from $\rm{Mat}_4({\mathbb{Q}})$.

```magma
> A := MatrixAlgebra(Rationals(), 4);
> t := CommutatorTensor(A);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 16 over Rational Field
U1 : Full Vector space of degree 16 over Rational Field
U0 : Full Vector space of degree 16 over Rational Field
> IsAlternating(t); // [X, X] = 0?
true
```

With this tensor, we will compute the dimension of the centralizer of the diagonal matrix $M$ with diagonal entries $(1,1,-1,-1)$ in $\rm{Mat}_4({\mathbb{Q}})$. To do this, we will subtract the dimension of the image of $[M, A]$ from the dimension of $A$.

```magma
> M := A![1,0,0,0,0,1,0,0,0,0,-1,0,0,0,0,-1];
> M;
[ 1  0  0  0]
[ 0  1  0  0]
[ 0  0 -1  0]
[ 0  0  0 -1]
> Dimension(A) - Dimension(<M, A> @ t);
8
```

<a id="example-ex-b964df"></a>
###### `Example: Jordan Product of a Matrix Algebra (ex-b964df)`

This time, we will obtain a Jordan product from $\rm{Mat}_4({\mathbb{Q}})$. That is, we will construct the bilinear map $* : \rm{Mat}_4({\mathbb{Q}})\times \rm{Mat}_4({\mathbb{Q}})\rightarrowtail \rm{Mat}_4({\mathbb{Q}})$ where $A*B = (AB+BA)/2$.

```magma
> A := MatrixAlgebra(Rationals(), 4);
> t := AnticommutatorTensor(A);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 16 over Rational Field
U1 : Full Vector space of degree 16 over Rational Field
U0 : Full Vector space of degree 16 over Rational Field
> SystemOfForms(t)[1];
[2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0]
[0 1 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 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 0 0 0 0 0 0 0 0]
[0 0 1 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 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 0 0 0 0 0 0 0]
[0 0 0 1 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 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 0 0 0 0 0 0]
> A.1*t*A.1;
(2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
```

From the documentation on `AnticommutatorTensor`, we have to scale our tensor above $t$ by $1/2$ to get what we want. Of course this won’t affect the proceeding tests though.

```magma
> s := (1/2)*t;
> A.1*s*A.1;
(1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
```

Now we will confirm that $s$ is a Jordan product. First, we check that $s$ is commutative, and then we check that it satisfies the Jordan identity: $(xy)(xx)=x(y(xx))$.

```magma
> IsSymmetric(s);
true
> JordanID := func< x, y | (x*s*y)*s*(x*s*x) - x*s*(y*s*(x*s*x)) >;
> forall{ <x,y> : x in Basis(A), y in Basis(A) |
>     JordanID(x, y) eq Codomain(s)!0 };
true
```

<a id="function-associatortensor-alg"></a>
###### `AssociatorTensor(A): Alg -> TenSpcElt, Map`

Given an algebra $A$ return the tensor corresponding to the trilinear associator map $[a,b,c]=(ab)c-a(bc)$ on the algebra $A$.

<a id="example-ex-4acc3b"></a>
###### `Example: Associator Tensor of the Octonions (ex-4acc3b)`

Do three random octonions satisfy the associate law? Hardly ever.

```magma
> O := OctonionAlgebra ( GF (1223) , -1 , -1 , -1);
> t := AssociatorTensor ( O );
> t;
Tensor of valence 4, U3 x U2 x U1 >-> U0
U3 : Full Vector space of degree 8 over GF(1223)
U2 : Full Vector space of degree 8 over GF(1223)
U1 : Full Vector space of degree 8 over GF(1223)
U0 : Full Vector space of degree 8 over GF(1223)
> <Random(O),Random(O),Random(O)> @ t eq O!0;
false
```

However, for all $a,b\in O$, $(aa)b=a(ab)$ as octonions are alternative algebras.

```magma
> a := Random ( O );
> b := Random ( O );
> <a, a, b> @ t eq O!0;
true
> IsAlternating ( t );
true
```

<a id="function-pcentraltensor-grp-rngintelt-rngintelt-rngintelt"></a>
###### `pCentralTensor(G, p, s, t): Grp, RngIntElt, RngIntElt, RngIntElt -> TenSpcElt, List`

<a id="function-pcentraltensor-grppc-rngintelt-rngintelt"></a>
###### `pCentralTensor(G, s, t): GrpPC, RngIntElt, RngIntElt -> TenSpcElt, List`

<a id="function-pcentraltensor-grp-rngintelt-rngintelt"></a>
###### `pCentralTensor(G, s, t): Grp, RngIntElt, RngIntElt -> TenSpcElt, List`

<a id="function-pcentraltensor-grp"></a>
###### `pCentralTensor(G): Grp -> TenSpcElt, List`

Returns the bilinear map of commutation from the associated graded Lie algebra of the lower exponent-$p$ central series $\eta$ of $G$. The bilinear map pairs $\eta_s/\eta_{s+1}$ with $\eta_{t}/\eta_{t+1}$ into $\eta_{s+t}/\eta_{s+t+1}$. If $s=t$ the tensor category is set to force $U_2=U_1$; otherwise it is the general homotopism category. In addition, maps from the subgroups into the vector spaces are returned as a list. If $p$, $s$, and $t$ are not given, it is assumed $G$ is a $p$-group and $s=t=1$.

<a id="example-ex-94b48f"></a>
###### `Example: Recovering a Ring from a p-Group (ex-94b48f)`

Groups have a single binary operation. So even when groups are built from rings it can be difficult to recover the ring from the group operations. Tensors supply one approach for that task. We will get the $p$-central tensor of $G=\rm{SL}(3,125)$; however, we will lose the fact that there is a field ${\bf F}_{125}$. The tensor we will get back is $[,] : K^6\times K^6 \rightarrowtail K^3$, where $K={\bf F}_{5}$.

```magma
> P := ClassicalSylow(SL(3,125), 5);
> Q := PCGroup(P);     // The group Q won't have explicit knowledge of GF(125).
> Q;
GrpPC : Q of order 1953125 = 5^9
PC-Relations:
    Q.4^Q.1 = Q.4 * Q.7^4,
    Q.4^Q.2 = Q.4 * Q.8^4,
    Q.4^Q.3 = Q.4 * Q.9^4,
    Q.5^Q.1 = Q.5 * Q.8^4,
    Q.5^Q.2 = Q.5 * Q.9^4,
    Q.5^Q.3 = Q.5 * Q.7^3 * Q.8^3,
    Q.6^Q.1 = Q.6 * Q.9^4,
    Q.6^Q.2 = Q.6 * Q.7^3 * Q.8^3,
    Q.6^Q.3 = Q.6 * Q.8^3 * Q.9^3
> t := pCentralTensor(Q);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 6 over GF(5)
U1 : Full Vector space of degree 6 over GF(5)
U0 : Full Vector space of degree 3 over GF(5)
```

Knowing that $G$ is defined over ${\bf F}_{125}$, we know that the commutator is really just the alternating form $\cdot : {\bf F}_{125}^2\times {\bf F}_{125}^2\rightarrowtail {\bf F}_{125}$. This information can be extracted from the centroid of $t$ above, and we can rewrite $t$ over the field ${\bf F}_{125}$.

```magma
> F := Centroid(t);  // Recover GF(125)
> Dimension(F);
3
> IsSimple(F);
true
> IsCommutative(F);
true
> s := TensorOverCentroid(t);
> s;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 2 over GF(5^3)
U1 : Full Vector space of degree 2 over GF(5^3)
U0 : Full Vector space of degree 1 over GF(5^3)
```

<a id="function-matrixtensor-fld-rngintelt"></a>
###### `MatrixTensor(K, S): Fld, [RngIntElt] -> TenSpcElt, List`

Given a field $K$ and a sequence of positive integers $S=[s_1,\dots, s_{\nu}]$, return the tensor

$$
\rm{Mat}_{s_1\times s_2}(K) \times \cdots \times \rm{Mat}_{s_{\nu-1}\times s_{\nu}}(K)\rightarrowtail \rm{Mat}_{s_1\times s_{\nu}}(K),
$$

given by matrix multiplication. A list of maps from the matrix spaces to the vector spaces is given as well even though the given tensor will evaluate matrices as well.

<a id="function-polarisation-mpolelt"></a>
###### `Polarisation(f): MPolElt -> TenSpcElt, MPolElt`

<a id="function-polarisation-rngupolelt"></a>
###### `Polarisation(f): RngUPolElt -> TenSpcElt`

<a id="function-polarization-mpolelt"></a>
###### `Polarization(f): MPolElt -> TenSpcElt, MPolElt`

<a id="function-polarization-rngupolelt"></a>
###### `Polarization(f): RngUPolElt -> TenSpcElt`

Returns the polarization of the homogeneous multivariate polynomial $f$ as a tensor and as a multivariate polynomial. Note that the intrinsic does not normalize by $1/d!$, where $d$ is the degree of $f$.

<a id="example-ex-794950"></a>
###### `Example: Polarization of a Binary Cubic Form (ex-794950)`

The polarization intrinsic is applied to the polynomial $f(x, y) = x^2 y$. Because $f$ is homogeneous of degree 3 with 2 variables, it is expected that the polarization will have 6 variables and that the corresponding multilinear form will be $K^2\times K^2\times K^2\rightarrowtail K$. The polarization of $f$ is given by $P(x_1,x_2,y_1,y_2,z_1,z_2 ) = 2 (x_1y_1z_2 + x_1y_2z_1 + x_2y_1z_1)$.

```magma
> R<x,y> := PolynomialRing(Rationals(), 2);
> T, p := Polarization(x^2*y);
> p;
2*$.1*$.3*$.6 + 2*$.1*$.4*$.5 + 2*$.2*$.3*$.5
> T;
Tensor of valence 4, U3 x U2 x U1 >-> U0
U3 : Full Vector space of degree 2 over Rational Field
U2 : Full Vector space of degree 2 over Rational Field
U1 : Full Vector space of degree 2 over Rational Field
U0 : Full Vector space of degree 1 over Rational Field
> <[1,0],[1,0],[1,0]> @ T;
(0)
> <[1,0],[1,0],[0,1]> @ T;
(2)
```

##### New Tensors from Old

A number of new tensors may be constructed from a given tensor.

<a id="function-alternatingtensor-tenspcelt"></a>
###### `AlternatingTensor(T): TenSpcElt -> TenSpcElt`

Returns the alternating tensor induced by the given tensor $T$. If the tensor is already alternating, then the given tensor is returned.

<a id="function-antisymmetrictensor-tenspcelt"></a>
###### `AntisymmetricTensor(T): TenSpcElt -> TenSpcElt`

Returns the antisymmetric tensor induced by the given tensor $T$. If the tensor is already antisymmetric, then the given tensor is returned.

<a id="function-symmetrictensor-tenspcelt"></a>
###### `SymmetricTensor(T): TenSpcElt -> TenSpcElt`

Returns the symmetric tensor induced by the given tensor $T$. If the tensor is already symmetric, then the given tensor is returned.

<a id="example-ex-3641e3"></a>
###### `Example: Alternating Tensor of a Lie Algebra (ex-3641e3)`

Tensors coming from Lie algebras are alternating. If we call `AlternatingTensor` on a tensor from a Lie algebra, nothing will be changed.

```magma
> L := LieAlgebra("A3", GF(3));
> t := Tensor(L);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 15 over GF(3)
U1 : Full Vector space of degree 15 over GF(3)
U0 : Full Vector space of degree 15 over GF(3)
> AlternatingTensor(t) eq t;
true
```

<a id="example-ex-73d5eb"></a>
###### `Example: Symmetrizing a Matrix Algebra Tensor (ex-73d5eb)`

We will make the tensor coming from the product in $\rm{Mat}_3({\mathbb{Q}})$ symmetric.

```magma
> A := MatrixAlgebra(Rationals(), 3);
> t := Tensor(A);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 9 over Rational Field
U1 : Full Vector space of degree 9 over Rational Field
U0 : Full Vector space of degree 9 over Rational Field
> SystemOfForms(t)[1];
[1 0 0 0 0 0 0 0 0]
[0 0 0 1 0 0 0 0 0]
[0 0 0 0 0 0 1 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 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 0 0]
```

The first matrix in the sequence of bilinear forms of $t$ is not symmetric, so $t$ is not symmetric (of course matrix multiplication is not commutative also). We will construct a symmetric version of $t$ and inspect the first matrix of the bilinear forms.

```magma
> s := SymmetricTensor(t);
> s;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 9 over Rational Field
U1 : Full Vector space of degree 9 over Rational Field
U0 : Full Vector space of degree 9 over Rational Field
> SystemOfForms(s)[1];
[2 0 0 0 0 0 0 0 0]
[0 0 0 1 0 0 0 0 0]
[0 0 0 0 0 0 1 0 0]
[0 1 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 1 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0]
```

<a id="function-shuffle-tenspcelt-grppermelt"></a>
###### `Shuffle(T, g): TenSpcElt, GrpPermElt -> TenSpcElt`

<a id="function-shuffle-tenspcelt-seqenum"></a>
###### `Shuffle(T, g): TenSpcElt, SeqEnum -> TenSpcElt`

Given a tensor $T$ in $\hom(U_{\nu},\dots,\hom(U_1,U_0)\cdots)$, this intrinsic generates the representation of $T$ in

$$
\hom(U_{{\nu}^g},\dots,\hom(U_{1^g},U_{0^g})\dots),
$$

where $g$ is a permutation of $\{0,\dots,\nu \}$. The permutation $g$ may be given as an element of a permutation group or as a sequence. Both the image and pre-image of $0$ under $g$ will be replaced by their $K$-dual space. For cotensors, $g$ must permute $\{1,\dots,\nu \}$. Sequences $[a_1,\dots,a_{\nu+1}]$ will be interpreted as a permutation in one-line notation.

<a id="example-ex-e67343"></a>
###### `Example: Transposing a Form by Shuffling (ex-e67343)`

We will shuffle the alternating form $\Q^2\times\Q^2\rightarrowtail \Q$ as a means of performing a transpose on the Gram matrix. To do this, we need to shuffle by the transposition $(1, 2)$ in $\Sym(\{0,1,2\})$.

```magma
> t := Tensor(Rationals(), [2, 2, 1], [0, 1, -1, 0]);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 2 over Rational Field
U1 : Full Vector space of degree 2 over Rational Field
U0 : Full Vector space of degree 1 over Rational Field
> SystemOfForms(t);
[
    [ 0  1]
    [-1  0]
]
>
> s := Shuffle(t, [0,2,1]);
> s;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 2 over Rational Field
U1 : Full Vector space of degree 2 over Rational Field
U0 : Full Vector space of degree 1 over Rational Field
> SystemOfForms(s);
[
    [ 0 -1]
    [ 1  0]
]
```

<a id="example-ex-ae928f"></a>
###### `Example: Shuffling a Random 5-Tensor (ex-ae928f)`

We will generate a random 5-tensor and shuffle it with $(0,2,4,1,3)$.

```magma
> t := RandomTensor(GF(2), [5,4,3,2,1]);
> t;
Tensor of valence 5, U4 x U3 x U2 x U1 >-> U0
U4 : Full Vector space of degree 5 over GF(2)
U3 : Full Vector space of degree 4 over GF(2)
U2 : Full Vector space of degree 3 over GF(2)
U1 : Full Vector space of degree 2 over GF(2)
U0 : Full Vector space of degree 1 over GF(2)
>
> G := Sym({0..4});
> g := G![2, 3, 4, 0, 1];
> g;
(0, 2, 4, 1, 3)
>
> s := Shuffle(t, g);
> s;
Tensor of valence 5, U4 x U3 x U2 x U1 >-> U0
U4 : Full Vector space of degree 2 over GF(2)
U3 : Full Vector space of degree 1 over GF(2)
U2 : Full Vector space of degree 5 over GF(2)
U1 : Full Vector space of degree 4 over GF(2)
U0 : Full Vector space of degree 3 over GF(2)
```

<a id="function-tensorproduct-tenspcelt-tenspcelt"></a>
###### `TensorProduct(t, s): TenSpcElt, TenSpcElt -> TenSpcElt`

Given $K$-tensors $t:U_{\nu}\times \cdots \times U_1\rightarrowtail U_0$ and $s:V_{\nu}\times \cdots \times V_1\rightarrowtail V_0$, returns the tensor $t\otimes s : U_{\nu}\otimes V_{\nu}\times \cdots \times U_1\otimes V_1\rightarrowtail U_0\otimes V_0$. This is like a generalized Kronecker product.

#### Operations with Tensors

Magma supports two perspectives for operations with tensors. Firstly, tensors determine multilinear maps and so behave as functions. Secondly, tensors are elements of a tensor space and so behave as elements of a module.

##### Elementary Operations

Treating the tensor space as a $K$-module, we have the standard operations.

<a id="operation-op-plus-tenspcelt-tenspcelt"></a>
###### `S + T: TenSpcElt, TenSpcElt -> TenSpcElt`

<a id="operation-op-minus-tenspcelt-tenspcelt"></a>
###### `S - T: TenSpcElt, TenSpcElt -> TenSpcElt`

<a id="operation-op-times-rngelt-tenspcelt"></a>
###### `k * T: RngElt, TenSpcElt -> TenSpcElt`

<a id="operation-operation-tenspcelt-tenspcelt"></a>
###### `-T: TenSpcElt -> TenSpcElt`

Given tensors $S$ and $T$ belonging to the same tensor space $V$, and an element $k$ belonging to the coefficient ring $K$, these intrinsics return the sum, difference, scalar multiple, or additive inverse of $S$ and $T$ as elements of $V$. The corresponding multilinear maps are the sum, difference, scalar multiple, or additive inverse of the multilinear maps.

<a id="example-ex-ce9931"></a>
###### `Example: Module Operations on Tensors (ex-ce9931)`

As tensors are elements of a tensor space, it inherits module operations. We will demonstrate them all here. First, here are the tensors we will operate with.

```magma
> K := Rationals();
> t := Tensor(K, [2, 2, 2], [1..8]);
> s := Tensor(K, [2, 2, 2], &cat[[2, -1] : i in [1..4]]);
> SystemOfForms(t);
[
    [1 3]
    [5 7],

    [2 4]
    [6 8]
]
> SystemOfForms(s);
[
    [2 2]
    [2 2],

    [-1 -1]
    [-1 -1]
]
```

Now we perform the module operations.

```magma
> SystemOfForms(-t);
[
    [-1 -3]
    [-5 -7],

    [-2 -4]
    [-6 -8]
]
> SystemOfForms((1/3)*s);
[
    [2/3 2/3]
    [2/3 2/3],

    [-1/3 -1/3]
    [-1/3 -1/3]
]
> SystemOfForms(t+s);
[
    [3 5]
    [7 9],

    [1 3]
    [5 7]
]
> SystemOfForms(t-2*s);
[
    [-3 -1]
    [ 1  3],

    [ 4  6]
    [ 8 10]
]
```

<a id="function-associatedform-tenspcelt"></a>
###### `AssociatedForm(T): TenSpcElt -> TenSpcElt`

For a tensor $T$ with frame $U_{\nu}\times \cdots \times U_1\rightarrowtail U_0$, this intrinsic creates the associated multilinear form $U_{\nu}\times\cdots\times U_1\times U_0^*\rightarrowtail K$. The valence is increased by $1$.

<a id="function-compress-tenspcelt"></a>
###### `Compress(T): TenSpcElt -> TenSpcElt`

<a id="procedure-compress-tenspcelt-ref"></a>
###### `Compress(~T): TenSpcElt`

Returns the compression of the tensor $T$. This removes all 1-dimensional spaces in the domain.

<a id="example-ex-9d2ed1"></a>
###### `Example: Associated Form of a Lie Algebra Tensor (ex-9d2ed1)`

We will construct the associated form of the tensor from the Lie algebra $B_3(5)$. The codomain of the original tensor gets moved (and dualed) to the domain.

```magma
> L := LieAlgebra("B3", GF(5));
> t := Tensor(L);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 21 over GF(5)
U1 : Full Vector space of degree 21 over GF(5)
U0 : Full Vector space of degree 21 over GF(5)
> s := AssociatedForm(t);
> s;
Tensor of valence 4, U3 x U2 x U1 >-> U0
U3 : Full Vector space of degree 21 over GF(5)
U2 : Full Vector space of degree 21 over GF(5)
U1 : Full Vector space of degree 21 over GF(5)
U0 : Full Vector space of degree 1 over GF(5)
> <L.2, L.11> @ t;
(0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
> <L.2, L.11, L.2> @ s;
(4)
> <L.2, L.11, L> @ s;
Full Vector space of degree 1 over GF(5)
Generators:
(4)
```

We shuffle the associated form by the permutation $(0,3)$ and compress it. The result is just the shuffle of the original bilinear map $t$ by $(0,2,1)$.

```magma
> shf := Shuffle(s, [3,1,2,0]);
> shf;
Tensor of valence 4, U3 x U2 x U1 >-> U0
U3 : Full Vector space of degree 1 over GF(5)
U2 : Full Vector space of degree 21 over GF(5)
U1 : Full Vector space of degree 21 over GF(5)
U0 : Full Vector space of degree 21 over GF(5)
> cmp := Compress(shf);
> cmp;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 21 over GF(5)
U1 : Full Vector space of degree 21 over GF(5)
U0 : Full Vector space of degree 21 over GF(5)
> cmp eq Shuffle(t, [2, 0, 1]);
true
```

##### General Properties

We provide basic intrinsics to retrieve data stored in the `TenSpcElt` object in Magma. Most of these functions are already stored as attributes. The ones that are not initially stored at construction are stored immediately after the initial computation, such as `Image`.

<a id="function-parent-tenspcelt"></a>
###### `Parent(T): TenSpcElt -> TenSpc`

Returns the tensor space that contains the tensor $T$. The default space is the universal tensor space.

<a id="function-domain-tenspcelt"></a>
###### `Domain(T): TenSpcElt -> List`

Returns the domain of the tensor $T$ as a list of modules.

<a id="function-codomain-tenspcelt"></a>
###### `Codomain(T): TenSpcElt -> Any`

Returns the codomain of the tensor $T$.

<a id="function-valence-tenspcelt"></a>
###### `Valence(T): TenSpcElt -> RngIntElt`

Returns the valence of the tensor $T$.

<a id="function-frame-tenspcelt"></a>
###### `Frame(T): TenSpcElt -> List`

Returns the modules in the frame of the tensor $T$ in the form of a list containing the domain modules and the codomain.

<a id="function-basering-tenspcelt"></a>
###### `BaseRing(T): TenSpcElt -> Rng`

<a id="function-basefield-tenspcelt"></a>
###### `BaseField(T): TenSpcElt -> Fld`

Returns the base ring or field of the tensor $T$.

<a id="example-ex-7020de"></a>
###### `Example: Basic Properties of a Tensor (ex-7020de)`

We demonstrate how to get basic properties of a tensor and what to expect as an output. We will construct a tensor $*:\rm{Mat}_{2\times 3}({\mathbb{Q}})\times {\mathbb{Q}}^3\rightarrowtail {\mathbb{Q}}^2$ given by multiplication. Nearly all of this information is displayed when printing a tensor.

```magma
> K := Rationals();
> U2 := KMatrixSpace(K, 2, 3);
> U1 := VectorSpace(K, 3);
> U0 := VectorSpace(K, 2);
> mult := func< x | Eltseq(x[1]*Matrix(3,1,Eltseq(x[2]))) >;
> t := Tensor([* U2, U1, U0 *], mult);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 6 over Rational Field
U1 : Full Vector space of degree 3 over Rational Field
U0 : Full Vector space of degree 2 over Rational Field
>
> Parent(t);
Tensor space of dimension 36 over Rational Field with valence 3
U2 : Full Vector space of degree 6 over Rational Field
U1 : Full Vector space of degree 3 over Rational Field
U0 : Full Vector space of degree 2 over Rational Field
>
> Domain(t);
[*
    Full Vector space of degree 6 over Rational Field,

    Full Vector space of degree 3 over Rational Field
*]
>
> Codomain(t);
Full Vector space of degree 2 over Rational Field
>
> Valence(t);
3
>
> Frame(t);
[*
    Full Vector space of degree 6 over Rational Field,

    Full Vector space of degree 3 over Rational Field,

    Full Vector space of degree 2 over Rational Field
*]
> BaseRing(t);
Rational Field
```

<a id="function-tensorcategory-tenspcelt"></a>
###### `TensorCategory(T): TenSpcElt -> TenCat`

Returns the underlying tensor category of tensor $T$.

<a id="function-changetensorcategory-tenspcelt-tencat"></a>
###### `ChangeTensorCategory(T, C): TenSpcElt, TenCat -> TenSpcElt`

<a id="procedure-changetensorcategory-tenspcelt-tencat-ref"></a>
###### `ChangeTensorCategory(~T, C): TenSpcElt, TenCat`

Returns the tensor $T$ with the given category.

<a id="function-iscovariant-tenspcelt"></a>
###### `IsCovariant(T): TenSpcElt -> BoolElt`

<a id="function-iscontravariant-tenspcelt"></a>
###### `IsContravariant(T): TenSpcElt -> BoolElt`

Returns `true` if the underlying category of the tensor $T$ is covariant or contravariant.

<a id="example-ex-bef887"></a>
###### `Example: Category of a Right Module Tensor (ex-bef887)`

We will construct a tensor from a right module, $*:{\mathbb{Q}}^2 \times \rm{Mat}_{2\times 2}({\mathbb{Q}})\rightarrowtail {\mathbb{Q}}^2$.

```magma
> K := Rationals();
> U := KMatrixSpace(K, 2, 2);
> V := VectorSpace(K, 2);
> mult := func< x | x[1]*x[2] >;
> t := Tensor([* V, U, V *], mult);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 2 over Rational Field
U1 : Full Vector space of degree 4 over Rational Field
U0 : Full Vector space of degree 2 over Rational Field
```

Because this tensor comes from a module, we want the tensor category to reflect this. Currently, the tensor category is the default homotopism category. We will keep everything about the category the same, except we will fuse coordinates 2 and 0. These changes could easily go unnoticed if no operators are constructed.

```magma
> TensorCategory(t);
Tensor category of valence 3 (->,->,->) ({ 1 },{ 2 },{ 0 })
> Cat := TensorCategory([1, 1, 1], {{2,0},{1}});
> Cat;
Tensor category of valence 3 (->,->,->) ({ 1 },{ 0, 2 })
> ChangeTensorCategory(~t, Cat);
> TensorCategory(t);
Tensor category of valence 3 (->,->,->) ({ 1 },{ 0, 2 })
> IsCovariant(t);
true
```

<a id="function-nondegeneratetensor-tenspcelt"></a>
###### `NondegenerateTensor(T): TenSpcElt -> TenSpcElt, Hmtp`

Returns the nondegenerate tensor associated to $T$ along with a homotopism from the given tensor to the returned nondegenerate tensor.

<a id="function-isnondegenerate-tenspcelt"></a>
###### `IsNondegenerate(T): TenSpcElt -> BoolElt`

<a id="function-isdegenerate-tenspcelt"></a>
###### `IsDegenerate(T): TenSpcElt -> BoolElt`

Returns `true` if $T$ is a degenerate or nondegenerate multilinear map.

<a id="example-ex-f6f9ff"></a>
###### `Example: Nondegeneracy of a Tensor (ex-f6f9ff)`

An important property for tensors is nondegeneracy: all radicals are trivial. First we create a tensor with degeneracy.

```magma
> K := GF(541);
> V := VectorSpace(K, 10);
> U := VectorSpace(K, 5);
> mult := function(x)
>   M := Matrix(3, 3, Eltseq(x[1])[2..10]);
>   v := VectorSpace(K, 3)!(Eltseq(x[2])[[1,3,5]]);
>   return Eltseq(v*M) cat [0,0];
> end function;
> t := Tensor([V, U, U], mult);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 10 over GF(541)
U1 : Full Vector space of degree 5 over GF(541)
U0 : Full Vector space of degree 5 over GF(541)
```

In this example, both $U_{\widehat{2}}^\perp$ and $U_{\widehat{1}}^\perp$ are nontrivial. We will construct the associated nondegenerate tensor $s$, which is given by $U_2/U_{\widehat{2}}^\perp \times U_1/U_{\widehat{1}}^\perp \rightarrowtail U_0$.

```magma
> IsNondegenerate(t);
false
> s, H := NondegenerateTensor(t);
> s;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 9 over GF(541)
U1 : Full Vector space of degree 3 over GF(541)
U0 : Full Vector space of degree 5 over GF(541)
> H;
Maps from U2 x U1 >-> U0 to V2 x V1 >-> V0.
U2 -> V2: Mapping from: Full Vector space of degree 10 over GF(541) to
Full Vector space of degree 9 over GF(541)
U1 -> V1: Mapping from: Full Vector space of degree 5 over GF(541) to
Full Vector space of degree 3 over GF(541)
U0 -> V0: Mapping from: Full Vector space of degree 5 over GF(541) to
Full Vector space of degree 5 over GF(541)
```

<a id="function-image-tenspcelt"></a>
###### `Image(T): TenSpcElt -> ModTupRng`

Returns the image of the tensor $T$.

<a id="function-fullynondegeneratetensor-tenspcelt"></a>
###### `FullyNondegenerateTensor(T): TenSpcElt -> TenSpcElt, Hmtp`

Returns the fully nondegenerate multilinear map associated to tensor $T$ along with a cohomotopism from the given tensor to the returned tensor.

<a id="function-isfullynondegenerate-tenspcelt"></a>
###### `IsFullyNondegenerate(T): TenSpcElt -> BoolElt`

Returns `true` if the tensor $T$ is a fully nondegenerate multilinear map.

<a id="example-ex-f9b7b8"></a>
###### `Example: Fully Nondegenerate Tensors (ex-f9b7b8)`

We use the same tensor as the previous example illustrating the use of `NondegenerateTensor`.

```magma
> K := GF(541);
> V := VectorSpace(K, 10);
> U := VectorSpace(K, 5);
> mult := function(x)
>   M := Matrix(3, 3, Eltseq(x[1])[2..10]);
>   v := VectorSpace(K, 3)!(Eltseq(x[2])[[1,3,5]]);
>   return Eltseq(v*M) cat [0,0];
> end function;
> t := Tensor([V, U, U], mult);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 10 over GF(541)
U1 : Full Vector space of degree 5 over GF(541)
U0 : Full Vector space of degree 5 over GF(541)
```

Here, we want to construct a fully nondegenerate tensor. Of course, the tensor form the previous example is not fully nondegenerate as it is not degenerate, but we check that the image is not isomorphic to the codomain.

```magma
> IsFullyNondegenerate(t);
false
> Image(t);
Vector space of degree 5, dimension 3 over GF(541)
Generators:
(  1   0   0   0   0)
(  0   1   0   0   0)
(  0   0   1   0   0)
Echelonized basis:
(  1   0   0   0   0)
(  0   1   0   0   0)
(  0   0   1   0   0)
```

Now we will construct the associated fully nondegenerate tensor: $U_2/U_{\widehat{2}}^\perp\times U_1/U_{\widehat{1}}^\perp\rightarrowtail U_2*U_1$. Notice that the morphism between the original tensor and the fully nondegenerate tensor is a cohomotopism.

```magma
> s, H := FullyNondegenerateTensor(t);
> s;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 9 over GF(541)
U1 : Full Vector space of degree 3 over GF(541)
U0 : Vector space of degree 5, dimension 3 over GF(541)
Generators:
(  1   0   0   0   0)
(  0   1   0   0   0)
(  0   0   1   0   0)
Echelonized basis:
(  1   0   0   0   0)
(  0   1   0   0   0)
(  0   0   1   0   0)
> H;
Maps from U2 x U1 >-> U0 to V2 x V1 >-> V0.
U2 -> V2: Mapping from: Full Vector space of degree 10 over GF(541) to
Full Vector space of degree 9 over GF(541)
U1 -> V1: Mapping from: Full Vector space of degree 5 over GF(541) to
Full Vector space of degree 3 over GF(541)
U0 <- V0: Mapping from: Full Vector space of degree 5 over GF(541) to
Full Vector space of degree 5 over GF(541)
Composition of Mapping from: Full Vector space of degree 5 over GF(541)
to Full Vector space of degree 5 over GF(541) and
Mapping from: Vector space of degree 5, dimension 3 over GF(541) to Full
Vector space of degree 5 over GF(541)
```

<a id="function-isalternating-tenspcelt"></a>
###### `IsAlternating(T): TenSpcElt -> BoolElt`

Returns `true` if the tensor $T$ is an alternating tensor.

<a id="function-isantisymmetric-tenspcelt"></a>
###### `IsAntisymmetric(T): TenSpcElt -> BoolElt`

Returns `true` if the tensor $T$ is an antisymmetric tensor.

<a id="function-issymmetric-tenspcelt"></a>
###### `IsSymmetric(T): TenSpcElt -> BoolElt`

Returns `true` if the tensor $T$ is a symmetric tensor.

<a id="example-ex-6f9baa"></a>
###### `Example: Symmetric Form from a Ternary Cubic (ex-6f9baa)`

We will construct the multilinear form given by polarizing the homogeneous polynomial $f(x,y,z)=x^3+y^3+z^3+xyz$. Since $f$ is a symmetric polynomial, its multilinear form is also symmetric.

```magma
> K := Rationals();
> R<x,y,z> := PolynomialRing(K, 3);
> f := x^3 + y^3 + z^3 + x*y*z;
> t, p := Polarization(f);
> p;
6*$.1*$.4*$.7 + $.1*$.5*$.9 + $.1*$.6*$.8 + $.2*$.4*$.9 +
    6*$.2*$.5*$.8 + $.2*$.6*$.7 + $.3*$.4*$.8 + $.3*$.5*$.7 +
    6*$.3*$.6*$.9
> t;
Tensor of valence 4, U3 x U2 x U1 >-> U0
U3 : Full Vector space of degree 3 over Rational Field
U2 : Full Vector space of degree 3 over Rational Field
U1 : Full Vector space of degree 3 over Rational Field
U0 : Full Vector space of degree 1 over Rational Field
```

The resulting homogeneous polynomial from polarizing is

$$
p(x_1,x_2,x_3,y_1,y_2,y_3,z_1,z_2,z_3) =\sum_{\sigma\in S_3} (x_{1^\sigma}y_{2^\sigma}z_{3^\sigma} + 3x_{1^\sigma}y_{1^\sigma}z_{1^\sigma}).
$$

```magma
> IsSymmetric(t);
true
> AsMatrices(t, 3, 1) eq AsMatrices(t, 2, 1);
true
> AsMatrices(t, 3, 1) eq AsMatrices(t, 3, 2);
true
> AsMatrices(t, 3, 1);
[
    [6 0 0]
    [0 0 1]
    [0 1 0],

    [0 0 1]
    [0 6 0]
    [1 0 0],

    [0 1 0]
    [1 0 0]
    [0 0 6]
]
```

Because the underlying field is ${\mathbb{Q}}$ and because $t$ is symmetric, we know that $t$ is not alternating nor antisymmetric.

```magma
> IsAlternating(t);
false
> IsAntisymmetric(t);
false
```

##### Tensors As Multilinear Maps

Regarding tensors as multilinear maps makes it possible to define the operations of composition and evaluation for tensors.

<a id="operation-operation-tup-tenspcelt-any"></a>
###### `x @ T: Tup, TenSpcElt -> Any`

Evaluates the tensor $T$ at $x\in U_{\nu}\times \cdots \times U_1$. The entries can be elements from the vector space $U_i$ or sequences that Magma can naturally coerce into the vector space $U_i$. In some circumstances, tensors come from algebraic objects (e.g. algebras), and in these cases the entries of $x$ can be contained in the original algebraic object as well.

<a id="example-ex-be5d59"></a>
###### `Example: Evaluating the Jacobi Identity Tensor (ex-be5d59)`

Here we create the 4-tensor $\langle \,\rangle$ of an algebra $A$ given by the Jacobi identity:

$$
(x,y,z)\mapsto (xy)z + (yz)x + (zx)y.
$$

Therefore, the algebra satisfies the Jacobi identity if $\langle A, A, A \rangle = 0$. We will also change the tensor category so that all the coordinates are fused together.

```magma
> A := MatrixAlgebra(GF(3), 3);
> JacobiID := func< x | x[1]*x[2]*x[3]+x[2]*x[3]*x[1]+x[3]*x[1]*x[2] >;
> Cat := TensorCategory([1 : i in [0..3]], {{0..3}});
> t, maps := Tensor([A : i in [0..3]], JacobiID, Cat);
> t;
Tensor of valence 4, U3 x U2 x U1 >-> U0
U3 : Full Vector space of degree 9 over GF(3)
U2 : Full Vector space of degree 9 over GF(3)
U1 : Full Vector space of degree 9 over GF(3)
U0 : Full Vector space of degree 9 over GF(3)
> TensorCategory(t);
Tensor category of valence 4 (->,->,->,->) ({ 0 .. 3 })
```

Even though our tensor originated over the algebra $A=\rm{Mat}_{3}({\bf F}_{3})$, the returned tensor is over vector spaces ${\bf F}_{3}^9$. However, the tensor $t$ can still evaluate elements from $\rm{Mat}_3({\bf F}_{3})$ as well as ${\bf F}_{3}^9$. Observe that the out of $t$ will be a vector regardless of the input. The second output at construction, the `List` of maps, can be used to map the vectors to $\rm{Mat}_3({\bf F}_{3})$.

```magma
> x := <A.1, A.2, A.2^2>;
> x;
<
    [1 0 0]
    [0 0 0]
    [0 0 0],

    [0 1 0]
    [0 0 1]
    [1 0 0],

    [0 0 1]
    [1 0 0]
    [0 1 0]
>
> x @ t;
(2 0 0 0 1 0 0 0 0)
>
> phi := maps[1];
> x := <A.1 @ phi, A.2 @ phi, (A.2^2) @ phi>;
> x;
<(1 0 0 0 0 0 0 0 0), (0 1 0 0 0 1 1 0 0), (0 0 1 1 0 0 0 1 0)>
> x @ t;
(2 0 0 0 1 0 0 0 0)
```

Because `@` takes `Tup` as input, $t$ can evaluate mixed tuples as well: where some entries are contained in $\rm{Mat}_3({\bf F}_{3})$ and other entries are contained in ${\bf F}_{3}^9$.

```magma
> x := <A.1, A.2 @ phi, Eltseq(A.2^2)>;
> x;
<
    [1 0 0]
    [0 0 0]
    [0 0 0],

    (0 1 0 0 0 1 1 0 0),

    [ 0, 0, 1, 1, 0, 0, 0, 1, 0 ]
>
> <Type(i) : i in x>;
<AlgMatElt, ModTupFldElt, SeqEnum>
> x @ t;
(2 0 0 0 1 0 0 0 0)
```

<a id="operation-op-times-tenspcelt-map"></a>
###### `T * f: TenSpcElt, Map -> TenSpcElt`

<a id="operation-op-times-tenspcelt-tenspcelt"></a>
###### `t * s: TenSpcElt, TenSpcElt -> TenSpcElt`

The tensor formed by composing the tensor $T$ with the map $f$ is constructed. If a tensor $s$ is used instead of a `Map`, $s$ must have valence $\leq 1$.

<a id="operation-op-eq-tenspcelt-tenspcelt"></a>
###### `S eq T: TenSpcElt, TenSpcElt -> BoolElt`

Returns `true` if the tensors $S$ and $T$ are the same. Two tensors are equivalent if, and only if, they have the same tensor category, base ring, frame, and structure constants.

<a id="example-ex-0a17aa"></a>
###### `Example: Composing Tensors with Linear Maps (ex-0a17aa)`

We start with the same tensor as the previous example: the tensor given by the Jacobi identity on the algebra $A=\rm{Mat}_3({\bf F}_{3})$.

```magma
> A := MatrixAlgebra(GF(3), 3);
> JacobiID := func< x | x[1]*x[2]*x[3]+x[2]*x[3]*x[1]+x[3]*x[1]*x[2] >;
> Cat := TensorCategory([1 : i in [0..3]], {{0..3}});
> t, maps := Tensor([A : i in [0..3]], JacobiID, Cat);
> t;
Tensor of valence 4, U3 x U2 x U1 >-> U0
U3 : Full Vector space of degree 9 over GF(3)
U2 : Full Vector space of degree 9 over GF(3)
U1 : Full Vector space of degree 9 over GF(3)
U0 : Full Vector space of degree 9 over GF(3)
> TensorCategory(t);
Tensor category of valence 4 (->,->,->,->) ({ 0 .. 3 })
```

The maps in `Maps` are vector space isomorphisms and map $A$ to $V$. Suppose $\phi: A\rightarrow V$ is a vector space isomorphism. If we compose $t$ with $\phi^{-1}$, the returned tensor is *still* over vector spaces. The codomain is *not* $A$; this is because all tensors are over vector spaces. In fact, the returned tensor is exactly the same as $t$.

```magma
> phi := maps[1];
> t * (phi^-1);
Tensor of valence 4, U3 x U2 x U1 >-> U0
U3 : Full Vector space of degree 9 over GF(3)
U2 : Full Vector space of degree 9 over GF(3)
U1 : Full Vector space of degree 9 over GF(3)
U0 : Full Vector space of degree 9 over GF(3)
> t * (phi^-1) eq t;
true
```

Let ${\cal E}\subset A$ be an orthogonal frame—a set of primitive, orthogonal, idempotents. We will compose $t$ with the linear transformation

$$
a \mapsto \sum_{e\in{\cal E}} eae.
$$

Because the codomain of $t$ is a vector space, we will precompose this map by $\phi^{-1}$.

```magma
> E := [A.1, A.2^-1*A.1*A.2, A.2^-2*A.1*A.2^2];
> E;
[
    [1 0 0]
    [0 0 0]
    [0 0 0],

    [0 0 0]
    [0 1 0]
    [0 0 0],

    [0 0 0]
    [0 0 0]
    [0 0 1]
]
> f := map< A -> A | x :-> &+[ E[i]*x*E[i] : i in [1..3] ] >;
> f;
Mapping from: AlgMat: A to AlgMat: A given by a rule [no inverse]
> s := t*(phi^-1*f);
> s;
Tensor of valence 4, U3 x U2 x U1 >-> U0
U3 : Full Vector space of degree 9 over GF(3)
U2 : Full Vector space of degree 9 over GF(3)
U1 : Full Vector space of degree 9 over GF(3)
U0 : Full Vector space of degree 9 over GF(3)
> s eq t;
false
```

We can also wrap $f$ as a 2-tensor and compose it with $t$.

```magma
> g := Tensor([A, A], func< x | x[1]@f >);
> g;
Tensor of valence 2, U1 >-> U0
U1 : Full Vector space of degree 9 over GF(3)
U0 : Full Vector space of degree 9 over GF(3)
> t * g eq s;
true
```

##### Operations with Bilinear Maps

Tensors of valence $3$, also known as bilinear tensors, or as bilinear maps, are commonly described as distributive products. Examples include the product of two elements of an algebra, the action of a ring on a module, or an inner product. Magma supports these interpretations in two ways: by permitting an infix $x*t*y$ notation for a 3-tensor $t$, and a product $x*y$ notation for the evaluation of bilinear tensors. For the latter, this is achieved by creating special types `BmpU[Elt]`, `BmpV[Elt]`, and `BmpW[Elt]` for the terms of the frame of a bilinear tensor. For bilinear maps, we refer to the modules in the frame as $U\times V\rightarrowtail W$.

<a id="operation-op-times-any-tenspcelt"></a>
###### `x * T: Any, TenSpcElt -> Any`

<a id="operation-op-times-tenspcelt-any"></a>
###### `T * y: TenSpcElt, Any -> Any`

Given a bilinear tensor $T$ framed by $[U, V, W]$, $x*t$ returns the action on the right as a linear map $L : V\rightarrow W$ given by $vL = x* v$ if $x$ is an element of $U$. If $x$ is a subspace of $U$, then this returns a subspace of the tensor space $T$ with frame $V\rightarrowtail W$. For the left action use $T*y$ instead. If $T$ is valence 1, then the image of either $x$ or $y$ is returned. Therefore, the possible outputs are a tensor space `TenSpc`, a tensor `TenSpcElt`, or a vector `ModTupFld`.

Related to this intrinsic is the following: using tensor spaces with the infix notation.

<a id="operation-op-times-any-tenspc"></a>
###### `x * T: Any, TenSpc -> Any`

<a id="operation-op-times-tenspc-any"></a>
###### `T * y: TenSpc, Any -> Any`

Given a subspace of bilinear tensors, return the subspace generated by all $x*t$, for $t\in T$. This is either a tensor space or a vector space.

<a id="example-ex-4ade75"></a>
###### `Example: Infix Notation for Bilinear Maps (ex-4ade75)`

We demonstrate the infix notation by constructing the tensor in $A=\rm{Mat}_2({\mathbb{Q}})$ given by multiplication.

```magma
> A := MatrixAlgebra(Rationals(), 2);
> t := Tensor(A);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 4 over Rational Field
U1 : Full Vector space of degree 4 over Rational Field
U0 : Full Vector space of degree 4 over Rational Field
```

Like tensor evaluation, the infix notation will accept elements of a vector space (or objects that Magma can easily coerce into a vector space) or elements from the original algebraic object. We will use the infix notation to construct the 2-tensor $* : A\rightarrowtail A$, where $X\mapsto MX$, for some matrix $M$.

```magma
> M := A![0, 1, 0, 0];
> M;
[0 1]
[0 0]
> s := M*t;
> s;
Tensor of valence 2, U1 >-> U0
U1 : Full Vector space of degree 4 over Rational Field
U0 : Full Vector space of degree 4 over Rational Field
> AsMatrices(s, 1, 0);
[
    [0 0 0 0]
    [0 0 0 0]
    [1 0 0 0]
    [0 1 0 0]
]
```

From the structure constants above, evaluating `M*t` at `V.3` should output `W.1`. Furthermore, the image of `M*t` is 2-dimensional in $W$.

```magma
> M*t*[0, 0, 1, 0];
(1 0 0 0)
> M*t*VectorSpace(Rationals(), 4);
Vector space of degree 4, dimension 2 over Rational Field
Generators:
(1 0 0 0)
(0 1 0 0)
Echelonized basis:
(1 0 0 0)
(0 1 0 0)
```

If we switch the order and multiply $t$ by $U$ on the left first, we will get a tensor space $T$. Because that tensor space came from $t$, which originally came from algebraic objects, we can use the returned tensor space to evaluate $M$. An arbitrary tensor space, however, would not evaluate $M$ unless it is an appropriate vector.

```magma
> T := VectorSpace(Rationals(), 4)*t;
> T;
Tensor space of dimension 4 over Rational Field with valence 2
U1 : Full Vector space of degree 4 over Rational Field
U0 : Full Vector space of degree 4 over Rational Field
> T*M;
Vector space of degree 4, dimension 2 over Rational Field
Generators:
(0 1 0 0)
(0 0 0 1)
Echelonized basis:
(0 1 0 0)
(0 0 0 1)
```

The next style of notation we support is the product notation, $x*y$. In order to use this style, the user needs to coerce both $x$ and $y$ into the `LeftDomain` and `RightDomain` respectively.

<a id="operation-op-times-bmpuelt-bmpvelt"></a>
###### `x * y: BmpUElt, BmpVElt -> Any`

<a id="operation-op-times-bmpu-bmpv"></a>
###### `x * y: BmpU, BmpV -> Any`

<a id="operation-op-times-bmpuelt-bmpv"></a>
###### `x * y: BmpUElt, BmpV -> Any`

<a id="operation-op-times-bmpu-bmpvelt"></a>
###### `x * y: BmpU, BmpVElt -> Any`

If $x$ and $y$ are associated to the bilinear map $B$, these operations return `<x,y> @ B`.

<a id="function-leftdomain-tenspcelt"></a>
###### `LeftDomain(B): TenSpcElt -> BmpU`

The left domain $U$ of the bilinear map $B$ with frame $[U,V,W]$ is returned. This operation is used when enabling the use of infix notation.

<a id="function-rightdomain-tenspcelt"></a>
###### `RightDomain(B): TenSpcElt -> BmpV`

The right domain $U$ of the bilinear map $B$ with frame $[U,V,W]$ is returned. This operation is used when enabling the use of infix notation.

<a id="function-iscoercible-bmpu-any"></a>
###### `IsCoercible(U, x): BmpU, Any -> BoolElt, BmpUElt`

<a id="function-iscoercible-bmpv-any"></a>
###### `IsCoercible(V, x): BmpV, Any -> BoolElt, BmpVElt`

<a id="operation-op-bmpu-any"></a>
###### `U ! x: BmpU, Any -> BmpUElt`

<a id="operation-op-bmpv-any"></a>
###### `V ! x: BmpV, Any -> BmpVElt`

Returns `true` if $x$ can be coerced into the left domain (right domain) $U$ ($V$) of a bilinear map. If successful it returns the coerced element.

<a id="example-ex-90f3f7"></a>
###### `Example: Product Notation for Bilinear Maps (ex-90f3f7)`

We demonstrate the product notation for tensors of valence 3 using a tensor derived from a $p$-group. Suppose $G$ is a $p$-group and $[,] : U\times V\rightarrowtail W$ is the tensor given by commutation where $U=V=G/\eta_2$ and $W=\eta_2/\eta_3$, where $\eta_i$ denotes the $i$th term of the exponent-$p$ central series of $G$.

```magma
> G := SmallGroup(512, 10^6);
> t := pCentralTensor(G);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 5 over GF(2)
U1 : Full Vector space of degree 5 over GF(2)
U0 : Full Vector space of degree 4 over GF(2)
> U := LeftDomain(t);
> V := RightDomain(t);
> U;
Bimap space U: Full Vector space of degree 5 over GF(2)
> V;
Bimap space V: Full Vector space of degree 5 over GF(2)
```

Like with the other styles of notation (infix and tuple), users can evaluate elements from the original algebraic object, vectors from the vector spaces, and even sequences that Magma can easily coerce into vector spaces. To use the product notation, coerce elements into the `LeftDomain` and `RightDomain`.

```magma
> x := U!(G.1*G.2*G.4);
> y := V![1,0,0,0,0];
> x;
Bimap element of U: (1 1 0 1 0)
> y;
Bimap element of V: (1 0 0 0 0)
> x*y;
(1 0 0 1)
```

We can take this further and evaluate subspaces of $U$ or $V$.

```magma
> H := sub< G | G.2,G.4 >;
> U!H * V!G.1;
Vector space of degree 4, dimension 2 over GF(2)
Generators:
(0 0 0 1)
(1 0 0 0)
Echelonized basis:
(1 0 0 0)
(0 0 0 1)
> U!H * V;
Vector space of degree 4, dimension 3 over GF(2)
Generators:
(1 0 0 0)
(0 0 1 0)
(0 0 0 1)
(1 0 0 0)
(1 0 0 0)
Echelonized basis:
(1 0 0 0)
(0 0 1 0)
(0 0 0 1)
```

<a id="function-parent-bmpuelt"></a>
###### `Parent(x): BmpUElt -> BmpU`

<a id="function-parent-bmpvelt"></a>
###### `Parent(x): BmpVElt -> BmpV`

The parent space of the bilinear map element $x$ is returned.

<a id="function-parent-bmpu"></a>
###### `Parent(X): BmpU -> TenSpcElt`

<a id="function-parent-bmpv"></a>
###### `Parent(X): BmpV -> TenSpcElt`

The original bilinear map from which the space $X$ originated is returned.

<a id="operation-op-eq-bmpuelt-bmpuelt"></a>
###### `u1 eq u2: BmpUElt, BmpUElt -> BoolElt`

Returns `true` if the elements $u1$ and $u2$ from the left domain of a bilinear map are equal.

<a id="operation-op-eq-bmpuelt-bmpuelt-2"></a>
###### `v1 eq v2: BmpUElt, BmpUElt -> BoolElt`

Returns `true` if the elements $v1$ and $v2$ from the right domain of a bilinear map are equal.

<a id="operation-op-eq-bmpu-bmpu"></a>
###### `U1 eq U2: BmpU, BmpU -> BoolElt`

Returns `true` if the subspaces $U1$ and $U2$ of the left domain of a bilinear map are equal.

<a id="operation-op-eq-bmpv-bmpv"></a>
###### `V1 eq V2: BmpV, BmpV -> BoolElt`

Returns `true` if the subspaces $V1$ and $V2$ of the right domain of a bilinear map are equal.

<a id="example-ex-77d198"></a>
###### `Example: Domains of a Bilinear Map (ex-77d198)`

We will construct the same tensor as the previous example.

```magma
> G := SmallGroup(512, 10^6);
> t := pCentralTensor(G);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 5 over GF(2)
U1 : Full Vector space of degree 5 over GF(2)
U0 : Full Vector space of degree 4 over GF(2)
> U := LeftDomain(t);
> V := RightDomain(t);
> U;
Bimap space U: Full Vector space of degree 5 over GF(2)
> V;
Bimap space V: Full Vector space of degree 5 over GF(2)
```

The product notation has some basic functions for comparing objects and retrieving information.

```magma
> V!G.1 eq V![1,0,0,0,0];
true
> Parent(U);
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 5 over GF(2)
U1 : Full Vector space of degree 5 over GF(2)
U0 : Full Vector space of degree 4 over GF(2)
> Parent(U) eq t;
true
```

##### Manipulating Tensor Data

The data associated with a tensor can be accessed in different ways. In the case of tensors given by structure constants this access is the multidimensional analog of choosing a row or column of a matrix. Other operations are a generalization of the transpose of a matrix. Magma does these operations with a degree of efficiency, that is, it may not physically move the values in a structure constant sequence but instead permute the lookup coordinates of the values.

<a id="function-slice-tenspcelt-setenum"></a>
###### `Slice(T, grid): TenSpcElt, [SetEnum] -> SeqEnum`

<a id="function-inducedtensor-tenspcelt-setenum"></a>
###### `InducedTensor(T, grid): TenSpcElt, [SetEnum] -> TenSpcElt`

Returns the slice of the structure constants running through the given grid. For a tensor $T$ framed by free modules $[U_{\nu},\dots,U_0]$ with $d_i=\dim U_i$, a *grid* is a sequence $[G_{\nu},\dots,G_0]$ of subsets $G_i\subseteq \{1,\dots, d_i\}\cup \{-d_i,\dots, -1\}$. If an entry $g\in G_i$ is negative, it will be taken to mean $d_i+g+1$, so $-1$ would be equivalent to $d_i$. The slice is the list of entries in the structure constants of the tensor indexed by $G_{\nu}\times \cdots \times G_0$. The intrinsic `Slice` returns the structure constants whereas `InducedTensor` produces a tensor with these structure constants.

<a id="example-ex-ff7268"></a>
###### `Example: Slicing a Tensor (ex-ff7268)`

We will construct a tensor $*: {\mathbb{Q}}^4\times {\mathbb{Q}}^3\rightarrowtail {\mathbb{Q}}^2$ with a structure constants sequence equal to $[1,\dots,24]$. If every $G_i=\{1,\dots, d_i\}$, then the result is the same as `Eltseq`.

```magma
> U := VectorSpace(Rationals(),4);
> V := VectorSpace(Rationals(),3);
> W := VectorSpace(Rationals(),2);
> T := TensorSpace([U, V, W]);
> t := T![1..24];
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 4 over Rational Field
U1 : Full Vector space of degree 3 over Rational Field
U0 : Full Vector space of degree 2 over Rational Field
> Slice(t, [{1..4},{1..3},{1..2}]) eq Eltseq(t);
true
```

Now we will slice with the following grid $[\{1,\dots,4\}, \{2\}, \{1\}]$. Compare this with the product $U*v_2$.

```magma
> [ U.i*t*V.2 : i in [1..4]];
[
    (3 4),
    ( 9 10),
    (15 16),
    (21 22)
]
> Slice(t, [{1..4},{2},{1}]);
[ 3, 9, 15, 21 ]
```

If, instead, we slice $W$ at its last basis vector, we get the following.

```magma
> Slice(t, [{1..4},{2},{-1}]);
[ 4, 10, 16, 22 ]
```

Notice that if we use $-1$ and $2$ in the last set of the grid we get the same output we got above.

```magma
> Slice(t, [{1..4},{2},{-1,2}]);
[ 4, 10, 16, 22 ]
```

Now we will compare `Slice` and `InducedTensor`. `InducedTensor` is basically a `Tensor` wrapping the `Slice` function.

```magma
> s := InducedTensor(t, [{1..4}, {2}, {1,2}]);
> s;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 4 over Rational Field
U1 : Full Vector space of degree 1 over Rational Field
U0 : Full Vector space of degree 2 over Rational Field
> s2 := Tensor([4, 1, 2], Slice(t, [{1..4}, {2}, {1,2}]));
> s2;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 4 over Rational Field
U1 : Full Vector space of degree 1 over Rational Field
U0 : Full Vector space of degree 2 over Rational Field
>
> s eq s2;
true
> Eltseq(s);
[ 3, 4, 9, 10, 15, 16, 21, 22 ]
```

<a id="function-sliceasmatrices-tenspcelt-setenum-rngintelt-rngintelt"></a>
###### `SliceAsMatrices(T, grid, a, b): TenSpcElt, [SetEnum], RngIntElt, RngIntElt -> SeqEnum`

Given a tensor $T$, a set and integers $a$ and $b$, returns a sequence of matrices whose output is equivalent to composing `InducedTensor` and `AsMatrices`. This intrinsic will be slightly faster than actually composing those two functions together as a tensor is not constructed with `SliceAsMatrices`.

<a id="example-ex-436f03"></a>
###### `Example: Slices as Matrices (ex-436f03)`

We will create the same tensor as the previous example.

```magma
> t := Tensor(Rationals(), [4,3,2], [1..24]);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 4 over Rational Field
U1 : Full Vector space of degree 3 over Rational Field
U0 : Full Vector space of degree 2 over Rational Field
> AsMatrices(t, 1, 0);
[
    [1 2]
    [3 4]
    [5 6],

    [ 7  8]
    [ 9 10]
    [11 12],

    [13 14]
    [15 16]
    [17 18],

    [19 20]
    [21 22]
    [23 24]
]
```

Now we will slice up this sequence of matrices. We will remove the second row and the second and third matrix from the sequence above.

```magma
> SliceAsMatrices(t, [{1,-1}, {1,-1}, {1,2}], 1, 0);
[
    [1 2]
    [5 6],

    [19 20]
    [23 24]
]
```

<a id="function-foliation-tenspcelt-rngintelt"></a>
###### `Foliation(T, i): TenSpcElt, RngIntElt -> Mtrx`

If $T$ is a tensor with frame $\hom(U_{\nu}\otimes \cdots \otimes U_1,U_0)$, and $i$ is the index of some term of the frame of $T$, this intrinsic returns the matrix representing the linear map $U_i\rightarrow \hom(\bigotimes_{j\ne i}U_i,U_0)$ using the bases of each $U_j$. If $i=0$, then the returned matrix is given by the representation $U_0^*\rightarrow \hom(\bigotimes U_i,K)$.

<a id="example-ex-c6ce4b"></a>
###### `Example: Exfoliating and Foliating a Tensor (ex-c6ce4b)`

We will, again, construct the same tensor, $*:{\mathbb{Q}}^4\times{\mathbb{Q}}^3\rightarrowtail {\mathbb{Q}}^2$, from the previous two examples whose structure constants sequence is $[1,\dots,24]$.

```magma
> K := Rationals();
> Forms := [Matrix(K, 3, 2, [6*i+1..6*(i+1)]) : i in [0..3]];
> t := Tensor(Forms, 1, 0);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 4 over Rational Field
U1 : Full Vector space of degree 3 over Rational Field
U0 : Full Vector space of degree 2 over Rational Field
```

We will use `Foliation` to compute the 2-radical of $t$. (This is essentially what `Radical` does in Magma.) That is, we will compute the subspace $U_{\hat{2}}^\perp\leq {\mathbb{Q}}^4$ such that $U_{\hat{2}}^\perp*{\mathbb{Q}}^3=0$. This computation can be regarded as a nullspace computation.

```magma
> F2 := Foliation(t, 2);
> F2;
[ 1  2  3  4  5  6]
[ 7  8  9 10 11 12]
[13 14 15 16 17 18]
[19 20 21 22 23 24]
> R := Nullspace(F2);
> R;
Vector space of degree 4, dimension 2 over Rational Field
Echelonized basis:
( 1  0 -3  2)
( 0  1 -2  1)
```

We claim this is the 2-radical of $t$. Our claim is verified if `R*t` is a 0-dimensional subspace of the tensor space $T$ with frame ${\mathbb{Q}}^3\rightarrowtail{\mathbb{Q}}^2$. In other words, `R*t` is the trivial 2-tensor.

```magma
> R*t;
Tensor space of dimension 0 over Rational Field with valence 2
U1 : Full Vector space of degree 3 over Rational Field
U0 : Full Vector space of degree 2 over Rational Field
> Dimension(R*t);
0
```

<a id="function-astensorspace-tenspcelt-rngintelt"></a>
###### `AsTensorSpace(T, i): TenSpcElt, RngIntElt -> TenSpc, Mtrx`

If $T$ is a tensor contained in $\hom(U_v\otimes \cdots \otimes U_1,U_0)$, and $i$ is the index of some term of the frame of $T$, this intrinsic returns the associated tensor space of $T$ at $i>0$ together with a matrix given by the foliation of $T$ at $i$. The returned tensor space is framed by $U_v\times \cdots \times U_{i+1}\times U_{i-1}\times \cdots \times U_1\rightarrowtail U_0$ and is generated by the tensors $T_u$ for each $u$ in the basis of $U_i$. For $i=0$, use `AsCotensorSpace`.

<a id="function-ascotensorspace-tenspcelt"></a>
###### `AsCotensorSpace(T): TenSpcElt -> TenSpc, Mtrx`

Given a tensor $T$, this intrinsic returns the associated cotensor space of $T$ together with a matrix given by the foliation of $T$ at $0$. The returned cotensor space has frame $U_{\nu}\times \cdots \times U_1\rightarrowtail K$ and is generated by the tensors $T_f$ for each $f$ in the basis of $U_0^*$. In the case that $T$ is a bilinear map, this is equivalent to the cotensor space generated by the `SystemOfForms`.

<a id="example-ex-8523ef"></a>
###### `Example: Tensor Space at a Coordinate (ex-8523ef)`

We begin by creating a 4-tensor and constructing the associated tensor space at the third coordinate. `AsCotensorSpace` works similarly but when $a=0$.

```magma
> t := Tensor(Rationals(), [5,4,3,2], [1..120]);
> t;
Tensor of valence 4, U3 x U2 x U1 >-> U0
U3 : Full Vector space of degree 5 over Rational Field
U2 : Full Vector space of degree 4 over Rational Field
U1 : Full Vector space of degree 3 over Rational Field
U0 : Full Vector space of degree 2 over Rational Field
> T := AsTensorSpace(t, 3);
> T;
Tensor space of dimension 2 over Rational Field with valence 3
U2 : Full Vector space of degree 4 over Rational Field
U1 : Full Vector space of degree 3 over Rational Field
U0 : Full Vector space of degree 2 over Rational Field
```

The dimension of $T$ cannot be larger than 5 because that is the dimension of $U_3$. However, $T$ is 2-dimensional. Slicing $t$ as a sequence of matrices will illuminate why $T$ is 2-dimensional.

```magma
> F := [SliceAsMatrices(t, [{k},{1..4},{1..3},{1,2}], 2, 1) :
>     k in [1..5]];
```

Here, $F$ is a sequence of a system of forms for $t$, one for each basis vector in $U_3$. If $T$ were 5-dimensional, the systems of forms in $F$ would be linearly independent. However, it is not, and evidently, three of the five systems of forms are linear combinations two systems of forms. We will determine the linear combinations. The first two systems of forms are independent.

```magma
> F[1];
[
    [ 1  3  5]
    [ 7  9 11]
    [13 15 17]
    [19 21 23],

    [ 2  4  6]
    [ 8 10 12]
    [14 16 18]
    [20 22 24]
]
> F[2];
[
    [25 27 29]
    [31 33 35]
    [37 39 41]
    [43 45 47],

    [26 28 30]
    [32 34 36]
    [38 40 42]
    [44 46 48]
]
```

So `F[3]` is `2*F[2]-F[1]`, and the rest of the linear combinations are filled in.

```magma
> F[3];
[
    [49 51 53]
    [55 57 59]
    [61 63 65]
    [67 69 71],

    [50 52 54]
    [56 58 60]
    [62 64 66]
    [68 70 72]
]
> Tensor(F[3], 2, 1) eq 2*Tensor(F[2], 2, 1) - Tensor(F[1], 2, 1);
true
> Tensor(F[4], 2, 1) eq 3*Tensor(F[2], 2, 1) - 2*Tensor(F[1], 2, 1);
true
> Tensor(F[5], 2, 1) eq 4*Tensor(F[2], 2, 1) - 3*Tensor(F[1], 2, 1);
true
```

So, indeed, $T$ is the tensor space generated by the tensors in `F`. Note that the dimension of the 3-radical of $t$ is 3.

```magma
> SystemOfForms(T.1) eq F[1];
true
> SystemOfForms(T.2) eq F[2];
true
> Radical(t, 3);
Vector space of degree 5, dimension 3 over Rational Field
Echelonized basis:
( 1  0  0 -4  3)
( 0  1  0 -3  2)
( 0  0  1 -2  1)

[ 0  0  0  0  1]
[ 0  0  0  1  0]
[ 0  0  1 -2  1]
[ 0  1  0 -3  2]
[ 1  0  0 -4  3]
```

<a id="function-astensor-tenspc"></a>
###### `AsTensor(S): TenSpc -> TenSpcElt`

Given a tensor space $S$, this intrinsic returns a tensor belonging to $S$. If $S$ is contravariant, then the returned tensor has the frame $U_{\nu}\times \cdots \times U_1\rightarrowtail S$, where $S$ is thought of as a free $K$-module.. If $S$ is covariant, then the returned tensor has the frame $S\times U_{\nu}\times \cdots \times U_1\rightarrowtail U_0$. Note that `AsTensor` is “inverse” to `AsCotensorSpace` and `AsTensorSpace` when $i={\nu}$.

<a id="example-ex-a38c03"></a>
###### `Example: Recovering a Tensor from Its Tensor Space (ex-a38c03)`

We will construct the same tensor as the previous example and turn it into a tensor space at the third coordinate.

```magma
> t := Tensor(Rationals(), [5,4,3,2], [1..120]);
> t;
Tensor of valence 4, U3 x U2 x U1 >-> U0
U3 : Full Vector space of degree 5 over Rational Field
U2 : Full Vector space of degree 4 over Rational Field
U1 : Full Vector space of degree 3 over Rational Field
U0 : Full Vector space of degree 2 over Rational Field
> T := AsTensorSpace(t, 3);
> T;
Tensor space of dimension 2 over Rational Field with valence 3
U2 : Full Vector space of degree 4 over Rational Field
U1 : Full Vector space of degree 3 over Rational Field
U0 : Full Vector space of degree 2 over Rational Field
```

Now we are going to “recover” $t$ by creating a tensor from $T$. However, it is not equal to $t$ because the 3-radical of the new tensor is trivial.

```magma
> s := AsTensor(T);
> s;
Tensor of valence 4, U3 x U2 x U1 >-> U0
U3 : Full Vector space of degree 2 over Rational Field
U2 : Full Vector space of degree 4 over Rational Field
U1 : Full Vector space of degree 3 over Rational Field
U0 : Full Vector space of degree 2 over Rational Field
> Radical(s, 3);
Vector space of degree 2, dimension 0 over Rational Field

[0 1]
[1 0]
```

We can even see the same sequences of matrices in $s$.

```magma
> AsMatrices(s, 2, 1);
[
    [ 1  3  5]
    [ 7  9 11]
    [13 15 17]
    [19 21 23],

    [ 2  4  6]
    [ 8 10 12]
    [14 16 18]
    [20 22 24],

    [25 27 29]
    [31 33 35]
    [37 39 41]
    [43 45 47],

    [26 28 30]
    [32 34 36]
    [38 40 42]
    [44 46 48]
]
```

#### Invariants of Tensors

In this subsection, we detail functions to construct invariants of tensors. To access the projections or the objects acting on a specific factor $U_i$, the following function(s) should be used.

<a id="function-induce-algmat-rngintelt"></a>
##### `Induce(X, i): AlgMat, RngIntElt -> Map, AlgMat`

<a id="function-induce-algmatlie-rngintelt"></a>
##### `Induce(X, i): AlgMatLie, RngIntElt -> Map, AlgMatLie`

<a id="function-induce-grpmat-rngintelt"></a>
##### `Induce(X, i): GrpMat, RngIntElt -> Map, GrpMat`

Returns the projection from the given object to the induced sub-object on the $i$th coordinate and the induced sub-object of the associated tensor.

<a id="example-ex-4be7ac"></a>
##### `Example: Inducing Derivations of a Symplectic Form (ex-4be7ac)`

To demonstrate how to `Induce`, we construct the 2-dimensional symplectic form on $K =$ GF$(3)$.

```magma
> t := Tensor(GF(3), [2, 2, 1], [0, 1, 2, 0]);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 2 over GF(3)
U1 : Full Vector space of degree 2 over GF(3)
U0 : Full Vector space of degree 1 over GF(3)
> IsAlternating(t);
true
```

This tensor has a nontrivial derivation algebra, isomorphic to $K^2\oplus \rm{SL}_2(3)$. However, $\rm{Der}(t)$ is represented in $\rm{End}(U_2)\times\rm{End}(U_1)\times \rm{End}(U_0)$. We will induce the action on the $1$st coordinate.

```magma
> D := DerivationAlgebra(t);
> D.1;
[1 0 0 0 0]
[0 1 0 0 0]
[0 0 1 0 0]
[0 0 0 1 0]
[0 0 0 0 2]
> D.2;
[1 0 0 0 0]
[2 0 0 0 0]
[0 0 2 0 0]
[0 0 2 1 0]
[0 0 0 0 2]
> pi, D1 := Induce(D, 1);
> D1;
Matrix Lie Algebra of degree 2 over Finite field of size 3
> pi;
Mapping from: AlgMatLie: D to AlgMatLie: D1 given by a rule [no inverse]
```

Now we can see that have the action of $D$ on $U_1$.

```magma
> D1.1;
[1 0]
[0 1]
> D1.2;
[2 0]
[2 1]
```

We include a partner intrinsic to `Include` and that is the following procedure.

<a id="procedure-derivedfrom-any-tenspcelt-rngintelt-rngintelt-ref"></a>
##### `DerivedFrom(~X, t, C, RC : parameters): Any, TenSpcElt, {RngIntElt}, {RngIntElt}`

```magma
Fused: BoolElt                    Default: true
```

Includes the following tensor data in the matrix object $X$: the tensor $t$, the relevant coordinates which are in the set $C\subseteq \{0,\dots,\nu\}$, and the coordinates $RC\subseteq C$ for which the object is represented on. The reason for the subset $C$ is so that we know the coordinates which can be induced on, see `Induce`. Currently, this only works for objects of type `AlgMat`, `AlgMatLie`, `GrpMat`, and `ModMatFld`. It is assumed that $X$ is block diagonal, whose blocks starting from the top left go in decreasing order in the coordinates—in the same way the coordinates of the frame decrease from left to right for a tensor.

##### Standard Invariants

We integrate the invariant theory associated to bilinear and multilinear maps into the realm of tensors.

<a id="function-radical-tenspcelt-rngintelt"></a>
###### `Radical(T, s): TenSpcElt, RngIntElt -> ModTupRng`

Returns the $s$th-radical of $T$ as a subspace of $U_s$ and a matrix that splits the radical in $V_s$. This is the subspace

$$
U_{\bar{s}}^\perp = \left\{ u_s \in U_s : \forall \left| u_{\bar{s}}\right\rangle,\; \left\langle T | u\right\rangle =0\right\}.
$$

<a id="function-radical-tenspcelt"></a>
###### `Radical(T): TenSpcElt -> Tup`

Returns the tuple of all the $s$-radicals for each $s\in \{1,\dots,\nu\}$.

<a id="function-coradical-tenspcelt"></a>
###### `Coradical(T): TenSpcElt -> ModTupRng, Map`

Returns the coradical of $T$ and a surjection from the codomain to the coradical. This is the quotient $U_0 / \langle T | U_{\nu}, \dots, U_1\rangle$.

<a id="example-ex-fef917"></a>
###### `Example: Radicals of the Commutator Tensor (ex-fef917)`

We will construct the tensor for multiplication in $\rm{GL}_3({\mathbb{Q}})$, or equivalently, the commutator tensor of $\rm{Mat}_3({\mathbb{Q}})$. Because $\rm{GL}_3({\mathbb{Q}})$ contains the center of $\rm{Mat}_3({\mathbb{Q}})$, there will be a 2- and 1-radical.

```magma
> K := Rationals();
> A := MatrixAlgebra(K, 3);
> t, phi := CommutatorTensor(A);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 9 over Rational Field
U1 : Full Vector space of degree 9 over Rational Field
U0 : Full Vector space of degree 9 over Rational Field
>
> R2 := Radical(t, 2);
> R2.1 @@ phi;
[1 0 0]
[0 1 0]
[0 0 1]
> Radical(t);
<
    Vector space of degree 9, dimension 1 over Rational Field
    Echelonized basis:
    (1 0 0 0 1 0 0 0 1),

    Vector space of degree 9, dimension 1 over Rational Field
    Echelonized basis:
    (1 0 0 0 1 0 0 0 1)
>
```

Similarly, the image of $t$ will be 8-dimensional in ${\mathbb{Q}}^9$, so the coradical is ${\mathbb{Q}}$.

```magma
> Image(t);
Vector space of degree 9, dimension 8 over Rational Field
Generators:
( 1  0  0  0  0  0  0  0 -1)
( 0  1  0  0  0  0  0  0  0)
( 0  0  1  0  0  0  0  0  0)
( 0  0  0  1  0  0  0  0  0)
( 0  0  0  0  1  0  0  0 -1)
( 0  0  0  0  0  1  0  0  0)
( 0  0  0  0  0  0  1  0  0)
( 0  0  0  0  0  0  0  1  0)
Echelonized basis:
( 1  0  0  0  0  0  0  0 -1)
( 0  1  0  0  0  0  0  0  0)
( 0  0  1  0  0  0  0  0  0)
( 0  0  0  1  0  0  0  0  0)
( 0  0  0  0  1  0  0  0 -1)
( 0  0  0  0  0  1  0  0  0)
( 0  0  0  0  0  0  1  0  0)
( 0  0  0  0  0  0  0  1  0)
> Coradical(t);
Full Vector space of degree 1 over Rational Field
Mapping from: Full Vector space of degree 9 over Rational Field to Full
Vector space of degree 1 over Rational Field
```

We include some well-known polynomial invariants for bilinear maps.

<a id="function-discriminant-tenspcelt"></a>
###### `Discriminant(B): TenSpcElt -> RngMPolElt`

Returns the discriminant of the bilinear map.

<a id="example-ex-8de961"></a>
###### `Example: Discriminant of the Octonions (ex-8de961)`

We will compute the discriminant of the tensor $\cdot : O \times O \rightarrowtail O$. The discriminant of this tensor is homogeneous of degree 8 with 330 terms.

```magma
> A := OctonionAlgebra(GF(7), -1, -1, -1);
> t := Tensor(A);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 8 over GF(7)
U1 : Full Vector space of degree 8 over GF(7)
U0 : Full Vector space of degree 8 over GF(7)
> R<a,b,c,d,e,f,g,h> := PolynomialRing(GF(7), 8);
> disc := R!Discriminant(t);
> Degree(disc);
8
> IsHomogeneous(disc);
true
> #Terms(disc);
330
```

However, if we factor the discriminant, then we can see that ${\tt disc} = \left(x_1^2 + \cdots x_8^2\right)^4$.

```magma
> Factorization(disc);
[
    <a^2 + b^2 + c^2 + d^2 + e^2 + f^2 + g^2 + h^2, 4>
]
```

<a id="function-pfaffian-tenspcelt"></a>
###### `Pfaffian(B): TenSpcElt -> RngMPolElt`

Returns the Pfaffian of the antisymmetric bilinear map.

<a id="example-ex-4cc2d2"></a>
###### `Example: Pfaffians of Genus 2 Groups (ex-4cc2d2)`

In this demonstration, we pull from [[BMW17](https://docs.magma-maths.org/references.md#cite-bmw-genus2)]. A $p$-group $G$ has genus 2, if the image of the exponent-$p$ central tensor of $G$ is 2-dimensional over the centroid. One of the algorithms in [[BMW17](https://docs.magma-maths.org/references.md#cite-bmw-genus2)] to decide isomorphism of such groups depends on the Pfaffian of the tensor.

First, we create two $3$-groups with genus 2. The first group we create as a quotient of the Sylow 3-subgroup of $\rm{GL}(3,\rm{GF}(3^5))$.

```magma
> P := ClassicalSylow(GL(3, 3^5), 3);
> P := PCPresentation(UnipotentMatrixGroup(P));
> Z := Center(P);
> N := sub< Z | [Random(Z) : i in [1..3]] >;
> G := P/N;
```

The second group we create will be a quotient of the Sylow 3-subgroup of the of $\rm{GL}(3, \rm{GF}(9))\times\rm{GL}(3, \rm{GF}(27))$.

```magma
> A := ClassicalSylow(GL(3, 9), 3);
> B := ClassicalSylow(GL(3, 27), 3);
> A := PCPresentation(UnipotentMatrixGroup(A));
> B := PCPresentation(UnipotentMatrixGroup(B));
> Q, inc := DirectProduct(A, B);
> ZA := Center(A);
> ZB := Center(B);
> gens := [(ZA.i@inc[1])*(ZB.i@inc[2])^-1 : i in [1..2]]
>     cat [ZB.3@inc[2]];
> M := sub< Q | gens >;
> H := Q/M;
```

Now we will construct the exponent-$p$ central tensors of $G$ and $H$. From the way we have created the groups, $G\cong H$ if, and only if, their tensors are pseudo-isometric.

```magma
> t := pCentralTensor(G);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 10 over GF(3)
U1 : Full Vector space of degree 10 over GF(3)
U0 : Full Vector space of degree 2 over GF(3)
>
> s := pCentralTensor(H);
> s;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 10 over GF(3)
U1 : Full Vector space of degree 10 over GF(3)
U0 : Full Vector space of degree 2 over GF(3)
```

An implication of the main algorithm in [[BMW17](https://docs.magma-maths.org/references.md#cite-bmw-genus2)] is that if the splitting behavior of the Pfaffians are different, then the groups are not isomorphic. Therefore, because the Pfaffian of $G$ has a different splitting behavior from the Pfaffian of $H$, we conclude that $G\not\cong H$.

```magma
> R<x,y> := PolynomialRing(GF(3), 2);
> f := R!Pfaffian(t);
> g := R!Pfaffian(s);
> f;
x^5 + x^3*y^2 + 2*x^2*y^3 + 2*x*y^4 + y^5
> g;
x^5 + 2*x^4*y + x^3*y^2 + 2*x^2*y^3 + x*y^4 + y^5
> Factorization(f), Factorization(g);
[
    <x^5 + x^3*y^2 + 2*x^2*y^3 + 2*x*y^4 + y^5, 1>
]
[
    <x^2 + x*y + 2*y^2, 1>,
    <x^3 + x^2*y + x*y^2 + 2*y^3, 1>
]
```

#### Exporting Tensors

In the previous sections, we used groups, rings, and algebras to define tensors, but tensors can be used to define algebraic structures as well. In this section, we describe ways to build groups and algebras from tensors. Currently, all intrinsics in this section only support 3-tensors.

<a id="function-heisenbergalgebra-tenspcelt"></a>
##### `HeisenbergAlgebra(T): TenSpcElt -> AlgGen`

Returns the Heisenberg algebra $A$ induced by the bilinear tensor $T: U\times V\rightarrowtail W$. The algebra $A$ depends on the tensor category of $T$. If the tensor category forces equality between $U$, $V$, and $W$, then $A\cong U$ as vector spaces and is a nonassociative algebra (i.e. not necessarily associative). If the tensor category forces equality between $U$ and $V$, then $A\cong U\oplus W$ as vector spaces and is a nilpotent algebra where $C(A)\geq W$ and $A^2\leq W$. Otherwise, $A\cong U\oplus V\oplus W$ as vector spaces, and using $*$ for $T$,

$$
(u,v,w)\cdot (u',v',w') = (0,0,u*v').
$$

<a id="example-ex-182a22"></a>
##### `Example: Heisenberg Algebras from Tensors (ex-182a22)`

We will demonstrate some of the nuances of `HeisenbergAlgebra` and how it interacts with the tensor category of the given tensor. We will use the same tensor throughout but changing the categories. The frame of the tensor is ${\mathbb{Q}}^3\times{\mathbb{Q}}^3\rightarrowtail{\mathbb{Q}}^3$.

```magma
> t := Tensor(Rationals(), [3, 3, 3], [i : i in [1..27]]);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 3 over Rational Field
U1 : Full Vector space of degree 3 over Rational Field
U0 : Full Vector space of degree 3 over Rational Field
> SystemOfForms(t);
[
    [ 1  4  7]
    [10 13 16]
    [19 22 25],

    [ 2  5  8]
    [11 14 17]
    [20 23 26],

    [ 3  6  9]
    [12 15 18]
    [21 24 27]
]
> Radical(t);
<
    Vector space of degree 3, dimension 1 over Rational Field
    Echelonized basis:
    ( 1 -2  1),

    Vector space of degree 3, dimension 1 over Rational Field
    Echelonized basis:
    ( 1 -2  1)
>
> Image(t);
Vector space of degree 3, dimension 2 over Rational Field
Generators:
( 1  0 -1)
( 0  1  2)
Echelonized basis:
( 1  0 -1)
( 0  1  2)
```

The default tensor category of $t$ above is the homotopism category where none of the modules are fused together. Therefore, if we construct the Heisenberg algebra of $t$, the resulting algebra will be 9-dimensional. Looking at the system of forms, the first 6 matrices will be zero, and the last 3 matrices will contain the above system of forms as a $3\times 3$ block, starting at the $(1,4)$ entry.

```magma
> A := HeisenbergAlgebra(t);
> A;
Algebra of dimension 9 with base ring Rational Field
> Center(A);
Algebra of dimension 5 with base ring Rational Field
> SystemOfForms(Tensor(A))[7..9];
[
    [ 0  0  0  1  4  7  0  0  0]
    [ 0  0  0 10 13 16  0  0  0]
    [ 0  0  0 19 22 25  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  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  0  0  0],

    [ 0  0  0  2  5  8  0  0  0]
    [ 0  0  0 11 14 17  0  0  0]
    [ 0  0  0 20 23 26  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  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  0  0  0],

    [ 0  0  0  3  6  9  0  0  0]
    [ 0  0  0 12 15 18  0  0  0]
    [ 0  0  0 21 24 27  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  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  0  0  0]
]
```

Now we will fuse $U$ and $V$ together with a new category. The resulting algebra will then be 6-dimensional. We will also look at the system of forms of $A$ to see the structure constants of $A$.

```magma
> NilCat := TensorCategory([1, 1, 1], {{2,1},{0}});
> NilCat;
Tensor category of valence 3 (->,->,->) ({ 0 },{ 1, 2 })
> ChangeTensorCategory(~t, NilCat);
> A := HeisenbergAlgebra(t);
> A;
Algebra of dimension 6 with base ring Rational Field
> Center(A);
Algebra of dimension 4 with base ring Rational Field
> A^2;
Algebra of dimension 2 with base ring Rational Field
> SystemOfForms(Tensor(A))[4..6];
[
    [ 1  4  7  0  0  0]
    [10 13 16  0  0  0]
    [19 22 25  0  0  0]
    [ 0  0  0  0  0  0]
    [ 0  0  0  0  0  0]
    [ 0  0  0  0  0  0],

    [ 2  5  8  0  0  0]
    [11 14 17  0  0  0]
    [20 23 26  0  0  0]
    [ 0  0  0  0  0  0]
    [ 0  0  0  0  0  0]
    [ 0  0  0  0  0  0],

    [ 3  6  9  0  0  0]
    [12 15 18  0  0  0]
    [21 24 27  0  0  0]
    [ 0  0  0  0  0  0]
    [ 0  0  0  0  0  0]
    [ 0  0  0  0  0  0]
]
```

Finally, we will put a tensor category on $t$ where $U$, $V$, and $W$ are all fused together. The Heisenberg algebra from this tensor is 3-dimensional, and the product is exactly the tensor $t$.

```magma
> AlgCat := TensorCategory([1, 1, 1], {{2,1,0}});
> AlgCat;
Tensor category of valence 3 (->,->,->) ({ 0, 1, 2 })
> ChangeTensorCategory(~t, AlgCat);
> A := HeisenbergAlgebra(t);
> A;
Algebra of dimension 3 with base ring Rational Field
> SystemOfForms(Tensor(A));
[
    [ 1  4  7]
    [10 13 16]
    [19 22 25],

    [ 2  5  8]
    [11 14 17]
    [20 23 26],

    [ 3  6  9]
    [12 15 18]
    [21 24 27]
]
```

<a id="function-heisenbergliealgebra-tenspcelt"></a>
##### `HeisenbergLieAlgebra(T): TenSpcElt -> AlgLie`

Returns the Heisenberg Lie algebra $L$ with Lie bracket given by the 3-tensor $T:U\times V\rightarrowtail W$. If the tensor category of $T$ forces equality only between $U$ and $V$ and $T$ is alternating, then the Heisenberg Lie algebra will have structure constants equal to $T$. In this case, $L\cong U\oplus W$ as vector spaces. Otherwise, $L\cong U\oplus V\oplus W$ as vector spaces, and, using $*$ in place for $T$, the product in $L$ is given by

$$
(u,v,w) * (u',v',w') = (0,0,uv'-u'v).
$$

<a id="example-ex-19a3f6"></a>
##### `Example: Lie Algebras from Tensors (ex-19a3f6)`

We will construct an alternating tensor with frame ${\mathbb{Q}}^3\times{\mathbb{Q}}^3\rightarrowtail {\mathbb{Q}}^2$.

```magma
> t := Tensor(Rationals(), [3, 3, 2], &cat[[1,-1,0] : i in [1..6]]);
> t := AlternatingTensor(t);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 3 over Rational Field
U1 : Full Vector space of degree 3 over Rational Field
U0 : Full Vector space of degree 2 over Rational Field
> SystemOfForms(t);
[
    [ 0 -1 -2]
    [ 1  0 -1]
    [ 2  1  0],

    [ 0  2  1]
    [-2  0 -1]
    [-1  1  0]
]
```

First, we will just construct the Heisenberg Lie algebra from $t$ as is. Because the tensor category of $t$ does not fuse together $U$, $V$, and $W$, the Lie algebra will be 8-dimensional.

```magma
> L := HeisenbergLieAlgebra(t);
> L;
Lie Algebra of dimension 8 with base ring Rational Field
> SystemOfForms(Tensor(L))[7..8];
[
    [ 0  0  0  0 -1 -2  0  0]
    [ 0  0  0  1  0 -1  0  0]
    [ 0  0  0  2  1  0  0  0]
    [ 0 -1 -2  0  0  0  0  0]
    [ 1  0 -1  0  0  0  0  0]
    [ 2  1  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  2  1  0  0]
    [ 0  0  0 -2  0 -1  0  0]
    [ 0  0  0 -1  1  0  0  0]
    [ 0  2  1  0  0  0  0  0]
    [-2  0 -1  0  0  0  0  0]
    [-1  1  0  0  0  0  0  0]
    [ 0  0  0  0  0  0  0  0]
    [ 0  0  0  0  0  0  0  0]
]
```

Now if we fuse $U$ and $V$ together, the resulting Lie algebra will be 5-dimensional, and the Lie bracket will essentially be equal to $t$.

```magma
> NilCat := TensorCategory([1, 1, 1], {{2,1},{0}});
> NilCat;
Tensor category of valence 3 (->,->,->) ({ 0 },{ 1, 2 })
> ChangeTensorCategory(~t, NilCat);
> L := HeisenbergLieAlgebra(t);
> L;
Lie Algebra of dimension 5 with base ring Rational Field
> SystemOfForms(Tensor(L))[4..5];
[
    [ 0 -1 -2  0  0]
    [ 1  0 -1  0  0]
    [ 2  1  0  0  0]
    [ 0  0  0  0  0]
    [ 0  0  0  0  0],

    [ 0  2  1  0  0]
    [-2  0 -1  0  0]
    [-1  1  0  0  0]
    [ 0  0  0  0  0]
    [ 0  0  0  0  0]
]
```

<a id="function-heisenberggroup-tenspcelt"></a>
##### `HeisenbergGroup(T): TenSpcElt -> GrpMat`

<a id="function-heisenberggrouppc-tenspcelt"></a>
##### `HeisenbergGroupPC(T): TenSpcElt -> GrpPC`

Returns the class 2, exponent $p$, Heisenberg $p$-group with commutator given by the bilinear tensor $T: U \times V \rightarrowtail W$ over a finite field. If $T$ is alternating and the tensor category of $T$ forces equality between $U$ and $V$, then the group returned is an extension of $V$ by $W$, so $|G| = |V|\cdot |W|$. Otherwise, the group returned is an extension of $U\oplus V$ by $W$, so $|G| = |U|\cdot |V| \cdot |W|$. If $T$ is not full, then $G$ is an extension of $U\oplus V\oplus W/\rm{im}(T)$ (or $V\oplus W/\rm{im}(T)$) by $\rm{im}(T)$.

<a id="example-ex-3bc793"></a>
##### `Example: p-Groups from Tensors (ex-3bc793)`

Here we demonstrate how to export a group from a tensor. We will start with a tensor that is alternating and compare the different outputs based on the category of the tensor.

```magma
> t := KTensorSpace(GF(5), [5, 5, 4])!0;
> for i in [1..4] do
>   Assign(~t, [i, i+1, i], 1);   // 1s above diag
>   Assign(~t, [i+1, i, i], -1);  // 4s below diag
> end for;
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 5 over GF(5)
U1 : Full Vector space of degree 5 over GF(5)
U0 : Full Vector space of degree 4 over GF(5)
> IsAlternating(t);
true
```

In this example, we will focus on the more straight-forward case, when $t$ is full. The next example demonstrates a tensor that is not full.

```magma
> SystemOfForms(t);
[
    [0 1 0 0 0]
    [4 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 1 0 0]
    [0 4 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 1 0]
    [0 0 4 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 1]
    [0 0 0 4 0]
]
> IsFullyNondegenerate(t);
true
```

Even though $t$ is alternating, the category does not fuse together $U$ and $V$. Therefore, the Heisenberg group $H$ is an extension of $U\oplus V$ by $W$, and hence, $|H|=5^{5+5+4}$.

```magma
> H := HeisenbergGroup(t);
> LMGOrder(LMGCenter(H)) eq 5^4;
true
> s := pCentralTensor(H, 5, 1, 1);
> s;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 10 over GF(5)
U1 : Full Vector space of degree 10 over GF(5)
U0 : Full Vector space of degree 4 over GF(5)
```

Now we will fuse the 2 and 1 coordinate, so that $|H|=5^{5+4}$.

```magma
> PgrpCat := TensorCategory([1, 1, 1], {{2,1},{0}});
> PgrpCat;
Tensor category of valence 3 (->,->,->) ({ 0 },{ 1, 2 })
> ChangeTensorCategory(~t, PgrpCat);
> H := HeisenbergGroup(t);
> LMGOrder(LMGCenter(H)) eq 5^4;
true
> s := pCentralTensor(H, 5, 1, 1);
> s;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 5 over GF(5)
U1 : Full Vector space of degree 5 over GF(5)
U0 : Full Vector space of degree 4 over GF(5)
```

Note that $t$ and $s$ are not the same tensor. However, they are pseudo-isometric (isotopic in the category with $U_2=U_1$). This effect is exaggerated with `HeisenbergGroupPC` because of how PC-generators are organized.

```magma
> SystemOfForms(s);
[
    [0 0 0 0 0]
    [0 0 0 0 1]
    [0 0 0 0 0]
    [0 0 0 0 0]
    [0 4 0 0 0],

    [0 0 0 0 0]
    [0 0 0 0 0]
    [0 0 0 0 4]
    [0 0 0 0 0]
    [0 0 1 0 0],

    [0 0 0 0 0]
    [0 0 0 0 0]
    [0 0 0 1 0]
    [0 0 4 0 0]
    [0 0 0 0 0],

    [0 0 0 4 0]
    [0 0 0 0 0]
    [0 0 0 0 0]
    [1 0 0 0 0]
    [0 0 0 0 0]
]
```

<a id="example-ex-ce8a17"></a>
##### `Example: p-Groups from Non-Full Tensors (ex-ce8a17)`

We will start with an alternating tensor that is not full with the frame ${\bf F}_{3}^4\times{\bf F}_{3}^4\rightarrowtail {\bf F}_{3}^3$.

```magma
> t := Tensor(GF(3), [4, 4, 3], &cat[[1,0,0,1] : i in [1..12]]);
> t := AlternatingTensor(t);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 4 over GF(3)
U1 : Full Vector space of degree 4 over GF(3)
U0 : Full Vector space of degree 3 over GF(3)
> Radical(t);
<
    Vector space of degree 4, dimension 1 over GF(3)
    Echelonized basis:
    (1 2 1 2),

    Vector space of degree 4, dimension 1 over GF(3)
    Echelonized basis:
    (1 2 1 2)
>
> Image(t);
Vector space of degree 3, dimension 2 over GF(3)
Generators:
(1 0 2)
(0 1 0)
Echelonized basis:
(1 0 2)
(0 1 0)
> SystemOfForms(t);
[
    [0 0 2 2]
    [0 0 2 2]
    [1 1 0 0]
    [1 1 0 0],

    [0 1 1 0]
    [2 0 0 2]
    [2 0 0 2]
    [0 1 1 0],

    [0 0 1 1]
    [0 0 1 1]
    [2 2 0 0]
    [2 2 0 0]
]
```

Because the tensor category of $t$ does not force equality between $U$ and $V$, the group $H$ created from $t$ will have order $3^{11}$ and be 8-generated. Furthermore, the tensor has a 2-dimensional image, so the tensor from the exponent-$p$ central series of $H$ will have frame ${\bf F}_{3}^{4+4+1}\times {\bf F}_{3}^{4+4+1}\rightarrowtail{\bf F}_{3}^2$. We display the system of forms of the exponent-$p$ central tensor of $H$ to show how different it looks compared to the original.

```magma
> G := HeisenbergGroup(t);
> LMGOrder(G) eq 3^11;
true
> s := pCentralTensor(G);
> s;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 9 over GF(3)
U1 : Full Vector space of degree 9 over GF(3)
U0 : Full Vector space of degree 2 over GF(3)
> SystemOfForms(s);
[
    [0 0 0 0 0 0 0 0 1]
    [0 0 0 0 0 0 2 2 0]
    [0 0 0 0 0 0 0 0 1]
    [0 0 0 0 0 0 1 1 2]
    [0 0 0 0 0 0 0 0 0]
    [0 0 0 0 0 0 0 0 0]
    [0 1 0 2 0 0 0 0 0]
    [0 1 0 2 0 0 0 0 0]
    [2 0 2 1 0 0 0 0 0],

    [0 0 0 0 0 0 1 0 0]
    [0 0 0 0 0 0 1 0 0]
    [0 0 0 0 0 0 0 2 2]
    [0 0 0 0 0 0 0 2 2]
    [0 0 0 0 0 0 0 0 0]
    [0 0 0 0 0 0 0 0 0]
    [2 2 0 0 0 0 0 0 0]
    [0 0 1 1 0 0 0 0 0]
    [0 0 1 1 0 0 0 0 0]
]
```

<a id="ch-tensor-spaces"></a>
<a id="id1"></a>
### Tensor Spaces

In Magma a tensor space is a parent type for tensors. It behaves as a module but also maintains an interpretation of its elements as multilinear maps. Each tensor space further maintains a tensor category which is assigned to its tensors.

#### Constructions of Tensor and Cotensor Spaces

##### Universal Tensor Spaces

Construction of universal tensor spaces is modeled after construction of free modules and matrix spaces. For efficiency reasons, the actual representation may vary based on the parameters, e.g. it may be a space of structure constants, black-box functions, or systems of forms. So access to the tensors in these tensor space should be made through the provided functions.

<a id="function-ktensorspace-fld-rngintelt"></a>
###### `KTensorSpace(K, S): Fld, [RngIntElt] -> TenSpc`

<a id="function-ktensorspace-fld-rngintelt-tencat"></a>
###### `KTensorSpace(K, S, C): Fld, [RngIntElt], TenCat -> TenSpc`

For a field $K$ and sequence $S=[d_{\nu},\cdots, d_0]$, returns the universal tensor space $\oslash_{a\in [\nu]} K^{d_a}$ with covariant tensor category given by $C$. The default category is the homotopism category.

<a id="function-rtensorspace-rng-rngintelt"></a>
###### `RTensorSpace(R, S): Rng, [RngIntElt] -> TenSpc`

<a id="function-rtensorspace-rng-rngintelt-tencat"></a>
###### `RTensorSpace(R, S, C): Rng, [RngIntElt], TenCat -> TenSpc`

For a commutative ring $R$ and sequence $S=[d_{\nu},\cdots, d_0]$, returns the universal tensor space $\oslash_{a\in [\nu]} R^{d_a}$ with covariant tensor category given by $C$. The default category is the homotopism category.

<a id="example-ex-9c4d34"></a>
###### `Example: Universal Tensor Space over a Field (ex-9c4d34)`

We demonstrate how to construct universal tensor spaces from a field $K={\mathbb{Q}}$ and a sequence of nonnegative integers $[6,5,4,3]$. The resulting tensor space is isomorphic to the space of multilinear maps with frame

$$
{\mathbb{Q}}^6\times {\mathbb{Q}}^5\times{\mathbb{Q}}^4\rightarrowtail{\mathbb{Q}}^3.
$$

```magma
> K := Rationals();
> S := [6, 5, 4, 3];
> T := KTensorSpace(K, S);
> T;
Tensor space of dimension 360 over Rational Field with valence 4
U3 : Full Vector space of degree 6 over Rational Field
U2 : Full Vector space of degree 5 over Rational Field
U1 : Full Vector space of degree 4 over Rational Field
U0 : Full Vector space of degree 3 over Rational Field
```

Because tensor spaces act like modules, we can construct tensors in the same way we construct vectors.

```magma
> t := T![Random([-1, 0, 1]) : i in [1..Dimension(T)]];
> t;
Tensor of valence 4, U3 x U2 x U1 >-> U0
U3 : Full Vector space of degree 6 over Rational Field
U2 : Full Vector space of degree 5 over Rational Field
U1 : Full Vector space of degree 4 over Rational Field
U0 : Full Vector space of degree 3 over Rational Field
> Parent(t);
Tensor space of dimension 360 over Rational Field with valence 4
U3 : Full Vector space of degree 6 over Rational Field
U2 : Full Vector space of degree 5 over Rational Field
U1 : Full Vector space of degree 4 over Rational Field
U0 : Full Vector space of degree 3 over Rational Field
```

<a id="function-tensorspace-seqenum"></a>
###### `TensorSpace(S): SeqEnum -> TenSpc, List`

<a id="function-tensorspace-list"></a>
###### `TensorSpace(S): List -> TenSpc, List`

<a id="function-tensorspace-seqenum-tencat"></a>
###### `TensorSpace(S, C): SeqEnum, TenCat -> TenSpc, List`

<a id="function-tensorspace-list-tencat"></a>
###### `TensorSpace(S, C): List, TenCat -> TenSpc, List`

Given a sequence $S=[U_{\nu},\dots, U_0]$ of $R$-modules returns a universal tensor space equivalent to $\oslash_{a\in[\nu]} U_a$ with covariant tensor category given by $C$ and a list of maps into the vector spaces in the frame. The default category is the homotopism category.

<a id="example-ex-d8700c"></a>
###### `Example: Universal Tensor Space from Modules (ex-d8700c)`

We will construct a similar tensor space as the previous example. However, the objects will be different, according to Magma.

```magma
> R := Integers();
> S := [* RMatrixSpace(R, 2, 3), RSpace(R, 5), RMatrixSpace(R, 2, 2),
>     RSpace(R, 3) *];
> T := TensorSpace(S);
> T;
Tensor space of dimension 360 over Integer Ring with valence 4
U3 : Full RSpace of degree 6 over Integer Ring
U2 : Full RSpace of degree 5 over Integer Ring
U1 : Full RSpace of degree 4 over Integer Ring
U0 : Full RSpace of degree 3 over Integer Ring
```

Even though the frame of $T$ does not include matrix spaces, like with tensors, it can still evaluate matrices. For example, we evaluate $T$ at $(0,0,0)$, which is the trivial subspace in ${\mathbb{Z}}^3$.

```magma
> x := < X!0 : X in S[1..3] >;
> x;
<
    [0 0 0]
    [0 0 0],

    (0 0 0 0 0),

    [0 0]
    [0 0]
>
> x @ T;
RSpace of degree 3, dimension 0 over Integer Ring
Generators:
```

<a id="function-tensorspace-modtupfld-rngintelt-rngintelt"></a>
###### `TensorSpace(V, p, q): ModTupFld, RngIntElt, RngIntElt -> TenSpc`

<a id="function-tensorspace-fld-rngintelt-rngintelt-rngintelt"></a>
###### `TensorSpace(K, d, p, q): Fld, RngIntElt, RngIntElt, RngIntElt -> TenSpc`

Given a field $K$ and a dimension $d$ or a vector space $V=K^d$ for which the first $p$ indices are covariant and the last $q$ indices are contravariant, returns the signatured $(p,q)$-tensor space over $V$. This is functionally equivalent to creating a universal tensor space from the sequence $[V,\dots,_p V, V^*,\dots,_q V^*, K]$ and the tensor category with arrows $[1,\dots,_p 1, -1,\dots,_q -1, 0]$ and duplicates $\{\{p+q,\dots,1+q\},\{q,\dots,1\},\{0\}\}$. The valence of the returned tensor space will be $p+q+1$.

<a id="example-ex-170743"></a>
###### `Example: Signatured Tensor Space (ex-170743)`

Here we simply demonstrate the nuances of the signatured tensor space constructor. We set $V={\bf F}_{5}^4$, $p=3$, and $q=2$, and the tensor space we will construct will have frame

$$
V\times V\times V \times V^* \times V^*\rightarrowtail{\bf F}_{5}.
$$

Notice this is equivalent to the frame $V\times V\times V\rightarrowtail V \times V$.

```magma
> K := GF(5);
> T := TensorSpace(K, 4, 3, 2);
> T;
Tensor space of dimension 1024 over GF(5) with valence 6
U5 : Full Vector space of degree 4 over GF(5)
U4 : Full Vector space of degree 4 over GF(5)
U3 : Full Vector space of degree 4 over GF(5)
U2 : Full Vector space of degree 4 over GF(5)
U1 : Full Vector space of degree 4 over GF(5)
U0 : Full Vector space of degree 1 over GF(5)
> S := KTensorSpace(K, [4, 4, 4, 4, 4, 1]);
> S;
Tensor space of dimension 1024 over GF(5) with valence 6
U5 : Full Vector space of degree 4 over GF(5)
U4 : Full Vector space of degree 4 over GF(5)
U3 : Full Vector space of degree 4 over GF(5)
U2 : Full Vector space of degree 4 over GF(5)
U1 : Full Vector space of degree 4 over GF(5)
U0 : Full Vector space of degree 1 over GF(5)
```

However, the subtleties of this construction lies in the tensor category. On the surface, the spaces $T$ and $S$ look the same, but probing the category reveals their differences.

```magma
> TensorCategory(S); // default category
Tensor category of valence 6 (->,->,->,->,->,->) ({ 1 },{ 2 },{ 0 },{ 3 },{ 4
},{ 5 })
> TensorCategory(T);
Tensor category of valence 6 (<-,<-,<-,->,->,==) ({ 0 },{ 3 .. 5 },{ 1 .. 2 })
> S eq T;
false
```

##### Universal Cotensor Spaces

Currently, we only consider cotensor spaces over fields.

<a id="function-kcotensorspace-fld-rngintelt"></a>
###### `KCotensorSpace(K, S): Fld, [RngIntElt] -> TenSpc`

<a id="function-kcotensorspace-fld-rngintelt-tencat"></a>
###### `KCotensorSpace(K, S, C): Fld, [RngIntElt], TenCat -> TenSpc`

For a field $K$ and sequence $S=[d_{\nu},\dots, d_1]$ returns the universal cotensor space $\bigotimes_{a\in\bar{0}}K^{d_a}$ with the given contravariant tensor category $C$. The default category is the homotopism category. Notice the sequence $S$ indices do *not* include 0.

<a id="function-cotensorspace-seqenum"></a>
###### `CotensorSpace(S): SeqEnum -> TenSpc`

<a id="function-cotensorspace-list"></a>
###### `CotensorSpace(S): List -> TenSpc, List`

<a id="function-cotensorspace-seqenum-tencat"></a>
###### `CotensorSpace(S, C): SeqEnum, TenCat -> TenSpc`

<a id="function-cotensorspace-list-tencat"></a>
###### `CotensorSpace(S, C): List, TenCat -> TenSpc, List`

Given a sequence $S=[U_{\nu},\dots, U_1]$ of $K$-vector spaces returns the universal tensor space equivalent to $\bigotimes_{a\in\bar{0}}U_a$ with contravariant tensor category given by $C$ and a list of maps into the vector spaces of the frame. The default category is the homotopism category. Notice the sequence $S$ indices do *not* include 0.

<a id="example-ex-a0d0fa"></a>
###### `Example: Universal Cotensor Spaces (ex-a0d0fa)`

Constructing cotensor spaces is nearly the same as constructing tensor spaces. When providing a sequence of modules or a sequence of dimensions, we do not include the entry for $U_0$. It is automatically set to $U_0=K$. Furthermore, the black-box construction forgets all other structure of the vector spaces and only builds a frame out of vector spaces. The maps are returned as a `List` in case they are needed.

```magma
> K := Rationals();
> S := [* KSpace(K, 3), MatrixAlgebra(K, 3), KMatrixSpace(K, 2, 3) *];
> S;
[*
    Full Vector space of degree 3 over Rational Field,
    Full Matrix Algebra of degree 3 over Rational Field,
    Full KMatrixSpace of 2 by 3 matrices over Rational Field
*]
> T := CotensorSpace(S);
> T;
Cotensor space of dimension 162 over Rational Field with valence 4
U3 : Full Vector space of degree 3 over Rational Field
U2 : Full Vector space of degree 9 over Rational Field
U1 : Full Vector space of degree 6 over Rational Field
```

Like with tensor spaces, cotensors are elements of cotensor spaces, and for many purposes in Magma, cotensor and tensor spaces have similar functionality.

```magma
> t := T.3;
> t;
Cotensor of valence 4, U3 x U2 x U1 >-> K
U3 : Full Vector space of degree 3 over Rational Field
U2 : Full Vector space of degree 9 over Rational Field
U1 : Full Vector space of degree 6 over Rational Field
> Eltseq(t);
[ 0, 0, 1, 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, 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, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0 ]
```

##### Some Standard Constructions

We include some subspaces generated by well-known tensors.

<a id="function-alternatingspace-tenspc"></a>
###### `AlternatingSpace(T): TenSpc -> TenSpc, Map`

Returns the sub(co-)tensor space generated by all the alternating (co-)tensors contained in the given (co-)tensor space.

<a id="function-antisymmetricspace-tenspc"></a>
###### `AntisymmetricSpace(T): TenSpc -> TenSpc, Map`

Returns the sub(co-)tensor space generated by all the antisymmetric (co-)tensors contained in the given (co-)tensor space.

<a id="function-symmetricspace-tenspc"></a>
###### `SymmetricSpace(T): TenSpc -> TenSpc, Map`

Returns the sub(co-)tensor space generated by all the symmetric (co-)tensors contained in the given (co-)tensor space.

<a id="example-ex-4fe5c3"></a>
###### `Example: Standard Tensor Subspaces (ex-4fe5c3)`

We will construct some standard tensor subspaces of the universal tensor space with frame ${\bf F}_{3}^4\times {\bf F}_{3}^4\rightarrowtail{\bf F}_{3}^4$.

```magma
> K := GF(3);
> T := KTensorSpace(K, [4, 4, 4]);
> T;
Tensor space of dimension 64 over GF(5) with valence 3
U2 : Full Vector space of degree 4 over GF(5)
U1 : Full Vector space of degree 4 over GF(5)
U0 : Full Vector space of degree 4 over GF(5)
```

First, we will construct the subspace of $T$ containing all alternating bilinear maps. We expect the subspace to be 24-dimensional in $T$.

```magma
> Alt := AlternatingSpace(T);
> Alt;
Tensor space of dimension 24 over GF(3) with valence 3
U2 : Full Vector space of degree 4 over GF(3)
U1 : Full Vector space of degree 4 over GF(3)
U0 : Full Vector space of degree 4 over GF(3)
> t := Random(Alt);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 4 over GF(3)
U1 : Full Vector space of degree 4 over GF(3)
U0 : Full Vector space of degree 4 over GF(3)
> IsAlternating(t);
true
```

Now we will construct the symmetric subspace of the alternating subspace, which is trivial.

```magma
> S := SymmetricSpace(Alt);
> S;
Tensor space of dimension 0 over GF(3) with valence 3
U2 : Full Vector space of degree 4 over GF(3)
U1 : Full Vector space of degree 4 over GF(3)
U0 : Full Vector space of degree 4 over GF(3)
```

<a id="function-exteriorcotensorspace-modtupfld-rngintelt"></a>
###### `ExteriorCotensorSpace(V, n): ModTupFld, RngIntElt -> TenSpc`

Returns the cotensor space given by the $n$th exterior power of the vector space $V$.

<a id="function-symmetriccotensorspace-modtupfld-rngintelt"></a>
###### `SymmetricCotensorSpace(V, n): ModTupFld, RngIntElt -> TenSpc`

Returns the cotensor space given by the $n$th symmetric power of the vector space $V$.

<a id="example-ex-cd38a4"></a>
###### `Example: Standard Cotensor Subspaces (ex-cd38a4)`

We set $V={\bf F}_{5}^6$ and we construct the cotensor space of the symmetric square of $V$, $V\wedge V$. The frame is $V\times V\rightarrowtail {\bf F}_{5}$, so the cotensor space is $15$-dimensional.

```magma
> V := VectorSpace(GF(5), 6);
> T := ExteriorCotensorSpace(V, 2);
> T;
Cotensor space of dimension 15 over GF(5) with valence 3
U2 : Full Vector space of degree 6 over GF(5)
U1 : Full Vector space of degree 6 over GF(5)
```

The cotensor space $T$ is generated by all alternating tensors $\langle t| : V\times V\rightarrowtail {\bf F}_{5}$. We will demonstrate by constructing a random cotensor from $T$.

```magma
> t := Random(T);
> t;
Cotensor of valence 3, U2 x U1 >-> K
U2 : Full Vector space of degree 6 over GF(5)
U1 : Full Vector space of degree 6 over GF(5)
> SystemOfForms(t);
[
    [0 2 2 2 4 1]
    [3 0 4 1 0 0]
    [3 1 0 3 1 1]
    [3 4 2 0 2 0]
    [1 0 4 3 0 2]
    [4 0 4 0 3 0]
]
> IsAlternating(t);
true
```

Notice this construction is not $V\times V\rightarrowtail V\wedge V$. However, if we want this tensor, we can use the intrinsic `AsTensor`.

```magma
> s := AsTensor(T);
> s;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 6 over GF(5)
U1 : Full Vector space of degree 6 over GF(5)
U0 : Full Vector space of degree 15 over GF(5)
> IsAlternating(s);
true
```

#### Operations on Tensor Spaces

##### Membership and Comparison with Tensor Spaces

We define some intuitive functions for tensor spaces, similar to those found for modules.

<a id="operation-op-in-tenspcelt-tenspc"></a>
###### `T in TS: TenSpcElt, TenSpc -> BoolElt`

Returns `true` if $T$ is contained in the tensor space $TS$.

<a id="operation-op-tenspc-tenspcelt"></a>
###### `TS ! T: TenSpc, TenSpcElt -> TenSpcElt`

If the tensor $T$ can be coerced into the tensor space $TS$, the tensor is returned as an element of $TS$.

<a id="operation-op-tenspc-seqenum"></a>
###### `TS ! S: TenSpc, SeqEnum -> TenSpcElt`

If the sequence $S$ can be coerced into the tensor space $TS$ as a tensor, the corresponding tensor is returned.

<a id="operation-op-tenspc-rngintelt"></a>
###### `T ! n: TenSpc, RngIntElt -> TenSpcElt`

This is a shortcut designed to only work when $n=0$, and thus, returns `true` and the zero tensor from the tensor space. Any other integer will yield an error.

<a id="function-iscoercible-tenspc-any"></a>
###### `IsCoercible(TS, x): TenSpc, Any -> BoolElt, TenSpcElt`

Returns `true` if $x$ can be coerced into the tensor space $TS$ and the corresponding tensor, otherwise `false`.

<a id="example-ex-e939dc"></a>
###### `Example: Coercion into a Tensor Space (ex-e939dc)`

We illustrate that using `!` is the same as creating the tensor from scratch.

```magma
> T := KTensorSpace( GF(2), [2,3,2] );
> T;
Tensor space of dimension 12 over GF(2) with valence 3
U2 : Full Vector space of degree 2 over GF(2)
U1 : Full Vector space of degree 3 over GF(2)
U0 : Full Vector space of degree 2 over GF(2)
>
> S := [ 1 : i in [1..12] ];
> t := T!S;
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 2 over GF(2)
U1 : Full Vector space of degree 3 over GF(2)
U0 : Full Vector space of degree 2 over GF(2)
>
> t eq Tensor(GF(2), [2,3,2], S);
true
>
> T!0 in T;
true
> SystemOfForms(T!0);
[
    [0 0 0]
    [0 0 0],

    [0 0 0]
    [0 0 0]
]
```

<a id="operation-op-eq-tenspc-tenspc"></a>
###### `S eq T: TenSpc, TenSpc -> BoolElt`

Decides if the tensor spaces $S$ and $T$ are equal.

<a id="operation-op-subset-tenspc-tenspc"></a>
###### `S subset T: TenSpc, TenSpc -> BoolElt`

Decides if $S$ is a subset of the tensor space $T$.

<a id="function-iscoercible-tenspc-any-2"></a>
###### `IsCoercible(T, S): TenSpc, Any -> BoolElt`

<a id="operation-op-tenspc-tenspc"></a>
###### `T ! S: TenSpc, TenSpc -> TenSpc`

Decides if the tensor space $S$ can be coerced into the tensor space $T$ as a subspace. If so, the corresponding subspace is returned.

<a id="example-ex-812352"></a>
###### `Example: Containment of Tensor Spaces (ex-812352)`

We construct the universal tensor space $T$ with the frame ${\bf F}_{2}^4\times {\bf F}_{2}^4\rightarrowtail {\bf F}_{2}^4$. We also create a tensor space $T_2$ with frame ${\bf F}_{2}^4\times {\bf F}_{2}\times {\bf F}_{2}^4\times{\bf F}_{2}\rightarrowtail {\bf F}_{2}^4$.

```magma
> T := KTensorSpace(GF(2), [4,4,4]);
> T;
Tensor space of dimension 64 over GF(2) with valence 3
U2 : Full Vector space of degree 4 over GF(2)
U1 : Full Vector space of degree 4 over GF(2)
U0 : Full Vector space of degree 4 over GF(2)
>
> T2 := KTensorSpace(GF(2), [4,1,4,1,4]);
> T2;
Tensor space of dimension 64 over GF(2) with valence 5
U4 : Full Vector space of degree 4 over GF(2)
U3 : Full Vector space of degree 1 over GF(2)
U2 : Full Vector space of degree 4 over GF(2)
U1 : Full Vector space of degree 1 over GF(2)
U0 : Full Vector space of degree 4 over GF(2)
>
> S := sub< T | T.2, T.4, T.8 >;
> S;
Tensor space of dimension 3 over GF(2) with valence 3
U2 : Full Vector space of degree 4 over GF(2)
U1 : Full Vector space of degree 4 over GF(2)
U0 : Full Vector space of degree 4 over GF(2)
```

We verify that $S$ is a subset of $T$ and not $T_2$. Since the tensors of $T$ naturally embed into $T_2$, the subspace $S$ can be coerced into $T_2$, which we label as $S_2$. We then verify that $S_2$ is a subset of $T_2$ and not $T$.

```magma
> S subset T2;
false
> S2 := T2!S;
> S2 subset T2;
true
> S2 subset T;
false
```

##### Tensor Spaces as Modules

We view a tensor space as a $K$-module, so we have notions of generators, dimension (if it is free), and cardinality.

<a id="function-basis-tenspc"></a>
###### `Basis(T): TenSpc -> SeqEnum`

<a id="function-generators-tenspc"></a>
###### `Generators(T): TenSpc -> SeqEnum`

Returns a basis for the tensor space $T$.

<a id="operation-operation-tenspc-rngintelt-tenspcelt"></a>
###### `T . i: TenSpc, RngIntElt -> TenSpcElt`

Returns the $i$th basis tensor of the tensor space $T$.

<a id="function-numberofgenerators-tenspc"></a>
###### `NumberOfGenerators(T): TenSpc -> RngIntElt`

<a id="function-ngens-tenspc"></a>
###### `Ngens(T): TenSpc -> RngIntElt`

Returns the number of generators of the tensor space $T$.

<a id="function-dimension-tenspc"></a>
###### `Dimension(T): TenSpc -> RngIntElt`

Returns the dimension of the tensor space $T$ as a free $K$-module.

<a id="operation-operation-tenspc-rngintelt"></a>
###### `# T: TenSpc -> RngIntElt`

Returns the size of the tensor space, provided $T$ is finite.

<a id="example-ex-d57848"></a>
###### `Example: Module Functions on Tensor Spaces (ex-d57848)`

We demonstrate the basic module functions of tensor spaces. We construct the universal tensor space $T$ with frame ${\bf F}_{8}^3\times{\bf F}_{8}^5\rightarrowtail{\bf F}_{8}^7$.

```magma
> K := GF(8);
> T := KTensorSpace(K, [3,5,7]);
> T;
Tensor space of dimension 105 over GF(2^3) with valence 3
U2 : Full Vector space of degree 3 over GF(2^3)
U1 : Full Vector space of degree 5 over GF(2^3)
U0 : Full Vector space of degree 7 over GF(2^3)
```

Now we obtain module properties of $T$.

```magma
> Dimension(T);
105
> #Basis(T);
105
> T.100 in Basis(T);
true
> T.100;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 3 over GF(2^3)
U1 : Full Vector space of degree 5 over GF(2^3)
U0 : Full Vector space of degree 7 over GF(2^3)
> #T eq 8^(3*5*7);
true
```

<a id="function-random-tenspc"></a>
###### `Random(T): TenSpc -> TenSpcElt`

Provided the base ring has a random algorithm in Magma, it returns a random element of the tensor space $T$.

<a id="function-randomtensor-rng-rngintelt"></a>
###### `RandomTensor(R, S): Rng, [RngIntElt] -> TenSpcElt`

<a id="function-randomtensor-rng-rngintelt-tencat"></a>
###### `RandomTensor(R, S, C): Rng, [RngIntElt], TenCat -> TenSpcElt`

<a id="function-randomcotensor-fld-rngintelt"></a>
###### `RandomCotensor(K, S): Fld, [RngIntElt] -> TenSpcElt`

Provided $R$ has a random algorithm in Magma, it returns a random (co)tensor from the universal (co)tensor space $\oslash_{s\in S} R^{s}$, with category $C$. The default category is the homotopism category.

<a id="example-ex-377558"></a>
###### `Example: Random Tensors (ex-377558)`

We create some random tensors, which works similarly to `RandomMatrix`. There are two main ways to obtain a random tensor: from a given tensor space or from a ring and a dimension sequence (the universal tensor space). First we will construct the alternating tensor space of the universal tensor space with frame ${\bf F}_{3}^4\times{\bf F}_{3}^4\rightarrowtail {\bf F}_{3}^2$.

```magma
> T := KTensorSpace(GF(3), [4,4,2]);
> T;
Tensor space of dimension 32 over GF(3) with valence 3
U2 : Full Vector space of degree 4 over GF(3)
U1 : Full Vector space of degree 4 over GF(3)
U0 : Full Vector space of degree 2 over GF(3)
> S := AlternatingSpace(T);
> S;
Tensor space of dimension 12 over GF(3) with valence 3
U2 : Full Vector space of degree 4 over GF(3)
U1 : Full Vector space of degree 4 over GF(3)
U0 : Full Vector space of degree 2 over GF(3)
```

Now we construct a random alternating tensor from $S$.

```magma
> t := Random(S);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 4 over GF(3)
U1 : Full Vector space of degree 4 over GF(3)
U0 : Full Vector space of degree 2 over GF(3)
> SystemOfForms(t);
[
    [0 2 0 0]
    [1 0 0 0]
    [0 0 0 2]
    [0 0 1 0],

    [0 2 1 0]
    [1 0 1 2]
    [2 2 0 1]
    [0 1 2 0]
]
```

<a id="function-randomalternatingtensor-rng-rngintelt-rngintelt-rngintelt"></a>
###### `RandomAlternatingTensor(R, d, n, c): Rng, RngIntElt, RngIntElt, RngIntElt -> TenSpcElt`

<a id="function-randomalternatingtensor-rng-rngintelt"></a>
###### `RandomAlternatingTensor(R, S): Rng, [RngIntElt] -> TenSpcElt`

Returns a random alternating tensor from the universal tensor space

$$
\prod_{k=1}^n R^d \rightarrowtail R^c.
$$

If $S$ is given instead, then we assume $S=[d,\dots,d,c]$. The returned tensor has the homotopism category but fuses every module in the domain. An error is raised if $R$ does not have a random algorithm in Magma.

<a id="function-randomantisymmetrictensor-rng-rngintelt-rngintelt-rngintelt"></a>
###### `RandomAntisymmetricTensor(R, d, n, c): Rng, RngIntElt, RngIntElt, RngIntElt -> TenSpcElt`

<a id="function-randomantisymmetrictensor-rng-rngintelt"></a>
###### `RandomAntisymmetricTensor(R, S): Rng, [RngIntElt] -> TenSpcElt`

Returns a random antisymmetric tensor from the universal tensor space

$$
\prod_{k=1}^n R^d \rightarrowtail R^c.
$$

If $S$ is given instead, then we assume $S=[d,\dots,d,c]$. The returned tensor has the homotopism category but fuses every module in the domain. An error is raised if $R$ does not have a random algorithm in Magma.

<a id="function-randomsymmetrictensor-rng-rngintelt-rngintelt-rngintelt"></a>
###### `RandomSymmetricTensor(R, d, n, c): Rng, RngIntElt, RngIntElt, RngIntElt -> TenSpcElt`

<a id="function-randomsymmetrictensor-rng-rngintelt"></a>
###### `RandomSymmetricTensor(R, S): Rng, [RngIntElt] -> TenSpcElt`

Returns a random symmetric tensor from the universal tensor space

$$
\prod_{k=1}^n R^d \rightarrowtail R^c.
$$

If $S$ is given instead, then we assume $S=[d,\dots,d,c]$. The returned tensor has the homotopism category but fuses every module in the domain. An error is raised if $R$ does not have a random algorithm in Magma.

<a id="example-ex-f99231"></a>
###### `Example: Random Symmetric Tensors (ex-f99231)`

We just demonstrate how to use the `RandomSymmetricTensor`. The other two intrinsics are the same. This is almost equivalent to constructing a random tensor whose category fuses all the modules in the domain and then applying `SymmetricTensor`. In characteristic 2, all entries on the diagonal will be 0, but with `RandomSymmetricTensor` this is not the case.

```magma
> t := RandomSymmetricTensor(GF(2), 4, 2, 3);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 4 over GF(2)
U1 : Full Vector space of degree 4 over GF(2)
U0 : Full Vector space of degree 3 over GF(2)
>
> TensorCategory(t);
Tensor category of valence 3 (->,->,->) ({ 0 },{ 1 .. 2 })
>
> SystemOfForms(t);
[
    [1 1 1 1]
    [1 0 1 0]
    [1 1 1 1]
    [1 0 1 0],

    [1 0 1 1]
    [0 0 1 0]
    [1 1 0 0]
    [1 0 0 1],

    [1 0 0 0]
    [0 0 1 1]
    [0 1 0 0]
    [0 1 0 1]
]
> IsSymmetric(t);
true
```

##### Properties of Tensor Spaces

We define some functions to access basic properties of tensor spaces.

<a id="function-valence-tenspc"></a>
###### `Valence(T): TenSpc -> RngIntElt`

Returns the valence of the tensor space.

<a id="function-frame-tenspc"></a>
###### `Frame(T): TenSpc -> List`

Returns the list of modules in the frame of the tensor space.

<a id="function-basering-tenspc"></a>
###### `BaseRing(T): TenSpc -> Rng`

<a id="function-basefield-tenspc"></a>
###### `BaseField(T): TenSpc -> Fld`

Returns the base ring (or field) of the tensor space.

<a id="example-ex-40631c"></a>
###### `Example: Properties of Tensor Spaces (ex-40631c)`

As with tensors, we can obtain the basic tensor properties from a tensor space.

```magma
> T := KTensorSpace(Rationals(), [7,5,3,2]);
> T;
Tensor space of dimension 210 over Rational Field with valence 4
U3 : Full Vector space of degree 7 over Rational Field
U2 : Full Vector space of degree 5 over Rational Field
U1 : Full Vector space of degree 3 over Rational Field
U0 : Full Vector space of degree 2 over Rational Field
> Valence(T);
4
> Frame(T);
[*
    Full Vector space of degree 7 over Rational Field,

    Full Vector space of degree 5 over Rational Field,

    Full Vector space of degree 3 over Rational Field,

    Full Vector space of degree 2 over Rational Field
*]
> BaseRing(T);
Rational Field
```

<a id="function-tensorcategory-tenspc"></a>
###### `TensorCategory(T): TenSpc -> TenCat`

Returns the underlying tensor category of the tensor space.

<a id="function-iscovariant-tenspc"></a>
###### `IsCovariant(T): TenSpc -> BoolElt`

<a id="function-iscontravariant-tenspc"></a>
###### `IsContravariant(T): TenSpc -> BoolElt`

Decides if the underlying tensor category is covariant or contravariant.

<a id="function-changetensorcategory-tenspc-tencat"></a>
###### `ChangeTensorCategory(T, C): TenSpc, TenCat -> TenSpc`

<a id="procedure-changetensorcategory-tenspc-tencat-ref"></a>
###### `ChangeTensorCategory(~T, C): TenSpc, TenCat`

Returns the tensor category with the given tensor category.

<a id="example-ex-066785"></a>
###### `Example: Categories of Tensor Spaces (ex-066785)`

Again, like with tensors, we can obtain categorical information from tensor spaces.

```magma
> T := KTensorSpace(Rationals(), [4,4,4]);
> T;
Tensor space of dimension 64 over Rational Field with valence 3
U2 : Full Vector space of degree 4 over Rational Field
U1 : Full Vector space of degree 4 over Rational Field
U0 : Full Vector space of degree 4 over Rational Field
>
> TensorCategory(T);
Tensor category of valence 3 (->,->,->) ({ 1 },{ 2 },{ 0 })
> C := TensorCategory([1,1,-1], {{0},{1,2}});
> C;
Tensor category of valence 3 (->,->,<-) ({ 0 },{ 1, 2 })
>
> ChangeTensorCategory(~T, C);
> T;
Tensor space of dimension 64 over Rational Field with valence 3
U2 : Full Vector space of degree 4 over Rational Field
U1 : Full Vector space of degree 4 over Rational Field
U0 : Full Vector space of degree 4 over Rational Field
> TensorCategory(T);
Tensor category of valence 3 (->,->,<-) ({ 0 },{ 1, 2 })
```

<a id="function-isalternating-tenspc"></a>
###### `IsAlternating(T): TenSpc -> BoolElt`

Decides if every tensor in the tensor space is an alternating tensor.

<a id="function-isantisymmetric-tenspc"></a>
###### `IsAntisymmetric(T): TenSpc -> BoolElt`

Decides if every tensor in the tensor space is an antisymmetric tensor.

<a id="function-issymmetric-tenspc"></a>
###### `IsSymmetric(T): TenSpc -> BoolElt`

Decides if every tensor in the tensor space is a symmetric tensor.

<a id="function-universaltensorspace-tenspc"></a>
###### `UniversalTensorSpace(T): TenSpc -> TenSpc`

<a id="function-universalcotensorspace-tenspc"></a>
###### `UniversalCotensorSpace(T): TenSpc -> TenSpc`

<a id="function-generic-tenspc"></a>
###### `Generic(T): TenSpc -> TenSpc`

Returns the universal (co-)tensor space with the same frame and category as $T$.

<a id="example-ex-c56f94"></a>
###### `Example: Subspace of Alternating Tensors (ex-c56f94)`

We construct the subspace of alternating tensors $S$ of the tensor space $T$ with the frame ${\mathbb{Q}}^6\times{\mathbb{Q}}^6\rightarrowtail {\mathbb{Q}}^2$. We verify that the space is in fact alternating (i.e. every tensor is alternating).

```magma
> T := KTensorSpace(Rationals(), [6,6,2]);
> S := AlternatingSpace(T);
> S;
Tensor space of dimension 30 over Rational Field with valence 3
U2 : Full Vector space of degree 6 over Rational Field
U1 : Full Vector space of degree 6 over Rational Field
U0 : Full Vector space of degree 2 over Rational Field
> IsAlternating(S);
true
```

From $S$, we construct the universal tensor space $U$, which in this example is equal to $T$.

```magma
> U := UniversalTensorSpace(S);
> U;
Tensor space of dimension 72 over Rational Field with valence 3
U2 : Full Vector space of degree 6 over Rational Field
U1 : Full Vector space of degree 6 over Rational Field
U0 : Full Vector space of degree 2 over Rational Field
> U eq T;
true
```

<a id="ch-tensor-categories"></a>
<a id="id1"></a>
### Tensor Categories

Magma allows tensors and tensor spaces to change categories. Unless a user specifies otherwise, all tensors are assigned a category that is natural to the method by which it was created. For example a tensor created from an algebra will be assigned an algebra category, whereas a tensor created by structure constants will be assigned the Albert homotopism category [[Alb42](https://docs.magma-maths.org/references.md#cite-albert-fundamentals)]. Tensor categories influence the behavior of commands such as kernels and images as well as the algebraic invariants such as derivation algebras of a tensor.

Our conventions follow [[Wil13a](https://docs.magma-maths.org/references.md#cite-wilson-division)]. In particular, given a tensor $T$ framed by $[U_{\nu},\dots,U_0]$ then a tensor category for $T$ will specify a function $A:[\nu]\to \{-1,0,1\}$ along with a partition ${\cal P}$ of $[\nu]$ such that the following rules apply to the tensors and morphisms in the category.

**(1)**
for each tensor $T$ framed by $[U_{\nu},\dots,U_0]$, if $X\in{\cal P}$, then

$$
\forall i,j\in X,\quad U_i=U_j.
$$

**(2)**
Given a second tensor $S$ framed by $[V_v,\dots,V_0]$, a morphism $f:T\to S$ (Magma type `Hmtp`) will be a list $[f_{\nu},\dots,f_0]$ of homomorphisms as follows:

**•**
(Covariant) if $A(i)=1$ then $f_i:U_i\to V_i$;

**•**
(Constant) if $A(i)=0$ then $U_i=V_i$ and $f_i=1_{U_i}$; or else

**•**
(Contravariant) $A(i)=-1$ and $f_i:U_i\leftarrow V_i$. So if $A(0)=1$ then

$$
\left\langle \sum_{i\in A^{-1}(1)} u_i f_i
        +\sum_{j\not\in A^{-1}(-1)} v_j\right\rangle_S
        = \left\langle  \sum_{i\in A^{-1}(1)} u_i
        +\sum_{j\not\in A^{-1}(-1)} v_j f_j\right\rangle_T f_0;
$$

if $A(0)=0$ then

$$
\left\langle \sum_{i\in A^{-1}(1)} u_i f_i
        +\sum_{j\not\in A^{-1}(-1)} v_j\right\rangle_S
        = \left\langle  \sum_{i\in A^{-1}(1)} u_i
        +\sum_{j\not\in A^{-1}(-1)} v_j f_j\right\rangle_T;
$$

else $A(0)=-1$ and

$$
\left\langle \sum_{i\in A^{-1}(1)} u_i f_i
        +\sum_{j\not\in A^{-1}(-1)} v_j\right\rangle_S f_0
        = \left\langle  \sum_{i\in A^{-1}(1)} u_i
        +\sum_{j\not\in A^{-1}(-1)} v_j f_j\right\rangle_T.
$$

Magma manages internally the differences between vectors and covectors and more generally tensors and cotensors. Both types are issued the Magma type `TenSpcElt`. For operations sensitive to the difference, Magma stores a value of co/contra-variance of the tensor as a property of the tensor category. This is the third general property stored in Magma’s tensor category type `TenCat`.

We use the phrase tensor category exclusively for categories that describe tensors and tensor spaces. In other words, the data structure of a tensor category is a function $A:[\nu]\rightarrow \{-1,0,1\}$ and a partition ${\cal P}$ of $[\nu]$. It is useful to distinguish from tensors and cotensors at the categorical level, so a tensor category is either covariant or contravariant as well (in the latter case, referred to as a cotensor category).

#### Constructing Tensor Categories

<a id="function-tensorcategory-rngintelt-setenum"></a>
##### `TensorCategory(A, P): [RngIntElt], {SetEnum} -> TenCat`

<a id="function-tensorcategory-map-setenum"></a>
##### `TensorCategory(A, P): Map, {SetEnum} -> TenCat`

Sets up a covariant tensor space category with specified direction of arrows $A$, and a partition ${\cal P}$ indicating variables to be treated as equivalent. The fiber $A^{-1}(1)$ denotes the covariant variables, $A^{-1}(0)$ identifies the constant variables, and $A^{-1}(-1)$ marks the contra-variant variables.

<a id="function-cotensorcategory-rngintelt-setenum"></a>
##### `CotensorCategory(A, P): [RngIntElt], {SetEnum} -> TenCat`

<a id="function-cotensorcategory-map-setenum"></a>
##### `CotensorCategory(A, P): Map, {SetEnum} -> TenCat`

Sets up a contra-variant tensor space category with specified direction of arrows $A$, and a partition ${\cal P}$ indicating variables to be treated as equivalent. The fiber $A^{-1}(1)$ denotes the covariant variables, $A^{-1}(0)$ identifies the constant variables, and $A^{-1}(-1)$ marks the contra-variant variables.

<a id="example-ex-2873fe"></a>
##### `Example: Basic Tensor Category Construction (ex-2873fe)`

We demonstrate the basic tensor category constructor. The difference between `TensorCategory` and `CotensorCategory` is only that the former is covariant and the latter is contravariant.

```magma
> C := TensorCategory([1,0,-1], {{0},{1},{2}});
> C;
Tensor category of valence 3 (->,==,<-) ({ 1 },{ 2 },{ 0 })
> IsCovariant(C);
true
>
> arrows := map< {1..5} -> {1} | x :-> 1 >;
> C := CotensorCategory(arrows, {{1..5}});
> C;
Cotensor category of valence 6 (->,->,->,->,->,==) ({ 0 },{ 1 .. 5 })
> IsContravariant(C);
true
```

<a id="function-homotopismcategory-rngintelt"></a>
##### `HomotopismCategory(v : parameters): RngIntElt -> TenCat`

```magma
Contravariant: BoolElt                    Default: false
```

Returns Albert’s homotopism category – all modules categories are covariant and no duplicates considered. Set the optional parameter `Contravariant` to `true` to make it a cotensor category.

<a id="function-cohomotopismcategory-rngintelt"></a>
##### `CohomotopismCategory(v): RngIntElt -> TenCat`

Returns the cohomotopism category – all domain modules categories are covariant, the codomain is contravariant, and no duplicates considered.

<a id="function-adjointcategory-rngintelt-rngintelt-rngintelt"></a>
##### `AdjointCategory(v, s, t): RngIntElt, RngIntElt, RngIntElt -> TenCat`

<a id="function-linearcategory-rngintelt-rngintelt-rngintelt"></a>
##### `LinearCategory(v, s, t): RngIntElt, RngIntElt, RngIntElt -> TenCat`

Returns the tensor category where all modules are constant except in position $s$ and $t$. Both $s$ and $t$ are in $[v]$. Position $s$ is covariant, position $t$ is contravariant.

<a id="example-ex-f54041"></a>
##### `Example: Special Tensor Category Constructors (ex-f54041)`

Now we look at a few special tensor category constructors. The default tensor category is the homotopism category, so we construct the homotopism category using `TensorCategory` and verify they are equivalent.

```magma
> C := TensorCategory([1,1,1,1], {{i} : i in [0..3]});
> C;
Tensor category of valence 4 (->,->,->,->) ({ 1 },{ 2 },{ 0 },{ 3 })
> HomotopismCategory(4) eq C;
true
```

The other special tensor categories can be constructed using `TensorCategory` as well, but we just construct a few to show their properties.

```magma
> CohomotopismCategory(3);
Tensor category of valence 3 (->,->,<-) ({ 1 },{ 2 },{ 0 })
>
> AdjointCategory(5, 4, 1);
Tensor category of valence 5 (<-,==,==,->,==) ({ 1 },{ 0, 2, 3 },{ 4 })
```

#### Operations on Tensor Categories

In this section the basic operations for tensor categories are described.

<a id="operation-op-eq-tencat-tencat"></a>
##### `C1 eq C2: TenCat, TenCat -> BoolElt`

Returns `true` if the tensor categories are the same.

<a id="function-valence-tencat"></a>
##### `Valence(C): TenCat -> RngIntElt`

Returns the valence of the tensor category.

<a id="function-arrows-tencat"></a>
##### `Arrows(C): TenCat -> SeqEnum`

Returns the sequence of arrows of the tensor category. A $-1$ signifies a contravariant index, a $0$ signifies a constant index, and a $1$ signifies a covariant index.

<a id="function-repeatpartition-tencat"></a>
##### `RepeatPartition(C): TenCat -> SetEnum`

Returns the repeat partition for the tensor category.

<a id="function-iscovariant-tencat"></a>
##### `IsCovariant(C): TenCat -> BoolElt`

<a id="function-iscontravariant-tencat"></a>
##### `IsContravariant(C): TenCat -> BoolElt`

Returns `true` if the tensor category is covariant or contravariant.

<a id="example-ex-d61054"></a>
##### `Example: Properties of Tensor Categories (ex-d61054)`

We obtain basic properties of tensor categories.

```magma
> C := CotensorCategory([1,0,-1,1],{{4,3},{1},{2}});
> C;
Cotensor category of valence 5 (->,==,<-,->,==) ({ 1 },{ 2 },{ 0 },{ 3, 4 })
>
> Valence(C);
5
> Arrows(C);
[ 1, 0, -1, 1 ]
> IsContravariant(C);
true
> RepeatPartition(C);
{
    { 1 },
    { 2 },
    { 3, 4 }
}
```

#### Categorical Operations

In this section, we define subtensors, local ideals, ideals, and quotients of tensors. For the following definitions fix a tensor $t\in T$, with frame $\oslash_{a\in[\nu]}U_a$—that is $U_{\nu}\times\cdots\times U_1\rightarrowtail U_0$.

A tensor $s:V_{\nu}\times \cdots\times V_1\rightarrowtail V_0$ is a *subtensor* of $t$ if for all $a$, $V_a\leq U_a$.

For $A\subseteq [\nu]-0$, a tensor $s:V_{\nu}\times \cdots\times V_1\rightarrowtail V_0$ is an $A$*-local ideal* of $t$ if $s$ is a subtensor of $t$ and for each $a\in A$,

$$
\langle s \,|\, V_{\nu},\dots, V_{a+1}, U_a,
V_{a-1},\dots, V_1\rangle \leq V_0.
$$

A tensor $s$ is an *ideal* of $t$ if it is a $\{1,\dots,\nu\}$-local ideal of $t$.

The $A$*-local quotient* of a tensor $t$ by an $A$-local ideal $s$ is the tensor $q:U_{\nu}/V_{\nu} \times \cdots \times U_1/V_1\rightarrowtail U_0/V_0$ where for all $| \overline{\nu}\rangle$,

$$
\langle q \,|\, \overline{\nu}\rangle
\equiv \langle q \,|\, \nu\rangle \rm{mod} V_0.
$$

The *quotient* of a tensor $t$ by an ideal $s$ is the $\{1,\dots,\nu\}$-local quotient of $t$ by $s$.

##### Categorical Operations on Tensors

We include functions defined for the category of tensors. Most functions are currently defined only for the homotopism category.

<a id="function-subtensor-tenspcelt-list"></a>
###### `Subtensor(T, S): TenSpcElt, List -> TenSpcElt`

<a id="function-subtensor-tenspcelt-seqenum"></a>
###### `Subtensor(T, S): TenSpcElt, SeqEnum -> TenSpcElt`

Returns the smallest submap of $T$ containing $S$.

<a id="function-subtensor-tenspcelt-list-any"></a>
###### `Subtensor(T, D, C): TenSpcElt, List, Any -> TenSpcElt`

<a id="function-subtensor-tenspcelt-seqenum-any"></a>
###### `Subtensor(T, D, C): TenSpcElt, SeqEnum, Any -> TenSpcElt`

Returns the smallest submap of $T$ containing $D$ in the domain and $C$ in the codomain.

<a id="function-issubtensor-tenspcelt-tenspcelt"></a>
###### `IsSubtensor(T, S): TenSpcElt, TenSpcElt -> BoolElt`

Decides whether $S$ is a subtensor of $T$.

<a id="example-ex-b3fa65"></a>
###### `Example: Subtensors of Octonion Multiplication (ex-b3fa65)`

We construct the tensor $t$ given by octonion multiplication. The quaternions $H$ are a subalgebra of $A= O$ generated by the first four basis elements. However, $H$ cannot be coerced into $A$ because of how Magma organizes algebras.

```magma
> A := OctonionAlgebra(Rationals(), -1, -1, -1);
> t := Tensor(A);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 8 over Rational Field
U1 : Full Vector space of degree 8 over Rational Field
U0 : Full Vector space of degree 8 over Rational Field
> H := sub< A | A.1, A.2, A.3, A.4 >;
> H;
Algebra of dimension 4 with base ring Rational Field
```

There are multiple ways to get the subtensor of multiplication from $H$. We will create $H\times H\rightarrowtail H$ as a subtensor of $A\times A\rightarrowtail A$.

```magma
> H_gens := [A.i : i in [1..4]];
> s := Subtensor(t, [*H_gens, H_gens, A!0*]);
> s;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Vector space of degree 8, dimension 4 over Rational Field
Generators:
(1 0 0 0 0 0 0 0)
(0 1 0 0 0 0 0 0)
(0 0 1 0 0 0 0 0)
(0 0 0 1 0 0 0 0)
Echelonized basis:
(1 0 0 0 0 0 0 0)
(0 1 0 0 0 0 0 0)
(0 0 1 0 0 0 0 0)
(0 0 0 1 0 0 0 0)
U1 : Vector space of degree 8, dimension 4 over Rational Field
Generators:
(1 0 0 0 0 0 0 0)
(0 1 0 0 0 0 0 0)
(0 0 1 0 0 0 0 0)
(0 0 0 1 0 0 0 0)
Echelonized basis:
(1 0 0 0 0 0 0 0)
(0 1 0 0 0 0 0 0)
(0 0 1 0 0 0 0 0)
(0 0 0 1 0 0 0 0)
U0 : Vector space of degree 8, dimension 4 over Rational Field
Generators:
(1 0 0 0 0 0 0 0)
(0 1 0 0 0 0 0 0)
(0 0 1 0 0 0 0 0)
(0 0 0 1 0 0 0 0)
Echelonized basis:
(1 0 0 0 0 0 0 0)
(0 1 0 0 0 0 0 0)
(0 0 1 0 0 0 0 0)
(0 0 0 1 0 0 0 0)
```

Note that because $H$ cannot be coerced into $A$ (i.e. `A!H` produces an error), a subtensor of `AlgGen` cannot be done by `Subtensor(t, [H, H, H])`. Now we will construct the tensor straight from $H$. There is a subtle difference between the subtensor from $A$ and the tensor from $H$—namely, the frame is different.

```magma
> s2 := Tensor(H);
> s2;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 4 over Rational Field
U1 : Full Vector space of degree 4 over Rational Field
U0 : Full Vector space of degree 4 over Rational Field
> s eq s2;
false
> Eltseq(s) eq Eltseq(s2);
true
```

<a id="function-localideal-tenspcelt-list-rngintelt"></a>
###### `LocalIdeal(T, S, I): TenSpcElt, List, {RngIntElt} -> TenSpcElt`

<a id="function-localideal-tenspcelt-seqenum-rngintelt"></a>
###### `LocalIdeal(T, S, I): TenSpcElt, SeqEnum, {RngIntElt} -> TenSpcElt`

Returns the local ideal of $T$ at $I$ containing $S$.

<a id="function-localideal-tenspcelt-list-any-rngintelt"></a>
###### `LocalIdeal(T, D, C, I): TenSpcElt, List, Any, {RngIntElt} -> TenSpcElt`

<a id="function-localideal-tenspcelt-seqenum-any-rngintelt"></a>
###### `LocalIdeal(T, D, C, I): TenSpcElt, SeqEnum, Any, {RngIntElt} -> TenSpcElt`

Returns the local ideal of $T$ at $I$ containing $D$ in the domain and $C$ in the codomain.

<a id="function-localideal-tenspcelt-tenspcelt-rngintelt"></a>
###### `LocalIdeal(T, S, I): TenSpcElt, TenSpcElt, {RngIntElt} -> TenSpcElt`

Returns the local ideal of $T$ at $I$ containing $S$ as a submap.

<a id="function-islocalideal-tenspcelt-tenspcelt-rngintelt"></a>
###### `IsLocalIdeal(T, S, I): TenSpcElt, TenSpcElt, {RngIntElt} -> BoolElt`

Decides if $S$ is a local ideal of $T$ at $I$.

<a id="example-ex-96befc"></a>
###### `Example: Local Ideals of a Tensor (ex-96befc)`

We use the same tensor $t$ as the previous example, multiplication in $A= O$, and we construct the subtensor $t_2$ given by multiplication in $H$. We construct a subtensor $s$ of $t$ as the submap containing $\langle A_2\rangle \times \langle A_1, A_4\rangle \rightarrowtail \langle 0\rangle$, which is equal to $\langle A_2\rangle \times \langle A_1, A_4\rangle \rightarrowtail \langle A_2A_1, A_2A_4\rangle$.

```magma
> A := OctonionAlgebra(Rationals(), -1, -1, -1);
> t := Tensor(A);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 8 over Rational Field
U1 : Full Vector space of degree 8 over Rational Field
U0 : Full Vector space of degree 8 over Rational Field
> H_gens := [A.i : i in [1..4]];
> t2 := Subtensor(t, [*H_gens, H_gens, H_gens*]);
> s := Subtensor(t, [* A.2, [A.1, A.4], A!0 *]);
> s;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Vector space of degree 8, dimension 1 over Rational Field
Generators:
(0 1 0 0 0 0 0 0)
Echelonized basis:
(0 1 0 0 0 0 0 0)
U1 : Vector space of degree 8, dimension 2 over Rational Field
Generators:
(1 0 0 0 0 0 0 0)
(0 0 0 1 0 0 0 0)
Echelonized basis:
(1 0 0 0 0 0 0 0)
(0 0 0 1 0 0 0 0)
U0 : Vector space of degree 8, dimension 2 over Rational Field
Generators:
(0 1 0 0 0 0 0 0)
(0 0 1 0 0 0 0 0)
Echelonized basis:
(0 1 0 0 0 0 0 0)
(0 0 1 0 0 0 0 0)
```

The quaternions are a subalgebra of $A$ generated by $\{A_1,A_2,A_3,A_4\}$. Therefore, the $\{2\}$-local ideal of $s$ in $t$ must contain $A$ in the codomain. However, the $\{2\}$-local ideal of $s$ in $t_2$ must only contain $\langle A_1, A_2, A_3, A_4\}$ in the codomain.

```magma
> s1 := LocalIdeal(t, s, {2});
> Codomain(s1);
Full Vector space of degree 8 over Rational Field
Generators:
(1 0 0 0 0 0 0 0)
(0 1 0 0 0 0 0 0)
(0 0 1 0 0 0 0 0)
(0 0 0 1 0 0 0 0)
(0 0 0 0 1 0 0 0)
(0 0 0 0 0 1 0 0)
(0 0 0 0 0 0 1 0)
(0 0 0 0 0 0 0 1)
> s2 := LocalIdeal(t2, s, {2});
> Codomain(s2);
Vector space of degree 8, dimension 4 over Rational Field
Generators:
(1 0 0 0 0 0 0 0)
(0 1 0 0 0 0 0 0)
(0 0 1 0 0 0 0 0)
(0 0 0 1 0 0 0 0)
Echelonized basis:
(1 0 0 0 0 0 0 0)
(0 1 0 0 0 0 0 0)
(0 0 1 0 0 0 0 0)
(0 0 0 1 0 0 0 0)
```

<a id="function-ideal-tenspcelt-list"></a>
###### `Ideal(T, S): TenSpcElt, List -> TenSpcElt`

<a id="function-ideal-tenspcelt-seqenum"></a>
###### `Ideal(T, S): TenSpcElt, SeqEnum -> TenSpcElt`

Returns the ideal of $T$ containing $S$.

<a id="function-ideal-tenspcelt-list-any"></a>
###### `Ideal(T, D, C): TenSpcElt, List, Any -> TenSpcElt`

<a id="function-ideal-tenspcelt-seqenum-any"></a>
###### `Ideal(T, D, C): TenSpcElt, SeqEnum, Any -> TenSpcElt`

Returns the ideal of $T$ containing $D$ in the domain and $C$ in the codomain.

<a id="function-ideal-tenspcelt-tenspcelt"></a>
###### `Ideal(T, S): TenSpcElt, TenSpcElt -> TenSpcElt`

Returns the ideal of $T$ containing $S$ as a submap.

<a id="function-isideal-tenspcelt-tenspcelt"></a>
###### `IsIdeal(T, S): TenSpcElt, TenSpcElt -> BoolElt`

Decides if $S$ is an ideal of $T$.

<a id="example-ex-fad333"></a>
###### `Example: Ideals of the Tensor of an Algebra (ex-fad333)`

First we will construct the tensor from the ${\mathbb{Q}}$-algebra, ${\mathbb{Q}}^5$.

```magma
> T := KTensorSpace(Rationals(), [5,5,5]);
> A := VectorSpace(Rationals(), 5);
> t := T!0;
> for i in [1..5] do
>   Assign(~t, [i,i,i], 1);
> end for;
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 5 over Rational Field
U1 : Full Vector space of degree 5 over Rational Field
U0 : Full Vector space of degree 5 over Rational Field
> SystemOfForms(t);
[
    [1 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 0 0]
    [0 1 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 0]
    [0 0 1 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]
    [0 0 0 1 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 0 0 0 1]
]
```

Now we will construct the ideal tensor from the subtensor containing $\langle A_1\rangle \times \langle A_2\rangle \rightarrowtail \langle A_3\rangle$. Note that the $\{2\}$-local ideal must include $\langle A_2,A_3\rangle$ in the codomain, and the $\{1\}$-local ideal must contain $\langle A_1,A_3\rangle$ in the codomain.

```magma
> s := Ideal(t, [A.1, A.2, A.3]);
> s;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Vector space of degree 5, dimension 1 over Rational Field
Generators:
(1 0 0 0 0)
Echelonized basis:
(1 0 0 0 0)
U1 : Vector space of degree 5, dimension 1 over Rational Field
Generators:
(0 1 0 0 0)
Echelonized basis:
(0 1 0 0 0)
U0 : Vector space of degree 5, dimension 3 over Rational Field
Generators:
(1 0 0 0 0)
(0 1 0 0 0)
(0 0 1 0 0)
Echelonized basis:
(1 0 0 0 0)
(0 1 0 0 0)
(0 0 1 0 0)
```

Finally, we verify that the subtensor containing $\langle A_1\rangle \times \langle A_2\rangle \rightarrowtail \langle A_2, A_3\rangle$ is not an ideal.

```magma
> r := Subtensor(t, [A.1, A.2], [A.2, A.3]);
> IsIdeal(t, r);
false
```

<a id="function-localquotient-tenspcelt-tenspcelt-rngintelt"></a>
###### `LocalQuotient(T, S, I : parameters): TenSpcElt, TenSpcElt, {RngIntElt} -> TenSpcElt, Hmtp`

```magma
Check: BoolElt                    Default: true
```

Returns the local quotient of $T$ by $S$ at $I\subseteq[\nu]-0$. If you know $S$ is a local ideal of $T$ at $I$, set `Check` to `false` to skip the verification. A homotopism is also returned, mapping from $T$ to $T/S$.

<a id="function-quotient-tenspcelt-tenspcelt"></a>
###### `Quotient(T, S : parameters): TenSpcElt, TenSpcElt -> TenSpcElt, Hmtp`

```magma
Check: BoolElt                    Default: true
```

<a id="operation-op-div-tenspcelt-tenspcelt"></a>
###### `T / S: TenSpcElt, TenSpcElt -> TenSpcElt, Hmtp`

Returns the quotient of $T$ by $S$. If you know $S$ is an ideal of $T$, set `Check` to `false` to skip the verification. A homotopism is also returned, mapping from $T$ to $T/S$.

<a id="example-ex-0f6850"></a>
###### `Example: Fully Nondegenerate Quotient Tensor (ex-0f6850)`

We will demonstrate one of the most common uses for quotienting tensors: constructing the associated fully nondegenerate tensor. We first construct a tensor with a nontrivial radical given by matrix multiplication: $\rm{Mat}_{3\times 2}({\mathbb{Q}})\times {\mathbb{Q}}^3\rightarrowtail {\mathbb{Q}}^3$, where we take a projection of ${\mathbb{Q}}^3$ onto ${\mathbb{Q}}^2$ in the 1 coordinate.

```magma
> K := Rationals();
> F := [*KMatrixSpace(K, 3, 2), VectorSpace(K, 3), VectorSpace(K, 3)*];
> mult := function(x)
>   return Transpose(x[1]*Matrix(2, 1, Eltseq(x[2])[2..3]));
> end function;
> t := Tensor(F, mult);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 6 over Rational Field
U1 : Full Vector space of degree 3 over Rational Field
U0 : Full Vector space of degree 3 over Rational Field
> s := Subtensor(t, [*[F[1].1, F[1].4], F[2], F[3]*]);
> s;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Vector space of degree 6, dimension 2 over Rational Field
Generators:
(1 0 0 0 0 0)
(0 0 0 1 0 0)
Echelonized basis:
(1 0 0 0 0 0)
(0 0 0 1 0 0)
U1 : Full Vector space of degree 3 over Rational Field
Generators:
(1 0 0)
(0 1 0)
(0 0 1)
U0 : Full Vector space of degree 3 over Rational Field
Generators:
(1 0 0)
(0 1 0)
(0 0 1)
> IsFullyNondegenerate(s);
false
```

Now we will construct the ideal $r$ that evaluates to 0 and the largest subspace of ${\mathbb{Q}}^3$ not contained in the image.

```magma
> r := Ideal(t, [*F[1]!0, F[2].1, F[3].3*]);
> r;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Vector space of degree 6, dimension 0 over Rational Field
Generators:

U1 : Vector space of degree 3, dimension 1 over Rational Field
Generators:
(1 0 0)
Echelonized basis:
(1 0 0)
U0 : Vector space of degree 3, dimension 1 over Rational Field
Generators:
(0 0 1)
Echelonized basis:
(0 0 1)
> IsIdeal(t, r);
true
```

Finally, we quotient $s$ by $r$ to obtain a fully nondegenerate tensor.

```magma
> q := s/r;
> q;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 2 over Rational Field
U1 : Full Vector space of degree 2 over Rational Field
U0 : Full Vector space of degree 2 over Rational Field
> IsFullyNondegenerate(q);
true
```

##### Categorical Operations on Tensor Spaces

We have categorical notions for tensor spaces as well, and these are inherited from the module structure on tensor spaces.

<a id="function-subconstructor-tenspc-any"></a>
###### `SubConstructor(T, L): TenSpc, Any -> TenSpc, Map`

<a id="constructor-constructor-sub-tenspc-any-tenspc-map"></a>
###### `sub< T | L >: TenSpc, Any -> TenSpc, Map`

Returns the subtensor space of $T$ generated by the tensors in the sequence $L$.

<a id="function-issubtensorspace-tenspc-tenspc"></a>
###### `IsSubtensorSpace(T, S): TenSpc, TenSpc -> BoolElt`

Decides if the tensor space $S$ is a subtensor space of $T$.

<a id="example-ex-40cd43"></a>
###### `Example: Subspace of Symmetric Forms (ex-40cd43)`

We will construct the subspace $S$ of symmetric forms from the tensor space $T$ with frame ${\mathbb{Q}}^2\times{\mathbb{Q}}^2\rightarrowtail {\mathbb{Q}}$.

```magma
> K := Rationals();
> T := KTensorSpace(K, [2,2,1]);
> T;
Tensor space of dimension 4 over Rational Field with valence 3
U2 : Full Vector space of degree 2 over Rational Field
U1 : Full Vector space of degree 2 over Rational Field
U0 : Full Vector space of degree 1 over Rational Field
> S := sub< T | T.1, T.2+T.3, T.4 >;
> S;
Tensor space of dimension 3 over Rational Field with valence 3
U2 : Full Vector space of degree 2 over Rational Field
U1 : Full Vector space of degree 2 over Rational Field
U0 : Full Vector space of degree 1 over Rational Field
> IsSymmetric(S);
true
```

Now we will construct the subspace $A$ of alternating forms from $T$.

```magma
> A := sub< T | T.2-T.3 >;
> A;
Tensor space of dimension 1 over Rational Field with valence 3
U2 : Full Vector space of degree 2 over Rational Field
U1 : Full Vector space of degree 2 over Rational Field
U0 : Full Vector space of degree 1 over Rational Field
> IsAlternating(A);
true
```

Now we verify that $A$ is not a subtensor space of $S$, and thus, we have constructed a direct decomposition of $T$ into its symmetric and alternating space.

```magma
> IsSubtensorSpace(S, A);
false
```

<a id="function-quoconstructor-tenspc-any"></a>
###### `QuoConstructor(T, X): TenSpc, Any -> TenSpc, Map`

<a id="constructor-constructor-quo-tenspc-any-tenspc-map"></a>
###### `quo< T | X >: TenSpc, Any -> TenSpc, Map`

<a id="operation-op-div-tenspc-tenspc"></a>
###### `T / S: TenSpc, TenSpc -> TenSpc, Map`

Returns the quotient tensor space of $T$ by $S$.

<a id="example-ex-87c8de"></a>
###### `Example: Quotients of Tensor Spaces (ex-87c8de)`

We pick up with the same tensor spaces as the previous example: $T$ has frame ${\mathbb{Q}}^2\times{\mathbb{Q}}^2\rightarrowtail {\mathbb{Q}}$, $S$ is the symmetric subspace, and $A$ is the alternating subspace.

```magma
> K := Rationals();
> T := KTensorSpace(K, [2,2,1]);
> T;
Tensor space of dimension 4 over Rational Field with valence 3
U2 : Full Vector space of degree 2 over Rational Field
U1 : Full Vector space of degree 2 over Rational Field
U0 : Full Vector space of degree 1 over Rational Field
> S := sub< T | T.1, T.2+T.3, T.4 >;
> A := sub< T | T.2-T.3 >;
```

Now we construct the quotient of $T$ by $A$. The result is not a symmetric tensor space. Note that $Q_2$ is equivalent to a symmetric tensor modulo $A$, but this choice is arbitrary.

```magma
> Q := T/A;
> Q;
Tensor space of dimension 3 over Rational Field with valence 3
U2 : Full Vector space of degree 2 over Rational Field
U1 : Full Vector space of degree 2 over Rational Field
U0 : Full Vector space of degree 1 over Rational Field
> SystemOfForms(Q.1);
[
    [1 0]
    [0 0]
]
> SystemOfForms(Q.2);
[
    [0 0]
    [1 0]
]
> SystemOfForms(Q.3);
[
    [0 0]
    [0 1]
]
```

#### Homotopisms

Magma provides functions for homotopisms, i.e. morphisms of tensors. Homotopisms are also equipped with a tensor category. Because homotopisms can contain multiple maps between modules, it is not really clear what is meant by the domain or codomain of a given homotopism. In this context, the *domain* of a homotopism $H$ will refer to the tensor, $t:U_{\nu}\times \cdots \times U_1\rightarrowtail U_0$, where an arrow equal to $1$ at coordinate $a$ will mean that the corresponding map at coordinate $a$ has domain equal to $U_a$. And in the same vain, the tensor $s:V_{\nu} \times\cdots \times V_1\rightarrowtail V_0$ is the *codomain* of $H$ if an arrow equal to $1$ at coordinate $a$ implies that the corresponding map at coordinate $a$ has codomain equal to $V_a$.

##### Constructions of Homotopisms

<a id="function-homotopism-tenspcelt-tenspcelt-list"></a>
###### `Homotopism(T, S, M : parameters): TenSpcElt, TenSpcElt, List -> Hmtp`

<a id="function-homotopism-tenspcelt-tenspcelt-seqenum"></a>
###### `Homotopism(T, S, M : parameters): TenSpcElt, TenSpcElt, SeqEnum -> Hmtp`

```magma
Check: BoolElt                    Default: true
```

<a id="function-homotopism-tenspcelt-tenspcelt-list-tencat"></a>
###### `Homotopism(T, S, M, C : parameters): TenSpcElt, TenSpcElt, List, TenCat -> Hmtp`

<a id="function-homotopism-tenspcelt-tenspcelt-seqenum-tencat"></a>
###### `Homotopism(T, S, M, C : parameters): TenSpcElt, TenSpcElt, SeqEnum, TenCat -> Hmtp`

```magma
Check: BoolElt                    Default: true
```

Returns the homotopism from $T$ to $S$ given by the list of maps $M$ and the category $C$. The default tensor category is the same as tensor categories for $T$ and $S$. If the maps $M$ will produce a homotopism, then set `Check` to `false` to skip the verification.

<a id="function-homotopism-list-tencat"></a>
###### `Homotopism(M, C): List, TenCat -> Hmtp`

<a id="function-homotopism-seqenum-tencat"></a>
###### `Homotopism(M, C): SeqEnum, TenCat -> Hmtp`

Returns the homotopism given by the maps in $M$ with tensor category $C$.

<a id="function-ishomotopism-tenspcelt-tenspcelt-hmtp"></a>
###### `IsHomotopism(T, s, H): TenSpcElt, TenSpcElt, Hmtp -> BoolElt`

<a id="function-ishomotopism-tenspcelt-tenspcelt-list"></a>
###### `IsHomotopism(T, s, M): TenSpcElt, TenSpcElt, List -> BoolElt`

<a id="function-ishomotopism-tenspcelt-tenspcelt-seqenum"></a>
###### `IsHomotopism(T, s, M): TenSpcElt, TenSpcElt, SeqEnum -> BoolElt`

<a id="function-ishomotopism-tenspcelt-tenspcelt-list-tencat"></a>
###### `IsHomotopism(T, s, M, C): TenSpcElt, TenSpcElt, List, TenCat -> BoolElt`

<a id="function-ishomotopism-tenspcelt-tenspcelt-seqenum-tencat"></a>
###### `IsHomotopism(T, s, M, C): TenSpcElt, TenSpcElt, SeqEnum, TenCat -> BoolElt`

Decides if the list of maps $M$ induces a homotopism from $T$ to $S$ in the tensor category $C$. The default tensor category is the homotopism category. If it does induce a homotopism, it is also returned.

<a id="example-ex-6fd856"></a>
###### `Example: Constructing Homotopisms (ex-6fd856)`

We will construct two symmetric tensors $t,s: {\bf F}_{3}^3 \times {\bf F}_{3}^3 \rightarrowtail {\bf F}_{3}^3$ and apply permutations to the bases.

```magma
> T := KTensorSpace(GF(3), [3,3,3]);
> t := T.1+T.14+T.27;
> SystemOfForms(t);
[
    [1 0 0]
    [0 0 0]
    [0 0 0],

    [0 0 0]
    [0 1 0]
    [0 0 0],

    [0 0 0]
    [0 0 0]
    [0 0 1]
]
> s := (T.4+T.10)+(T.8+T.20)+(T.18+T.24);
> SystemOfForms(s);
[
    [0 1 0]
    [1 0 0]
    [0 0 0],

    [0 0 1]
    [0 0 0]
    [1 0 0],

    [0 0 0]
    [0 0 1]
    [0 1 0]
]
```

Now we construct a homotopism from $t$ to $t$ given by apply a permutation matrix in every coordinate.

```magma
> P := PermutationMatrix(GF(3), [2,1,3]);
> H := Homotopism(t, t, [*P, P, P*]);
> H;
Maps from U2 x U1 >-> U0 to V2 x V1 >-> V0.
U2 -> V2:
[0 1 0]
[1 0 0]
[0 0 1]
U1 -> V1:
[0 1 0]
[1 0 0]
[0 0 1]
U0 -> V0:
[0 1 0]
[1 0 0]
[0 0 1]
```

Note that this permutation matrix does not induce a homotopism of $s$.

```magma
> IsHomotopism(s, s, [*P, P, P*]);
false
```

<a id="example-ex-d02f12"></a>
###### `Example: Homotopisms from Mixed Maps (ex-d02f12)`

Homotopisms can take mixed categories of maps. To reuse the above example, we can encode the permutation as a `Map` and construct homotopisms from these types.

```magma
> V := VectorSpace(GF(3), 3);
> T := TensorSpace([V, V, V]);
> t := T.1+T.14+T.27;
> P := PermutationMatrix(GF(3), [2,1,3]);
> f := hom< V -> V | [<V.1, V.2>, <V.2, V.1>, <V.3, V.3>] >;
> H := Homotopism(t, t, [*f, f, f*]);
> H;
Maps from U2 x U1 >-> U0 to V2 x V1 >-> V0.
U2 -> V2: Mapping from: Full Vector space of degree 3 over GF(3) to Full
Vector space of degree 3 over GF(3)
U1 -> V1: Mapping from: Full Vector space of degree 3 over GF(3) to Full
Vector space of degree 3 over GF(3)
U0 -> V0: Mapping from: Full Vector space of degree 3 over GF(3) to Full
Vector space of degree 3 over GF(3)
```

Furthermore, we can input lists with types `Mtrx` and `Map` included.

```magma
> H2 := Homotopism(t, t, [*P, f, P*]);
> H2;
Maps from U2 x U1 >-> U0 to V2 x V1 >-> V0.
U2 -> V2:
[0 1 0]
[1 0 0]
[0 0 1]
U1 -> V1: Mapping from: Full Vector space of degree 3 over GF(3) to Full
Vector space of degree 3 over GF(3)
U0 -> V0:
[0 1 0]
[1 0 0]
[0 0 1]
```

##### Basic Operations with Homotopisms

We provide some operations for homotopisms.

<a id="operation-op-times-hmtp-hmtp"></a>
###### `H1 * H2: Hmtp, Hmtp -> Hmtp`

Returns the composition of the homotopisms $H_1$ and $H_2$.

<a id="operation-operation-hmtp-rngintelt-map"></a>
###### `H . a: Hmtp, RngIntElt -> Map`

Returns the map on the $a$th coordinate.

<a id="example-ex-c4051c"></a>
###### `Example: Operations with Homotopisms (ex-c4051c)`

We construct a nondegenerate alternating form $t$ on $V={\mathbb{Q}}^6$. The group of isometries are isomorphic to $\rm{Sp}(6, {\mathbb{Q}})$, the group generated by all transvections. We construct a transvection $L$ and a corresponding matrix.

```magma
> V := VectorSpace(Rationals(), 6);
> T := KTensorSpace(Rationals(), [6, 6, 1]);
> t := T.2-T.7+T.16-T.21+T.30-T.35;
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 6 over Rational Field
U1 : Full Vector space of degree 6 over Rational Field
U0 : Full Vector space of degree 1 over Rational Field
>
> u := V.2+2*V.3-V.5;
> L := map< V -> V | x :-> x + (x*t*u)[1]*u >;
> L;
Mapping from: ModTupFld: V to ModTupFld: V given by a rule [no inverse]
> M := Matrix(6, 6, [V.i @ L : i in [1..6]]);
> M;
[ 1  1  2  0 -1  0]
[ 0  1  0  0  0  0]
[ 0  0  1  0  0  0]
[ 0 -2 -4  1  2  0]
[ 0  0  0  0  1  0]
[ 0  1  2  0 -1  1]
```

We construct a homotopism from the transvection.

```magma
> H := Homotopism(t, t, [*L, L, IdentityMatrix(Rationals(), 1)*]);
> H;
Maps from U2 x U1 >-> U0 to V2 x V1 >-> V0.
U2 -> V2: Mapping from: Full Vector space of degree 6 over Rational Field to
Full Vector space of degree 6 over Rational Field given by a rule [no inverse]
U1 -> V1: Mapping from: Full Vector space of degree 6 over Rational Field to
Full Vector space of degree 6 over Rational Field given by a rule [no inverse]
U0 -> V0:
[1]
```

Since $H$ is an isometry of $t$, $H^2$ is also an isometry of $t$. We verify that the 2-coordinate map of $H^2$ is exactly $M^2$.

```magma
> H2 := H*H;
> H2;
Maps from U2 x U1 >-> U0 to V2 x V1 >-> V0.
U2 -> V2: Mapping from: Full Vector space of degree 6 over Rational Field to
Full Vector space of degree 6 over Rational Field
Composition of Mapping from: Full Vector space of degree 6 over Rational Field
to Full Vector space of degree 6 over Rational Field given by a rule [no
inverse] and
Mapping from: Full Vector space of degree 6 over Rational Field to Full Vector
space of degree 6 over Rational Field given by a rule [no inverse]
U1 -> V1: Mapping from: Full Vector space of degree 6 over Rational Field to
Full Vector space of degree 6 over Rational Field
Composition of Mapping from: Full Vector space of degree 6 over Rational Field
to Full Vector space of degree 6 over Rational Field given by a rule [no
inverse] and
Mapping from: Full Vector space of degree 6 over Rational Field to Full Vector
space of degree 6 over Rational Field given by a rule [no inverse]
U0 -> V0:
[1]
> M2 := Matrix(6, 6, [V.i @ H2.2 : i in [1..6]]);
> M2;
[ 1  2  4  0 -2  0]
[ 0  1  0  0  0  0]
[ 0  0  1  0  0  0]
[ 0 -4 -8  1  4  0]
[ 0  0  0  0  1  0]
[ 0  2  4  0 -2  1]
> M^2 eq M2;
true
```

<a id="function-precompose-tenspcelt-map-rngintelt"></a>
###### `Precompose(T, f, a): TenSpcElt, Map, RngIntElt -> TenSpcElt`

<a id="function-precompose-tenspcelt-mtrx-rngintelt"></a>
###### `Precompose(T, M, a): TenSpcElt, Mtrx, RngIntElt -> TenSpcElt`

If $a>0$, then the tensor returned is the tensor that has been pre-composed by the map $f$ or matrix $M$.

<a id="operation-operation-tenspcelt-hmtp-tenspcelt"></a>
###### `T @ H: TenSpcElt, Hmtp -> TenSpcElt`

If $H$ is a cohomotopism (a homotopism in the cohomotopism category), then either the domain or codomain of $H$ is returned, depending on the orientation of the arrows of $H$.

##### Basic Properties of Homotopisms

<a id="function-domain-hmtp"></a>
###### `Domain(H): Hmtp -> TenSpcElt`

Returns the domain tensor of $H$.

<a id="function-codomain-hmtp"></a>
###### `Codomain(H): Hmtp -> TenSpcElt`

Returns the codomain tensor of $H$.

<a id="function-maps-hmtp"></a>
###### `Maps(H): Hmtp -> List`

Returns the list of maps for the various modules in the domain and codomain tensors.

<a id="function-tensorcategory-hmtp"></a>
###### `TensorCategory(H): Hmtp -> TenCat`

Returns the tensor category of $H$.

<a id="function-changetensorcategory-hmtp-tencat"></a>
###### `ChangeTensorCategory(H, C): Hmtp, TenCat -> Hmtp`

<a id="procedure-changetensorcategory-hmtp-tencat-ref"></a>
###### `ChangeTensorCategory(~H, C): Hmtp, TenCat`

Changes the tensor category of $H$ to the given category.

<a id="function-valence-hmtp"></a>
###### `Valence(H): Hmtp -> RngIntElt`

Returns the valence of the underlying tensor category of the homotopism $H$.

<a id="function-kernel-hmtp"></a>
###### `Kernel(H): Hmtp -> TenSpcElt`

Returns the kernel of $H$ as an ideal of its domain tensor.

<a id="function-image-hmtp"></a>
###### `Image(H): Hmtp -> TenSpcElt`

Returns the image of $H$ as a submap of the codomain tensor.

<a id="example-ex-5a1efc"></a>
###### `Example: Properties of Homotopisms (ex-5a1efc)`

We demonstrate how to access properties of a homotopism. We construct tensors $t:{\mathbb{Q}}^4\times{\mathbb{Q}}^4\rightarrowtail {\mathbb{Q}}$ and $s:{\mathbb{Q}}^6\times{\mathbb{Q}}^6\rightarrowtail{\mathbb{Q}}$ given by the dot product.

```magma
> t := Tensor(IdentityMatrix(Rationals(), 4), 2, 1);
> s := Tensor(IdentityMatrix(Rationals(), 6), 2, 1);
> Z := ZeroMatrix(Rationals(), 4, 6);
> M := InsertBlock(Z, IdentityMatrix(Rationals(), 4), 1, 1);
> H := Homotopism(t, s, [*M, M, IdentityMatrix(Rationals(), 1)*]);
> H;
Maps from U2 x U1 >-> U0 to V2 x V1 >-> V0.
U2 -> V2:
[1 0 0 0 0 0]
[0 1 0 0 0 0]
[0 0 1 0 0 0]
[0 0 0 1 0 0]
U1 -> V1:
[1 0 0 0 0 0]
[0 1 0 0 0 0]
[0 0 1 0 0 0]
[0 0 0 1 0 0]
U0 -> V0:
[1]
```

Like with maps, we can obtain standard properties of homotopisms.

```magma
> Domain(H);
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 4 over Rational Field
U1 : Full Vector space of degree 4 over Rational Field
U0 : Full Vector space of degree 1 over Rational Field
> Codomain(H);
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 6 over Rational Field
U1 : Full Vector space of degree 6 over Rational Field
U0 : Full Vector space of degree 1 over Rational Field
> Maps(H);
[*
    [1 0 0 0 0 0]
    [0 1 0 0 0 0]
    [0 0 1 0 0 0]
    [0 0 0 1 0 0],

    [1 0 0 0 0 0]
    [0 1 0 0 0 0]
    [0 0 1 0 0 0]
    [0 0 0 1 0 0],

    [1]
*]
> TensorCategory(H);
Tensor category of valence 3 (->,->,->) ({ 1 },{ 2 },{ 0 })
```

When the image and kernel can be computed for the each of the maps in the homotopism, then the image and kernel can be computed for the homotopism.

```magma
> Im := Image(H);
> Im;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Vector space of degree 6, dimension 4 over Rational Field
Echelonized basis:
(1 0 0 0 0 0)
(0 1 0 0 0 0)
(0 0 1 0 0 0)
(0 0 0 1 0 0)
U1 : Vector space of degree 6, dimension 4 over Rational Field
Echelonized basis:
(1 0 0 0 0 0)
(0 1 0 0 0 0)
(0 0 1 0 0 0)
(0 0 0 1 0 0)
U0 : Full Vector space of degree 1 over Rational Field
> Ker := Kernel(H);
> Ker;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Vector space of degree 4, dimension 0 over Rational Field
U1 : Vector space of degree 4, dimension 0 over Rational Field
U0 : Vector space of degree 1, dimension 0 over Rational Field
```

<a id="function-shuffle-hmtp-grppermelt"></a>
###### `Shuffle(H, g): Hmtp, GrpPermElt -> Hmtp`

<a id="function-shuffle-hmtp-rngintelt"></a>
###### `Shuffle(H, g): Hmtp, [RngIntElt] -> Hmtp`

Just like the shuffle for tensors, this returns the shuffle of the homotopism $H$. This is a functor from one tensor category to another and changes the order of the maps to

$$
\{H_{\nu^g},\dots, H_{1^g}, H_{0^g}\}.
$$

In order to be defined, $g\in{\operatorname{Sym}}(\{0,\dots,\nu \})$. If $0^g\ne 0$, then both the image and pre-image of $0$ under $g$ will be replaced by their $K$-dual space. For cotensors, $g\in{\operatorname{Sym}}(\{1,\dots,\nu\})$. Sequences $[a_1,\dots,a_{\nu+1}]$ will be interpreted as a permutation in one-line notation.

<a id="ch-invariants"></a>
<a id="id1"></a>
### Linear Invariants of Tensors

#### Invariants for Bilinear Tensors

The following intrinsics are specialized for tensors of valence 3, but equivalent intrinsics for general tensors are presented in the proceeding subsection.

<a id="function-adjointalgebra-tenspcelt"></a>
##### `AdjointAlgebra(B): TenSpcElt -> AlgMat`

Returns the adjoint $*$-algebra of the given Hermitian bilinear map $B$, represented on $\rm{End}(U_2)$. This is using algorithms from StarAlge, see the `AdjointAlgebra` intrinsic in [[BW](https://docs.magma-maths.org/references.md#cite-bw-staralge)]. If the current version of StarAlge is not attached, the default Magma version will be used instead.

<a id="example-ex-55dbd9"></a>
##### `Example: Adjoint Algebra of a p-Group Tensor (ex-55dbd9)`

Given the context of [[BW12b](https://docs.magma-maths.org/references.md#cite-bw-isometry)], we construct a tensor from a $p$-group and compute its adjoint algebra.

```magma
> G := SmallGroup(3^7, 7000);
> t := pCentralTensor(G);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 4 over GF(3)
U1 : Full Vector space of degree 4 over GF(3)
U0 : Full Vector space of degree 3 over GF(3)
```

Unlike other intrinsics that compute invariants of tensors, `AdjointAlgebra` exploits the fact that $t$ is Hermitian so that the adjoint algebra is faithfully represented on $\rm{End}(U_2)=\rm{End}(U_1)$.

```magma
> A := AdjointAlgebra(t);
> A;
Matrix Algebra of degree 4 and dimension 4 with 4 generators over GF(3)
> A.1;
[1 0 0 0]
[0 0 0 0]
[0 0 0 0]
[0 0 0 1]
```

Because $A$ is constructed from algorithms for $*$-algebras, we can apply other algorithms from that package specifically dealing with the involution on $A$.

```magma
> RecognizeStarAlgebra(A);
true
> SimpleParameters(A);
[ <"symplectic", 2, 3> ]
> Star(A);
Mapping from: AlgMat: A to AlgMat: A given by a rule [no inverse]
```

<a id="function-leftnucleus-tenspcelt"></a>
##### `LeftNucleus(B : parameters): TenSpcElt -> AlgMat`

```magma
op: BoolElt                    Default: false
```

Returns the left nucleus of the bilinear map $B$ as a subalgebra of $\rm{End}_K(U_2)\times \rm{End}_K(U_0)$. In previous versions of TensorSpace (and eMAGma), the left nucleus was returned as a subalgebra of $\rm{End}(U_2)^\circ\times \rm{End}(U_0)^\circ$. To enable this, set the optional argument `op` to `true`.

<a id="function-midnucleus-tenspcelt"></a>
##### `MidNucleus(B): TenSpcElt -> AlgMat`

Returns the mid nucleus of the bilinear map $B$ as a subalgebra of $\rm{End}_K(U_2)\times \rm{End}_K(U_1)$.

<a id="function-rightnucleus-tenspcelt"></a>
##### `RightNucleus(B): TenSpcElt -> AlgMat`

Returns the right nucleus of the bilinear map $B$ as a subalgebra of $\rm{End}_K(U_1)\times \rm{End}_K(U_0)$.

<a id="example-ex-75db37"></a>
##### `Example: Nuclei Embed in the Derivation Algebra (ex-75db37)`

We will verify a theorem from [[FMW19](https://docs.magma-maths.org/references.md#cite-fmw-densors)] and [[Wil17](https://docs.magma-maths.org/references.md#cite-wilson-lmr)]: all the nuclei of a tensor embed into the derivation algebra. We construct the tensor given by $(3\times 4\times 5)$-matrix multiplication.

```magma
> K := Rationals();
> A := KMatrixSpace(K, 3, 4);
> B := KMatrixSpace(K, 4, 5);
> C := KMatrixSpace(K, 3, 5);
> F := func< x | x[1]*x[2] >;
> t := Tensor([A, B, C], F);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 12 over Rational Field
U1 : Full Vector space of degree 20 over Rational Field
U0 : Full Vector space of degree 15 over Rational Field
```

Because matrix multiplication is associative, the left, middle, and right nuclei contain $\rm{Mat}_3({\mathbb{Q}})$, $\rm{Mat}_4({\mathbb{Q}})$, and $\rm{Mat}_5({\mathbb{Q}})$ respectively. In fact, the following computation shows that this is equality.

```magma
> L := LeftNucleus(t : op := true);
> M := MidNucleus(t);
> R := RightNucleus(t);
> Dimension(L), Dimension(M), Dimension(R);
9 16 25
> D := DerivationAlgebra(t);
> Dimension(D);
49
```

Now we will embed these nuclei into the derivation algebra of $t$.

```magma
> Omega := KMatrixSpace(K, 47, 47);
> Z1 := ZeroMatrix(K, 20, 20);
> L_L2, L2 := Induce(L, 2);
> L_L0, L0 := Induce(L, 0);
> embedL := map< L -> Omega | x :->
>     DiagonalJoin(<Transpose(x @ L_L2), Z1, Transpose(x @ L_L0)>) >;
>
> Z0 := ZeroMatrix(K, 15, 15);
> M_M2, M2 := Induce(M, 2);
> M_M1, M1 := Induce(M, 1);
> embedM := map< M -> Omega | x :->
>     DiagonalJoin(<x @ M_M2, -Transpose(x @ M_M1), Z0>) >;
>
> Z2 := ZeroMatrix(K, 12, 12);
> R_R1, R1 := Induce(R, 1);
> R_R0, R0 := Induce(R, 0);
> embedR := map< R -> Omega | x :->
>     DiagonalJoin(<Z2, x @ R_R1, x @ R_R0>) >;
>
> Random(Basis(L)) @ embedL in D;
true
> Random(Basis(M)) @ embedM in D;
true
> Random(Basis(R)) @ embedR in D;
true
```

#### Invariants of General Multilinear Maps

The following functions can be used for general tensors.

<a id="function-centroid-tenspcelt"></a>
##### `Centroid(T): TenSpcElt -> AlgMat`

<a id="function-centroid-tenspcelt-rngintelt"></a>
##### `Centroid(T, A): TenSpcElt, {RngIntElt} -> AlgMat`

Returns the $A$-centroid of the tensor as a subalgebra of

$$
\prod_{a\in A}\rm{End}(U_a),
$$

where $A\subseteq [\nu]$. If no $A$ is given, it is assumed that $A=[\nu]$. If $t$ is contained in a category where coordinates $a$ and $b$ (also contained in $A$) are fused together, then the corresponding operators on those coordinates will be equal.

<a id="example-ex-71158e"></a>
##### `Example: Centroid of a Multiplication Tensor (ex-71158e)`

The centroid $C$ of a tensor $t$ is the largest ring for which $t$ is $C$-linear, see [[FMW19](https://docs.magma-maths.org/references.md#cite-fmw-densors), Theorem D]. To demonstrate this, we will construct the tensor given by multiplication of the splitting field of $f(x)=x^4-x^2-2$ over ${\mathbb{Q}}$. However, this field won’t explicitly be given with the tensor data.

```magma
> A := MatrixAlgebra(Rationals(), 4);
> R<x> := PolynomialRing(Rationals());
> F := sub< A | A!1, CompanionMatrix(x^4-x^2-2) >;
> F;
Matrix Algebra of degree 4 with 2 generators over Rational Field
> t := Tensor(F);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 4 over Rational Field
U1 : Full Vector space of degree 4 over Rational Field
U0 : Full Vector space of degree 4 over Rational Field
```

The centroid is the field ${\mathbb{Q}}(\sqrt{2},i)$.

```magma
> C := Centroid(t);
> C;
Matrix Algebra of degree 12 with 4 generators over Rational Field
> sub< C | C.1 > eq C;
true
> forall{ c : c in Generators(C) | IsInvertible(c) };
true
> IsCommutative(C);
true
> MinimalPolynomial(C.1);
x^4 + 2*x^2 - 8
> Factorization(MinimalPolynomial(C.1));
[
    <x^2 - 2, 1>,
    <x^2 + 4, 1>
]
```

<a id="function-derivationalgebra-tenspcelt"></a>
##### `DerivationAlgebra(T): TenSpcElt -> AlgMatLie`

<a id="function-derivationalgebra-tenspcelt-rngintelt"></a>
##### `DerivationAlgebra(T, A): TenSpcElt, {RngIntElt} -> AlgMatLie`

Returns the $A$-derivation Lie algebra of the tensor as a Lie subalgebra of

$$
\prod_{a\in A}\rm{End}(U_a),
$$

where $A\subseteq [\nu]$. If no $A$ is given, it is assumed that $A=[\nu]$. If $t$ is contained in a category where coordinates $a$ and $b$ (also contained in $A$) are fused together, then the corresponding operators on those coordinates will be equal.

<a id="function-nucleus-tenspcelt-rngintelt-rngintelt"></a>
##### `Nucleus(T, a, b): TenSpcElt, RngIntElt, RngIntElt -> AlgMat`

<a id="function-nucleus-tenspcelt-setenum"></a>
##### `Nucleus(T, A): TenSpcElt, SetEnum -> AlgMat`

Returns the $A$-nucleus, for $A=\{a,b\}$ ($a\ne b$), of the tensor as a subalgebra of $\rm{End}(U_i)\times \rm{End}(U_j)$, where $i=\max(a,b)$ and $j=\min(a,b)$. If $j>0$, then replace $\rm{End}(U_j)$ with $\rm{End}(U_j)^\circ$. If $T$ is contained in a category where coordinates $a$ and $b$ are fused together, then the corresponding operators on those coordinates will not be forced to be equal.

<a id="example-ex-84e946"></a>
##### `Example: Restricting the Derivation Algebra (ex-84e946)`

In a previous example, we embedded the nuclei of a tensor into the derivation algebra. For a tensor $t: U_{\nu}\times \cdots\times U_1\rightarrowtail U_0$, the derivation algebra is represented in

$$
\Omega=\prod_{a\in[\nu]}\rm{GL}(U_a).
$$

We will restrict the derivation algebra to

$$
\prod_{c\notin\{a,b\}} \rm{GL}(U_c)
$$

for distinct $a,b\in[\nu]$. From [[FMW19](https://docs.magma-maths.org/references.md#cite-fmw-densors), Lemma 4.11], the kernel of this restriction is equal to Nuc$_{\{a,b\}}(t)^-$. We will just verify that the dimensions match.

We will construct a tensor given by matrix multiplication:

$$
\rm{Mat}_{3\times 4}({\bf F}_{2})\times \rm{Mat}_{4\times 2}({\bf F}_{2}) \times \rm{Mat}_{2\times 2}({\bf F}_{2}) \rightarrowtail \rm{Mat}_{3\times 2}({\bf F}_{2}).
$$

```magma
> A := KMatrixSpace(GF(2), 3, 4);
> B := KMatrixSpace(GF(2), 4, 2);
> C := KMatrixSpace(GF(2), 2, 2);
> D := KMatrixSpace(GF(2), 3, 2);
> trip := func< x | x[1]*x[2]*x[3] >;
> t := Tensor([A, B, C, D], trip);
> t;
Tensor of valence 4, U3 x U2 x U1 >-> U0
U3 : Full Vector space of degree 12 over GF(2)
U2 : Full Vector space of degree 8 over GF(2)
U1 : Full Vector space of degree 4 over GF(2)
U0 : Full Vector space of degree 6 over GF(2)
```

Now we will compute the derivation algebra of `t`. We choose $a=3$ and $b=2$, so the $\{3,2\}$-nucleus is $\rm{Mat}_{4\times 4}({\bf F}_{2})$.

```magma
> D := DerivationAlgebra(t);
> Dimension(D);
32
> N32 := Nucleus(t, 3, 2);
> N32;
Matrix Algebra of degree 20 with 16 generators over GF(2)
```

To construct the restriction of $\rm{Der}(t)$ into $\rm{GL}(U_1)\times\rm{GL}(U_0)$ we will use the `Induce` function.

```magma
> Omega_10 := KMatrixSpace(GF(2), 10, 10);
> D_vs := sub< KMatrixSpace(GF(2), 30, 30) | Basis(D) >;
> pi1, D1 := Induce(D, 1);
> pi0, D0 := Induce(D, 0);
> res := hom< D_vs -> Omega_10 |
>     [<x, DiagonalJoin(x @ pi1, x @ pi0)> : x in Basis(D)] >;
> res;
Mapping from: ModMatFld: D_vs to ModMatFld: Omega_10
> Kernel(res);
KMatrixSpace of 30 by 30 matrices and dimension 16 over GF(2)
```

<a id="function-selfadjointalgebra-tenspcelt-rngintelt-rngintelt"></a>
##### `SelfAdjointAlgebra(t, a, b): TenSpcElt, RngIntElt, RngIntElt -> ModMatFld`

Returns the self-adjoint elements of the $ab$-nucleus of $t$ as a subspace of $\rm{End}(U_a)$, with $a,b\in[\nu]$ and $a\ne b$. It is not required that $t$ be in a tensor category with coordinates $a$ and $b$ fused. Unlike other invariants associated to tensors, the self-adjoint algebra is not currently stored with the tensor.

<a id="function-tensorovercentroid-tenspcelt"></a>
##### `TensorOverCentroid(T): TenSpcElt -> TenSpcElt, Hmtp`

If the given tensor $T$ is framed by $K$-vector spaces, then the returned tensor is framed by $E$-vector spaces where $E$ is the residue field of the centroid. The returned homotopism is an isotopism of the $K$-tensors. This only works if the centroid of $T$ is a finite commutative local ring. We employ the algorithms developed by Brooksbank and Wilson [[BW15](https://docs.magma-maths.org/references.md#cite-bw-module-iso)] to efficiently determine if a matrix algebra is cyclic.

<a id="example-ex-93b5e7"></a>
##### `Example: Recovering a Field with the Centroid (ex-93b5e7)`

In the context of groups, centroids can be used to recover an underlying field of a matrix group, even if the given group is not input as such. Here we will construct the exponent-$p$ central tensor of the Sylow 2-subgroup of $\rm{GL}(3,\rm{GF}(2^{10}))$. We will not print the `GrpPC` version of this group as the number of relations is very large.

```magma
> U := ClassicalSylow(GL(3, 2^10), 2);
> U.3;
[       1    $.1^2        0]
[       0        1        0]
[       0        0        1]
> G := PCPresentation(UnipotentMatrixGroup(U));
> #G eq 2^30;
true
> t := pCentralTensor(G);
> t;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 20 over GF(2)
U1 : Full Vector space of degree 20 over GF(2)
U0 : Full Vector space of degree 10 over GF(2)
```

Even though our tensor right now is ${\bf F}_{2}^{20}\times {\bf F}_{2}^{20}\rightarrowtail{\bf F}_{2}^{10}$, we know it is the 2-dimensional alternating form over $\rm{GF}(2^{10})$. We will construct the centroid, and then rewrite our tensor over the centroid to get the tensor we expect.

```magma
> C := Centroid(t);
> C;
Matrix Algebra of degree 50 and dimension 10 with 1 generator over GF(2)
> IsCyclic(C) and IsSimple(C);
true
> s := TensorOverCentroid(t);
> s;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 2 over GF(2^10)
U1 : Full Vector space of degree 2 over GF(2^10)
U0 : Full Vector space of degree 1 over GF(2^10)
```

### Some Extended Examples

In this section some further examples are presented to demonstrate some uses of this package.

#### Distinguishing Groups

<a id="example-ex-d908f2"></a>
##### `Example: Distinguishing Payne's Elation Groups (ex-d908f2)`

We can use these functions to build groups from bilinear maps and distinguish seemingly indistinguishable groups. In 2004, S. E. Payne asked if two elation groups were isomorphic but suspected they were not [[Pay06](https://docs.magma-maths.org/references.md#cite-payne-elation-grps)].

The first group, $G_f$, is the elation group of the generalized quadrangle $H(3,q^2)$, the Hermitian geometry. This group is defined as a Heisenberg group whose bilinear map is the usual dot product.

```magma
> p := 3;
> e := 4;
> q := p^e; // q = 3^e >= 27
> F := [KSpace(GF(q),2), KSpace(GF(q),2), KSpace(GF(q),1)];
>
> DotProd := function(x)
>   return KSpace(GF(q),1)!(x[1]*Matrix(2,1,x[2]));
> end function;
>
> DoubleForm := function(T)
>   F := SystemOfForms(T)[1];
>   K := BaseRing(F);
>   n := Nrows(F);
>   m := Ncols(F);
>   MS := KMatrixSpace(K,n,m);
>   Z := MS!0;
>   M1 := HorizontalJoin(Z,-Transpose(F));
>   M2 := HorizontalJoin(F,Z);
>   D := VerticalJoin( M1, M2 );
>   return Tensor( D, 2, 1 );
> end function;
>
> f := DoubleForm( Tensor( F, DotProd ) );
> f;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 4 over GF(3^4)
U1 : Full Vector space of degree 4 over GF(3^4)
U0 : Full Vector space of degree 1 over GF(3^4)
>
> IsAlternating(f);
true
> Gf := HeisenbergGroupPC(f);
```

Now we define Payne’s second group, $G_{\bar{f}}$, which is the elation group of the Roman quadrangle with parameters $(q^2,q)$. In this example, $\bar{f}$ is a biadditive map, but is bilinear over the prime field ${\mathbb{F}}_3$. Therefore, we construct a vector space isomorphism from ${\mathbb{F}}_3^e$ to ${\mathbb{F}}_{3^e}$ and the bilinear commutator map, induced by $\bar{f}$. Hence, $G_{\bar{f}}$ is the Heisenberg group of this bilinear commutator map.

```magma
> n := PrimitiveElement(GF(q)); // nonsquare
> MS := KMatrixSpace(GF(q),2,2);
> A := MS![-1,0,0,n];
> B := MS![0,1,1,0];
> C := MS![0,0,0,n^-1];
> F1 := Frame(f);
> F2 := [KSpace(GF(p),4*e), KSpace(GF(p),4*e), KSpace(GF(p),e)];
>
> // take 1/3^r root
> Root := function(v,r)
>   k := Eltseq(v)[1];
>   K := Parent(k);
>   if k eq K!0 then return k; end if;
>   R<x> := PolynomialRing(K);
>   f := Factorization(x^(3^r)-k)[1][1];
>   return K!(x-f);
> end function;
>
> // bi-additive map defining elation grp
> RomanGQ := function(x)
>   u := Matrix(1,2,x[1]);
>   v := Matrix(2,1,x[2]);
>   M := [A,B,C];
>   f := &+[Root(u*M[i]*v,i-1) : i in [1..3]];
>   return KSpace(GF(q),1)![f];
> end function;
>
> // vector space isomorphisms
> phi := map< F2[1] -> F1[1] |
>   x :-> F1[1]![ GF(q)![ s : s in Eltseq(x)[i+1..e+i] ] :
>     i in [0,e,2*e,3*e] ] >;
> gamma := map< F1[3] -> F2[3] |
>   x :-> F2[3]!&cat[ Eltseq(s) : s in Eltseq(x) ] >;
>
> // bilinear commutator from RomanGQ
> RomanGQComm := function(x)
>   x1 := Eltseq(x[1]@phi)[1..2];
>   x2 := Eltseq(x[1]@phi)[3..4];
>   y1 := Eltseq(x[2]@phi)[1..2];
>   y2 := Eltseq(x[2]@phi)[3..4];
>   comm := RomanGQ( <x2,y1> ) - RomanGQ( <y2,x1> );
>   return comm @ gamma;
> end function;
>
> f_bar := Tensor( F2, RomanGQComm );
> f_bar;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 16 over GF(3)
U1 : Full Vector space of degree 16 over GF(3)
U0 : Full Vector space of degree 4 over GF(3)
>
> IsAlternating(f_bar);
true
> Gfb := HeisenbergGroupPC(f_bar);
```

The groups $G_f$ and $G_{\bar{f}}$ have order $3^{20}$ and are class 2, exponent 3, and minimally generated by 16 elements. In other words, the groups $G_f$ and $G_{\bar{f}}$ are central extensions of ${\mathbb{Z}}_3^{16}$ by ${\mathbb{Z}}_3^{4}$ and have exponent $3$. Using standard heuristics, these groups are indistinguishable. However, the invariants associated to their exponent-$p$ central tensor are vastly different, and thus, they determine that these groups are nonisomorphic. We show that the centroids of the tensors are not isomorphic.

```magma
> Tf := pCentralTensor(Gf,1,1);
> Tf;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 32 over GF(3)
U1 : Full Vector space of degree 32 over GF(3)
U0 : Full Vector space of degree 4 over GF(3)
>
> Tfb := pCentralTensor(Gfb,1,1);
> Tfb;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 32 over GF(3)
U1 : Full Vector space of degree 32 over GF(3)
U0 : Full Vector space of degree 4 over GF(3)
>
> Cf := Centroid(Tf);
> Cfb := Centroid(Tfb);
> Dimension(Cf) eq Dimension(Cfb);
false
```

#### Simplifying Automorphism Group Computations

<a id="example-ex-c87b8b"></a>
##### `Example: Automorphisms via the Adjoint Algebra (ex-c87b8b)`

We demonstrate how to simplify the automorphism group computation as discussed in [[BW14](https://docs.magma-maths.org/references.md#cite-bw-grps-tensor)]. We construct a class 2, exponent $p$, $p$-group $G$ which is a quotient of a maximal unipotent subgroup of ${\operatorname{GL}}(3,317^4)$.

```magma
> p := 317;
> e := 4;
> H := ClassicalSylow( GL(3,p^e), p );
> U := UnipotentMatrixGroup(H);
> P := PCPresentation(U);
> Z := Center(P);
>
> N := sub< P | >;
> while #N lt p^2 do
>   N := sub< P | Random(Z), N >;
> end while;
>
> G := P/N;
> G;
GrpPC : G of order 10246902931634286779441449 = 317^10
PC-Relations:
    G.5^G.1 = G.5 * G.9^62 * G.10^133,
    G.5^G.2 = G.5 * G.9^312 * G.10^295,
    G.5^G.3 = G.5 * G.9^316,
    G.5^G.4 = G.5 * G.10^316,
    G.6^G.1 = G.6 * G.9^312 * G.10^295,
    G.6^G.2 = G.6 * G.9^316,
    G.6^G.3 = G.6 * G.10^316,
    G.6^G.4 = G.6 * G.9^138 * G.10^163,
    G.7^G.1 = G.7 * G.9^316,
    G.7^G.2 = G.7 * G.10^316,
    G.7^G.3 = G.7 * G.9^138 * G.10^163,
    G.7^G.4 = G.7 * G.9^188 * G.10^50,
    G.8^G.1 = G.8 * G.10^316,
    G.8^G.2 = G.8 * G.9^138 * G.10^163,
    G.8^G.3 = G.8 * G.9^188 * G.10^50,
    G.8^G.4 = G.8 * G.9^125 * G.10^151
```

We construct the exponent-$p$ central tensor of $G$ and compute its adjoint $*$-algebra $A$.

```magma
> T := pCentralTensor(G,1,1);
> T;
Tensor of valence 3, U2 x U1 >-> U0
U2 : Full Vector space of degree 8 over GF(317)
U1 : Full Vector space of degree 8 over GF(317)
U0 : Full Vector space of degree 2 over GF(317)
>
> A := AdjointAlgebra(T);
> Dimension(A);
16
> star := Star(A);
```

If $V=G/\Phi(G)$ is the Frattini quotient of $G$, then our goal is to get the cotensor space $V\wedge_A V$. Note that $\dim V\wedge V=28$, so standard methods will compute a stabilizer of ${\operatorname{GL}}(8,317)$ inside $V\wedge V$. We will decrease the size of the ambient space resulting in an easier stabilizer computation.

```magma
> V := Domain(T)[1];
> E := ExteriorCotensorSpace(V,2);
> E;
Cotensor space of dimension 28 over GF(317) with valence 1
U2 : Full Vector space of degree 8 over GF(317)
U1 : Full Vector space of degree 8 over GF(317)
```

Now we create a sub cotensor space $S$ generated by all $(e_iX)\wedge e_j - e_i\wedge (e_jX)$ for $X\in A$, and then quotient $V\wedge V$ by $S$. The result is a 4 dimensional space.

```magma
> L := [];
> for E_gen in Generators(E) do
>   F := SystemOfForms(E_gen)[1];
>   for X in Basis(A) do
>     L cat:= [E!Eltseq(X*F - F*Transpose(X@star))];
>   end for;
> end for;
>
> S := SubtensorSpace(E,L);
> S;
Cotensor space of dimension 24 over GF(317) with valence 1
U2 : Full Vector space of degree 8 over GF(317)
U1 : Full Vector space of degree 8 over GF(317)
>
> Q := E/S;
> Q;
Cotensor space of dimension 4 over GF(317) with valence 1
U2 : Full Vector space of degree 8 over GF(317)
U1 : Full Vector space of degree 8 over GF(317)
```
