1
0
mirror of https://github.com/kalmarek/Groups.jl.git synced 2024-11-24 07:45:28 +01:00

Compare commits

...

6 Commits

Author SHA1 Message Date
Marek Kaluba
7230106bfc
Merge pull request #27 from kalmarek/enh/simplify_wlmetric
simplify wlmetric_ball
2023-03-22 23:59:07 +01:00
751850568c
make equality_data immutable operation 2023-03-22 21:45:04 +01:00
038fc29b81
update benchmark on wl_ball 2023-03-22 21:44:33 +01:00
c69eff1540
freely reduce words upon * 2023-03-22 21:44:09 +01:00
a1bc334fb2
make AutomorphismGroup mutable
parent field of an automorphism is now a pointer (i.e. 8 bytes)
2023-03-22 21:43:00 +01:00
1f1e51917a
remove threaded wlmetric_ball
* the threaded version was hardly faster
* there was a memory leak (?) that was gone with -t 1
* simplifies the whole thing
2023-03-22 21:41:37 +01:00
9 changed files with 66 additions and 95 deletions

View File

@ -1,20 +1,19 @@
name = "Groups" name = "Groups"
uuid = "5d8bd718-bd84-11e8-3b40-ad14f4a32557" uuid = "5d8bd718-bd84-11e8-3b40-ad14f4a32557"
authors = ["Marek Kaluba <kalmar@amu.edu.pl>"] authors = ["Marek Kaluba <kalmar@amu.edu.pl>"]
version = "0.7.5" version = "0.7.6"
[deps] [deps]
Folds = "41a02a25-b8f0-4f67-bc48-60067656b558"
GroupsCore = "d5909c97-4eac-4ecc-a3dc-fdd0858a4120" GroupsCore = "d5909c97-4eac-4ecc-a3dc-fdd0858a4120"
KnuthBendix = "c2604015-7b3d-4a30-8a26-9074551ec60a" KnuthBendix = "c2604015-7b3d-4a30-8a26-9074551ec60a"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
PermutationGroups = "8bc5a954-2dfc-11e9-10e6-cd969bffa420" PermutationGroups = "8bc5a954-2dfc-11e9-10e6-cd969bffa420"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
[compat] [compat]
Folds = "0.2.7"
GroupsCore = "0.4" GroupsCore = "0.4"
KnuthBendix = "0.4" KnuthBendix = "0.4"
OrderedCollections = "1" OrderedCollections = "1"

View File

@ -1,12 +1,9 @@
module Groups module Groups
import Folds
import Logging import Logging
using GroupsCore using GroupsCore
import GroupsCore.Random import Random
import OrderedCollections: OrderedSet
import KnuthBendix import KnuthBendix
import KnuthBendix: AbstractWord, Alphabet, Word import KnuthBendix: AbstractWord, Alphabet, Word

View File

@ -4,7 +4,7 @@ function KnuthBendix.Alphabet(S::AbstractVector{<:GSymbol})
return Alphabet(S, inversions) return Alphabet(S, inversions)
end end
struct AutomorphismGroup{G<:Group,T,RW,S} <: AbstractFPGroup mutable struct AutomorphismGroup{G<:Group,T,RW,S} <: AbstractFPGroup
group::G group::G
gens::Vector{T} gens::Vector{T}
rw::RW rw::RW

View File

@ -1,6 +1,6 @@
## Hashing ## Hashing
equality_data(g::AbstractFPGroupElement) = (normalform!(g); word(g)) equality_data(g::AbstractFPGroupElement) = word(g)
bitget(h::UInt, n::Int) = Bool((h & (1 << n)) >> n) bitget(h::UInt, n::Int) = Bool((h & (1 << n)) >> n)
bitclear(h::UInt, n::Int) = h & ~(1 << n) bitclear(h::UInt, n::Int) = h & ~(1 << n)

View File

@ -1,3 +1,5 @@
import OrderedCollections: OrderedSet
mutable struct FPGroupIter{S,T,GEl} mutable struct FPGroupIter{S,T,GEl}
seen::S seen::S
seen_iter_state::T seen_iter_state::T

View File

