mirror of
https://github.com/kalmarek/Groups.jl.git
synced 2024-11-19 06:30:29 +01:00
add Homomorphisms
This commit is contained in:
parent
cb933c3f87
commit
dd6588f018
@ -9,15 +9,17 @@ import Random
|
||||
|
||||
import OrderedCollections: OrderedSet
|
||||
|
||||
export Alphabet, AutomorphismGroup, FreeGroup, FreeGroup, FPGroup, FPGroupElement, SpecialAutomorphismGroup
|
||||
export MatrixGroups
|
||||
|
||||
export Alphabet, AutomorphismGroup, FreeGroup, FreeGroup, FPGroup, FPGroupElement, SpecialAutomorphismGroup, Homomorphism
|
||||
|
||||
export alphabet, evaluate, word, gens
|
||||
|
||||
include("types.jl")
|
||||
include("hashing.jl")
|
||||
include("normalform.jl")
|
||||
include("autgroups.jl")
|
||||
include("homomorphisms.jl")
|
||||
|
||||
include("aut_groups/sautFn.jl")
|
||||
include("aut_groups/mcg.jl")
|
||||
@ -25,5 +27,7 @@ include("aut_groups/mcg.jl")
|
||||
include("matrix_groups/MatrixGroups.jl")
|
||||
using .MatrixGroups
|
||||
|
||||
include("abelianize.jl")
|
||||
|
||||
include("wl_ball.jl")
|
||||
end # of module Groups
|
||||
|
23
src/abelianize.jl
Normal file
23
src/abelianize.jl
Normal file
@ -0,0 +1,23 @@
|
||||
function _abelianize(
|
||||
i::Integer,
|
||||
source::AutomorphismGroup{<:FreeGroup},
|
||||
target::MatrixGroups.SpecialLinearGroup{N, T}) where {N, T}
|
||||
n = ngens(object(source))
|
||||
@assert n == N
|
||||
aut = alphabet(source)[i]
|
||||
if aut isa Transvection
|
||||
# we change (i,j) to (j, i) to be consistent with the action:
|
||||
# Automorphisms act on the right which corresponds to action on
|
||||
# the columns in the matrix case
|
||||
eij = MatrixGroups.ElementaryMatrix{N}(
|
||||
aut.j,
|
||||
aut.i,
|
||||
ifelse(aut.inv, -one(T), one(T))
|
||||
)
|
||||
k = alphabet(target)[eij]
|
||||
return word_type(target)([k])
|
||||
else
|
||||
throw("unexpected automorphism symbol: $(typeof(aut))")
|
||||
end
|
||||
end
|
||||
|
114
src/homomorphisms.jl
Normal file
114
src/homomorphisms.jl
Normal file
@ -0,0 +1,114 @@
|
||||
"""
|
||||
Homomorphism(f, G::AbstractFPGroup, H::AbstractFPGroup[, check=true])
|
||||
Struct representing homomorphism map from `G` to `H` given by map `f`.
|
||||
|
||||
To define `h = Homomorphism(f, G, H)` function (or just callable) `f` must
|
||||
implement method `f(i::Integer, source, target)::AbstractWord` with the
|
||||
following meaning. Suppose that word `w = Word([i])` consists of a single
|
||||
letter in the `alphabet` of `source` (usually it means that in `G` it
|
||||
represents a generator or its inverse). Then `f(i, G, H)` must return the
|
||||
**word** representing the image in `H` of `G(w)` under the homomorphism.
|
||||
|
||||
In more mathematical terms it means that if `h(G(w)) == h`, then
|
||||
`f(i, G, H) == word(h)`.
|
||||
|
||||
Images of both `AbstractWord`s and elements of `G` can be obtained by simply
|
||||
calling `h(w)`, or `h(g)`.
|
||||
|
||||
If `check=true` then the correctness of the definition of `h` will be performed
|
||||
when creating the homomorphism.
|
||||
|
||||
!!! note
|
||||
`f(i, G, H)` must be implemented for all letters in the alphabet of `G`,
|
||||
not only for those `i` which represent `gens(G)`. Function `f` will be
|
||||
evaluated exactly once per letter of `alphabet(G)` and the results will be
|
||||
cached.
|
||||
|
||||
# Examples
|
||||
```julia
|
||||
julia> F₂ = FreeGroup(2)
|
||||
free group on 2 generators
|
||||
|
||||
julia> g,h = gens(F₂)
|
||||
2-element Vector{FPGroupElement{FreeGroup{Symbol, KnuthBendix.LenLex{Symbol}}, …}}:
|
||||
f1
|
||||
f2
|
||||
|
||||
julia> ℤ² = FPGroup(F₂, [g*h => h*g])
|
||||
Finitely presented group generated by:
|
||||
{ f1 f2 },
|
||||
subject to relations:
|
||||
f1*f2 => f2*f1
|
||||
|
||||
julia> hom = Groups.Homomorphism(
|
||||
(i, G, H) -> Groups.word_type(H)([i]),
|
||||
F₂,
|
||||
ℤ²
|
||||
)
|
||||
Homomorphism
|
||||
from : free group on 2 generators
|
||||
to : ⟨ f1 f2 |
|
||||
f1*f2 => f2*f1 ⟩
|
||||
|
||||
julia> hom(g*h*inv(g))
|
||||
f2
|
||||
|
||||
julia> hom(g*h*inv(g)) == hom(h)
|
||||
true
|
||||
```
|
||||
|
||||
"""
|
||||
struct Homomorphism{Gr1, Gr2, I, W}
|
||||
gens_images::Dict{I, W}
|
||||
source::Gr1
|
||||
target::Gr2
|
||||
|
||||
function Homomorphism(
|
||||
f,
|
||||
source::AbstractFPGroup,
|
||||
target::AbstractFPGroup;
|
||||
check=true
|
||||
)
|
||||
A = alphabet(source)
|
||||
dct = Dict(i=>convert(word_type(target), f(i, source, target))
|
||||
for i in 1:length(A))
|
||||
I = eltype(word_type(source))
|
||||
W = word_type(target)
|
||||
hom = new{typeof(source), typeof(target), I, W}(dct, source, target)
|
||||
|
||||
if check
|
||||
@assert hom(one(source)) == one(target)
|
||||
for x in gens(source)
|
||||
|
||||
@assert hom(x^-1) == hom(x)^-1
|
||||
|
||||
for y in gens(source)
|
||||
@assert hom(x*y) == hom(x)*hom(y)
|
||||
@assert hom(x*y)^-1 == hom(y^-1)*hom(x^-1)
|
||||
end
|
||||
end
|
||||
for (lhs, rhs) in relations(source)
|
||||
relator = lhs*inv(alphabet(source), rhs)
|
||||
im_r = hom.target(hom(relator))
|
||||
@assert isone(im_r) "Map does not define a homomorphism: h($relator) = $(im_r) ≠ $(one(target))."
|
||||
end
|
||||
end
|
||||
return hom
|
||||
end
|
||||
end
|
||||
|
||||
function (h::Homomorphism)(w::AbstractWord)
|
||||
result = one(word_type(h.target)) # Word
|
||||
for l in w
|
||||
append!(result, h.gens_images[l])
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function (h::Homomorphism)(g::AbstractFPGroupElement)
|
||||
@assert parent(g) === h.source
|
||||
w = h(word(g))
|
||||
return h.target(w)
|
||||
end
|
||||
|
||||
Base.show(io::IO, h::Homomorphism) = print(io, "Homomorphism\n from : $(h.source)\n to : $(h.target)")
|
49
test/homomorphisms.jl
Normal file
49
test/homomorphisms.jl
Normal file
@ -0,0 +1,49 @@
|
||||
function test_homomorphism(hom)
|
||||
F = hom.source
|
||||
@test isone(hom(one(F)))
|
||||
@test all(inv(hom(g)) == hom(inv(g)) for g in gens(F))
|
||||
@test all(isone(hom(g)*hom(inv(g))) for g in gens(F))
|
||||
@test all(hom(g*h) == hom(g)*hom(h) for g in gens(F) for h in gens(F))
|
||||
end
|
||||
|
||||
@testset "Homomorphisms" begin
|
||||
|
||||
F₂ = FreeGroup(2)
|
||||
g,h = gens(F₂)
|
||||
|
||||
ℤ² = FPGroup(F₂, [g*h => h*g])
|
||||
|
||||
let hom = Groups.Homomorphism((i, G, H) -> Groups.word_type(H)([i]), F₂, ℤ²)
|
||||
|
||||
@test hom(word(g)) == word(g)
|
||||
|
||||
@test hom(word(g*h*inv(g))) == [1,3,2]
|
||||
|
||||
@test hom(g*h*inv(g)) == hom(h)
|
||||
@test isone(hom(g*h*inv(g)*inv(h)))
|
||||
|
||||
@test contains(sprint(print, hom), "Homomorphism")
|
||||
|
||||
test_homomorphism(hom)
|
||||
end
|
||||
|
||||
SAutF3 = SpecialAutomorphismGroup(FreeGroup(3))
|
||||
SL3Z = MatrixGroups.SpecialLinearGroup{3}(Int8)
|
||||
|
||||
let hom = Groups.Homomorphism(
|
||||
Groups._abelianize,
|
||||
SAutF3,
|
||||
SL3Z,
|
||||
)
|
||||
|
||||
A = alphabet(SAutF3)
|
||||
g = SAutF3([A[Groups.ϱ(1,2)]])
|
||||
h = SAutF3([A[Groups.λ(1,2)]])^-1
|
||||
|
||||
@test !isone(g) && !isone(hom(g))
|
||||
@test !isone(h) && !isone(hom(h))
|
||||
@test !isone(g*h) && isone(hom(g*h))
|
||||
|
||||
test_homomorphism(hom)
|
||||
end
|
||||
end
|
@ -26,8 +26,10 @@ include(joinpath(pathof(GroupsCore), "..", "..", "test", "conformance_test.jl"))
|
||||
include("fp_groups.jl")
|
||||
|
||||
include("matrix_groups.jl")
|
||||
|
||||
include("AutFn.jl")
|
||||
|
||||
include("homomorphisms.jl")
|
||||
|
||||
include("AutSigma_41.jl")
|
||||
include("AutSigma3.jl")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user