1
0
mirror of https://github.com/kalmarek/Groups.jl.git synced 2024-11-19 14:35:28 +01:00

add implementation of MatrixGroups as fp groups

This commit is contained in:
Marek Kaluba 2022-04-02 14:21:42 +02:00
parent db5d60134c
commit cb933c3f87
No known key found for this signature in database
GPG Key ID: 8BF1A3855328FC15
9 changed files with 314 additions and 0 deletions

View File

@ -10,6 +10,8 @@ import Random
import OrderedCollections: OrderedSet import OrderedCollections: OrderedSet
export Alphabet, AutomorphismGroup, FreeGroup, FreeGroup, FPGroup, FPGroupElement, SpecialAutomorphismGroup export Alphabet, AutomorphismGroup, FreeGroup, FreeGroup, FPGroup, FPGroupElement, SpecialAutomorphismGroup
export MatrixGroups
export alphabet, evaluate, word, gens export alphabet, evaluate, word, gens
include("types.jl") include("types.jl")
@ -20,6 +22,8 @@ include("autgroups.jl")
include("aut_groups/sautFn.jl") include("aut_groups/sautFn.jl")
include("aut_groups/mcg.jl") include("aut_groups/mcg.jl")
include("matrix_groups/MatrixGroups.jl")
using .MatrixGroups
include("wl_ball.jl") include("wl_ball.jl")
end # of module Groups end # of module Groups

View File

@ -0,0 +1,17 @@
module MatrixGroups
using GroupsCore
using Groups
using KnuthBendix
using LinearAlgebra # Identity matrix
using Random # GroupsCore rand
export SpecialLinearGroup, SymplecticGroup
include("abstract.jl")
include("SLn.jl")
include("Spn.jl")
end # module

42
src/matrix_groups/SLn.jl Normal file
View File

@ -0,0 +1,42 @@
include("eltary_matrices.jl")
struct SpecialLinearGroup{N, T, R, A, S} <: MatrixGroup{N,T}
base_ring::R
alphabet::A
gens::S
function SpecialLinearGroup{N}(base_ring) where N
S = [ElementaryMatrix{N}(i,j, one(base_ring)) for i in 1:N for j in 1:N if i≠j]
alphabet = Alphabet(S)
return new{
N,
eltype(base_ring),
typeof(base_ring),
typeof(alphabet),
typeof(S)
}(base_ring, alphabet, S)
end
end
GroupsCore.ngens(SL::SpecialLinearGroup{N}) where N = N^2 - N
Base.show(io::IO, SL::SpecialLinearGroup{N, T}) where {N, T} =
print(io, "special linear group of $N×$N matrices over $T")
function Base.show(
io::IO,
::MIME"text/plain",
sl::Groups.AbstractFPGroupElement{<:SpecialLinearGroup{N}}
) where N
Groups.normalform!(sl)
print(io, "SL{$N,$(eltype(sl))} matrix: ")
KnuthBendix.print_repr(io, word(sl), alphabet(sl))
println(io)
Base.print_array(io, matrix_repr(sl))
end
Base.show(io::IO, sl::Groups.AbstractFPGroupElement{<:SpecialLinearGroup}) =
KnuthBendix.print_repr(io, word(sl), alphabet(sl))

68
src/matrix_groups/Spn.jl Normal file
View File