@ -144,7 +144,18 @@ end
function Base.:(*)(g::GEl, h::GEl) where {GEl<:AbstractFPGroupElement} function Base.:(*)(g::GEl, h::GEl) where {GEl<:AbstractFPGroupElement}
@boundscheck @assert parent(g) === parent(h) @boundscheck @assert parent(g) === parent(h)
return GEl(word(g) * word(h), parent(g)) A = alphabet(parent(g))
k = 0
while k + 1 min(length(word(g)), length(word(h)))
if inv(word(g)[end-k], A) == word(h)[k+1]
k += 1
else
break
end
end
w = @view(word(g)[1:end-k]) * @view(word(h)[k+1:end])
res = GEl(w, parent(g))
return res
end end
function GroupsCore.isfiniteorder(g::AbstractFPGroupElement) function GroupsCore.isfiniteorder(g::AbstractFPGroupElement)

View File

@ -1,6 +1,6 @@
""" """
wlmetric_ball(S::AbstractVector{<:GroupElem} wlmetric_ball(S::AbstractVector{<:GroupElem}
[, center=one(first(S)); radius=2, op=*, threading=true]) [, center=one(first(S)); radius=2, op=*])
Compute metric ball as a list of elements of non-decreasing length, given the Compute metric ball as a list of elements of non-decreasing length, given the
word-length metric on the group generated by `S`. The ball is centered at `center` word-length metric on the group generated by `S`. The ball is centered at `center`
(by default: the identity element). `radius` and `op` keywords specify the (by default: the identity element). `radius` and `op` keywords specify the
@ -11,57 +11,27 @@ function wlmetric_ball(
center::T = one(first(S)); center::T = one(first(S));
radius = 2, radius = 2,
op = *, op = *,
threading = true,
) where {T} ) where {T}
threading && return wlmetric_ball_thr(S, center; radius = radius, op = op) ball = [center]
return wlmetric_ball_serial(S, center; radius = radius, op = op) sizes = [1]
end if radius 0
return ball, sizes[2:end]
function wlmetric_ball_serial( else
S::AbstractVector{T}, ball = union!(ball, [center * s for s in S])
center::T = one(first(S)); push!(sizes, length(ball))
radius = 2, if radius == 1
op = *, return ball, sizes[2:end]
) where {T} else
@assert radius >= 1 for _ in 2:radius
old = union!(OrderedSet([center]), [center * s for s in S]) new = collect(
sizes = [1, length(old)] op(o, s) for o in @view(ball[sizes[end-1]:end]) for s in S
for _ in 2:radius )
new = collect( append!(ball, new)
op(o, s) for o in @view(old.dict.keys[sizes[end-1]:end]) for s in S unique!(ball)
) push!(sizes, length(ball))
union!(old, new) end
push!(sizes, length(old))
end
return old.dict.keys, sizes[2:end]
end
function wlmetric_ball_thr(
S::AbstractVector{T},
center::T = one(first(S));
radius = 2,
op = *,
) where {T}
@assert radius >= 1
old = union!([center], [center * s for s in S])
return _wlmetric_ball(S, old, radius, op, Folds.collect, Folds.unique)
end
function _wlmetric_ball(S, old, radius, op, collect, unique)
sizes = [1, length(old)]
for _ in 2:radius
old = let old = old, S = S
new = collect(
(g = op(o, s);
normalform!(g);
hash(g);
g) for o in @view(old[sizes[end-1]:end]) for s in S
)
append!(old, new)
unique(old)
end end
push!(sizes, length(old)) return ball, sizes[2:end]
end end
return old, sizes[2:end] # return wlmetric_ball_serial(S, center; radius = radius, op = op)
end end

View File

