Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement dual semigroups #470

Merged
merged 1 commit into from
Aug 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions doc/dual.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#############################################################################
##
#W dual.xml
#Y Copyright (C) 2018 Finn Smith
##
## Licensing information can be found in the README file of this package.
##
#############################################################################
##

<#GAPDoc Label="DualSemigroup">
<ManSection>
<Attr Name = "DualSemigroup" Arg = "S"/>
<Returns>The dual semigroup of the given semigroup.</Returns>
<Description>
The dual semigroup of a semigroup <A>S</A> is the semigroup with the
same underlying set as <A>S</A>, but with multiplication reversed; this
is anti-isomorphic to <A>S</A>. This attribute returns a semigroup
isomorphic to the dual semigroup of <A>S</A>.
<Example>
<![CDATA[
gap> S := Semigroup([Transformation([1, 4, 3, 2, 2]),
> Transformation([5, 4, 4, 1, 2])]);;
gap> D := DualSemigroup(S);
<dual semigroup of <transformation semigroup of degree 5 with 2
generators>>
gap> Size(S) = Size(D);
true
gap> NrDClasses(S) = NrDClasses(D);
true]]></Example> </Description> </ManSection>
<#/GAPDoc>

<#GAPDoc Label="AntiIsomorphismDualSemigroup">
<ManSection>
<Attr Name= "AntiIsomorphismDualSemigroup" Arg = "S"/>
<Returns>
An anti-isomorphism from <A>S</A> to the corresponding dual semigroup.
</Returns>
<Description>
The dual semigroup of <A>S</A> mathematically has the same underlying
set as <A>S</A>, but is represented with a different set of elements in
&Semigroups;. This function returns a mapping which is an anti-isomorphism from
<A>S</A> to its dual.
<Example>
<![CDATA[
gap> S := PartitionMonoid(3);
<regular bipartition *-monoid of size 203, degree 3 with 4 generators>
gap> map := AntiIsomorphismDualSemigroup(S);
MappingByFunction( <regular bipartition *-monoid of size 203,
degree 3 with 4 generators>, <dual semigroup of
<regular bipartition *-monoid of size 203, degree 3 with 4 generators>
>, function( x ) ... end, function( x ) ... end )
gap> inv := InverseGeneralMapping(map);;
gap> x := Bipartition([[1, -2], [2, -3], [3, -1]]);
<block bijection: [ 1, -2 ], [ 2, -3 ], [ 3, -1 ]>
gap> y := Bipartition([[1], [2, -2], [3, -3], [-1]]);
<bipartition: [ 1 ], [ 2, -2 ], [ 3, -3 ], [ -1 ]>
gap> (x ^ map) * (y ^ map) = (y * x) ^ map;
true
gap> x ^ map;
<<block bijection: [ 1, -2 ], [ 2, -3 ], [ 3, -1 ]>
in the dual semigroup>]]></Example> </Description> </ManSection>
<#/GAPDoc>

<#GAPDoc Label="IsDualSemigroupElement">
<ManSection>
<Filt Name = "IsDualSemigroupElement" Type = "Category" Arg="elt"/>
<Returns>Returns <K>true</K> if <A>elt</A> has the representation of a dual
semigroup element.</Returns>
<Description>
Elements of a dual semigroup obtained using
<Ref Attr = "AntiIsomorphismDualSemigroup"/> normally lie in this
category. The exception is elements obtained by applying
the map <Ref Attr = "AntiIsomorphismDualSemigroup"/> to elements already
in this category. That is, the elements of a semigroup lie in the
category <Ref Filt="IsDualSemigroupElement"/> if and only if the
elements of the corresponding dual semigroup do not.
<Example>
<![CDATA[
gap> S := SingularPartitionMonoid(4);;
gap> D := DualSemigroup(S);;
gap> s := GeneratorsOfSemigroup(S)[1];;
gap> map := AntiIsomorphismDualSemigroup(S);;
gap> t := s ^ map;
<<block bijection: [ 1, 2, -1, -2 ], [ 3, -3 ], [ 4, -4 ]>
in the dual semigroup>
gap> IsDualSemigroupElement(t);
true
gap> inv := InverseGeneralMapping(map);;
gap> x := t ^ inv;
<block bijection: [ 1, 2, -1, -2 ], [ 3, -3 ], [ 4, -4 ]>
gap> IsDualSemigroupElement(x);
false]]></Example> </Description> </ManSection>
<#/GAPDoc>

