mirror of
https://github.com/kalmarek/SmallHyperbolic
synced 2024-09-01 13:25:35 +02:00
151 lines
5.0 KiB
Julia
151 lines
5.0 KiB
Julia
struct TriangleGrp
|
|
half_girth_type::NTuple{3,Int}
|
|
generators::Vector{String}
|
|
relations::Vector{String}
|
|
order1::Int
|
|
order2::Int
|
|
order3::Int
|
|
index::Int
|
|
presentation_length::Int
|
|
hyperbolic::Union{Missing,Bool}
|
|
witnesses_non_hyperbolictity::Union{Missing,Vector{String}}
|
|
virtually_torsion_free::Union{Missing,Bool}
|
|
Kazdhdan_property_T::Union{Missing,Bool}
|
|
abelianization_dimension::Int
|
|
L2_quotients::Vector{String}
|
|
quotients::Vector{Pair{String,Int}}
|
|
alternating_quotients::Vector{Int}
|
|
maximal_degree_alternating_quotients::Int
|
|
end
|
|
|
|
_name(G) = "G_$(G.order1)_$(G.order2)_$(G.order3)_$(G.index)"
|
|
name(G::TriangleGrp) = _name(G)
|
|
grp_name(nt::NamedTuple) = _name(nt)
|
|
|
|
latex_name(G::TriangleGrp) = "G^{$(G.order1),$(G.order2),$(G.order3)}_$(G.index)"
|
|
|
|
function _ishyperbolic(half_girth_type, nt::NamedTuple)
|
|
a, b, c = half_girth_type
|
|
if 1 // a + 1 // b + 1 // c < 1
|
|
return true, missing
|
|
elseif hasproperty(nt, :hyperbolic)
|
|
hyperbolic = _tf_missing(nt.hyperbolic)
|
|
nh_witnesses = let w = strip(nt.witnesses_for_non_hyperbolicity)
|
|
isempty(w) ? missing : parse_vec(String, '[' * w * ']')
|
|
end
|
|
@debug "$(nt.hyperbolic) was parsed as $hyperbolic" nh_witnesses
|
|
if hyperbolic isa Bool && hyperbolic
|
|
@assert ismissing(nh_witnesses)
|
|
end
|
|
if !ismissing(nh_witnesses)
|
|
@assert !hyperbolic
|
|
end
|
|
return hyperbolic, nh_witnesses
|
|
else
|
|
return missing, missing
|
|
end
|
|
end
|
|
|
|
function _sanitize_group_name(s::AbstractString)
|
|
s = replace(s, '$'=>"")
|
|
s = replace(s, "\\infty"=>"inf")
|
|
s = replace(s, r"\\textrm{(.*?)}"=>s"\1")
|
|
s = replace(s, r"(Alt)_{(\d+)}"=>s"\1(\2)")
|
|
s = replace(s, "_{}"=>"")
|
|
return s
|
|
end
|
|
|
|
function _delatexify(dict)
|
|
map(dict) do (key, val)
|
|
key = _sanitize_group_name(key)
|
|
key = replace(key, r"_{(\d+)}"=>s"\1")
|
|
key = replace(key, "{}^"=>"")
|
|
key => val
|
|
end |> Dict
|
|
end
|
|
|
|
function TriangleGrp(half_girth_type::NTuple{3,Int}, generators, relations, nt::NamedTuple)
|
|
# @assert fieldnames(SmallHyperbolicGrp) == propertynames(nt)
|
|
hyperbolic, witness = _ishyperbolic(half_girth_type, nt)
|
|
|
|
l2_quotients = let v = _sanitize_group_name.(parse_vec(String, nt.L2_quotients))
|
|
if isempty(v) || (length(v)==1 && isempty(first(v)))
|
|
Vector{String}()
|
|
else
|
|
String.(v)
|
|
end
|
|
end
|
|
|
|
TriangleGrp(
|
|
half_girth_type,
|
|
convert(Vector{String}, generators),
|
|
convert(Vector{String}, relations),
|
|
convert(Int, nt.order1),
|
|
convert(Int, nt.order2),
|
|
convert(Int, nt.order3),
|
|
convert(Int, nt.index),
|
|
convert(Int, nt.presentation_length),
|
|
hyperbolic,
|
|
witness,
|
|
_tf_missing(nt.virtually_torsion_free),
|
|
_tf_missing(nt.Kazhdan),
|
|
convert(Int, nt.abelianization_dimension),
|
|
l2_quotients,
|
|
[Pair(_sanitize_group_name(p[1]), p[2]) for p in parse_vec(Tuple{String,Int}, nt.quotients)],
|
|
parse_vec(Int, nt.alternating_quotients),
|
|
convert(Int, nt.maximal_order_for_alternating_quotients),
|
|
)
|
|
end
|
|
|
|
import DataStructures
|
|
|
|
import JSON.Serializations: CommonSerialization, StandardSerialization
|
|
import JSON.Writer: StructuralContext, show_json
|
|
struct TriangleGrpSerialization <: CommonSerialization end
|
|
|
|
function subscriptify(n::Integer)
|
|
n, sgn = abs(n), sign(n)
|
|
# Char(0x2080) == '₀'
|
|
s = join(Char(0x2080+d) for d in reverse(digits(n)))
|
|
return sgn >= 0 ? s : "₋"*s
|
|
end
|
|
|
|
function superscriptify(n::Integer)
|
|
n, sgn = abs(n), sign(n);
|
|
# (Char(0x2070), '¹', '²', '³', [Char(0x2070+i) for i in 4:9]...)
|
|
dgts = ('⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹')
|
|
s = join(dgts[d+1] for d in reverse(digits(n)))
|
|
return sgn >= 0 ? s : "⁻"*s
|
|
end
|
|
|
|
function _to_utf8(s::AbstractString)
|
|
s = _sanitize_group_name(s)
|
|
while (m = match(r"(_{(-?\d+)}|_(\d))", s)) !== nothing
|
|
n = parse(Int, something(m[2], m[3]))
|
|
s = replace(s, m[1]=>subscriptify(n))
|
|
end
|
|
while (m = match(r"(\^{(-?\d+)}|\^(\d))", s)) !== nothing
|
|
n = parse(Int, something(m[2], m[3]))
|
|
s = replace(s, m[1]=>superscriptify(n))
|
|
end
|
|
if (m = match(r"G(\^{(\d+),(\d+),(\d+)})", s)) !== nothing
|
|
i,j,k = superscriptify.(parse.(Int, (m[2], m[3], m[4])))
|
|
s = replace(s, m[1] => "$(i)'$(j)'$(k)")
|
|
end
|
|
s = replace(s, "{}"=>"")
|
|
return s
|
|
end
|
|
|
|
function show_json(io::StructuralContext, ::TriangleGrpSerialization, G::TriangleGrp)
|
|
D = DataStructures.OrderedDict{Symbol,Any}(:name => latex_name(G))
|
|
D[:name_utf8] = _to_utf8(D[:name])
|
|
for fname in fieldnames(TriangleGrp)
|
|
D[fname] = getfield(G, fname)
|
|
end
|
|
D[:L2_quotients_utf8] = _to_utf8.(D[:L2_quotients])
|
|
D[:quotients_utf8] = Dict(_to_utf8(k) => v for (k,v) in D[:quotients])
|
|
D[:quotients_plain] = _delatexify(D[:quotients])
|
|
D[:quotients] = Dict(D[:quotients])
|
|
return show_json(io, StandardSerialization(), D)
|
|
end
|