270 lines
6.9 KiB
Julia
270 lines
6.9 KiB
Julia
struct ΡΛ
|
||
id::Symbol
|
||
A::Alphabet
|
||
N::Int
|
||
end
|
||
|
||
function Base.getindex(rl::ΡΛ, i::Integer, j::Integer)
|
||
@assert 1 ≤ i ≤ rl.N "Got $i > $(rl.N)"
|
||
@assert 1 ≤ j ≤ rl.N "Got $j > $(rl.N)"
|
||
@assert i ≠ j
|
||
@assert rl.id ∈ (:λ, :ϱ)
|
||
rl.id == :λ && return Word([rl.A[λ(i, j)]])
|
||
rl.id == :ϱ && return Word([rl.A[ϱ(i, j)]])
|
||
end
|
||
|
||
function Te_diagonal(λ::Groups.ΡΛ, ϱ::Groups.ΡΛ, i::Integer)
|
||
@assert λ.N == ϱ.N
|
||
@assert λ.id == :λ && ϱ.id == :ϱ
|
||
|
||
N = λ.N
|
||
@assert iseven(N)
|
||
A = λ.A
|
||
n = N ÷ 2
|
||
j = i + 1
|
||
|
||
if i == n
|
||
τ = rotation_element(λ, ϱ)
|
||
return inv(τ, A) * Te_diagonal(λ, ϱ, 1) * τ
|
||
end
|
||
|
||
@assert 1 <= i < n
|
||
|
||
NI = (2n - 2i) + 1
|
||
NJ = (2n - 2j) + 1
|
||
I = (2n - 2i) + 2
|
||
J = (2n - 2j) + 2
|
||
|
||
g = one(Word(Int[]))
|
||
g *= λ[NJ, NI] # β ↦ α*β
|
||
g *= λ[NI, I] * inv(ϱ[NI, J], A) # α ↦ a*α*b^-1
|
||
g *= inv(λ[NJ, NI], A) # β ↦ b*α^-1*a^-1*α*β
|
||
g *= λ[J, NI] * inv(λ[J, I], A) # b ↦ α
|
||
g *= inv(λ[J, NI], A) # b ↦ b*α^-1*a^-1*α
|
||
g *= inv(ϱ[J, NI], A) * ϱ[J, I] # b ↦ b*α^-1*a^-1*α*b*α^-1
|
||
g *= ϱ[J, NI] # b ↦ b*α^-1*a^-1*α*b*α^-1*a*α*b^-1
|
||
|
||
return g
|
||
end
|
||
|
||
function Te_lantern(A::Alphabet, b₀::T, a₁::T, a₂::T, a₃::T, a₄::T, a₅::T) where {T}
|
||
a₀ = (a₁ * a₂ * a₃)^4 * inv(b₀, A)
|
||
X = a₄ * a₅ * a₃ * a₄ # from Primer
|
||
b₁ = inv(X, A) * a₀ * X # from Primer
|
||
Y = a₂ * a₃ * a₁ * a₂
|
||
return inv(Y, A) * b₁ * Y # b₂ from Primer
|
||
end
|
||
|
||
function Ta(λ::Groups.ΡΛ, i::Integer)
|
||
@assert λ.id == :λ
|
||
return λ[mod1(λ.N - 2i + 1, λ.N), mod1(λ.N - 2i + 2, λ.N)]
|
||
end
|
||
|
||
function Tα(λ::Groups.ΡΛ, i::Integer)
|
||
@assert λ.id == :λ
|
||
return inv(λ[mod1(λ.N - 2i + 2, λ.N), mod1(λ.N - 2i + 1, λ.N)], λ.A)
|
||
end
|
||
|
||
function Te(λ::ΡΛ, ϱ::ΡΛ, i, j)
|
||
@assert i ≠ j
|
||
|
||
@assert λ.N == ϱ.N
|
||
@assert λ.A == ϱ.A
|
||
@assert λ.id == :λ && ϱ.id == :ϱ
|
||
|
||
@assert iseven(λ.N)
|
||
genus = λ.N ÷ 2
|
||
i = mod1(i, genus)
|
||
j = mod1(j, genus)
|
||
|
||
@assert 1 ≤ i ≤ λ.N
|
||
@assert 1 ≤ j ≤ λ.N
|
||
|
||
A = λ.A
|
||
|
||
if mod(j - (i + 1), genus) == 0
|
||
return Te_diagonal(λ, ϱ, i)
|
||
else
|
||
return inv(Te_lantern(
|
||
A,
|
||
# Our notation: # Primer notation:
|
||
inv(Ta(λ, i + 1), A), # b₀
|
||
inv(Ta(λ, i), A), # a₁
|
||
inv(Tα(λ, i), A), # a₂
|
||
inv(Te_diagonal(λ, ϱ, i), A), # a₃
|
||
inv(Tα(λ, i + 1), A), # a₄
|
||
inv(Te(λ, ϱ, i + 1, j), A), # a₅
|
||
), A)
|
||
end
|
||
end
|
||
|
||
"""
|
||
rotation_element(G::AutomorphismGroup{<:FreeGroup})
|
||
Return the element of `G` which corresponds to shifting generators of the free group.
|
||
|
||
In the corresponding mapping class group this element acts by rotation of the surface anti-clockwise.
|
||
"""
|
||
function rotation_element(G::AutomorphismGroup{<:FreeGroup})
|
||
|
||
A = alphabet(G)
|
||
@assert iseven(ngens(object(G)))
|
||
genus = ngens(object(G)) ÷ 2
|
||
|
||
λ = ΡΛ(:λ, A, 2genus)
|
||
ϱ = ΡΛ(:ϱ, A, 2genus)
|
||
|
||
return G(rotation_element(λ, ϱ))
|
||
end
|
||
|
||
function rotation_element(λ::ΡΛ, ϱ::ΡΛ)
|
||
@assert iseven(λ.N)
|
||
genus = λ.N ÷ 2
|
||
A = λ.A
|
||
|
||
halftwists = map(1:genus-1) do i
|
||
j = i + 1
|
||
x = Ta(λ, j) * inv(Ta(λ, i), A) * Tα(λ, j) * Te_diagonal(λ, ϱ, i)
|
||
δ = x * Tα(λ, i) * inv(x, A)
|
||
c =
|
||
inv(Ta(λ, j), A) *
|
||
Te(λ, ϱ, i, j) *
|
||
Tα(λ, i)^2 *
|
||
inv(δ, A) *
|
||
inv(Ta(λ, j), A) *
|
||
Ta(λ, i) *
|
||
δ
|
||
z =
|
||
Te_diagonal(λ, ϱ, i) *
|
||
inv(Ta(λ, i), A) *
|
||
Tα(λ, i) *
|
||
Ta(λ, i) *
|
||
inv(Te_diagonal(λ, ϱ, i), A)
|
||
|
||
Ta(λ, i) * inv(Ta(λ, j) * Tα(λ, j), A)^6 * (Ta(λ, j) * Tα(λ, j) * z)^4 * c
|
||
end
|
||
|
||
τ = (Ta(λ, 1) * Tα(λ, 1))^6 * prod(halftwists)
|
||
return τ
|
||
end
|
||
|
||
function mcg_twists(G::AutomorphismGroup{<:FreeGroup})
|
||
|
||
@assert iseven(ngens(object(G)))
|
||
genus = ngens(object(G)) ÷ 2
|
||
|
||
genus < 3 && throw("Not Implemented: genus = $genus < 3")
|
||
|
||
A = KnuthBendix.alphabet(G)
|
||
|
||
λ = ΡΛ(:λ, A, 2genus)
|
||
ϱ = ΡΛ(:ϱ, A, 2genus)
|
||
|
||
Tas = [Ta(λ, i) for i in 1:genus]
|
||
Tαs = [Tα(λ, i) for i in 1:genus]
|
||
|
||
idcs = ((i, j) for i in 1:genus for j in i+1:genus)
|
||
Tes = [Te(λ, ϱ, i, j) for (i, j) in idcs]
|
||
|
||
return Tas, Tαs, Tes
|
||
end
|
||
|
||
struct SymplecticMappingClass{T,F} <: GSymbol
|
||
id::Symbol # :A, :B
|
||
i::UInt
|
||
j::UInt
|
||
minus::Bool
|
||
inv::Bool
|
||
autFn_word::T
|
||
f::F
|
||
end
|
||
|
||
Base.:(==)(a::SymplecticMappingClass, b::SymplecticMappingClass) = a.autFn_word == b.autFn_word
|
||
|
||
Base.hash(a::SymplecticMappingClass, h::UInt) = hash(a.autFn_word, h)
|
||
|
||
function SymplecticMappingClass(
|
||
sautFn::AutomorphismGroup{<:FreeGroup},
|
||
id::Symbol,
|
||
i::Integer,
|
||
j::Integer;
|
||
minus=false,
|
||
inverse=false
|
||
)
|
||
@assert i > 0 && j > 0
|
||
id === :A && @assert i ≠ j
|
||
@assert iseven(ngens(object(sautFn)))
|
||
genus = ngens(object(sautFn)) ÷ 2
|
||
|
||
A = alphabet(sautFn)
|
||
λ = ΡΛ(:λ, A, 2genus)
|
||
ϱ = ΡΛ(:ϱ, A, 2genus)
|
||
|
||
w = if id === :A
|
||
Te(λ, ϱ, i, j) *
|
||
inv(Ta(λ, i), A) *
|
||
Tα(λ, i) *
|
||
Ta(λ, i) *
|
||
inv(Te(λ, ϱ, i, j), A) *
|
||
inv(Tα(λ, i), A) *
|
||
inv(Ta(λ, j), A)
|
||
elseif id === :B
|
||
if !minus
|
||
if i ≠ j
|
||
x = Ta(λ, j) * inv(Ta(λ, i), A) * Tα(λ, j) * Te(λ, ϱ, i, j)
|
||
δ = x * Tα(λ, i) * inv(x, A)
|
||
Tα(λ, i) * Tα(λ, j) * inv(δ, A)
|
||
else
|
||
inv(Tα(λ, i), A)
|
||
end
|
||
else
|
||
if i ≠ j
|
||
Ta(λ, i) * Ta(λ, j) * inv(Te(λ, ϱ, i, j), A)
|
||
else
|
||
Ta(λ, i)
|
||
end
|
||
end
|
||
else
|
||
throw("Type not recognized: $id")
|
||
end
|
||
|
||
# w is a word defined in the context of A (= alphabet(sautFn))
|
||
# so this "coercion" is correct
|
||
a = sautFn(w)
|
||
|
||
f = compiled(a)
|
||
# f = t -> evaluate!(t, a)
|
||
|
||
res = SymplecticMappingClass(id, UInt(i), UInt(j), minus, inverse, a, f)
|
||
|
||
return res
|
||
end
|
||
|
||
function Base.show(io::IO, smc::SymplecticMappingClass)
|
||
smc.minus && print(io, 'm')
|
||
if smc.i < 10 && smc.j < 10
|
||
print(io, smc.id, subscriptify(smc.i), subscriptify(smc.j))
|
||
else
|
||
print(io, smc.id, subscriptify(smc.i), ".", subscriptify(smc.j))
|
||
end
|
||
smc.inv && print(io, "^-1")
|
||
end
|
||
|
||
function Base.inv(m::SymplecticMappingClass)
|
||
inv_w = inv(m.autFn_word)
|
||
# f(t) = evaluate!(t, inv_w)
|
||
f = compiled(inv_w)
|
||
return SymplecticMappingClass(m.id, m.i, m.j, m.minus, !m.inv, inv_w, f)
|
||
end
|
||
|
||
function evaluate!(
|
||
t::NTuple{N,T},
|
||
smc::SymplecticMappingClass,
|
||
tmp=nothing,
|
||
) where {N,T}
|
||
t = smc.f(t)
|
||
for i in 1:N
|
||
normalform!(t[i])
|
||
end
|
||
return t
|
||
end
|