Skip to content

Commit

Permalink
Merge pull request #51 from kalmarek/mk/update_docs_0_5
Browse files Browse the repository at this point in the history
update docs and more for 0.5
  • Loading branch information
Marek Kaluba committed Dec 11, 2023
2 parents 2e536fc + af51cab commit 998e889
Show file tree
Hide file tree
Showing 18 changed files with 225 additions and 266 deletions.
9 changes: 9 additions & 0 deletions .JuliaFormatter.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Configuration file for JuliaFormatter.jl
# For more information, see: https://domluna.github.io/JuliaFormatter.jl/stable/config/

always_for_in = true
always_use_return = true
margin = 80
remove_extra_newlines = true
separate_kwargs_with_semicolon = true
short_to_long_function_def = true
1 change: 0 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ authors = ["Marek Kaluba <kalmar@mailbox.org>"]
version = "0.5.0"

[deps]
Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[compat]
Expand Down
2 changes: 1 addition & 1 deletion docs/src/extensions.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Extensions

The following functions are defined in `GroupsCore` only to be extended
The following (empty) functions are defined in `GroupsCore` only to be extended
externally:

```julia
Expand Down
57 changes: 28 additions & 29 deletions docs/src/group_elements.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,66 +5,65 @@ of group elements should subtype.

## Obligatory methods

```@docs
parent(::GroupElement)
:(==)(::GEl, ::GEl) where {GEl <: GroupElement}
isfiniteorder(::GroupElement)
```

As well as the two arithmetic operations:

```julia
Base.inv(::GroupElement)
Base.:(*)(::GEl, ::GEl) where {GEl <: GroupElement}
```

### A note on `deepcopy`

The elements which are not of `isbitstype` should extend

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

according to
[`Base.deepcopy`](https://docs.julialang.org/en/v1/base/base/#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:

```@docs
parent(::GroupElement)
:(==)(::GEl, ::GEl) where {GEl <: GroupElement}
isfiniteorder(::GroupElement)
inv(::GroupElement)
:(*)(::GEl, ::GEl) where {GEl <: GroupElement}
```
!!! 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:

```julia
:(^)(::GroupElement, ::Integer)
:(/)(::GEl, ::GEl) where {GEl <: GroupElement}
Base.:(^)(::GroupElement, ::Integer)
Base.:(/)(::GEl, ::GEl) where {GEl <: GroupElement}
Base.one(::GroupElement)
```

and

```@docs
one(::GroupElement)
isequal(::GEl, ::GEl) where {GEl <: GroupElement}
order(::Type{T}, ::GroupElement) where T
conj
:(^)(::GEl, ::GEl) where {GEl <: GroupElement}
commutator
```

### Performance modifications

Some of the mentioned implemented methods may be altered for performance
Moreover we provide basic implementation which should be altered for performance
reasons:
* [`isequal`](@ref)
* `Base.:(^)(g::GroupElement, n::Integer)`
* [`order(::Type{T}, g::GroupElement) where T`](@ref)
* `Base.hash(::GroupElement, ::UInt)`

```@docs
similar(::GroupElement)
isone(::GroupElement)
```julia
Base.:(^)(g::GroupElement, n::Integer)
Groups.Core.order([::Type{T}], g::GroupElement) where T
Base.hash(::GroupElement, ::UInt)
```

### Mutable API

!!! warning
Work-in-progress.

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

Expand Down
43 changes: 25 additions & 18 deletions docs/src/groups.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# [Groups](@id H1_groups)

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

## Assumptions

Expand All @@ -12,11 +12,11 @@ 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.
* `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)`
* **For finite groups only** we define `Base.length(G) = order(Int, G)`

!!! danger
In general `length` is used **for iteration purposes only**.
Expand All @@ -27,13 +27,13 @@ manipulating groups can be implemented only with access to a generating set.
## Obligatory methods

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

* `Base.one(::Group)` and

```@docs
one(::Group)
order(::Type{T}, ::Group) where T
gens(::Group)
rand
```

### Iteration
Expand All @@ -44,41 +44,48 @@ 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

```math
a, a^2, a^3, \ldots,
```

which is arguably less useful than