<#GAPDoc Label="IsDualSemigroupRep">
<ManSection>
<Filt Name = "IsDualSemigroupRep" Type = "Category" Arg="sgrp"/>
<Returns>Returns <K>true</K> if <A>sgrp</A> is represented as
a dual semigroup.</Returns>
<Description>
Semigroups created using <Ref Func="DualSemigroup"/>
normally have this representation. The exception is semigroups
which are the dual of semigroups already lying in this category.
That is, a semigroup has the representation
<Ref Filt="IsDualSemigroupRep"/> if and only if the corresponding
dual semigroup does not.
<Example>
<![CDATA[
gap> S := Semigroup([Transformation([3, 5, 1, 1, 2]),
> Transformation([1, 2, 4, 4, 3])]);
<transformation semigroup of degree 5 with 2 generators>
gap> D := DualSemigroup(S);
<dual semigroup of <transformation semigroup of degree 5 with 2
generators>>
gap> IsDualSemigroupRep(D);
true
gap> R := DualSemigroup(D);
<transformation semigroup of degree 5 with 2 generators>
gap> IsDualSemigroupRep(R);
false
gap> R = S;
true
gap> T := Range(IsomorphismTransformationSemigroup(D));
<transformation semigroup of size 16, degree 17 with 2 generators>
gap> IsDualSemigroupRep(T);
false
gap> x := Representative(D);
<Transformation( [ 3, 5, 1, 1, 2 ] ) in the dual semigroup>
gap> V := Semigroup(x);
<dual semigroup of <commutative transformation semigroup of degree 5
with 1 generator>>
gap> IsDualSemigroupRep(V);
true]]></Example> </Description> </ManSection>
<#/GAPDoc>
13 changes: 13 additions & 0 deletions doc/z-chap06.xml
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,19 @@ true]]></Log>
<#Include Label = "InverseSubsemigroupByProperty">
<#Include Label = "DirectProduct">
<#Include Label = "WreathProduct">

</Section>

<Section>
<Heading> Dual semigroups </Heading>
The <E>dual semigroup</E> of a semigroup <C>S</C> is the semigroup with the
same underlying set of elements but with reversed multiplication; this is
anti-isomorphic to <C>S</C>. In &Semigroups; a semigroup and its dual
are represented with disjoint sets of elements.
<#Include Label = "DualSemigroup">
<#Include Label = "IsDualSemigroupRep">
<#Include Label = "IsDualSemigroupElement">
<#Include Label = "AntiIsomorphismDualSemigroup">
</Section>

<Section Label = "Changing the representation of a semigroup">
Expand Down
28 changes: 28 additions & 0 deletions gap/attributes/dual.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#############################################################################
##
## dual.gd
## Copyright (C) 2018 James D. Mitchell
## Finn Smith
##
## Licensing information can be found in the README file of this package.
##
#############################################################################
##

DeclareCategory("IsDualSemigroupElement", IsAssociativeElement);
DeclareCategoryCollections("IsDualSemigroupElement");
DeclareAttribute("DualSemigroup", IsSemigroup);

# Every semigroup is mathematically a dual semigroup
# What we care about is whether it is represented as one
DeclareRepresentation("IsDualSemigroupRep",
IsEnumerableSemigroupRep and
IsDualSemigroupElementCollection,
[]);

DeclareAttribute("DualSemigroupOfFamily", IsFamily);
DeclareAttribute("AntiIsomorphismDualSemigroup", IsSemigroup);
DeclareGlobalFunction("UnderlyingElementOfDualSemigroupElement");

InstallTrueMethod(IsDualSemigroupRep,
IsSemigroup and IsDualSemigroupElementCollection);
210 changes: 210 additions & 0 deletions gap/attributes/dual.gi
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
#############################################################################
##
## dual.gi
## Copyright (C) 2018 James D. Mitchell
## Finn Smith
##
## Licensing information can be found in the README file of this package.
##
#############################################################################
##
## This file contains an implementation of dual semigroups. We only provide
## enough functionality to allow dual semigroups to work as enumerable
## semigroups. This is to avoid having to install versions of every function
## in Semigroups specially for dual semigroup representations. In some cases
## special functions would be faster.

InstallMethod(DualSemigroup, "for a semigroup",
[IsSemigroup],
function(S)
local dual, fam, filts, map, type;

if IsDualSemigroupRep(S) then
if HasGeneratorsOfSemigroup(S) then
return Semigroup(List(GeneratorsOfSemigroup(S),
x -> UnderlyingElementOfDualSemigroupElement(x)));
fi;
ErrorNoReturn("Semigroups: DualSemigroup: \n",
"this dual semigroup cannot be constructed ",
"without knowing generators,");
fi;

fam := NewFamily("DualSemigroupElementsFamily", IsDualSemigroupElement);
dual := Objectify(NewType(CollectionsFamily(fam),
IsWholeFamily and
IsDualSemigroupRep and
IsAttributeStoringRep),
rec());

filts := IsDualSemigroupElement;
if IsMultiplicativeElementWithOne(Representative(S)) then
filts := filts and IsMultiplicativeElementWithOne;
fi;

type := NewType(fam, filts);
fam!.type := type;

SetDualSemigroupOfFamily(fam, dual);

SetElementsFamily(FamilyObj(dual), fam);
SetDualSemigroup(dual, S);

if HasIsFinite(S) then
SetIsFinite(dual, IsFinite(S));
fi;

if IsTransformationSemigroup(S) then
map := AntiIsomorphismDualSemigroup(dual);
SetAntiIsomorphismTransformationSemigroup(dual, map);
fi;

if HasGeneratorsOfSemigroup(S) then
SetGeneratorsOfSemigroup(dual,
List(GeneratorsOfSemigroup(S),
x -> SEMIGROUPS.DualSemigroupElementNC(dual,
x)));
fi;

if HasGeneratorsOfMonoid(S) then
SetGeneratorsOfMonoid(dual,
List(GeneratorsOfMonoid(S),
x -> SEMIGROUPS.DualSemigroupElementNC(dual,
x)));
fi;
return dual;
end);