@ -0,0 +1,68 @@
include("eltary_symplectic.jl")
struct SymplecticGroup{N, T, R, A, S} <: MatrixGroup{N,T}
base_ring::R
alphabet::A
gens::S
function SymplecticGroup{N}(base_ring) where N
S = symplectic_gens(N, eltype(base_ring))
alphabet = Alphabet(S)
return new{
N,
eltype(base_ring),
typeof(base_ring),
typeof(alphabet),
typeof(S)
}(base_ring, alphabet, S)
end
end
GroupsCore.ngens(Sp::SymplecticGroup) = length(Sp.gens)
Base.show(io::IO, ::SymplecticGroup{N}) where N = print(io, "group of $N×$N symplectic matrices")
function Base.show(
io::IO,
::MIME"text/plain",
sp::Groups.AbstractFPGroupElement{<:SymplecticGroup{N}}
) where {N}
print(io, "$N×$N Symplectic matrix: ")
KnuthBendix.print_repr(io, word(sp), alphabet(sp))
println(io)
Base.print_array(io, matrix_repr(sp))
end
function symplectic_gens(N, T=Int8)
iseven(N) || throw(ArgumentError("N needs to be even!"))
n = N÷2
a_ijs = [ElementarySymplectic{N}(:A, i,j, one(T)) for (i,j) in offdiagonal_indexing(n)]
b_is = [ElementarySymplectic{N}(:B, n+i,i, one(T)) for i in 1:n]
c_ijs = [ElementarySymplectic{N}(:B, n+i,j, one(T)) for (i,j) in offdiagonal_indexing(n)]
S = [a_ijs; b_is; c_ijs]
S = [S; transpose.(S)]
return unique(S)
end
function _std_symplectic_form(m::AbstractMatrix)
r,c = size(m)
r == c || return false
iseven(r) || return false
n = r÷2
Ω = zero(m)
for i in 1:n
Ω[2i-1:2i, 2i-1:2i] .= [0 -1; 1 0]
end
return Ω
end
function issymplectic(mat::M, Ω = _std_symplectic_form(mat)) where M <: AbstractMatrix
r, c = size(mat)
return Ω == transpose(mat) * Ω * mat
end

View File

@ -0,0 +1,41 @@
abstract type MatrixGroup{N, T} <: Groups.AbstractFPGroup end
const MatrixGroupElement{N, T} = Groups.AbstractFPGroupElement{<:MatrixGroup{N, T}}
Base.isone(g::MatrixGroupElement{N, T}) where {N, T} = matrix_repr(g) == I
function Base.:(==)(m1::M1, m2::M2) where {M1<:MatrixGroupElement, M2<:MatrixGroupElement}
parent(m1) === parent(m2) || return false
word(m1) == word(m2) && return true
return matrix_repr(m1) == matrix_repr(m2)
end
Base.size(m::MatrixGroupElement{N}) where N = (N, N)
Base.eltype(m::MatrixGroupElement{N, T}) where {N, T} = T
# three structural assumptions about matrix groups
Groups.word(sl::MatrixGroupElement) = sl.word
Base.parent(sl::MatrixGroupElement) = sl.parent
Groups.alphabet(M::MatrixGroup) = M.alphabet
Groups.rewriting(M::MatrixGroup) = alphabet(M)
Base.hash(sl::MatrixGroupElement, h::UInt) =
hash(matrix_repr(sl), hash(parent(sl), h))
Base.getindex(sl::MatrixGroupElement, i, j) = matrix_repr(sl)[i,j]
# Base.iterate(sl::MatrixGroupElement) = iterate(sl.elts)
# Base.iterate(sl::MatrixGroupElement, state) = iterate(sl.elts, state)
function matrix_repr(m::MatrixGroupElement{N, T}) where {N, T}
isempty(word(m)) && return StaticArrays.SMatrix{N, N, T}(I)
A = alphabet(parent(m))
return prod(matrix_repr(A[l]) for l in word(m))
end
function Base.rand(
rng::Random.AbstractRNG,
rs::Random.SamplerTrivial{<:MatrixGroup},
)
Mgroup = rs[]
S = gens(Mgroup)
return prod(g -> rand(Bool) ? g : inv(g), rand(S, rand(1:30)))
end

View File

@ -0,0 +1,31 @@
using Groups
using StaticArrays
struct ElementaryMatrix{N, T} <: Groups.GSymbol
i::Int
j::Int
val::T
ElementaryMatrix{N}(i, j, val=1) where N =
(@assert i≠j; new{N, typeof(val)}(i, j, val))
end
function Base.show(io::IO, e::ElementaryMatrix)
print(io, 'E', Groups.subscriptify(e.i), Groups.subscriptify(e.j))
!isone(e.val) && print(io, "^$(e.val)")
end
Base.:(==)(e::ElementaryMatrix{N}, f::ElementaryMatrix{N}) where N =
e.i == f.i && e.j == f.j && e.val == f.val
Base.hash(e::ElementaryMatrix, h::UInt) =
hash(typeof(e), hash((e.i, e.j, e.val), h))
Base.inv(e::ElementaryMatrix{N}) where N =
ElementaryMatrix{N}(e.i, e.j, -e.val)
function matrix_repr(e::ElementaryMatrix{N, T}) where {N, T}
m = StaticArrays.MMatrix{N, N, T}(I)
m[e.i, e.j] = e.val
x = StaticArrays.SMatrix{N, N}(m)
return x
end

