diff --git a/dev/extensions/index.html b/dev/extensions/index.html index be3f284..75aeee4 100644 --- a/dev/extensions/index.html +++ b/dev/extensions/index.html @@ -10,4 +10,4 @@ centralizer normalizer stabilizer -right_coset_representatives
GroupsCore.indexFunction
index(H::Gr, G::Gr) where {Gr <: Group}

Return the index $|G : H|$, where $H \subseteq G$. If $H$ is not contained in $G$, an error is thrown.

source
GroupsCore.left_coset_representativesFunction
left_coset_representatives(H::Gr, G::Gr) where {Gr <: Group}

Return representatives of the left cosets $h G$ where $h$ are elements of $H$. If $H$ is not contained in $G$, an error is thrown.

source
+right_coset_representatives
GroupsCore.indexFunction
index(H::Gr, G::Gr) where {Gr <: Group}

Return the index $|G : H|$, where $H \subseteq G$. If $H$ is not contained in $G$, an error is thrown.

source
GroupsCore.left_coset_representativesFunction
left_coset_representatives(H::Gr, G::Gr) where {Gr <: Group}

Return representatives of the left cosets $h G$ where $h$ are elements of $H$. If $H$ is not contained in $G$, an error is thrown.

source
diff --git a/dev/group_elements/index.html b/dev/group_elements/index.html index acfdbf0..f87921f 100644 --- a/dev/group_elements/index.html +++ b/dev/group_elements/index.html @@ -1,3 +1,3 @@ -Group elements · GroupsCore.jl

Group elements

GroupsCore defines abstract type GroupElement, which all implementations of group elements should subtype.

Obligatory methods

The elements which are not of isbitstype should extend

Base.deepcopy_internal(g::GroupElement, ::IdDict)

according to Base.deepcopy docstring. Due to our assumption on parents of group elements (acting as local singleton objects), a group element and its deepcopy should have identical (i.e. ===) parents.

The remaining obligatory methods are:

Base.parentMethod
parent(g::GroupElement)

Return the parent object of the group element.

source
Base.:==Method
==(g::GEl, h::GEl) where {GEl <: GroupElement}

Return true if and only if the mathematical equality $g = h$ holds.

Note

This function may not return, due to unsolvable word problem.

source
Base.invMethod
inv(g::GroupElement)

Return $g^{-1}$, the group inverse.

source
Base.:*Method
*(g::GEl, h::GEl) where {GEl <: GroupElement}

Return $g h$, the result of group binary operation.

source
Note

If finiteness of a group can be decided based on its type there is no need to extend isfiniteorder.

Implemented methods

Using the obligatory methods we implement the rest of the functions in GroupsCore. For starters, the first of these are:

:(^)(::GroupElement, ::Integer)
-:(/)(::GEl, ::GEl) where {GEl <: GroupElement}

and

Base.oneMethod
one(g::GroupElement)

Return the identity element in the group of $g$.

source
Base.isequalMethod
isequal(g::GEl, h::GEl) where {GEl <: GroupElement}

Return the "best effort" equality for group elements.

The implication isequal(g, h)$g = h$, must be always satisfied, i.e. isequal(g, h) might return false even if g == h holds (i.e. $g$ and $h$ are mathematically equal).

For example, in a finitely presented group, isequal may return the equality of words.

source
GroupsCore.orderMethod
order(::Type{T} = BigInt, g::GroupElement) where T

Return the order of $g$ as an instance of I. If $g$ is of infinite order GroupsCore.InfiniteOrder exception will be thrown.

Warning

Only arbitrary sized integers are required to return a mathematically correct answer.

source
Base.conjFunction
conj(g::GEl, h::GEl) where {GEl <: GroupElement}

Return conjugation of $g$ by $h$, i.e. $h^{-1} g h$.

source
GroupsCore.commutatorFunction
commutator(g::GEl, h::GEl, k::GEl...) where {GEl <: GroupElement}

Return the left associative iterated commutator $[[g, h], ...]$, where $[g, h] = g^{-1} h^{-1} g h$.

source

Performance modifications

Some of the mentioned implemented methods may be altered for performance reasons:

Base.similarMethod
similar(g::GroupElement)

Return a group element sharing the parent with $g$. Might be arbitrary and possibly uninitialized.

source
Base.isoneMethod
isone(g::GroupElement)

Return true if $g$ is the identity element.

source

Mutable API

Warning

Work-in-progress.

Mutable API is considered private and hence may change between versions without warning.

For the purpose of mutable arithmetic the following methods may be overloaded to provide more tailored versions for a given type and reduce the allocations. These functions should be used when writing libraries, in performance critical sections. However one should only use the returned value and there are no guarantees on in-place modifications actually happening.

All of these functions (possibly) alter only the first argument, and must unalias their arguments when necessary.

