Extending the interface of AbstractAlgebra.jl
In this section we will discuss on how to extend the interface of AbstractAlgebra.jl.
Elements and parents
Any implementation with elements and parents should implement the following interface:
Base.parent
— Functionparent(a)
Return parent object of given element $a$.
Examples
julia> G = SymmetricGroup(5); g = Perm([3,4,5,2,1])
(1,3,5)(2,4)
julia> parent(g) == G
true
julia> S, x = laurent_series_ring(ZZ, 3, :x)
(Laurent series ring in x over integers, x + O(x^4))
julia> parent(x) == S
true
AbstractAlgebra.elem_type
— Functionelem_type(parent)
elem_type(parent_type)
Given a parent object (or its type), return the type of its elements.
Examples
julia> S, x = power_series_ring(QQ, 2, :x)
(Univariate power series ring over rationals, x + O(x^3))
julia> elem_type(S) == typeof(x)
true
AbstractAlgebra.parent_type
— Functionparent_type(element)
parent_type(element_type)
Given an element (or its type), return the type of its parent object.
Examples
julia> R, x = polynomial_ring(ZZ, :x)
(Univariate polynomial ring in x over integers, x)
julia> S = matrix_space(R, 2, 2)
Matrix space of 2 rows and 2 columns
over univariate polynomial ring in x over integers
julia> a = rand(S, 0:1, 0:1);
julia> parent_type(a) == typeof(S)
true
Acquiring associated elements and parents
Further, if one has a base ring, like polynomials over the integers $\mathbb{Z}[x]$, then one should implement
AbstractAlgebra.base_ring
— Functionbase_ring(a)
Return base ring $R$ of given element or parent $a$.
Examples
julia> S, x = polynomial_ring(QQ, :x)
(Univariate polynomial ring in x over rationals, x)
julia> base_ring(S) == QQ
true
julia> R = GF(7)
Finite field F_7
julia> base_ring(R)
Union{}
AbstractAlgebra.base_ring_type
— Functionbase_ring_type(a)
Return the type of the base ring of the given element, element type, parent or parent type $a$.
Examples
julia> R, x = polynomial_ring(ZZ, :x)
(Univariate polynomial ring in x over integers, x)
julia> base_ring_type(R) == typeof(base_ring(R))
true
julia> base_ring_type(zero(R)) == typeof(base_ring(zero(R)))
true
julia> base_ring_type(typeof(R)) == typeof(base_ring(R))
true
julia> base_ring_type(typeof(zero(R))) == typeof(base_ring(zero(R)))
true
Special elements
For rings, one has to extend the following methods:
Base.one
— Functionone(a)
Return the multiplicative identity in the algebraic structure of $a$, which can be either an element or parent.
Examples
julia> S = matrix_space(ZZ, 2, 2)
Matrix space of 2 rows and 2 columns
over integers
julia> one(S)
[1 0]
[0 1]
julia> R, x = puiseux_series_field(QQ, 4, :x)
(Puiseux series field in x over rationals, x + O(x^5))
julia> one(x)
1 + O(x^4)
julia> G = GF(5)
Finite field F_5
julia> one(G)
1
Base.zero
— Functionzero(a)
Return the additive identity in the algebraic structure of $a$, which can be either an element or parent.
Examples
julia> S = matrix_ring(QQ, 2)
Matrix ring of degree 2
over rationals
julia> zero(S)
[0//1 0//1]
[0//1 0//1]
julia> R, x = polynomial_ring(ZZ, :x)
(Univariate polynomial ring in x over integers, x)
julia> zero(x^3 + 2)
0
Groups should only extend at least one of these. The one that is required depends on if the group is additive (commutative) or multiplicative.
Basic manipulation
If one would like to implement a ring, these are the basic manipulation methods that all rings should extend:
Base.isone
— Functionisone(a)
Return true if $a$ is the multiplicative identity, else return false.
Examples
julia> S = matrix_space(ZZ, 2, 2); T = matrix_space(ZZ, 2, 3); U = matrix_space(ZZ, 3, 2);
julia> isone(S([1 0; 0 1]))
true
julia> isone(T([1 0 0; 0 1 0]))
false
julia> isone(U([1 0; 0 1; 0 0]))
false
julia> T, x = puiseux_series_field(QQ, 10, :x)
(Puiseux series field in x over rationals, x + O(x^11))
julia> isone(x), isone(T(1))
(false, true)
Base.iszero
— Functioniszero(a)
Return true if $a$ is the additative identity, else return false.
Examples
julia> T, x = puiseux_series_field(QQ, 10, :x)
(Puiseux series field in x over rationals, x + O(x^11))
julia> a = T(0)
O(x^10)
julia> iszero(a)
true
AbstractAlgebra.is_unit
— Functionis_unit(a::T) where {T <: NCRingElem}
Return true if $a$ is invertible, else return false.
Examples
julia> S, x = polynomial_ring(QQ, :x)
(Univariate polynomial ring in x over rationals, x)
julia> is_unit(x), is_unit(S(1)), is_unit(S(4))
(false, true, true)
julia> is_unit(ZZ(-1)), is_unit(ZZ(4))
(true, false)
With the same logic as earlier, groups only need to extend one of the methods isone
and iszero
.