SEMIGROUPS.DualSemigroupElementNC := function(S, s)
if not IsDualSemigroupElement(s) then
return Objectify(ElementsFamily(FamilyObj(S))!.type, [s]);
fi;
return s![1];
end;

InstallMethod(AntiIsomorphismDualSemigroup, "for a semigroup",
[IsSemigroup],
function(S)
local dual, inv, iso;

dual := DualSemigroup(S);
iso := function(x)
return SEMIGROUPS.DualSemigroupElementNC(dual, x);
end;

inv := function(x)
return SEMIGROUPS.DualSemigroupElementNC(S, x);
end;
return MappingByFunction(S, dual, iso, inv);
end);

InstallGlobalFunction(UnderlyingElementOfDualSemigroupElement,
"for a dual semigroup element",
function(s)
if not IsDualSemigroupElement(s) then
ErrorNoReturn("Semigroups: UnderlyingElementOfDualSemigroupElement: \n",
"the argument must be an element represented as a dual ",
"semigroup element,");
fi;
return s![1];
end);

################################################################################
## Technical methods
################################################################################

InstallMethod(OneMutable, "for a dual semigroup element",
[IsDualSemigroupElement and IsMultiplicativeElementWithOne],
function(s)
local S, x;
S := DualSemigroupOfFamily(FamilyObj(s));
x := SEMIGROUPS.DualSemigroupElementNC(DualSemigroup(S), s);
return SEMIGROUPS.DualSemigroupElementNC(S, OneMutable(x));
end);

InstallMethod(MultiplicativeNeutralElement, "for a dual semigroup",
[IsDualSemigroupRep],
10, # add rank to beat enumeration methods
function(S)
local m;
m := MultiplicativeNeutralElement(DualSemigroup(S));
if m <> fail then
return SEMIGROUPS.DualSemigroupElementNC(S, m);
fi;
return fail;
end);

InstallMethod(Representative, "for a dual semigroup",
[IsDualSemigroupRep],
function(S)
if HasGeneratorsOfSemigroup(S) then
return GeneratorsOfSemigroup(S)[1];
fi;
return SEMIGROUPS.DualSemigroupElementNC(S, Representative(DualSemigroup(S)));
end);

InstallMethod(Size, "for a dual semigroup",
[IsDualSemigroupRep],
10, # add rank to beat enumeration methods
function(S)
return Size(DualSemigroup(S));
end);

InstallMethod(AsList, "for a dual semigroup",
[IsDualSemigroupRep],
10, # add rank to beat enumeration methods
function(S)
return List(DualSemigroup(S), s -> SEMIGROUPS.DualSemigroupElementNC(S, s));
end);

InstallMethod(\*, "for dual semigroup elements",
IsIdenticalObj,
[IsDualSemigroupElement, IsDualSemigroupElement],
function(x, y)
return Objectify(FamilyObj(x)!.type, [y![1] * x![1]]);
end);

InstallMethod(\=, "for dual semigroup elements",
IsIdenticalObj,
[IsDualSemigroupElement, IsDualSemigroupElement],
function(x, y)
return x![1] = y![1];
end);

InstallMethod(\<, "for dual semigroup elements",
IsIdenticalObj,
[IsDualSemigroupElement, IsDualSemigroupElement],
function(x, y)
return x![1] < y![1];
end);

InstallMethod(ViewObj, "for dual semigroup elements",
[IsDualSemigroupElement], PrintObj);

InstallMethod(PrintObj, "for dual semigroup elements",
[IsDualSemigroupElement],
function(x)
Print("<", ViewString(x![1]), " in the dual semigroup>");
end);

InstallMethod(ViewObj, "for a dual semigroup",
[IsDualSemigroupRep], PrintObj);

InstallMethod(PrintObj, "for a dual semigroup",
[IsDualSemigroupRep],
function(S)
Print("<dual semigroup of ",
ViewString(DualSemigroup(S)),
">");
end);

InstallMethod(ChooseHashFunction, "for a dual semigroup element and int",
[IsDualSemigroupElement, IsInt],
function(x, data)
local H, hashfunc;

H := ChooseHashFunction(x![1], data);
hashfunc := function(a, b)
return H.func(a![1], b);
end;
return rec(func := hashfunc, data := H.data);
end);
Loading