mirror of
https://github.com/kalmarek/Groups.jl.git
synced 2024-11-19 14:35:28 +01:00
Merge branch 'enh/FPGroups'
This commit is contained in:
commit
b61c06cd96
@ -13,7 +13,7 @@ end
|
|||||||
|
|
||||||
typealias AutGroupElem GWord{AutSymbol}
|
typealias AutGroupElem GWord{AutSymbol}
|
||||||
|
|
||||||
type AutGroup <: FPGroup
|
type AutGroup <: AbstractFPGroup
|
||||||
objectGroup::Group
|
objectGroup::Group
|
||||||
gens::Vector{AutSymbol}
|
gens::Vector{AutSymbol}
|
||||||
end
|
end
|
||||||
|
188
src/FPGroups.jl
Normal file
188
src/FPGroups.jl
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
###############################################################################
|
||||||
|
#
|
||||||
|
# FPSymbol/FPGroupElem/FPGroup definition
|
||||||
|
#
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
immutable FPSymbol <: GSymbol
|
||||||
|
str::String
|
||||||
|
pow::Int
|
||||||
|
end
|
||||||
|
|
||||||
|
typealias FPGroupElem = GWord{FPSymbol}
|
||||||
|
|
||||||
|
type FPGroup <: AbstractFPGroup
|
||||||
|
gens::Vector{FPSymbol}
|
||||||
|
rels::Dict{FPGroupElem, FPGroupElem}
|
||||||
|
|
||||||
|
function FPGroup{T<:GSymbol}(gens::Vector{T}, rels::Dict{FPGroupElem, FPGroupElem})
|
||||||
|
G = new(gens)
|
||||||
|
G.rels = Dict(G(k) => G(v) for (k,v) in rels)
|
||||||
|
return G
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
export FPGroupElem, FPGroup
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
#
|
||||||
|
# Type and parent object methods
|
||||||
|
#
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
parent_type(::Type{FPGroupElem}) = FPGroup
|
||||||
|
|
||||||
|
elem_type(::FPGroup) = FPGroupElem
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
#
|
||||||
|
# FPSymbol constructors
|
||||||
|
#
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
FPSymbol(s::String) = FPSymbol(s,1)
|
||||||
|
|
||||||
|
convert(::Type{FPSymbol}, s::FreeSymbol) = FPSymbol(s.str, s.pow)
|
||||||
|
|
||||||
|
FPGroup(gens::Vector{FPSymbol}) = FPGroup(gens, Dict{FPGroupElem, FPGroupElem}())
|
||||||
|
|
||||||
|
FPGroup(a::Vector{String}) = FPGroup([FPSymbol(i) for i in a])
|
||||||
|
|
||||||
|
FPGroup(n::Int, symbol::String="f") = FPGroup(["$symbol$i" for i in 1:n])
|
||||||
|
FPGroup(H::FreeGroup) = FPGroup([FPSymbol(s) for s in H.gens])
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
#
|
||||||
|
# Parent object call overloads
|
||||||
|
#
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
function (G::FPGroup)()
|
||||||
|
id = FPGroupElem(FPSymbol("", 0))
|
||||||
|
id.parent = G
|
||||||
|
return id
|
||||||
|
end
|
||||||
|
|
||||||
|
function (G::FPGroup)(w::GWord)
|
||||||
|
if length(w) == 0
|
||||||
|
return G()
|
||||||
|
end
|
||||||
|
|
||||||
|
if eltype(w.symbols) == FreeSymbol
|
||||||
|
w = FPGroupElem(w.symbols)
|
||||||
|
end
|
||||||
|
|
||||||
|
if eltype(w.symbols) == FPSymbol
|
||||||
|
for s in w.symbols
|
||||||
|
i = findfirst(g -> g.str == s.str, G.gens)
|
||||||
|
i == 0 && throw("Symbol $s does not belong to $G.")
|
||||||
|
s.pow % G.gens[i].pow == 0 || throw("Symbol $s doesn't belong to $G.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
w.parent = G
|
||||||
|
return reduce!(w)
|
||||||
|
end
|
||||||
|
|
||||||
|
(G::FPGroup)(s::FPSymbol) = G(FPGroupElem(s))
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
#
|
||||||
|
# Basic manipulation
|
||||||
|
#
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
hash(s::FPSymbol, h::UInt) = hash(s.str, hash(s.pow, hash(FPSymbol, h)))
|
||||||
|
|
||||||
|
change_pow(s::FPSymbol, n::Int) = FPSymbol(s.str, n)
|
||||||
|
|
||||||
|
length(s::FPSymbol) = abs(s.pow)
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
#
|
||||||
|
# String I/O
|
||||||
|
#
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
function show(io::IO, G::FPGroup)
|
||||||
|
print(io, "FPgroup on $(length(G.gens)) generators: ")
|
||||||
|
print(io, "⟨ ", join(G.gens, ", "), " | ", join(G.rels, ", "), " ⟩.")
|
||||||
|
end
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
#
|
||||||
|
# Comparison
|
||||||
|
#
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
function (==)(s::FPSymbol, t::FPSymbol)
|
||||||
|
isone(s) && isone(t) && return true
|
||||||
|
s.str == t.str || return false
|
||||||
|
s.pow == t.pow || return false
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
#
|
||||||
|
# Inversion
|
||||||
|
#
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
inv(s::FPSymbol) = change_pow(s, -s.pow)
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
#
|
||||||
|
# Binary operations
|
||||||
|
#
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
(*)(W::FPGroupElem, Z::FPGroupElem) = r_multiply(W, Z.symbols)
|
||||||
|
(*)(W::FPGroupElem, s::FPSymbol) = r_multiply(W, [s])
|
||||||
|
(*)(s::FPSymbol, W::FPGroupElem) = l_multiply(W, [s])
|
||||||
|
|
||||||
|
function reduce!(W::FPGroupElem)
|
||||||
|
if length(W) < 2
|
||||||
|
deleteat!(W.symbols, find(x -> x.pow == 0, W.symbols))
|
||||||
|
else
|
||||||
|
reduced = false
|
||||||
|
while !reduced
|
||||||
|
reduced = free_reduce!(W) || replace_all!(W, parent(W).rels)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
W.savedhash = hash(W.symbols, hash(typeof(W)))
|
||||||
|
W.modified = false
|
||||||
|
return W
|
||||||
|
end
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
#
|
||||||
|
# Misc
|
||||||
|
#
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
function add_rels!(G::FPGroup, newrels::Dict{FPGroupElem,FPGroupElem})
|
||||||
|
for w in keys(newrels)
|
||||||
|
if !(w in keys(G.rels))
|
||||||
|
G.rels[w] = G(newrels[w])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function /(G::FPGroup, newrels::Vector{FPGroupElem})
|
||||||
|
for r in rels
|
||||||
|
parent(r) == G || throw("Can not form quotient group: $r is not an element of $G")
|
||||||
|
end
|
||||||
|
H = deepcopy(G)
|
||||||
|
newrels = Dict(H(r) => H() for r in newrels)
|
||||||
|
add_rels!(H, newrels)
|
||||||
|
return H
|
||||||
|
end
|
||||||
|
|
||||||
|
function /(G::FreeGroup, rels::Vector{FreeGroupElem})
|
||||||
|
for r in rels
|
||||||
|
parent(r) == G || throw("Can not form quotient group: $r is not an element of $G")
|
||||||
|
end
|
||||||
|
H = FPGroup(G)
|
||||||
|
H.rels = Dict(H(rel) => H() for rel in unique(rels))
|
||||||
|
return H
|
||||||
|
end
|
@ -11,7 +11,7 @@ end
|
|||||||
|
|
||||||
typealias FreeGroupElem GWord{FreeSymbol}
|
typealias FreeGroupElem GWord{FreeSymbol}
|
||||||
|
|
||||||
type FreeGroup <: FPGroup
|
type FreeGroup <: AbstractFPGroup
|
||||||
gens::Vector{FreeSymbol}
|
gens::Vector{FreeSymbol}
|
||||||
# order::Vector{T}
|
# order::Vector{T}
|
||||||
# fastmult_table::Array{Int,2}
|
# fastmult_table::Array{Int,2}
|
||||||
@ -22,7 +22,7 @@ type FreeGroup <: FPGroup
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
export FreeGroupElem, FreeGroup, generators
|
export FreeGroupElem, FreeGroup
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
#
|
#
|
||||||
@ -116,28 +116,3 @@ end
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
inv(s::FreeSymbol) = change_pow(s, -s.pow)
|
inv(s::FreeSymbol) = change_pow(s, -s.pow)
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
#
|
|
||||||
# Misc
|
|
||||||
#
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
# function add_rel!{T<:FreeSymbol}(G::FreeGroup, w::GWord{T})
|
|
||||||
# if !(w in G.rels)
|
|
||||||
# w = G(w)
|
|
||||||
# push!(G.rels, w)
|
|
||||||
# end
|
|
||||||
# return G
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# function quotientgroup(G::FreeGroup, rels::Vector{FreeGroupElem})
|
|
||||||
# for r in rels
|
|
||||||
# parent(r) == G || throw("Can not form quotient group: $r is not an element of $G")
|
|
||||||
# end
|
|
||||||
# H = deepcopy(G)
|
|
||||||
# for rel in rels
|
|
||||||
# add_rel!(H, rel)
|
|
||||||
# end
|
|
||||||
# return H
|
|
||||||
# end
|
|
||||||
|
@ -18,7 +18,7 @@ import Base: deepcopy_internal
|
|||||||
|
|
||||||
doc"""
|
doc"""
|
||||||
::GSymbol
|
::GSymbol
|
||||||
> Abstract type which all group symbols of FPGroups should subtype. Each
|
> Abstract type which all group symbols of AbstractFPGroups should subtype. Each
|
||||||
> concrete subtype should implement fields:
|
> concrete subtype should implement fields:
|
||||||
> * `str` which is the string representation/identification of a symbol
|
> * `str` which is the string representation/identification of a symbol
|
||||||
> * `pow` which is the (multiplicative) exponent of a symbol.
|
> * `pow` which is the (multiplicative) exponent of a symbol.
|
||||||
@ -53,7 +53,7 @@ type GWord{T<:GSymbol} <: GroupElem
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
abstract FPGroup <: Group
|
abstract AbstractFPGroup <: Group
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
#
|
#
|
||||||
@ -140,7 +140,7 @@ doc"""
|
|||||||
> returns vector of generators of `G`, as its elements.
|
> returns vector of generators of `G`, as its elements.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
gens(G::FPGroup) = [G(g) for g in G.gens]
|
gens(G::AbstractFPGroup) = [G(g) for g in G.gens]
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
#
|
#
|
||||||
@ -352,18 +352,25 @@ function replace(W::GWord, index, toreplace::GWord, replacement::GWord)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function replace_all!{T}(W::GWord{T}, subst_dict::Dict{GWord{T}, GWord{T}})
|
function replace_all!{T}(W::GWord{T}, subst_dict::Dict{GWord{T}, GWord{T}})
|
||||||
|
modified = false
|
||||||
for toreplace in reverse!(sort!(collect(keys(subst_dict)), by=length))
|
for toreplace in reverse!(sort!(collect(keys(subst_dict)), by=length))
|
||||||
replacement = subst_dict[toreplace]
|
replacement = subst_dict[toreplace]
|
||||||
i = findfirst(W, toreplace)
|
i = findfirst(W, toreplace)
|
||||||
while i ≠ 0
|
while i ≠ 0
|
||||||
|
modified = true
|
||||||
replace!(W,i,toreplace, replacement)
|
replace!(W,i,toreplace, replacement)
|
||||||
i = findnext(W, toreplace, i)
|
i = findnext(W, toreplace, i)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return W
|
return modified
|
||||||
end
|
end
|
||||||
|
|
||||||
replace_all{T<:GSymbol}(W::GWord{T}, subst_dict::Dict{GWord{T}, GWord{T}}) = replace_all!(deepcopy(W), subst_dict)
|
function replace_all{T<:GSymbol}(W::GWord{T},
|
||||||
|
subst_dict::Dict{GWord{T}, GWord{T}})
|
||||||
|
W = deepcopy(W)
|
||||||
|
replace_all!(W, subst_dict)
|
||||||
|
return W
|
||||||
|
end
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
#
|
#
|
||||||
@ -404,6 +411,7 @@ end
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
include("FreeGroup.jl")
|
include("FreeGroup.jl")
|
||||||
|
include("FPGroups.jl")
|
||||||
include("AutGroup.jl")
|
include("AutGroup.jl")
|
||||||
|
|
||||||
include("DirectProducts.jl")
|
include("DirectProducts.jl")
|
||||||
|
@ -87,7 +87,7 @@
|
|||||||
@test isa(AutGroupElem(f), Groups.GWord)
|
@test isa(AutGroupElem(f), Groups.GWord)
|
||||||
@test isa(AutGroupElem(f), AutGroupElem)
|
@test isa(AutGroupElem(f), AutGroupElem)
|
||||||
@test isa(AutGroup(FreeGroup(3)), Nemo.Group)
|
@test isa(AutGroup(FreeGroup(3)), Nemo.Group)
|
||||||
@test isa(AutGroup(FreeGroup(1)), Groups.FPGroup)
|
@test isa(AutGroup(FreeGroup(1)), Groups.AbstractFPGroup)
|
||||||
A = AutGroup(FreeGroup(1))
|
A = AutGroup(FreeGroup(1))
|
||||||
@test isa(Nemo.gens(A), Vector{AutGroupElem})
|
@test isa(Nemo.gens(A), Vector{AutGroupElem})
|
||||||
@test length(Nemo.gens(A)) == 1
|
@test length(Nemo.gens(A)) == 1
|
||||||
|
@ -131,7 +131,7 @@ end
|
|||||||
@test Groups.replace(c, 1, w, subst[w]) == s*t^-1
|
@test Groups.replace(c, 1, w, subst[w]) == s*t^-1
|
||||||
@test Groups.replace(s*c*t^-1, 1, w, subst[w]) == s^2*t^-2
|
@test Groups.replace(s*c*t^-1, 1, w, subst[w]) == s^2*t^-2
|
||||||
@test Groups.replace(t*c*t, 2, w, subst[w]) == t*s
|
@test Groups.replace(t*c*t, 2, w, subst[w]) == t*s
|
||||||
@test Groups.replace_all!(s*c*s*c*s, subst) == s*t^4*s*t^4*s
|
@test Groups.replace_all(s*c*s*c*s, subst) == s*t^4*s*t^4*s
|
||||||
|
|
||||||
G = FreeGroup(["x", "y"])
|
G = FreeGroup(["x", "y"])
|
||||||
x,y = Nemo.gens(G)
|
x,y = Nemo.gens(G)
|
||||||
|
Loading…
Reference in New Issue
Block a user