GroupsCore.inv!Function
inv!(out::GEl, g::GEl) where {GEl <: GroupElement}

Return inv(g), possibly modifying out. Aliasing of g with out is allowed.

source
GroupsCore.mul!Function
mul!(out::GEl, g::GEl, h::GEl) where {GEl <: GroupElement}

Return $g h$, possibly modifying out. Aliasing of g or h with out is allowed.

source
GroupsCore.div_left!Function
div_left!(out::GEl, g::GEl, h::GEl) where {GEl <: GroupElement}

Return $h^{-1} g$, possibly modifying out. Aliasing of g or h with out is allowed.

source
GroupsCore.div_right!Function
div_right!(out::GEl, g::GEl, h::GEl) where {GEl <: GroupElement}

Return $g h^{-1}$, possibly modifying out. Aliasing of g or h with out is allowed.

source
GroupsCore.conj!Function
conj!(out::GEl, g::GEl, h::GEl) where {GEl <: GroupElement}

Return $h^{-1} g h$, possibly modifying out. Aliasing of g or h with out is allowed.

source
GroupsCore.commutator!Function
commutator!(out::GEl, g::GEl, h::GEl) where {GEl <: GroupElement}

Return $g^{-1} h^{-1} g h$, possibly modifying out. Aliasing of g or h with out is allowed.

source
+Group elements · GroupsCore.jl

Group elements

GroupsCore defines abstract type GroupElement, which all implementations of group elements should subtype.

Obligatory methods

The elements which are not of isbitstype should extend

Base.deepcopy_internal(g::GroupElement, ::IdDict)

according to Base.deepcopy docstring. Due to our assumption on parents of group elements (acting as local singleton objects), a group element and its deepcopy should have identical (i.e. ===) parents.

The remaining obligatory methods are:

Base.parentMethod
parent(g::GroupElement)

Return the parent object of the group element.

source
Base.:==Method
==(g::GEl, h::GEl) where {GEl <: GroupElement}

Return true if and only if the mathematical equality $g = h$ holds.

Note

This function may not return, due to unsolvable word problem.

source
Base.invMethod
inv(g::GroupElement)

Return $g^{-1}$, the group inverse.

source
Base.:*Method
*(g::GEl, h::GEl) where {GEl <: GroupElement}

Return $g h$, the result of group binary operation.

source
Note

If finiteness of a group can be decided based on its type there is no need to extend isfiniteorder.

Implemented methods

Using the obligatory methods we implement the rest of the functions in GroupsCore. For starters, the first of these are:

:(^)(::GroupElement, ::Integer)
+:(/)(::GEl, ::GEl) where {GEl <: GroupElement}

and

Base.oneMethod
one(g::GroupElement)

Return the identity element in the group of $g$.

source
Base.isequalMethod
isequal(g::GEl, h::GEl) where {GEl <: GroupElement}

Return the "best effort" equality for group elements.

The implication isequal(g, h)$g = h$, must be always satisfied, i.e. isequal(g, h) might return false even if g == h holds (i.e. $g$ and $h$ are mathematically equal).

For example, in a finitely presented group, isequal may return the equality of words.

source
GroupsCore.orderMethod
order(::Type{T} = BigInt, g::GroupElement) where T

Return the order of $g$ as an instance of I. If $g$ is of infinite order GroupsCore.InfiniteOrder exception will be thrown.

Warning

Only arbitrary sized integers are required to return a mathematically correct answer.

source
Base.conjFunction
conj(g::GEl, h::GEl) where {GEl <: GroupElement}

Return conjugation of $g$ by $h$, i.e. $h^{-1} g h$.

source
GroupsCore.commutatorFunction
commutator(g::GEl, h::GEl, k::GEl...) where {GEl <: GroupElement}

Return the left associative iterated commutator $[[g, h], ...]$, where $[g, h] = g^{-1} h^{-1} g h$.

source

Performance modifications

Some of the mentioned implemented methods may be altered for performance reasons:

Base.similarMethod
similar(g::GroupElement)

Return a group element sharing the parent with $g$. Might be arbitrary and possibly uninitialized.

source
Base.isoneMethod
isone(g::GroupElement)

Return true if $g$ is the identity element.

source

Mutable API

Warning

Work-in-progress.

Mutable API is considered private and hence may change between versions without warning.

For the purpose of mutable arithmetic the following methods may be overloaded to provide more tailored versions for a given type and reduce the allocations. These functions should be used when writing libraries, in performance critical sections. However one should only use the returned value and there are no guarantees on in-place modifications actually happening.

All of these functions (possibly) alter only the first argument, and must unalias their arguments when necessary.

GroupsCore.inv!Function
inv!(out::GEl, g::GEl) where {GEl <: GroupElement}

Return inv(g), possibly modifying out. Aliasing of g with out is allowed.

