mirror of
https://github.com/kalmarek/Groups.jl.git
synced 2025-01-08 13:22:33 +01:00
add PoissonSampler for FPGroupElements
Words of length following the Poisson(λ=8) distribution are chosen uniformly at random.
This commit is contained in:
parent
5993cb328f
commit
148a472dd2
@ -27,6 +27,7 @@ include(joinpath("constructions", "constructions.jl"))
|
|||||||
import .Constructions
|
import .Constructions
|
||||||
|
|
||||||
include("types.jl")
|
include("types.jl")
|
||||||
|
include("rand.jl")
|
||||||
include("hashing.jl")
|
include("hashing.jl")
|
||||||
include("normalform.jl")
|
include("normalform.jl")
|
||||||
include("autgroups.jl")
|
include("autgroups.jl")
|
||||||
|
62
src/rand.jl
Normal file
62
src/rand.jl
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
"""
|
||||||
|
PoissonSampler
|
||||||
|
For a finitely presented group PoissonSampler returns group elements represented
|
||||||
|
by words of length at most `R ~ Poisson(λ)` chosen uniformly at random.
|
||||||
|
|
||||||
|
For finitely presented groups the Product Replacement Algorithm
|
||||||
|
(see `PRASampler` from `GroupsCore.jl`) doesn't make much sense due to
|
||||||
|
overly long words it produces. We therefore resort to a pseudo-random method,
|
||||||
|
where a word `w` of length `R` is chosen uniformly at random among all
|
||||||
|
words of length `R` where `R` follows the Poisson distribution.
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
Due to the choice of the parameters (`λ=8`) and the floating point
|
||||||
|
arithmetic the sampler will always return group elements represented by
|
||||||
|
words of length at most `42`.
|
||||||
|
"""
|
||||||
|
struct PoissonSampler{G,T} <: Random.Sampler{T}
|
||||||
|
group::G
|
||||||
|
λ::Int
|
||||||
|
end
|
||||||
|
|
||||||
|
function PoissonSampler(G::AbstractFPGroup; λ)
|
||||||
|
return PoissonSampler{typeof(G),eltype(G)}(G, λ)
|
||||||
|
end
|
||||||
|
|
||||||
|
function __poisson_invcdf(val; λ)
|
||||||
|
# __poisson_pdf(k, λ) = λ^k * ℯ^-λ / factorial(k)
|
||||||
|
# pdf = ntuple(k -> __poisson_pdf(k - 1, λ), 21)
|
||||||
|
# cdf = accumulate(+, pdf)
|
||||||
|
# radius = something(findfirst(>(val), cdf) - 1, 0)
|
||||||
|
# this is the iterative version:
|
||||||
|
pdf = ℯ^-λ
|
||||||
|
cdf = pdf
|
||||||
|
k = 0
|
||||||
|
while cdf < val
|
||||||
|
k += 1
|
||||||
|
pdf = pdf * λ / k
|
||||||
|
cdf += pdf
|
||||||
|
end
|
||||||
|
return k
|
||||||
|
end
|
||||||
|
|
||||||
|
function Random.rand(rng::Random.AbstractRNG, sampler::PoissonSampler)
|
||||||
|
R = __poisson_invcdf(rand(rng); λ = sampler.λ)
|
||||||
|
|
||||||
|
G = sampler.group
|
||||||
|
n = length(alphabet(G))
|
||||||
|
W = word_type(G)
|
||||||
|
T = eltype(W)
|
||||||
|
|
||||||
|
letters = rand(rng, T(1):T(n), R)
|
||||||
|
word = W(letters, false)
|
||||||
|
return G(word)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Random.Sampler(
|
||||||
|
RNG::Type{<:Random.AbstractRNG},
|
||||||
|
G::AbstractFPGroup,
|
||||||
|
repetition::Random.Repetition = Val(Inf),
|
||||||
|
)
|
||||||
|
return PoissonSampler(G; λ = 8)
|
||||||
|
end
|
11
src/types.jl
11
src/types.jl
@ -67,17 +67,6 @@ function GroupsCore.gens(G::AbstractFPGroup)
|
|||||||
return [gens(G, i) for i in 1:GroupsCore.ngens(G)]
|
return [gens(G, i) for i in 1:GroupsCore.ngens(G)]
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: ProductReplacementAlgorithm
|
|
||||||
function Base.rand(
|
|
||||||
rng::Random.AbstractRNG,
|
|
||||||
rs::Random.SamplerTrivial{<:AbstractFPGroup},
|
|
||||||
)
|
|
||||||
l = rand(10:100)
|
|
||||||
G = rs[]
|
|
||||||
nletters = length(alphabet(G))
|
|
||||||
return FPGroupElement(word_type(G)(rand(1:nletters, l)), G)
|
|
||||||
end
|
|
||||||
|
|
||||||
function Base.isfinite(::AbstractFPGroup)
|
function Base.isfinite(::AbstractFPGroup)
|
||||||
return (
|
return (
|
||||||
@warn "using generic isfinite(::AbstractFPGroup): the returned `false` might be wrong"; false
|
@warn "using generic isfinite(::AbstractFPGroup): the returned `false` might be wrong"; false
|
||||||
|
Loading…
Reference in New Issue
Block a user