```math
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.

* 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.
* There is no requirement that in the iteration sequence elements are returned
only once.

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

* [`Base.iterate`](https://docs.julialang.org/en/v1/base/collections/#Base.iterate)
* [`Base.eltype`](https://docs.julialang.org/en/v1/base/collections/#Base.eltype)
* [`Base.iterate`](https://docs.julialang.org/en/v1/base/collections/#Base.iterate)
* [`Base.eltype`](https://docs.julialang.org/en/v1/base/collections/#Base.eltype)

```@docs
Base.IteratorSize(::Type{<:Group})
```

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`](@ref).
information is derivable from the type, there is no need to extend
[`Base.isfinite`](@ref).

!!! 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.
Expand Down
24 changes: 12 additions & 12 deletions docs/src/index.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
# GroupsCore

```@meta
CurrentModule = GroupsCore
```

# GroupsCore

The aim of this package is to standardize the common assumptions and functions on group i.e. to create
Group interface.
The aim of this package is to standardize the common assumptions and functions
on group i.e. to create Group interface.

The protocol consists of two parts:
* [`Group`](@ref H1_groups) (parent object) methods,
* [`GroupElement`](@ref H1_group_elements) methods.

* [`Group`](@ref H1_groups) (parent object) methods,
* [`GroupElement`](@ref H1_group_elements) methods.

This is due to the fact that hardly any information can be encoded in `Type`, we
rely on parent objects that represent groups, as well as ordinary group
elements. It is assumed that all elements of a group have **identical** parent
(i.e. `===`) so that parent objects behave locally as singletons. More on this
can be read under
[AbstractAlgebra.jl](https://nemocas.github.io/AbstractAlgebra.jl/latest/types/).
(i.e. `===`) so that parent objects behave locally as singletons.

## Examples and Conformance testing

For an implemented interface please have a look at `/test` folder, where several
example implementations are tested against the conformance test suite:
* [`CyclicGroup`](https://github.com/kalmarek/GroupsCore.jl/blob/main/test/cyclic.jl)

* [`CyclicGroup`](https://github.com/kalmarek/GroupsCore.jl/blob/main/test/cyclic.jl)

To test the conformance of e.g. `CyclicGroup` defined above one can run

Expand All @@ -38,6 +38,6 @@ end
```

## Users
* [PermutationGroups.jl](https://github.com/kalmarek/PermutationGroups.jl)
* [Groups.jl](https://github.com/kalmarek/Groups.jl),
* [SymbolicWedderburn.jl](https://github.com/kalmarek/SymbolicWedderburn.jl),
* [Oscar](https://github.com/oscar-system/Oscar.jl) project.
* [SymbolicWedderburn.jl](https://github.com/kalmarek/SymbolicWedderburn.jl).
1 change: 0 additions & 1 deletion src/GroupsCore.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
module GroupsCore

import Random
import Markdown

abstract type Group end
abstract type GroupElement end
Expand Down
16 changes: 10 additions & 6 deletions src/exceptions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@ struct InterfaceNotImplemented <: Exception
method::String
end

Base.showerror(io::IO, err::InterfaceNotImplemented) =
print(io, "Missing method from $(err.family) interface: `$(err.method)`")
function Base.showerror(io::IO, err::InterfaceNotImplemented)
return print(
io,
"Missing method from $(err.family) interface: `$(err.method)`",
)
end

struct InfiniteOrder{T} <: Exception
x::T
msg
InfiniteOrder(g::Union{GroupElement, Group}) = new{typeof(g)}(g)
InfiniteOrder(g::Union{GroupElement, Group}, msg) = new{typeof(g)}(g, msg)
msg::Any
InfiniteOrder(g::Union{GroupElement,Group}) = new{typeof(g)}(g)
InfiniteOrder(g::Union{GroupElement,Group}, msg) = new{typeof(g)}(g, msg)
end

function Base.showerror(io::IO, err::InfiniteOrder{T}) where T
function Base.showerror(io::IO, err::InfiniteOrder{T}) where {T}
println(io, "Infinite order exception with ", err.x)
if isdefined(err, :msg)
print(io, err.msg)
Expand Down
14 changes: 6 additions & 8 deletions src/extensions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,17 @@ function centralizer end
function normalizer end
function stabilizer end

@doc Markdown.doc"""
"""
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.
Return the index `|G : H|`, where `H ≤ G` is a subgroup. If `H` is not
contained in `G`, an error is thrown.
"""
function index end

@doc Markdown.doc"""
"""
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.
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.
"""
function left_coset_representatives end
function right_coset_representatives end
Loading

0 comments on commit 998e889

Please sign in to comment.