source
GroupsCore.mul!Function
mul!(out::GEl, g::GEl, h::GEl) where {GEl <: GroupElement}

Return $g h$, possibly modifying out. Aliasing of g or h with out is allowed.

source
GroupsCore.div_left!Function
div_left!(out::GEl, g::GEl, h::GEl) where {GEl <: GroupElement}

Return $h^{-1} g$, possibly modifying out. Aliasing of g or h with out is allowed.

source
GroupsCore.div_right!Function
div_right!(out::GEl, g::GEl, h::GEl) where {GEl <: GroupElement}

Return $g h^{-1}$, possibly modifying out. Aliasing of g or h with out is allowed.

source
GroupsCore.conj!Function
conj!(out::GEl, g::GEl, h::GEl) where {GEl <: GroupElement}

Return $h^{-1} g h$, possibly modifying out. Aliasing of g or h with out is allowed.

source
GroupsCore.commutator!Function
commutator!(out::GEl, g::GEl, h::GEl) where {GEl <: GroupElement}

Return $g^{-1} h^{-1} g h$, possibly modifying out. Aliasing of g or h with out is allowed.

source
diff --git a/dev/groups/index.html b/dev/groups/index.html index 993ced9..c5878b4 100644 --- a/dev/groups/index.html +++ b/dev/groups/index.html @@ -1,2 +1,2 @@ -Groups · GroupsCore.jl

Groups

The abstract type Group encompasses all groups. Since these are already abstract, we skip the Abstract prefix.

Assumptions

GroupsCore implements some methods with default values, which may not be generally true for all groups. The intent is to limit the extent of the required interface. This require special care when implementing groups that need to override these default methods.

The methods we currently predefine are:

  • GroupsCore.hasgens(::Group) = true

This is based on the assumption that reasonably generic functions manipulating groups can be implemented only with access to a generating set.

  • For finite groups only we define Base.length(G) = order(Int, G)
Danger

In general length is used for iteration purposes only. If you are interested in the number of distinct elements of a group, use order(::Type{<:Integer}, ::Group). For more information see Iteration.

Obligatory methods

Here we list the minimal set of functions that a group object must extend to implement the Group interface.

Base.oneMethod
one(G::Group)

Return the identity element of the group $G$.

source
GroupsCore.orderMethod
order(::Type{T} = BigInt, G::Group) where T

Return the order of $G$ as an instance of T. If $G$ is of infinite order, GroupsCore.InfiniteOrder exception will be thrown.

Warning

Only arbitrary sized integers are required to return a mathematically correct answer.

source
GroupsCore.gensMethod
gens(G::Group)

Return a random-access collection of generators of $G$.

The result of this function is undefined unless GroupsCore.hasgens(G) return true.

source
Base.randFunction
Base.rand(rng::Random.AbstractRNG, rs::Random.SamplerTrivial{Gr}) where {Gr <: Group}

Return a random group element, treating the group as a collection.

source

Iteration

If a group is defined by generators (i.e. hasgens(G) returns true) an important aspect of this interface is the iteration over a group.

Iteration over infinite objects seem to be useful only when the returned elements explore the whole group. To be precise, for the free group $F_2 = ⟨a,b⟩$, one could implement iteration by sequence

\[a, a^2, a^3, \ldots,\]

which is arguably less useful than

\[a, b, a^{-1}, b^{-1}, ab, \ldots.\]

Therefore we put the following assumptions on iteration.

  • Iteration is mandatory only if hasgens(G) returns true.
  • The first element of the iteration (e.g. given by Base.first) is the group identity.
  • Iteration over a finitely generated group should exhaust every fixed radius ball around the identity (in word-length metric associated to gens(G)) in finite time.

These are just the conventions, the iteration interface consists of standard julia methods:

Base.IteratorSizeMethod
IteratorSize(::Type{Gr}) where {Gr <: Group}

Given the type of a group, return one of the following values:

  • Base.IsInfinite() if all instances of groups of type Gr are infinite.
  • Base.HasLength() or Base.HasShape{N}() if all instances are finite.
  • Base.SizeUnknown() otherwise, [the default].
source

In contrast to julia we default to Base.SizeUnknown() to provide a mathematically correct fallback. If your group is finite by definition, implementing the correct IteratorSize (i.e. Base.HasLength(), or Base.HasShape{N}()) will simplify several other methods, which will be then optimized to work only based on the type of the group. In particular when the information is derivable from the type, there is no need to extend Base.isfinite.

Note

In the case that IteratorSize(Gr) == IsInfinite(), one should define Base.length(Gr) to be a "best effort", length of the group iterator.

For practical reasons the largest group you could iterate over in your lifetime is of order that fits into an Int. For example, $2^{63}$ nanoseconds comes to 290 years.

Additional methods

Base.isfiniteMethod
isfinite(G::Group)