View File

@ -0,0 +1,85 @@
using Groups
using StaticArrays
struct ElementarySymplectic{N, T} <: Groups.GSymbol
symbol::Symbol
i::Int
j::Int
val::T
function ElementarySymplectic{N}(s::Symbol, i::Integer, j::Integer, val=1) where N
@assert s (:A, :B)
@assert iseven(N)
n = N÷2
if s === :A
@assert 1 i n && 1 j n && i j
elseif s === :B
@assert xor(1 i n, 1 j n) && xor(n < i N, n < j N)
end
return new{N, typeof(val)}(s, i, j, val)
end
end
function Base.show(io::IO, s::ElementarySymplectic)
i, j = Groups.subscriptify(s.i), Groups.subscriptify(s.j)
print(io, s.symbol, i, j)
!isone(s.val) && print(io, "^$(s.val)")
end
function Base.show(io::IO, ::MIME"text/plain", s::ElementarySymplectic)
print(io, s)
print(io, " → corresponding root: ")
print(io, Roots.Root(s))
end
_ind(s::ElementarySymplectic{N}) where N = (s.i, s.j)
_local_ind(N_half::Integer, i::Integer) = ifelse(i<=N_half, i, i-N_half)
function _dual_ind(s::ElementarySymplectic{N}) where N
if s.symbol === :A && return _ind(s)
else#if s.symbol === :B
return _dual_ind(N÷2, s.i, s.j)
end
end
function _dual_ind(N_half, i, j)
@assert i <= N_half < j || j <= N_half < i
if i <= N_half # && j > N_half
i, j = j - N_half, i + N_half
else
i, j = j + N_half, i - N_half
end
return i, j
end
function Base.:(==)(s::ElementarySymplectic{N}, t::ElementarySymplectic{M}) where {N, M}
N == M || return false
s.symbol == t.symbol || return false
s.val == t.val || return false
return _ind(t) == _ind(s) || _ind(t) == _dual_ind(s)
end
Base.hash(s::ElementarySymplectic, h::UInt) =
hash(Set([_ind(s); _dual_ind(s)]), hash(s.symbol, hash(s.val, h)))
LinearAlgebra.transpose(s::ElementarySymplectic{N}) where N =
ElementarySymplectic{N}(s.symbol, s.j, s.i, s.val)
Base.inv(s::ElementarySymplectic{N}) where N =
ElementarySymplectic{N}(s.symbol, s.i, s.j, -s.val)
function matrix_repr(s::ElementarySymplectic{N, T}) where {N, T}
@assert iseven(N)
n = div(N, 2)
m = StaticArrays.MMatrix{N, N, T}(I)
i,j = _ind(s)
m[i,j] = s.val
if s.symbol === :A
m[n+j, n+i] = -s.val
else#if s.symbol === :B
if i > n
m[j+n, i-n] = s.val
else
m[j-n, i+n] = s.val
end
end
return StaticArrays.SMatrix{N, N}(m)
end

24
test/matrix_groups.jl Normal file
View File

@ -0,0 +1,24 @@
using Groups.MatrixGroups
@testset "Matrix Groups" begin
@testset "SL(n, )" begin
SL3Z = SpecialLinearGroup{3}(Int8)
S = gens(SL3Z); union!(S, inv.(S))
E, sizes = Groups.wlmetric_ball(S, radius=4)
@test sizes = [13, 121, 883, 5455]
@testset "GroupsCore conformance" begin
test_Group_interface(SL3Z)
g = A(rand(1:length(alphabet(SL3Z)), 10))
h = A(rand(1:length(alphabet(SL3Z)), 10))
test_GroupElement_interface(g, h)
end
end
end

View File

@ -25,6 +25,8 @@ include(joinpath(pathof(GroupsCore), "..", "..", "test", "conformance_test.jl"))
include("free_groups.jl") include("free_groups.jl")
include("fp_groups.jl") include("fp_groups.jl")
include("matrix_groups.jl")
include("AutFn.jl") include("AutFn.jl")
include("AutSigma_41.jl") include("AutSigma_41.jl")
include("AutSigma3.jl") include("AutSigma3.jl")