more formatting
This commit is contained in:
parent
3cdef72977
commit
af3913d085
|
@ -0,0 +1 @@
|
||||||
|
../.JuliaFormatter.toml
|
|
@ -14,7 +14,14 @@ import KnuthBendix: alphabet, ordering
|
||||||
|
|
||||||
export MatrixGroups
|
export MatrixGroups
|
||||||
|
|
||||||
export Alphabet, AutomorphismGroup, FreeGroup, FreeGroup, FPGroup, FPGroupElement, SpecialAutomorphismGroup, Homomorphism
|
export Alphabet,
|
||||||
|
AutomorphismGroup,
|
||||||
|
FreeGroup,
|
||||||
|
FreeGroup,
|
||||||
|
FPGroup,
|
||||||
|
FPGroupElement,
|
||||||
|
SpecialAutomorphismGroup,
|
||||||
|
Homomorphism
|
||||||
|
|
||||||
export alphabet, evaluate, word, gens
|
export alphabet, evaluate, word, gens
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
function _abelianize(
|
function _abelianize(
|
||||||
i::Integer,
|
i::Integer,
|
||||||
source::AutomorphismGroup{<:FreeGroup},
|
source::AutomorphismGroup{<:FreeGroup},
|
||||||
target::MatrixGroups.SpecialLinearGroup{N,T}) where {N,T}
|
target::MatrixGroups.SpecialLinearGroup{N,T},
|
||||||
|
) where {N,T}
|
||||||
n = ngens(object(source))
|
n = ngens(object(source))
|
||||||
@assert n == N
|
@assert n == N
|
||||||
aut = alphabet(source)[i]
|
aut = alphabet(source)[i]
|
||||||
|
@ -12,7 +13,7 @@ function _abelianize(
|
||||||
eij = MatrixGroups.ElementaryMatrix{N}(
|
eij = MatrixGroups.ElementaryMatrix{N}(
|
||||||
aut.j,
|
aut.j,
|
||||||
aut.i,
|
aut.i,
|
||||||
ifelse(aut.inv, -one(T), one(T))
|
ifelse(aut.inv, -one(T), one(T)),
|
||||||
)
|
)
|
||||||
k = alphabet(target)[eij]
|
k = alphabet(target)[eij]
|
||||||
return word_type(target)([k])
|
return word_type(target)([k])
|
||||||
|
@ -24,7 +25,8 @@ end
|
||||||
function _abelianize(
|
function _abelianize(
|
||||||
i::Integer,
|
i::Integer,
|
||||||
source::AutomorphismGroup{<:Groups.SurfaceGroup},
|
source::AutomorphismGroup{<:Groups.SurfaceGroup},
|
||||||
target::MatrixGroups.SpecialLinearGroup{N,T}) where {N,T}
|
target::MatrixGroups.SpecialLinearGroup{N,T},
|
||||||
|
) where {N,T}
|
||||||
n = ngens(Groups.object(source))
|
n = ngens(Groups.object(source))
|
||||||
@assert n == N
|
@assert n == N
|
||||||
g = alphabet(source)[i].autFn_word
|
g = alphabet(source)[i].autFn_word
|
||||||
|
@ -39,7 +41,7 @@ end
|
||||||
function Groups._abelianize(
|
function Groups._abelianize(
|
||||||
i::Integer,
|
i::Integer,
|
||||||
source::AutomorphismGroup{<:Groups.SurfaceGroup},
|
source::AutomorphismGroup{<:Groups.SurfaceGroup},
|
||||||
target::MatrixGroups.SymplecticGroup{N,T}
|
target::MatrixGroups.SymplecticGroup{N,T},
|
||||||
) where {N,T}
|
) where {N,T}
|
||||||
@assert iseven(N)
|
@assert iseven(N)
|
||||||
As = alphabet(source)
|
As = alphabet(source)
|
||||||
|
@ -50,7 +52,7 @@ function Groups._abelianize(
|
||||||
MatrixGroups.SpecialLinearGroup{2genus}(T)
|
MatrixGroups.SpecialLinearGroup{2genus}(T)
|
||||||
end
|
end
|
||||||
|
|
||||||
ab = Groups.Homomorphism(Groups._abelianize, source, SlN, check=false)
|
ab = Groups.Homomorphism(Groups._abelianize, source, SlN; check = false)
|
||||||
|
|
||||||
matrix_spn_map = let S = gens(target)
|
matrix_spn_map = let S = gens(target)
|
||||||
Dict(MatrixGroups.matrix(g) => word(g) for g in union(S, inv.(S)))
|
Dict(MatrixGroups.matrix(g) => word(g) for g in union(S, inv.(S)))
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
function KnuthBendix.Alphabet(S::AbstractVector{<:GSymbol})
|
function KnuthBendix.Alphabet(S::AbstractVector{<:GSymbol})
|
||||||
S = unique!([S; inv.(S)])
|
S = union(S, inv.(S))
|
||||||
inversions = [findfirst(==(inv(s)), S) for s in S]
|
inversions = [findfirst(==(inv(s)), S) for s in S]
|
||||||
return Alphabet(S, inversions)
|
return Alphabet(S, inversions)
|
||||||
end
|
end
|
||||||
|
@ -26,7 +26,10 @@ function equality_data(f::AbstractFPGroupElement{<:AutomorphismGroup})
|
||||||
return imf
|
return imf
|
||||||
end
|
end
|
||||||
|
|
||||||
function Base.:(==)(g::A, h::A) where {A<:AbstractFPGroupElement{<:AutomorphismGroup}}
|
function Base.:(==)(
|
||||||
|
g::A,
|
||||||
|
h::A,
|
||||||
|
) where {A<:AbstractFPGroupElement{<:AutomorphismGroup}}
|
||||||
@assert parent(g) === parent(h)
|
@assert parent(g) === parent(h)
|
||||||
|
|
||||||
if _isvalidhash(g) && _isvalidhash(h)
|
if _isvalidhash(g) && _isvalidhash(h)
|
||||||
|
@ -79,32 +82,46 @@ end
|
||||||
|
|
||||||
# eye-candy
|
# eye-candy
|
||||||
|
|
||||||
Base.show(io::IO, ::Type{<:FPGroupElement{<:AutomorphismGroup{T}}}) where {T} =
|
function Base.show(
|
||||||
print(io, "Automorphism{$T, …}")
|
io::IO,
|
||||||
|
::Type{<:FPGroupElement{<:AutomorphismGroup{T}}},
|
||||||
|
) where {T}
|
||||||
|
return print(io, "Automorphism{$T, …}")
|
||||||
|
end
|
||||||
|
|
||||||
Base.show(io::IO, A::AutomorphismGroup) = print(io, "automorphism group of ", object(A))
|
function Base.show(io::IO, A::AutomorphismGroup)
|
||||||
|
return print(io, "automorphism group of ", object(A))
|
||||||
|
end
|
||||||
|
|
||||||
function Base.show(io::IO, ::MIME"text/plain", a::AbstractFPGroupElement{<:AutomorphismGroup})
|
function Base.show(
|
||||||
|
io::IO,
|
||||||
|
::MIME"text/plain",
|
||||||
|
a::AbstractFPGroupElement{<:AutomorphismGroup},
|
||||||
|
)
|
||||||
println(io, " ┌ $(a):")
|
println(io, " ┌ $(a):")
|
||||||
d = domain(a)
|
d = domain(a)
|
||||||
im = evaluate(a)
|
im = evaluate(a)
|
||||||
for (x, imx) in zip(d, im[1:end-1])
|
for (x, imx) in zip(d, im[1:end-1])
|
||||||
println(io, " │ $x ↦ $imx")
|
println(io, " │ $x ↦ $imx")
|
||||||
end
|
end
|
||||||
println(io, " └ $(last(d)) ↦ $(last(im))")
|
return println(io, " └ $(last(d)) ↦ $(last(im))")
|
||||||
end
|
end
|
||||||
|
|
||||||
## Automorphism Evaluation
|
## Automorphism Evaluation
|
||||||
|
|
||||||
domain(f::AbstractFPGroupElement{<:AutomorphismGroup}) = deepcopy(parent(f).domain)
|
function domain(f::AbstractFPGroupElement{<:AutomorphismGroup})
|
||||||
|
return deepcopy(parent(f).domain)
|
||||||
|
end
|
||||||
# tuple(gens(object(parent(f)))...)
|
# tuple(gens(object(parent(f)))...)
|
||||||
|
|
||||||
evaluate(f::AbstractFPGroupElement{<:AutomorphismGroup}) = evaluate!(domain(f), f)
|
function evaluate(f::AbstractFPGroupElement{<:AutomorphismGroup})
|
||||||
|
return evaluate!(domain(f), f)
|
||||||
|
end
|
||||||
|
|
||||||
function evaluate!(
|
function evaluate!(
|
||||||
t::NTuple{N,T},
|
t::NTuple{N,T},
|
||||||
f::AbstractFPGroupElement{<:AutomorphismGroup{<:Group}},
|
f::AbstractFPGroupElement{<:AutomorphismGroup{<:Group}},
|
||||||
tmp=one(first(t)),
|
tmp = one(first(t)),
|
||||||
) where {N,T<:FPGroupElement}
|
) where {N,T<:FPGroupElement}
|
||||||
A = alphabet(f)
|
A = alphabet(f)
|
||||||
for idx in word(f)
|
for idx in word(f)
|
||||||
|
@ -113,7 +130,11 @@ function evaluate!(
|
||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
evaluate!(t::NTuple{N,T}, s::GSymbol, tmp=nothing) where {N,T} = throw("you need to implement `evaluate!(::$(typeof(t)), ::$(typeof(s)), ::Alphabet, tmp=one(first(t)))`")
|
function evaluate!(t::NTuple{N,T}, s::GSymbol, tmp = nothing) where {N,T}
|
||||||
|
throw(
|
||||||
|
"you need to implement `evaluate!(::$(typeof(t)), ::$(typeof(s)), ::Alphabet, tmp=one(first(t)))`",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
# forward evaluate by substitution
|
# forward evaluate by substitution
|
||||||
|
|
||||||
|
@ -135,13 +156,13 @@ function LettersMap(a::FPGroupElement{<:AutomorphismGroup})
|
||||||
# (trusting it's a set of generators that define a)
|
# (trusting it's a set of generators that define a)
|
||||||
@assert length(dom) == length(img)
|
@assert length(dom) == length(img)
|
||||||
|
|
||||||
indices_map = Dict(A[A[fl]] => word(im) for (fl, im) in zip(first_letters, img))
|
indices_map =
|
||||||
|
Dict(A[A[fl]] => word(im) for (fl, im) in zip(first_letters, img))
|
||||||
# inverses of generators are dealt lazily in getindex
|
# inverses of generators are dealt lazily in getindex
|
||||||
|
|
||||||
return LettersMap(indices_map, A)
|
return LettersMap(indices_map, A)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function Base.getindex(lm::LettersMap, i::Integer)
|
function Base.getindex(lm::LettersMap, i::Integer)
|
||||||
# here i is an index of an alphabet
|
# here i is an index of an alphabet
|
||||||
@boundscheck 1 ≤ i ≤ length(lm.A)
|
@boundscheck 1 ≤ i ≤ length(lm.A)
|
||||||
|
|
|
@ -12,25 +12,29 @@ struct DirectPowerElement{GEl,N,Gr<:GroupsCore.Group} <: GroupsCore.GroupElement
|
||||||
parent::DirectPower{Gr,N,GEl}
|
parent::DirectPower{Gr,N,GEl}
|
||||||
end
|
end
|
||||||
|
|
||||||
DirectPowerElement(
|
function DirectPowerElement(
|
||||||
elts::AbstractVector{<:GroupsCore.GroupElement},
|
elts::AbstractVector{<:GroupsCore.GroupElement},
|
||||||
G::DirectPower,
|
G::DirectPower,
|
||||||
) = DirectPowerElement(ntuple(i -> elts[i], _nfold(G)), G)
|
)
|
||||||
|
return DirectPowerElement(ntuple(i -> elts[i], _nfold(G)), G)
|
||||||
|
end
|
||||||
|
|
||||||
_nfold(::DirectPower{Gr,N}) where {Gr,N} = N
|
_nfold(::DirectPower{Gr,N}) where {Gr,N} = N
|
||||||
|
|
||||||
Base.one(G::DirectPower) =
|
function Base.one(G::DirectPower)
|
||||||
DirectPowerElement(ntuple(_ -> one(G.group), _nfold(G)), G)
|
return DirectPowerElement(ntuple(_ -> one(G.group), _nfold(G)), G)
|
||||||
|
end
|
||||||
|
|
||||||
Base.eltype(::Type{<:DirectPower{Gr,N,GEl}}) where {Gr,N,GEl} =
|
function Base.eltype(::Type{<:DirectPower{Gr,N,GEl}}) where {Gr,N,GEl}
|
||||||
DirectPowerElement{GEl,N,Gr}
|
return DirectPowerElement{GEl,N,Gr}
|
||||||
|
end
|
||||||
|
|
||||||
function Base.iterate(G::DirectPower)
|
function Base.iterate(G::DirectPower)
|
||||||
itr = Iterators.ProductIterator(ntuple(i -> G.group, _nfold(G)))
|
itr = Iterators.ProductIterator(ntuple(i -> G.group, _nfold(G)))
|
||||||
res = iterate(itr)
|
res = iterate(itr)
|
||||||
@assert res !== nothing
|
@assert res !== nothing
|
||||||
elt = DirectPowerElement(first(res), G)
|
elt = DirectPowerElement(first(res), G)
|
||||||
return elt, (iterator=itr, state=last(res))
|
return elt, (iterator = itr, state = last(res))
|
||||||
end
|
end
|
||||||
|
|
||||||
function Base.iterate(G::DirectPower, state)
|
function Base.iterate(G::DirectPower, state)
|
||||||
|
@ -38,7 +42,7 @@ function Base.iterate(G::DirectPower, state)
|
||||||
res = iterate(itr, st)
|
res = iterate(itr, st)
|
||||||
res === nothing && return nothing
|
res === nothing && return nothing
|
||||||
elt = DirectPowerElement(first(res), G)
|
elt = DirectPowerElement(first(res), G)
|
||||||
return elt, (iterator=itr, state=last(res))
|
return elt, (iterator = itr, state = last(res))
|
||||||
end
|
end
|
||||||
|
|
||||||
function Base.IteratorSize(::Type{<:DirectPower{Gr,N}}) where {Gr,N}
|
function Base.IteratorSize(::Type{<:DirectPower{Gr,N}}) where {Gr,N}
|
||||||
|
@ -49,8 +53,9 @@ end
|
||||||
|
|
||||||
Base.size(G::DirectPower) = ntuple(_ -> length(G.group), _nfold(G))
|
Base.size(G::DirectPower) = ntuple(_ -> length(G.group), _nfold(G))
|
||||||
|
|
||||||
GroupsCore.order(::Type{I}, G::DirectPower) where {I<:Integer} =
|
function GroupsCore.order(::Type{I}, G::DirectPower) where {I<:Integer}
|
||||||
convert(I, order(I, G.group)^_nfold(G))
|
return convert(I, order(I, G.group)^_nfold(G))
|
||||||
|
end
|
||||||
|
|
||||||
GroupsCore.ngens(G::DirectPower) = _nfold(G) * ngens(G.group)
|
GroupsCore.ngens(G::DirectPower) = _nfold(G) * ngens(G.group)
|
||||||
|
|
||||||
|
@ -83,13 +88,18 @@ end
|
||||||
|
|
||||||
GroupsCore.parent(g::DirectPowerElement) = g.parent
|
GroupsCore.parent(g::DirectPowerElement) = g.parent
|
||||||
|
|
||||||
Base.:(==)(g::DirectPowerElement, h::DirectPowerElement) =
|
function Base.:(==)(g::DirectPowerElement, h::DirectPowerElement)
|
||||||
(parent(g) === parent(h) && g.elts == h.elts)
|
return (parent(g) === parent(h) && g.elts == h.elts)
|
||||||
|
end
|
||||||
|
|
||||||
Base.hash(g::DirectPowerElement, h::UInt) = hash(g.elts, hash(parent(g), h))
|
Base.hash(g::DirectPowerElement, h::UInt) = hash(g.elts, hash(parent(g), h))
|
||||||
|
|
||||||
Base.deepcopy_internal(g::DirectPowerElement, stackdict::IdDict) =
|
function Base.deepcopy_internal(g::DirectPowerElement, stackdict::IdDict)
|
||||||
DirectPowerElement(Base.deepcopy_internal(g.elts, stackdict), parent(g))
|
return DirectPowerElement(
|
||||||
|
Base.deepcopy_internal(g.elts, stackdict),
|
||||||
|
parent(g),
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
Base.inv(g::DirectPowerElement) = DirectPowerElement(inv.(g.elts), parent(g))
|
Base.inv(g::DirectPowerElement) = DirectPowerElement(inv.(g.elts), parent(g))
|
||||||
|
|
||||||
|
@ -98,15 +108,25 @@ function Base.:(*)(g::DirectPowerElement, h::DirectPowerElement)
|
||||||
return DirectPowerElement(g.elts .* h.elts, parent(g))
|
return DirectPowerElement(g.elts .* h.elts, parent(g))
|
||||||
end
|
end
|
||||||
|
|
||||||
GroupsCore.order(::Type{I}, g::DirectPowerElement) where {I<:Integer} =
|
function GroupsCore.order(::Type{I}, g::DirectPowerElement) where {I<:Integer}
|
||||||
convert(I, reduce(lcm, (order(I, h) for h in g.elts), init=one(I)))
|
return convert(I, reduce(lcm, (order(I, h) for h in g.elts); init = one(I)))
|
||||||
|
end
|
||||||
|
|
||||||
Base.isone(g::DirectPowerElement) = all(isone, g.elts)
|
Base.isone(g::DirectPowerElement) = all(isone, g.elts)
|
||||||
|
|
||||||
function Base.show(io::IO, G::DirectPower)
|
function Base.show(io::IO, G::DirectPower)
|
||||||
n = _nfold(G)
|
n = _nfold(G)
|
||||||
nn = n == 1 ? "1-st" : n == 2 ? "2-nd" : n == 3 ? "3-rd" : "$n-th"
|
nn = n == 1 ? "1-st" : n == 2 ? "2-nd" : n == 3 ? "3-rd" : "$n-th"
|
||||||
print(io, "Direct $(nn) power of $(G.group)")
|
return print(io, "Direct $(nn) power of $(G.group)")
|
||||||
|
end
|
||||||
|
function Base.show(io::IO, g::DirectPowerElement)
|
||||||
|
return print(io, "( ", join(g.elts, ", "), " )")
|
||||||
|
end
|
||||||
|
|
||||||
|
# convienience:
|
||||||
|
Base.@propagate_inbounds function Base.getindex(
|
||||||
|
g::DirectPowerElement,
|
||||||
|
i::Integer,
|
||||||
|
)
|
||||||
|
return g.elts[i]
|
||||||
end
|
end
|
||||||
Base.show(io::IO, g::DirectPowerElement) =
|
|
||||||
print(io, "( ", join(g.elts, ", "), " )")
|
|
||||||
|
|
|
@ -14,18 +14,22 @@ end
|
||||||
|
|
||||||
DirectProductElement(g, h, G::DirectProduct) = DirectProduct((g, h), G)
|
DirectProductElement(g, h, G::DirectProduct) = DirectProduct((g, h), G)
|
||||||
|
|
||||||
Base.one(G::DirectProduct) =
|
function Base.one(G::DirectProduct)
|
||||||
DirectProductElement((one(G.first), one(G.last)), G)
|
return DirectProductElement((one(G.first), one(G.last)), G)
|
||||||
|
end
|
||||||
|
|
||||||
Base.eltype(::Type{<:DirectProduct{Gt,Ht,GEl,HEl}}) where {Gt,Ht,GEl,HEl} =
|
function Base.eltype(
|
||||||
DirectProductElement{GEl,HEl,Gt,Ht}
|
::Type{<:DirectProduct{Gt,Ht,GEl,HEl}},
|
||||||
|
) where {Gt,Ht,GEl,HEl}
|
||||||
|
return DirectProductElement{GEl,HEl,Gt,Ht}
|
||||||
|
end
|
||||||
|
|
||||||
function Base.iterate(G::DirectProduct)
|
function Base.iterate(G::DirectProduct)
|
||||||
itr = Iterators.product(G.first, G.last)
|
itr = Iterators.product(G.first, G.last)
|
||||||
res = iterate(itr)
|
res = iterate(itr)
|
||||||
@assert res !== nothing
|
@assert res !== nothing
|
||||||
elt = DirectProductElement(first(res), G)
|
elt = DirectProductElement(first(res), G)
|
||||||
return elt, (iterator=itr, state=last(res))
|
return elt, (iterator = itr, state = last(res))
|
||||||
end
|
end
|
||||||
|
|
||||||
function Base.iterate(G::DirectProduct, state)
|
function Base.iterate(G::DirectProduct, state)
|
||||||
|
@ -33,7 +37,7 @@ function Base.iterate(G::DirectProduct, state)
|
||||||
res = iterate(itr, st)
|
res = iterate(itr, st)
|
||||||
res === nothing && return nothing
|
res === nothing && return nothing
|
||||||
elt = DirectProductElement(first(res), G)
|
elt = DirectProductElement(first(res), G)
|
||||||
return elt, (iterator=itr, state=last(res))
|
return elt, (iterator = itr, state = last(res))
|
||||||
end
|
end
|
||||||
|
|
||||||
function Base.IteratorSize(::Type{<:DirectProduct{Gt,Ht}}) where {Gt,Ht}
|
function Base.IteratorSize(::Type{<:DirectProduct{Gt,Ht}}) where {Gt,Ht}
|
||||||
|
@ -50,15 +54,18 @@ end
|
||||||
|
|
||||||
Base.size(G::DirectProduct) = (length(G.first), length(G.last))
|
Base.size(G::DirectProduct) = (length(G.first), length(G.last))
|
||||||
|
|
||||||
GroupsCore.order(::Type{I}, G::DirectProduct) where {I<:Integer} =
|
function GroupsCore.order(::Type{I}, G::DirectProduct) where {I<:Integer}
|
||||||
convert(I, order(I, G.first) * order(I, G.last))
|
return convert(I, order(I, G.first) * order(I, G.last))
|
||||||
|
end
|
||||||
|
|
||||||
GroupsCore.ngens(G::DirectProduct) = ngens(G.first) + ngens(G.last)
|
GroupsCore.ngens(G::DirectProduct) = ngens(G.first) + ngens(G.last)
|
||||||
|
|
||||||
function GroupsCore.gens(G::DirectProduct)
|
function GroupsCore.gens(G::DirectProduct)
|
||||||
gens_first = [DirectProductElement((g, one(G.last)), G) for g in gens(G.first)]
|
gens_first =
|
||||||
|
[DirectProductElement((g, one(G.last)), G) for g in gens(G.first)]
|
||||||
|
|
||||||
gens_last = [DirectProductElement((one(G.first), g), G) for g in gens(G.last)]
|
gens_last =
|
||||||
|
[DirectProductElement((one(G.first), g), G) for g in gens(G.last)]
|
||||||
|
|
||||||
return [gens_first; gens_last]
|
return [gens_first; gens_last]
|
||||||
end
|
end
|
||||||
|
@ -75,28 +82,45 @@ end
|
||||||
|
|
||||||
GroupsCore.parent(g::DirectProductElement) = g.parent
|
GroupsCore.parent(g::DirectProductElement) = g.parent
|
||||||
|
|
||||||
Base.:(==)(g::DirectProductElement, h::DirectProductElement) =
|
function Base.:(==)(g::DirectProductElement, h::DirectProductElement)
|
||||||
(parent(g) === parent(h) && g.elts == h.elts)
|
return (parent(g) === parent(h) && g.elts == h.elts)
|
||||||
|
end
|
||||||
|
|
||||||
Base.hash(g::DirectProductElement, h::UInt) = hash(g.elts, hash(parent(g), h))
|
Base.hash(g::DirectProductElement, h::UInt) = hash(g.elts, hash(parent(g), h))
|
||||||
|
|
||||||
Base.deepcopy_internal(g::DirectProductElement, stackdict::IdDict) =
|
function Base.deepcopy_internal(g::DirectProductElement, stackdict::IdDict)
|
||||||
DirectProductElement(Base.deepcopy_internal(g.elts, stackdict), parent(g))
|
return DirectProductElement(
|
||||||
|
Base.deepcopy_internal(g.elts, stackdict),
|
||||||
|
parent(g),
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
Base.inv(g::DirectProductElement) =
|
function Base.inv(g::DirectProductElement)
|
||||||
DirectProductElement(inv.(g.elts), parent(g))
|
return DirectProductElement(inv.(g.elts), parent(g))
|
||||||
|
end
|
||||||
|
|
||||||
function Base.:(*)(g::DirectProductElement, h::DirectProductElement)
|
function Base.:(*)(g::DirectProductElement, h::DirectProductElement)
|
||||||
@assert parent(g) === parent(h)
|
@assert parent(g) === parent(h)
|
||||||
return DirectProductElement(g.elts .* h.elts, parent(g))
|
return DirectProductElement(g.elts .* h.elts, parent(g))
|
||||||
end
|
end
|
||||||
|
|
||||||
GroupsCore.order(::Type{I}, g::DirectProductElement) where {I<:Integer} =
|
function GroupsCore.order(::Type{I}, g::DirectProductElement) where {I<:Integer}
|
||||||
convert(I, lcm(order(I, first(g.elts)), order(I, last(g.elts))))
|
return convert(I, lcm(order(I, first(g.elts)), order(I, last(g.elts))))
|
||||||
|
end
|
||||||
|
|
||||||
Base.isone(g::DirectProductElement) = all(isone, g.elts)
|
Base.isone(g::DirectProductElement) = all(isone, g.elts)
|
||||||
|
|
||||||
Base.show(io::IO, G::DirectProduct) =
|
function Base.show(io::IO, G::DirectProduct)
|
||||||
print(io, "Direct product of $(G.first) and $(G.last)")
|
return print(io, "Direct product of $(G.first) and $(G.last)")
|
||||||
Base.show(io::IO, g::DirectProductElement) =
|
end
|
||||||
print(io, "( $(join(g.elts, ",")) )")
|
function Base.show(io::IO, g::DirectProductElement)
|
||||||
|
return print(io, "( $(join(g.elts, ",")) )")
|
||||||
|
end
|
||||||
|
|
||||||
|
# convienience:
|
||||||
|
Base.@propagate_inbounds function Base.getindex(
|
||||||
|
g::DirectProductElement,
|
||||||
|
i::Integer,
|
||||||
|
)
|
||||||
|
return g.elts[i]
|
||||||
|
end
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import PermutationGroups: AbstractPermutationGroup, AbstractPerm, degree, SymmetricGroup
|
import PermutationGroups:
|
||||||
|
AbstractPermutationGroup, AbstractPerm, degree, SymmetricGroup
|
||||||
|
|
||||||
"""
|
"""
|
||||||
WreathProduct(G::Group, P::AbstractPermutationGroup) <: Group
|
WreathProduct(G::Group, P::AbstractPermutationGroup) <: Group
|
||||||
|
@ -38,21 +39,22 @@ struct WreathProductElement{
|
||||||
p::AbstractPerm,
|
p::AbstractPerm,
|
||||||
W::WreathProduct,
|
W::WreathProduct,
|
||||||
)
|
)
|
||||||
new{typeof(n),typeof(p),typeof(W)}(n, p, W)
|
return new{typeof(n),typeof(p),typeof(W)}(n, p, W)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Base.one(W::WreathProduct) = WreathProductElement(one(W.N), one(W.P), W)
|
Base.one(W::WreathProduct) = WreathProductElement(one(W.N), one(W.P), W)
|
||||||
|
|
||||||
Base.eltype(::Type{<:WreathProduct{DP,PGr}}) where {DP,PGr} =
|
function Base.eltype(::Type{<:WreathProduct{DP,PGr}}) where {DP,PGr}
|
||||||
WreathProductElement{eltype(DP),eltype(PGr),WreathProduct{DP,PGr}}
|
return WreathProductElement{eltype(DP),eltype(PGr),WreathProduct{DP,PGr}}
|
||||||
|
end
|
||||||
|
|
||||||
function Base.iterate(G::WreathProduct)
|
function Base.iterate(G::WreathProduct)
|
||||||
itr = Iterators.product(G.N, G.P)
|
itr = Iterators.product(G.N, G.P)
|
||||||
res = iterate(itr)
|
res = iterate(itr)
|
||||||
@assert res !== nothing
|
@assert res !== nothing
|
||||||
elt = WreathProductElement(first(res)..., G)
|
elt = WreathProductElement(first(res)..., G)
|
||||||
return elt, (iterator=itr, state=last(res))
|
return elt, (iterator = itr, state = last(res))
|
||||||
end
|
end
|
||||||
|
|
||||||
function Base.iterate(G::WreathProduct, state)
|
function Base.iterate(G::WreathProduct, state)
|
||||||
|
@ -60,7 +62,7 @@ function Base.iterate(G::WreathProduct, state)
|
||||||
res = iterate(itr, st)
|
res = iterate(itr, st)
|
||||||
res === nothing && return nothing
|
res === nothing && return nothing
|
||||||
elt = WreathProductElement(first(res)..., G)
|
elt = WreathProductElement(first(res)..., G)
|
||||||
return elt, (iterator=itr, state=last(res))
|
return elt, (iterator = itr, state = last(res))
|
||||||
end
|
end
|
||||||
|
|
||||||
function Base.IteratorSize(::Type{<:WreathProduct{DP,PGr}}) where {DP,PGr}
|
function Base.IteratorSize(::Type{<:WreathProduct{DP,PGr}}) where {DP,PGr}
|
||||||
|
@ -78,8 +80,9 @@ end
|
||||||
|
|
||||||
Base.size(G::WreathProduct) = (length(G.N), length(G.P))
|
Base.size(G::WreathProduct) = (length(G.N), length(G.P))
|
||||||
|
|
||||||
GroupsCore.order(::Type{I}, G::WreathProduct) where {I<:Integer} =
|
function GroupsCore.order(::Type{I}, G::WreathProduct) where {I<:Integer}
|
||||||
convert(I, order(I, G.N) * order(I, G.P))
|
return convert(I, order(I, G.N) * order(I, G.P))
|
||||||
|
end
|
||||||
|
|
||||||
function GroupsCore.gens(G::WreathProduct)
|
function GroupsCore.gens(G::WreathProduct)
|
||||||
N_gens = [WreathProductElement(n, one(G.P), G) for n in gens(G.N)]
|
N_gens = [WreathProductElement(n, one(G.P), G) for n in gens(G.N)]
|
||||||
|
@ -93,18 +96,19 @@ function Base.rand(
|
||||||
rng::Random.AbstractRNG,
|
rng::Random.AbstractRNG,
|
||||||
rs::Random.SamplerTrivial{<:WreathProduct},
|
rs::Random.SamplerTrivial{<:WreathProduct},
|
||||||
)
|
)
|
||||||
|
|
||||||
G = rs[]
|
G = rs[]
|
||||||
return WreathProductElement(rand(rng, G.N), rand(rng, G.P), G)
|
return WreathProductElement(rand(rng, G.N), rand(rng, G.P), G)
|
||||||
end
|
end
|
||||||
|
|
||||||
GroupsCore.parent(g::WreathProductElement) = g.parent
|
GroupsCore.parent(g::WreathProductElement) = g.parent
|
||||||
|
|
||||||
Base.:(==)(g::WreathProductElement, h::WreathProductElement) =
|
function Base.:(==)(g::WreathProductElement, h::WreathProductElement)
|
||||||
parent(g) === parent(h) && g.n == h.n && g.p == h.p
|
return parent(g) === parent(h) && g.n == h.n && g.p == h.p
|
||||||
|
end
|
||||||
|
|
||||||
Base.hash(g::WreathProductElement, h::UInt) =
|
function Base.hash(g::WreathProductElement, h::UInt)
|
||||||
hash(g.n, hash(g.p, hash(g.parent, h)))
|
return hash(g.n, hash(g.p, hash(g.parent, h)))
|
||||||
|
end
|
||||||
|
|
||||||
function Base.deepcopy_internal(g::WreathProductElement, stackdict::IdDict)
|
function Base.deepcopy_internal(g::WreathProductElement, stackdict::IdDict)
|
||||||
return WreathProductElement(
|
return WreathProductElement(
|
||||||
|
@ -114,8 +118,9 @@ function Base.deepcopy_internal(g::WreathProductElement, stackdict::IdDict)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
_act(p::AbstractPerm, n::DirectPowerElement) =
|
function _act(p::AbstractPerm, n::DirectPowerElement)
|
||||||
DirectPowerElement(n.elts^p, parent(n))
|
return DirectPowerElement(n.elts^p, parent(n))
|
||||||
|
end
|
||||||
|
|
||||||
function Base.inv(g::WreathProductElement)
|
function Base.inv(g::WreathProductElement)
|
||||||
pinv = inv(g.p)
|
pinv = inv(g.p)
|
||||||
|
@ -129,8 +134,9 @@ end
|
||||||
|
|
||||||
Base.isone(g::WreathProductElement) = isone(g.n) && isone(g.p)
|
Base.isone(g::WreathProductElement) = isone(g.n) && isone(g.p)
|
||||||
|
|
||||||
Base.show(io::IO, G::WreathProduct) =
|
function Base.show(io::IO, G::WreathProduct)
|
||||||
print(io, "Wreath product of $(G.N.group) by $(G.P)")
|
return print(io, "Wreath product of $(G.N.group) by $(G.P)")
|
||||||
|
end
|
||||||
Base.show(io::IO, g::WreathProductElement) = print(io, "( $(g.n)≀$(g.p) )")
|
Base.show(io::IO, g::WreathProductElement) = print(io, "( $(g.n)≀$(g.p) )")
|
||||||
|
|
||||||
Base.copy(g::WreathProductElement) = WreathProductElement(g.n, g.p, parent(g))
|
Base.copy(g::WreathProductElement) = WreathProductElement(g.n, g.p, parent(g))
|
||||||
|
|
|
@ -20,8 +20,12 @@ _isvalidhash(g::AbstractFPGroupElement) = bitget(g.savedhash, 1)
|
||||||
_setnormalform(h::UInt, v::Bool) = bitset(h, v, 0)
|
_setnormalform(h::UInt, v::Bool) = bitset(h, v, 0)
|
||||||
_setvalidhash(h::UInt, v::Bool) = bitset(h, v, 1)
|
_setvalidhash(h::UInt, v::Bool) = bitset(h, v, 1)
|
||||||
|
|
||||||
_setnormalform!(g::AbstractFPGroupElement, v::Bool) = g.savedhash = _setnormalform(g.savedhash, v)
|
function _setnormalform!(g::AbstractFPGroupElement, v::Bool)
|
||||||
_setvalidhash!(g::AbstractFPGroupElement, v::Bool) = g.savedhash = _setvalidhash(g.savedhash, v)
|
return g.savedhash = _setnormalform(g.savedhash, v)
|
||||||
|
end
|
||||||
|
function _setvalidhash!(g::AbstractFPGroupElement, v::Bool)
|
||||||
|
return g.savedhash = _setvalidhash(g.savedhash, v)
|
||||||
|
end
|
||||||
|
|
||||||
# To update hash use this internal method, possibly only after computing the
|
# To update hash use this internal method, possibly only after computing the
|
||||||
# normal form of `g`:
|
# normal form of `g`:
|
||||||
|
|
|
@ -67,11 +67,13 @@ struct Homomorphism{Gr1,Gr2,I,W}
|
||||||
f,
|
f,
|
||||||
source::AbstractFPGroup,
|
source::AbstractFPGroup,
|
||||||
target::AbstractFPGroup;
|
target::AbstractFPGroup;
|
||||||
check=true
|
check = true,
|
||||||
)
|
)
|
||||||
A = alphabet(source)
|
A = alphabet(source)
|
||||||
dct = Dict(i => convert(word_type(target), f(i, source, target))
|
dct = Dict(
|
||||||
for i in 1:length(A))
|
i => convert(word_type(target), f(i, source, target)) for
|
||||||
|
i in 1:length(A)
|
||||||
|
)
|
||||||
I = eltype(word_type(source))
|
I = eltype(word_type(source))
|
||||||
W = word_type(target)
|
W = word_type(target)
|
||||||
hom = new{typeof(source),typeof(target),I,W}(dct, source, target)
|
hom = new{typeof(source),typeof(target),I,W}(dct, source, target)
|
||||||
|
@ -79,7 +81,6 @@ struct Homomorphism{Gr1,Gr2,I,W}
|
||||||
if check
|
if check
|
||||||
@assert hom(one(source)) == one(target)
|
@assert hom(one(source)) == one(target)
|
||||||
for x in gens(source)
|
for x in gens(source)
|
||||||
|
|
||||||
@assert hom(x^-1) == hom(x)^-1
|
@assert hom(x^-1) == hom(x)^-1
|
||||||
|
|
||||||
for y in gens(source)
|
for y in gens(source)
|
||||||
|
@ -111,4 +112,6 @@ function (h::Homomorphism)(g::AbstractFPGroupElement)
|
||||||
return h.target(w)
|
return h.target(w)
|
||||||
end
|
end
|
||||||
|
|
||||||
Base.show(io::IO, h::Homomorphism) = print(io, "Homomorphism\n from : $(h.source)\n to : $(h.target)")
|
function Base.show(io::IO, h::Homomorphism)
|
||||||
|
return print(io, "Homomorphism\n from : $(h.source)\n to : $(h.target)")
|
||||||
|
end
|
||||||
|
|
71
src/types.jl
71
src/types.jl
|
@ -42,10 +42,7 @@ KnuthBendix.alphabet(G::AbstractFPGroup) = alphabet(ordering(G))
|
||||||
Base.@propagate_inbounds function (G::AbstractFPGroup)(
|
Base.@propagate_inbounds function (G::AbstractFPGroup)(
|
||||||
word::AbstractVector{<:Integer},
|
word::AbstractVector{<:Integer},
|
||||||
)
|
)
|
||||||
@boundscheck @assert all(
|
@boundscheck @assert all(l -> 1 <= l <= length(alphabet(G)), word)
|
||||||
l -> 1 <= l <= length(alphabet(G)),
|
|
||||||
word,
|
|
||||||
)
|
|
||||||
return FPGroupElement(word_type(G)(word), G)
|
return FPGroupElement(word_type(G)(word), G)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -53,8 +50,9 @@ end
|
||||||
|
|
||||||
Base.one(G::AbstractFPGroup) = FPGroupElement(one(word_type(G)), G)
|
Base.one(G::AbstractFPGroup) = FPGroupElement(one(word_type(G)), G)
|
||||||
|
|
||||||
Base.eltype(::Type{FPG}) where {FPG<:AbstractFPGroup} =
|
function Base.eltype(::Type{FPG}) where {FPG<:AbstractFPGroup}
|
||||||
FPGroupElement{FPG,word_type(FPG)}
|
return FPGroupElement{FPG,word_type(FPG)}
|
||||||
|
end
|
||||||
|
|
||||||
include("iteration.jl")
|
include("iteration.jl")
|
||||||
|
|
||||||
|
@ -65,8 +63,9 @@ function GroupsCore.gens(G::AbstractFPGroup, i::Integer)
|
||||||
l = alphabet(G)[G.gens[i]]
|
l = alphabet(G)[G.gens[i]]
|
||||||
return FPGroupElement(word_type(G)([l]), G)
|
return FPGroupElement(word_type(G)([l]), G)
|
||||||
end
|
end
|
||||||
GroupsCore.gens(G::AbstractFPGroup) =
|
function GroupsCore.gens(G::AbstractFPGroup)
|
||||||
[gens(G, i) for i in 1:GroupsCore.ngens(G)]
|
return [gens(G, i) for i in 1:GroupsCore.ngens(G)]
|
||||||
|
end
|
||||||
|
|
||||||
# TODO: ProductReplacementAlgorithm
|
# TODO: ProductReplacementAlgorithm
|
||||||
function Base.rand(
|
function Base.rand(
|
||||||
|
@ -79,9 +78,11 @@ function Base.rand(
|
||||||
return FPGroupElement(word_type(G)(rand(1:nletters, l)), G)
|
return FPGroupElement(word_type(G)(rand(1:nletters, l)), G)
|
||||||
end
|
end
|
||||||
|
|
||||||
Base.isfinite(::AbstractFPGroup) = (
|
function Base.isfinite(::AbstractFPGroup)
|
||||||
@warn "using generic isfinite(::AbstractFPGroup): the returned `false` might be wrong"; false
|
return (
|
||||||
)
|
@warn "using generic isfinite(::AbstractFPGroup): the returned `false` might be wrong"; false
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
## FPGroupElement
|
## FPGroupElement
|
||||||
|
|
||||||
|
@ -93,18 +94,22 @@ mutable struct FPGroupElement{Gr<:AbstractFPGroup,W<:AbstractWord} <:
|
||||||
savedhash::UInt
|
savedhash::UInt
|
||||||
parent::Gr
|
parent::Gr
|
||||||
|
|
||||||
FPGroupElement(
|
function FPGroupElement(
|
||||||
word::W,
|
word::W,
|
||||||
G::AbstractFPGroup,
|
G::AbstractFPGroup,
|
||||||
hash::UInt=UInt(0),
|
hash::UInt = UInt(0),
|
||||||
) where {W<:AbstractWord} = new{typeof(G),W}(word, hash, G)
|
) where {W<:AbstractWord}
|
||||||
|
return new{typeof(G),W}(word, hash, G)
|
||||||
|
end
|
||||||
|
|
||||||
FPGroupElement{Gr,W}(word::AbstractWord, G::Gr) where {Gr,W} =
|
function FPGroupElement{Gr,W}(word::AbstractWord, G::Gr) where {Gr,W}
|
||||||
new{Gr,W}(word, UInt(0), G)
|
return new{Gr,W}(word, UInt(0), G)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Base.show(io::IO, ::Type{<:FPGroupElement{Gr}}) where {Gr} =
|
function Base.show(io::IO, ::Type{<:FPGroupElement{Gr}}) where {Gr}
|
||||||
print(io, FPGroupElement, "{$Gr, …}")
|
return print(io, FPGroupElement, "{$Gr, …}")
|
||||||
|
end
|
||||||
|
|
||||||
word(f::AbstractFPGroupElement) = f.word
|
word(f::AbstractFPGroupElement) = f.word
|
||||||
|
|
||||||
|
@ -142,11 +147,12 @@ function Base.:(*)(g::GEl, h::GEl) where {GEl<:AbstractFPGroupElement}
|
||||||
return GEl(word(g) * word(h), parent(g))
|
return GEl(word(g) * word(h), parent(g))
|
||||||
end
|
end
|
||||||
|
|
||||||
GroupsCore.isfiniteorder(g::AbstractFPGroupElement) =
|
function GroupsCore.isfiniteorder(g::AbstractFPGroupElement)
|
||||||
isone(g) ? true :
|
return isone(g) ? true :
|
||||||
(
|
(
|
||||||
@warn "using generic isfiniteorder(::AbstractFPGroupElement): the returned `false` might be wrong"; false
|
@warn "using generic isfiniteorder(::AbstractFPGroupElement): the returned `false` might be wrong"; false
|
||||||
)
|
)
|
||||||
|
end
|
||||||
|
|
||||||
# additional methods:
|
# additional methods:
|
||||||
Base.isone(g::AbstractFPGroupElement) = (normalform!(g); isempty(word(g)))
|
Base.isone(g::AbstractFPGroupElement) = (normalform!(g); isempty(word(g)))
|
||||||
|
@ -167,9 +173,7 @@ end
|
||||||
FreeGroup(gens, A::Alphabet) = FreeGroup(gens, KnuthBendix.LenLex(A))
|
FreeGroup(gens, A::Alphabet) = FreeGroup(gens, KnuthBendix.LenLex(A))
|
||||||
|
|
||||||
function FreeGroup(A::Alphabet)
|
function FreeGroup(A::Alphabet)
|
||||||
@boundscheck @assert all(
|
@boundscheck @assert all(KnuthBendix.hasinverse(l, A) for l in A)
|
||||||
KnuthBendix.hasinverse(l, A) for l in A
|
|
||||||
)
|
|
||||||
gens = Vector{eltype(A)}()
|
gens = Vector{eltype(A)}()
|
||||||
invs = Vector{eltype(A)}()
|
invs = Vector{eltype(A)}()
|
||||||
for l in A
|
for l in A
|
||||||
|
@ -193,8 +197,9 @@ function FreeGroup(n::Integer)
|
||||||
return FreeGroup(symbols[1:2:2n], Alphabet(symbols, inverses))
|
return FreeGroup(symbols[1:2:2n], Alphabet(symbols, inverses))
|
||||||
end
|
end
|
||||||
|
|
||||||
Base.show(io::IO, F::FreeGroup) =
|
function Base.show(io::IO, F::FreeGroup)
|
||||||
print(io, "free group on $(ngens(F)) generators")
|
return print(io, "free group on $(ngens(F)) generators")
|
||||||
|
end
|
||||||
|
|
||||||
# mandatory methods:
|
# mandatory methods:
|
||||||
KnuthBendix.ordering(F::FreeGroup) = F.ordering
|
KnuthBendix.ordering(F::FreeGroup) = F.ordering
|
||||||
|
@ -205,8 +210,9 @@ relations(F::FreeGroup) = Pair{eltype(F),eltype(F)}[]
|
||||||
# these are mathematically correct
|
# these are mathematically correct
|
||||||
Base.isfinite(::FreeGroup) = false
|
Base.isfinite(::FreeGroup) = false
|
||||||
|
|
||||||
GroupsCore.isfiniteorder(g::AbstractFPGroupElement{<:FreeGroup}) =
|
function GroupsCore.isfiniteorder(g::AbstractFPGroupElement{<:FreeGroup})
|
||||||
isone(g) ? true : false
|
return isone(g) ? true : false
|
||||||
|
end
|
||||||
|
|
||||||
## FP Groups
|
## FP Groups
|
||||||
|
|
||||||
|
@ -222,8 +228,8 @@ rewriting(G::FPGroup) = G.rw
|
||||||
function FPGroup(
|
function FPGroup(
|
||||||
G::AbstractFPGroup,
|
G::AbstractFPGroup,
|
||||||
rels::AbstractVector{<:Pair{GEl,GEl}};
|
rels::AbstractVector{<:Pair{GEl,GEl}};
|
||||||
ordering=KnuthBendix.ordering(G),
|
ordering = KnuthBendix.ordering(G),
|
||||||
kwargs...
|
kwargs...,
|
||||||
) where {GEl<:FPGroupElement}
|
) where {GEl<:FPGroupElement}
|
||||||
for (lhs, rhs) in rels
|
for (lhs, rhs) in rels
|
||||||
@assert parent(lhs) === parent(rhs) === G
|
@assert parent(lhs) === parent(rhs) === G
|
||||||
|
@ -253,8 +259,9 @@ function Base.show(io::IO, G::FPGroup)
|
||||||
return print(io, " ⟩")
|
return print(io, " ⟩")
|
||||||
end
|
end
|
||||||
|
|
||||||
Base.show(io::IO, ::Type{<:FPGroup{T}}) where {T} =
|
function Base.show(io::IO, ::Type{<:FPGroup{T}}) where {T}
|
||||||
print(io, FPGroup, "{$T, …}")
|
return print(io, FPGroup, "{$T, …}")
|
||||||
|
end
|
||||||
|
|
||||||
## GSymbol aka letter of alphabet
|
## GSymbol aka letter of alphabet
|
||||||
|
|
||||||
|
|
|
@ -8,22 +8,40 @@ radius and multiplication operation to be used.
|
||||||
"""
|
"""
|
||||||
function wlmetric_ball(
|
function wlmetric_ball(
|
||||||
S::AbstractVector{T},
|
S::AbstractVector{T},
|
||||||
center::T=one(first(S));
|
center::T = one(first(S));
|
||||||
radius=2,
|
radius = 2,
|
||||||
op=*,
|
op = *,
|
||||||
threading=true
|
threading = true,
|
||||||
) where {T}
|
) where {T}
|
||||||
threading && return wlmetric_ball_thr(S, center, radius=radius, op=op)
|
threading && return wlmetric_ball_thr(S, center; radius = radius, op = op)
|
||||||
return wlmetric_ball_serial(S, center, radius=radius, op=op)
|
return wlmetric_ball_serial(S, center; radius = radius, op = op)
|
||||||
end
|
end
|
||||||
|
|
||||||
function wlmetric_ball_serial(S::AbstractVector{T}, center::T=one(first(S)); radius=2, op=*) where {T}
|
function wlmetric_ball_serial(
|
||||||
|
S::AbstractVector{T},
|
||||||
|
center::T = one(first(S));
|
||||||
|
radius = 2,
|
||||||
|
op = *,
|
||||||
|
) where {T}
|
||||||
@assert radius >= 1
|
@assert radius >= 1
|
||||||
old = union!([center], [center * s for s in S])
|
old = union!(OrderedSet([center]), [center * s for s in S])
|
||||||
return _wlmetric_ball(S, old, radius, op, collect, unique!)
|
sizes = [1, length(old)]
|
||||||
|
for _ in 2:radius
|
||||||
|
new = collect(
|
||||||
|
op(o, s) for o in @view(old.dict.keys[sizes[end-1]:end]) for s in S
|
||||||
|
)
|
||||||
|
union!(old, new)
|
||||||
|
push!(sizes, length(old))
|
||||||
|
end
|
||||||
|
return old.dict.keys, sizes[2:end]
|
||||||
end
|
end
|
||||||
|
|
||||||
function wlmetric_ball_thr(S::AbstractVector{T}, center::T=one(first(S)); radius=2, op=*) where {T}
|
function wlmetric_ball_thr(
|
||||||
|
S::AbstractVector{T},
|
||||||
|
center::T = one(first(S));
|
||||||
|
radius = 2,
|
||||||
|
op = *,
|
||||||
|
) where {T}
|
||||||
@assert radius >= 1
|
@assert radius >= 1
|
||||||
old = union!([center], [center * s for s in S])
|
old = union!([center], [center * s for s in S])
|
||||||
return _wlmetric_ball(S, old, radius, op, Folds.collect, Folds.unique)
|
return _wlmetric_ball(S, old, radius, op, Folds.collect, Folds.unique)
|
||||||
|
@ -31,12 +49,13 @@ end
|
||||||
|
|
||||||
function _wlmetric_ball(S, old, radius, op, collect, unique)
|
function _wlmetric_ball(S, old, radius, op, collect, unique)
|
||||||
sizes = [1, length(old)]
|
sizes = [1, length(old)]
|
||||||
for r in 2:radius
|
for _ in 2:radius
|
||||||
old = let old = old, S = S,
|
old = let old = old, S = S
|
||||||
new = collect(
|
new = collect(
|
||||||
(g = op(o, s); normalform!(g); hash(g); g)
|
(g = op(o, s);
|
||||||
# normalform! and hash are to make assure thread-safety of produced elts
|
normalform!(g);
|
||||||
for o in @view(old[sizes[end-1]:end]) for s in S
|
hash(g);
|
||||||
|
g) for o in @view(old[sizes[end-1]:end]) for s in S
|
||||||
)
|
)
|
||||||
|
|
||||||
append!(old, new)
|
append!(old, new)
|
||||||
|
@ -46,4 +65,3 @@ function _wlmetric_ball(S, old, radius, op, collect, unique)
|
||||||
end
|
end
|
||||||
return old, sizes[2:end]
|
return old, sizes[2:end]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue