Field Interface

AbstractAlgebra.jl generic code makes use of a standardised set of functions which it expects to be implemented for all fields. Here we document this interface. All libraries which want to make use of the generic capabilities of AbstractAlgebra.jl must supply all of the required functionality for their fields.

Types

Most fields must supply two types:

  • a type for the parent object (representing the field itself)
  • a type for elements of that field

For example, the generic fraction field type in AbstractAlgebra.jl provides two types in generic/GenericTypes.jl:

  • Generic.FracField{T} for the parent objects
  • Generic.FracFieldElem{T} for the actual fractions

The parent type must belong to Field and the element type must belong to FieldElem. Of course, the types may belong to these abstract types transitively.

For parameterised fields, we advise that the types of both the parent objects and element objects to be parameterised by the types of the elements of the base ring.

There can be variations on this theme: e.g. in some areas of mathematics there is a notion of a coefficient domain, in which case it may make sense to parameterise all types by the type of elements of this coefficient domain. But note that this may have implications for the ad hoc operators one might like to explicitly implement.

FieldElement type union

Because of its lack of multiple inheritance, Julia does not allow Julia Base types to belong to FieldElem. To allow us to work equally with AbstractAlgebra and Julia types that represent elements of fields we define a union type FieldElement in src/julia/JuliaTypes.

So far, in addition to FieldElem the union type FieldElement includes the Julia types Rational and AbstractFloat.

Most of the generic code in AbstractAlgebra makes use of the union type FieldElement instead of FieldElem so that the generic functions also accept the Julia Base field types.

Note

One must be careful when defining ad hoc binary operations for field element types. It is often necessary to define separate versions of the functions for FieldElem then for each of the Julia types separately in order to avoid ambiguity warnings.

Note that even though FieldElement is a union type we still have the following inclusion

FieldElement <: RingElement

Parent object caches

In many cases, it is desirable to have only one object in the system to represent each field. This means that if the same field is constructed twice, elements of the two fields will be compatible as far as arithmetic is concerned.

In order to facilitate this, global caches of fields are stored in AbstractAlgebra.jl, usually implemented using dictionaries. For example, the Generic.FracField parent objects are looked up in a dictionary FracDict to see if they have been previously defined.

Whether these global caches are provided or not, depends on both mathematical and algorithmic considerations. E.g. in the case of number fields, it isn't desirable to identify all number fields with the same defining polynomial, as they may be considered with distinct embeddings into one another. In other cases, identifying whether two fields are the same may be prohibitively expensive. Generally, it may only make sense algorithmically to identify two fields if they were constructed from identical data.

If a global cache is provided, it must be optionally possible to construct the parent objects without caching. This is done by passing a boolean value cached to the inner constructor of the parent object. See generic/GenericTypes.jl for examples of how to construct and handle such caches.

Required functions for all fields

In the following, we list all the functions that are required to be provided for fields in AbstractAlgebra.jl or by external libraries wanting to use AbstractAlgebra.jl.

We give this interface for fictitious types MyParent for the type of the field parent object R and MyElem for the type of the elements of the field.

Note

Generic functions in AbstractAlgebra.jl may not rely on the existence of functions that are not documented here. If they do, those functions will only be available for fields that implement that additional functionality, and should be documented as such.

In the first place, all fields are rings and therefore any field type must implement all of the Ring interface. The functionality below is in addition to this basic functionality.

Data type and parent object methods

characteristic(R::MyParent)

Return the characteristic of the field. If the characteristic is not known, an exception is raised.

Basic manipulation of rings and elements

is_unit(f::MyElem)

Return true if the given element is invertible, i.e. nonzero in the field.