@ -5,14 +5,18 @@ using Groups
function wl_ball(F; radius::Integer) function wl_ball(F; radius::Integer)
g, state = iterate(F) g, state = iterate(F)
while length(word(g)) <= radius sizes = Int[]
while length(sizes) radius
res = iterate(F, state) res = iterate(F, state)
isnothing(res) && break isnothing(res) && break
g, state = res g, state = res
if length(word(g)) > length(sizes)
push!(sizes, length(state.seen) - 1)
end
end end
elts = collect(state.seen) elts = collect(state.seen)
elts = resize!(elts, length(elts)-1) resize!(elts, sizes[end] - 1)
return elts return elts, sizes[2:end]
end end
@testset "Benchmarks" begin @testset "Benchmarks" begin
@ -25,21 +29,16 @@ end
let G = FN let G = FN
S = unique([gens(G); inv.(gens(G))]) S = unique([gens(G); inv.(gens(G))])
sizes1 = last(Groups.wlmetric_ball(S, radius=R, threading=false)) sizes1 = last(Groups.wlmetric_ball(S; radius = R))
sizes2 = last(Groups.wlmetric_ball(S, radius=R, threading=true)) sizes2 = last(wl_ball(G; radius = R))
l = length(wl_ball(G, radius=R))
@test sizes1 == sizes2 @test sizes1 == sizes2
@test last(sizes1) == l
@info "Ball of radius $R in $(parent(first(S)))" sizes=sizes1 @info "Ball of radius $R in $(parent(first(S)))" sizes = sizes1
@info "serial" @info "serial"
@time Groups.wlmetric_ball(S, radius=R, threading=false) @time Groups.wlmetric_ball(S, radius = R)
@info "threaded"
@time Groups.wlmetric_ball(S, radius=R, threading=true)
@info "iteration" @info "iteration"
@time wl_ball(G, radius=R) @time wl_ball(G, radius = R)
end end
end end
@ -51,21 +50,16 @@ end
let G = SAutFN let G = SAutFN
S = unique([gens(G); inv.(gens(G))]) S = unique([gens(G); inv.(gens(G))])
sizes1 = last(Groups.wlmetric_ball(S, radius=R, threading=false)) sizes1 = last(Groups.wlmetric_ball(S; radius = R))
sizes2 = last(Groups.wlmetric_ball(S, radius=R, threading=true)) sizes2 = last(wl_ball(G; radius = R))
l = length(wl_ball(G, radius=R))
@test sizes1 == sizes2 @test sizes1 == sizes2
@test last(sizes1) == l
@info "Ball of radius $R in $(parent(first(S)))" sizes=sizes1 @info "Ball of radius $R in $(parent(first(S)))" sizes = sizes1
@info "serial" @info "serial"
@time Groups.wlmetric_ball(S, radius=R, threading=false) @time Groups.wlmetric_ball(S, radius = R)
@info "threaded"
@time Groups.wlmetric_ball(S, radius=R, threading=true)
@info "iteration" @info "iteration"
@time wl_ball(G, radius=R) @time wl_ball(G, radius = R)
end end
end end
end end

View File

@ -22,8 +22,6 @@ using Groups.MatrixGroups
S = unique([S; inv.(S)]) S = unique([S; inv.(S)])
_, sizes = Groups.wlmetric_ball(S; radius = 4) _, sizes = Groups.wlmetric_ball(S; radius = 4)
@test sizes == [7, 33, 141, 561] @test sizes == [7, 33, 141, 561]
_, sizes = Groups.wlmetric_ball_serial(S; radius = 4)
@test sizes == [7, 33, 141, 561]
Logging.with_logger(Logging.NullLogger()) do Logging.with_logger(Logging.NullLogger()) do
@testset "GroupsCore conformance" begin @testset "GroupsCore conformance" begin
@ -35,9 +33,9 @@ using Groups.MatrixGroups
end end
end end
x = w * inv(w) * r x = w * inv(SL3Z(word(w)[end:end])) * r
@test length(word(x)) == 5 @test length(word(x)) == length(word(r))
@test size(x) == (3, 3) @test size(x) == (3, 3)
@test eltype(x) == Int8 @test eltype(x) == Int8
@ -65,10 +63,10 @@ using Groups.MatrixGroups
end end
end end
x = gens(Sp6, 1) x = gens(Sp6, 1) * gens(Sp6, 2)^2
x *= inv(x) * gens(Sp6, 2) x *= inv(gens(Sp6, 2)^2) * gens(Sp6, 3)
@test length(word(x)) == 3 @test length(word(x)) == 2
@test size(x) == (6, 6) @test size(x) == (6, 6)
@test eltype(x) == Int8 @test eltype(x) == Int8
@ -80,7 +78,7 @@ using Groups.MatrixGroups
@test contains(sprint(show, MIME"text/plain"(), x), "∈ Sp{6,Int8}") @test contains(sprint(show, MIME"text/plain"(), x), "∈ Sp{6,Int8}")
@test sprint(print, x) isa String @test sprint(print, x) isa String
@test length(word(x)) == 1 @test length(word(x)) == 2
for g in gens(Sp6) for g in gens(Sp6)
@test MatrixGroups.issymplectic(MatrixGroups.matrix(g)) @test MatrixGroups.issymplectic(MatrixGroups.matrix(g))
@ -101,10 +99,10 @@ using Groups.MatrixGroups
end end
end end
x = gens(G, 1) x = gens(G, 1) * gens(G, 2)^3
x *= inv(x) * gens(G, 2) x *= gens(G, 2)^-3
@test length(word(x)) == 3 @test length(word(x)) == 1
@test size(x) == (6, 6) @test size(x) == (6, 6)
@test eltype(x) == Int16 @test eltype(x) == Int16