From 00f5fc1f239daec1c8a5377ac8ff948d23ccce55 Mon Sep 17 00:00:00 2001 From: kalmar Date: Thu, 22 Jun 2017 14:21:25 +0200 Subject: [PATCH] add DirectProducts and WreathProducts --- src/DirectProducts.jl | 248 ++++++++++++++++++++++++++++++++++++++++++ src/WreathProducts.jl | 236 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 484 insertions(+) create mode 100644 src/DirectProducts.jl create mode 100644 src/WreathProducts.jl diff --git a/src/DirectProducts.jl b/src/DirectProducts.jl new file mode 100644 index 0000000..c0332bf --- /dev/null +++ b/src/DirectProducts.jl @@ -0,0 +1,248 @@ +module DirectProducts + +using Nemo + +import Base: show, ==, hash, deepcopy_internal +import Base: ×, *, inv + +import Nemo: parent, parent_type, elem_type +import Nemo: elements, order, Group, GroupElem, Ring + +export DirectProductGroup, DirectProductGroupElem + +############################################################################### +# +# DirectProductGroup / DirectProductGroupElem +# +############################################################################### + +doc""" + DirectProductGroup(factors::Vector{Group}) <: Group +Implements direct product of groups as vector factors. The group operation is +`*` distributed component-wise, with component-wise identity as neutral element. +""" + +type DirectProductGroup <: Group + factors::Vector{Group} + operations::Vector{Function} +end + +type DirectProductGroupElem <: GroupElem + elts::Vector{GroupElem} + parent::DirectProductGroup + + DirectProductGroupElem{T<:GroupElem}(a::Vector{T}) = new(a) +end + +############################################################################### +# +# Type and parent object methods +# +############################################################################### + +elem_type(G::DirectProductGroup) = DirectProductGroupElem + +parent_type(::Type{DirectProductGroupElem}) = DirectProductGroup + +parent(g::DirectProductGroupElem) = g.parent + +############################################################################### +# +# DirectProductGroup / DirectProductGroupElem constructors +# +############################################################################### + +DirectProductGroup(G::Group, H::Group) = DirectProductGroup([G, H], Function[(*),(*)]) + +DirectProductGroup(G::Group, H::Ring) = DirectProductGroup([G, H], Function[(*),(+)]) + +DirectProductGroup(G::Ring, H::Group) = DirectProductGroup([G, H], Function[(+),(*)]) + +DirectProductGroup(G::Ring, H::Ring) = DirectProductGroup([G, H], Function[(+),(+)]) + +DirectProductGroup{T<:Ring}(X::Vector{T}) = DirectProductGroup(Group[X...], Function[(+) for _ in X]) + +×(G::Group, H::Group) = DirectProductGroup(G,H) + +function DirectProductGroup{T<:Group, S<:Group}(G::Tuple{T, Function}, H::Tuple{S, Function}) + return DirectProductGroup([G[1], H[1]], Function[G[2],H[2]]) +end + +function DirectProductGroup(groups::Vector) + for G in groups + typeof(G) <: Group || throw("$G is not a group!") + end + ops = Function[typeof(G) <: Ring ? (+) : (*) for G in groups] + + return DirectProductGroup(groups, ops) +end + +############################################################################### +# +# Parent object call overloads +# +############################################################################### + +(G::DirectProductGroup)() = G([H() for H in G.factors]; checked=false) + +function (G::DirectProductGroup)(g::DirectProductGroupElem; checked=true) + if checked + return G(g.elts) + else + g.parent = G + return g + end +end + +doc""" + (G::DirectProductGroup)(a::Vector; checked=true) +> Constructs element of the direct product group `G` by coercing each element +> of vector `a` to the corresponding factor of `G`. If `checked` flag is set to +> `false` no checks on the correctness are performed. + +""" +function (G::DirectProductGroup)(a::Vector; checked=true) + length(a) == length(G.factors) || throw("Cannot coerce $a to $G: they have + different number of factors") + if checked + for (F,g) in zip(G.factors, a) + try + F(g) + catch + throw("Cannot coerce to $G: $g cannot be coerced to $F.") + end + end + end + elt = DirectProductGroupElem([F(g) for (F,g) in zip(G.factors, a)]) + elt.parent = G + return elt +end + +############################################################################### +# +# Basic manipulation +# +############################################################################### + +function deepcopy_internal(g::DirectProductGroupElem, dict::ObjectIdDict) + G = parent(g) + return G(deepcopy(g.elts)) +end + +function hash(G::DirectProductGroup, h::UInt) + return hash(G.factors, hash(G.operations, hash(DirectProductGroup,h))) +end + +function hash(g::DirectProductGroupElem, h::UInt) + return hash(g.elts, hash(g.parent, hash(DirectProductGroupElem, h))) +end + +doc""" + eye(G::DirectProductGroup) +> Return the identity element for the given direct product of groups. + +""" +eye(G::DirectProductGroup) = G() + +############################################################################### +# +# String I/O +# +############################################################################### + +function show(io::IO, G::DirectProductGroup) + println(io, "Direct product of groups") + join(io, G.factors, ", ", " and ") +end + +function show(io::IO, g::DirectProductGroupElem) + print(io, "("*join(g.elts,",")*")") +end + +############################################################################### +# +# Comparison +# +############################################################################### + +function (==)(G::DirectProductGroup, H::DirectProductGroup) + G.factors == H.factors || return false + G.operations == H.operations || return false + return true +end + +doc""" + ==(g::DirectProductGroupElem, h::DirectProductGroupElem) +> Return `true` if the given elements of direct products are equal, otherwise return `false`. + +""" +function (==)(g::DirectProductGroupElem, h::DirectProductGroupElem) + parent(g) == parent(h) || return false + g.elts == h.elts || return false + return true +end + +############################################################################### +# +# Binary operators +# +############################################################################### + +function direct_mult(g::DirectProductGroupElem, h::DirectProductGroupElem) + parent(g) == parent(h) || throw("Can't multiply elements from different groups: $g, $h") + G = parent(g) + return G([op(a,b) for (op,a,b) in zip(G.operations, g.elts, h.elts)]) +end + +doc""" + *(g::DirectProductGroupElem, h::DirectProductGroupElem) +> Return the direct-product group operation of elements, i.e. component-wise +> operation as defined by `operations` field of the parent object. + +""" +(*)(g::DirectProductGroupElem, h::DirectProductGroupElem) = direct_mult(g,h) + +############################################################################### +# +# Inversion +# +############################################################################### + +doc""" + inv(g::DirectProductGroupElem) +> Return the inverse of the given element in the direct product group. + +""" +# TODO: dirty hack around `+` operation +function inv(g::DirectProductGroupElem) + G = parent(g) + return G([(op == (*) ? inv(elt): -elt) for (op,elt) in zip(G.operations, g.elts)]) +end + +############################################################################### +# +# Misc +# +############################################################################### + +doc""" + elements(G::DirectProductGroup) +> Returns `Task` that produces all elements of group `G` (provided that factors +> implement the elements function). + +""" +# TODO: can Base.product handle generators? +# now it returns nothing's so we have to collect ellements... +function elements(G::DirectProductGroup) + cartesian_prod = Base.product([collect(elements(H)) for H in G.factors]...) + return (G(collect(elt)) for elt in cartesian_prod) +end + +doc""" + order(G::DirectProductGroup) +> Returns the order (number of elements) in the group. + +""" +order(G::DirectProductGroup) = prod([order(H) for H in G.factors]) + +end # of module DirectProduct diff --git a/src/WreathProducts.jl b/src/WreathProducts.jl new file mode 100644 index 0000000..24aa589 --- /dev/null +++ b/src/WreathProducts.jl @@ -0,0 +1,236 @@ +module WreathProducts + +using Nemo +using DirectProducts + +import Base: convert, deepcopy_internal, show, isequal, ==, hash, size, inv +import Base: +, -, *, // + +import Nemo: Group, GroupElem, elem_type, parent_type, parent, elements, order + +############################################################################### +# +# WreathProduct / WreathProductElem +# +############################################################################### + +doc""" + WreathProduct <: Group +> Implements Wreath product of a group N by permutation (sub)group P < Sₖ, +> usually written as $N \wr P$. +> The multiplication inside wreath product is defined as +> (n, σ) * (m, τ) = (n*ψ(σ)(m), σ*τ), +> where ψ:P → Aut(Nᵏ) is the permutation representation of Sₖ restricted to P. + +# Arguments: +* `::Group` : the single factor of group N +* `::PermutationGroup` : full PermutationGroup +""" + +type WreathProduct <: Group + N::DirectProductGroup + P::PermutationGroup + + function WreathProduct(G::Group, P::PermutationGroup) + N = DirectProductGroup(typeof(G)[G for _ in 1:P.n]) + return new(N, P) + end +end + +type WreathProductElem <: GroupElem + n::DirectProductGroupElem + p::perm + parent::WreathProduct + + function WreathProductElem(n::DirectProductGroupElem, p::perm) + length(n.elts) == parent(p).n + return new(n, p) + end +end + +export WreathProduct, WreathProductElem + +############################################################################### +# +# Type and parent object methods +# +############################################################################### + +elem_type(::WreathProduct) = WreathProductElem + +parent_type(::WreathProductElem) = WreathProduct + +parent(g::WreathProductElem) = g.parent + +############################################################################### +# +# WreathProduct / WreathProductElem constructors +# +############################################################################### + +# converts??? + +############################################################################### +# +# Parent object call overloads +# +############################################################################### + +function (G::WreathProduct)(g::WreathProductElem) + try + G.N(g.n) + catch + throw("Can't coerce $(g.n) to $(G.N) factor of $G") + end + try + G.P(g.p) + catch + throw("Can't coerce $(g.p) to $(G.P) factor of $G") + end + elt = WreathProductElem(G.N(g.n), G.P(g.p)) + elt.parent = G + return elt +end + +doc""" + (G::WreathProduct)(n::DirectProductGroupElem, p::perm) +> Creates an element of wreath product `G` by coercing `n` and `p` to `G.N` and +> `G.P`, respectively. + +""" +function (G::WreathProduct)(n::DirectProductGroupElem, p::perm) + result = WreathProductElem(n,p) + result.parent = G + return result +end + +(G::WreathProduct)() = G(G.N(), G.P()) + +doc""" + (G::WreathProduct)(p::perm) +> Returns the image of permutation `p` in `G` via embedding `p -> (id,p)`. + +""" +(G::WreathProduct)(p::perm) = G(G.N(), p) + +doc""" + (G::WreathProduct)(n::DirectProductGroupElem) +> Returns the image of `n` in `G` via embedding `n -> (n,())`. This is the +> embedding that makes sequence `1 -> N -> G -> P -> 1` exact. + +""" +(G::WreathProduct)(n::DirectProductGroupElem) = G(n, G.P()) + +############################################################################### +# +# Basic manipulation +# +############################################################################### + +function deepcopy_internal(g::WreathProductElem, dict::ObjectIdDict) + G = parent(g) + return G(deepcopy(g.n), deepcopy(g.p)) +end + +function hash(G::WreathProduct, h::UInt) + return hash(G.N, hash(G.P, hash(WreathProduct, h))) +end + +function hash(g::WreathProductElem, h::UInt) + return hash(g.n, hash(g.p, hash(parent(g), h))) +end + +############################################################################### +# +# String I/O +# +############################################################################### + +function show(io::IO, G::WreathProduct) + print(io, "Wreath Product of $(G.N.factors[1]) and $(G.P)") +end + +function show(io::IO, g::WreathProductElem) + # println(io, "Element of WreathProduct over $T of size $(size(X)):") + # show(io, "text/plain", matrix_repr(X)) + print(io, "($(g.n)≀$(g.p))") +end + +############################################################################### +# +# Comparison +# +############################################################################### + +function (==)(G::WreathProduct, H::WreathProduct) + G.N == H.N || return false + G.P == H.P || return false + return true +end + +function (==)(g::WreathProductElem, h::WreathProductElem) + parent(g) == parent(h) || return false + g.n == h.n || return false + g.p == h.p || return false + return true +end + +############################################################################### +# +# Binary operators +# +############################################################################### + +function wreath_multiplication(g::WreathProductElem, h::WreathProductElem) + parent(g) == parent(h) || throw("Can not multiply elements from different + groups!") + G = parent(g) + w=G.N((h.n).elts[inv(g.p).d]) + return G(g.n*w, g.p*h.p) +end + +doc""" + *(g::WreathProductElem, h::WreathProductElem) +> Return the wreath product group operation of elements, i.e. +> +> g*h = (g.n*g.p(h.n), g.p*h.p), +> +> where g.p(h.n) denotes the action of `g.p::perm` on +> `h.n::DirectProductGroupElem` via standard permutation of coordinates. +""" +(*)(g::WreathProductElem, h::WreathProductElem) = wreath_multiplication(g,h) + + +############################################################################### +# +# Inversion +# +############################################################################### + +doc""" + inv(g::WreathProductElem) +> Returns the inverse of element of a wreath product, according to the formula +> g^-1 = (g.n, g.p)^-1 = (g.p^-1(g.n^-1), g.p^-1). +""" +function inv(g::WreathProductElem) + G = parent(g) + w = G.N(inv(g.n).elts[g.p.d]) + return G(w, inv(g.p)) +end + +############################################################################### +# +# Misc +# +############################################################################### + +matrix_repr(g::WreathProductElem) = Any[matrix_repr(g.p) g.n] + +function elements(G::WreathProduct) + iter = Base.product(collect(elements(G.N)), collect(elements(G.P))) + return (G(n)*G(p) for (n,p) in iter) +end + +order(G::WreathProduct) = order(G.P)*order(G.N) + +end # of module WreatProduct