Types, Category Names, and Structures

The following functions deal with types or category names and general structures. Magma has two levels of granularity when referring to types. In most cases, the coarser grained types (of type Cat) are used. Examples of these kinds of types are "polynomial rings" (RngUPol) and "finite fields" (FldFin). However, sometimes more specific typing information is sometimes useful. For instance, the algorithm used to factorize polynomials differs significantly, depending on the coefficient ring. Hence, we might wish to implement a specialized factorization algorithm polynomials over some particular ring type. Due to this need, Magma also supports extended types.

An extended type (of type ECat) can be thought of as a type taking a parameter. Using extended types, we can talk about "polynomial rings over the integers" (RngUPol[RngInt]), or "maps from the integers to the rationals" (Map[RngInt, FldRat]). Extended types can interact with normal types in all ways, and thus generally only need to be used when the extra level of information is required.

Type(x) : Elt -> Cat
Category(x) : Elt -> Cat
Given any object x, return the type (or category name) of x.
ExtendedType(x) : Elt -> ECat
ExtendedCategory(x) : Elt -> ECat
Given any object x, return the extended type (or category name) of x.
ISA(T, U) : Cat, Cat -> BoolElt
ISA(T, U) : Cat, ECat -> BoolElt
ISA(T, U) : ECat, Cat -> BoolElt
ISA(T, U) : ECat, ECat -> BoolElt
Given types (or extended types) T and U, return whether T ISA U, i.e., whether objects of type T inherit properties of type U. For example, ISA(RngInt, Rng) is true, because the ring of integers Z is a ring.
BaseType(T) : ECat -> Cat
Returns the underlying base type of the extended type T.
# T : ECat -> RngIntElt
Returns the number of parametrizing objects for the extended type T.
T[i] : ECat, RngIntElt -> .
The i-th parametrizing object of the extended type T. Although this will usually be another extended type, as the example below shows it may not be.

Example State_ExtendedTypeAccessors (H1E22)

We show some of the possibilities of the extended types. First we define some simple objects and show their extended types.
> Z := Integers();
> Zx<x> := PolynomialRing(Z);
> S := [ x ];
> f1 := map<Zx -> Z | f :-> Evaluate(f, 1)>;
> D := CremonaDatabase();
>
> ExtendedType(Z);
RngInt
> ExtendedType(Zx);
RngUPol[RngInt]
> ExtendedType(S);
SeqEnum[RngUPolElt[RngInt]]
> ExtendedType(f1);
Map[RngUPol[RngInt], RngInt]
> ExtendedType(D);
DB["CrvEll"]
We can see a few points of note from the above. If the type is not parameterized at all, like Z, then the extended type prints as just the base type. The printing for S shows that extended types may themselves be further parameterized. The printing for f1 shows that there may be more than one parametrizing object. The printing for D shows that parametrizing objects are not necessarily extended types.

We can use further investigate these with the intrinsics BaseType, '#', and indexing.

> tS := ExtendedType(S);
> BaseType(tS);
SeqEnum
> #tS;
1
> tS[1];
RngUPolElt[RngInt]
> #tS[1];
1
> tS[1][1];
RngInt
> Type(tS[1][1]);
ECat
>
> tD := ExtendedType(D);
> BaseType(tD);
DB
> #tD;
1
> tD[1];
CrvEll
> Type(tD[1]);
MonStgElt
This information could be put together to generate a tree of the type information (represented as a list).
> function tree(t)
>     if Type(t) ne ECat then
>         return [* t *];
>     end if;
>     return [* BaseType(t) *] cat [* $$(t[i]) : i in [1..#t] *];
> end function;
> function type_tree(object)
>     return tree(ExtendedType(object));
> end function;
>
> type_tree(Z);
[* RngInt *]
> type_tree(Zx);
[* RngUPol, [* RngInt *] *]
> type_tree(S);
[* SeqEnum, [* RngUPolElt, [* RngInt *] *] *]
> type_tree(f1);
[* Map, [* RngUPol, [* RngInt *] *], [* RngInt *] *]
> type_tree(D);
[* DB, [* CrvEll *] *]
Remember that the "CrvEll" in the last tree is a string, not a type.
> Type($1[2][1]);
MonStgElt
MakeType(S) : MonStgElt -> Cat
Given a string S specifying a type return the actual type corresponding to S. This is useful when some intrinsic name hides the symbol which normally refers to the actual type.
ElementType(S) : Str -> Cat
Given any structure S, return the type of the elements of S. For example, the element type of the ring of integers Z is RngIntElt since that is the type of the integers which lie in Z.
CoveringStructure(S, T) : Str, Str -> Str
Given structures S and T, return a covering structure C for S and T, so that S and T both embed into C. An error results if no such covering structure exists.
ExistsCoveringStructure(S, T) : Str, Str -> BoolElt, Str
Given structures S and T, return whether a covering structure C for S and T exists, and if so, return such a C, so that S and T both embed into C.

Example State_TypeStructures (H1E23)

We demonstrate the type and structure functions.
> Type(3);
RngIntElt
> t := MakeType("RngIntElt");
> t;
RngIntElt
> Type(3) eq t;
true
> Z := IntegerRing();
> Type(Z);
RngInt
> ElementType(Z);
RngIntElt
> ISA(RngIntElt, RngElt);
true
> ISA(RngIntElt, GrpElt);
false
> ISA(FldRat, Fld);
true
The following give examples of when covering structures exist or do not exist.
> Q := RationalField();
> CoveringStructure(Z, Q);
Rational Field
> ExistsCoveringStructure(Z, DihedralGroup(3));
false
> ExistsCoveringStructure(Z, CyclotomicField(5));
true Cyclotomic Field of order 5 and degree 4
> ExistsCoveringStructure(CyclotomicField(3), CyclotomicField(5));
true Cyclotomic Field of order 15 and degree 8
> ExistsCoveringStructure(GF(2), GF(3));
false
> ExistsCoveringStructure(GF(2^6), GF(2, 15));
true Finite field of size 2^30
Our last example demonstrates the use of extended types:
> R<x> := PolynomialRing(Integers());
> ExtendedType(R);
RngUPol[RngInt]
> ISA(RngUPol[RngInt], RngUPol);
true
> f := x + 1;
> ExtendedType(f);
RngUPolElt[RngInt]
> ISA(RngUPolElt[RngInt], RngUPolElt);
true
V2.29, 21 October 2025