Test whether group $G$ is finite.

The default implementation is based on Base.IteratorSize. Only groups of returning Base.SizeUnknown() should extend this method.

source
GroupsCore.istrivialMethod
istrivial(G::Group)

Test whether group $G$ is trivial.

The default implementation is based on isfinite and order.

source
+Groups · GroupsCore.jl

Groups

The abstract type Group encompasses all groups. Since these are already abstract, we skip the Abstract prefix.

Assumptions

GroupsCore implements some methods with default values, which may not be generally true for all groups. The intent is to limit the extent of the required interface. This require special care when implementing groups that need to override these default methods.

The methods we currently predefine are:

  • GroupsCore.hasgens(::Group) = true

This is based on the assumption that reasonably generic functions manipulating groups can be implemented only with access to a generating set.

  • For finite groups only we define Base.length(G) = order(Int, G)
Danger

In general length is used for iteration purposes only. If you are interested in the number of distinct elements of a group, use order(::Type{<:Integer}, ::Group). For more information see Iteration.

Obligatory methods

Here we list the minimal set of functions that a group object must extend to implement the Group interface.

Base.oneMethod
one(G::Group)

Return the identity element of the group $G$.

source
GroupsCore.orderMethod
order(::Type{T} = BigInt, G::Group) where T

Return the order of $G$ as an instance of T. If $G$ is of infinite order, GroupsCore.InfiniteOrder exception will be thrown.

Warning

Only arbitrary sized integers are required to return a mathematically correct answer.

source
GroupsCore.gensMethod
gens(G::Group)

Return a random-access collection of generators of $G$.

The result of this function is undefined unless GroupsCore.hasgens(G) return true.

source
Base.randFunction
Base.rand(rng::Random.AbstractRNG, rs::Random.SamplerTrivial{Gr}) where {Gr <: Group}

Return a random group element, treating the group as a collection.

source

Iteration

If a group is defined by generators (i.e. hasgens(G) returns true) an important aspect of this interface is the iteration over a group.

Iteration over infinite objects seem to be useful only when the returned elements explore the whole group. To be precise, for the free group $F_2 = ⟨a,b⟩$, one could implement iteration by sequence

\[a, a^2, a^3, \ldots,\]

which is arguably less useful than

\[a, b, a^{-1}, b^{-1}, ab, \ldots.\]

Therefore we put the following assumptions on iteration.

  • Iteration is mandatory only if hasgens(G) returns true.
  • The first element of the iteration (e.g. given by Base.first) is the group identity.
  • Iteration over a finitely generated group should exhaust every fixed radius ball around the identity (in word-length metric associated to gens(G)) in finite time.

These are just the conventions, the iteration interface consists of standard julia methods:

Base.IteratorSizeMethod
IteratorSize(::Type{Gr}) where {Gr <: Group}

Given the type of a group, return one of the following values:

  • Base.IsInfinite() if all instances of groups of type Gr are infinite.
  • Base.HasLength() or Base.HasShape{N}() if all instances are finite.
  • Base.SizeUnknown() otherwise, [the default].
source

In contrast to julia we default to Base.SizeUnknown() to provide a mathematically correct fallback. If your group is finite by definition, implementing the correct IteratorSize (i.e. Base.HasLength(), or Base.HasShape{N}()) will simplify several other methods, which will be then optimized to work only based on the type of the group. In particular when the information is derivable from the type, there is no need to extend Base.isfinite.

Note

In the case that IteratorSize(Gr) == IsInfinite(), one should define Base.length(Gr) to be a "best effort", length of the group iterator.

For practical reasons the largest group you could iterate over in your lifetime is of order that fits into an Int. For example, $2^{63}$ nanoseconds comes to 290 years.

Additional methods

Base.isfiniteMethod
isfinite(G::Group)

Test whether group $G$ is finite.

The default implementation is based on Base.IteratorSize. Only groups of returning Base.SizeUnknown() should extend this method.

source
GroupsCore.istrivialMethod
istrivial(G::Group)

Test whether group $G$ is trivial.

The default implementation is based on isfinite and order.

source
diff --git a/dev/index.html b/dev/index.html index 288bce3..43fb480 100644 --- a/dev/index.html +++ b/dev/index.html @@ -14,4 +14,4 @@ Test Summary: | Pass Total Time Group interface | 24 24 0.0s Test Summary: | Pass Total Time -GroupElement interface | 95 95 0.0s

Users

+GroupElement interface | 95 95 0.0s

Users

diff --git a/dev/search/index.html b/dev/search/index.html index 31dec2a..150cc44 100644 --- a/dev/search/index.html +++ b/dev/search/index.html @@ -1,2 +1,2 @@ -Search · GroupsCore.jl

Loading search...

    +Search · GroupsCore.jl

    Loading search...