#############################################################################
##
#W  cong.xml
#Y  Copyright (C) 2015-16                                   Michael Young
##
##  Licensing information can be found in the README file of this package.
##
#############################################################################
##

<#GAPDoc Label="IsSemigroupCongruence">
  <ManSection>
    <Prop Name="IsSemigroupCongruence" Arg="obj"/>
    <Description>
      A semigroup congruence <C>cong</C> is an equivalence relation on a
      semigroup <C>S</C> which respects left and right multiplication. <P/>

      That is, if <M>(a,b)</M> is a pair in <C>cong</C>, and <M>x</M> is an
      element of <C>S</C>, then <M>(ax,bx)</M> and <M>(xa,xb)</M> are both in
      <C>cong</C>. <P/>

      The simplest way of creating a congruence in &SEMIGROUPS; is by a set of
      <E>generating pairs</E>.  See <Ref Func="SemigroupCongruence"/>.

      <Example><![CDATA[
gap> S := Semigroup([
>   Transformation([2, 1, 1, 2, 1]),
>   Transformation([3, 4, 3, 4, 4]),
>   Transformation([3, 4, 3, 4, 3]),
>   Transformation([4, 3, 3, 4, 4])]);;
gap> pair1 := [Transformation([3, 4, 3, 4, 3]),
>              Transformation([1, 2, 1, 2, 1])];;
gap> pair2 := [Transformation([4, 3, 4, 3, 4]),
>              Transformation([3, 4, 3, 4, 3])];;
gap> cong := SemigroupCongruence(S, [pair1, pair2]);
<semigroup congruence over <simple transformation semigroup of
 degree 5 with 4 generators> with linked triple (2,4,1)>
gap> IsSemigroupCongruence(cong);
true]]></Example>
    </Description>
  </ManSection>
<#/GAPDoc>

<#GAPDoc Label="IsLeftSemigroupCongruence">
  <ManSection>
    <Prop Name="IsLeftSemigroupCongruence" Arg="obj"/>
    <Description>
      A left semigroup congruence <C>cong</C> is an equivalence relation on a
      semigroup <C>S</C> which respects left multiplication. <P/>

      That is, if <M>(a,b)</M> is a pair in <C>cong</C>, and <M>x</M> is an
      element of <C>S</C>, then <M>(xa,xb)</M> is also in <C>cong</C>. <P/>

      The simplest way of creating a left congruence in &SEMIGROUPS; is by a set
      of <E>generating pairs</E>.  See <Ref Func="LeftSemigroupCongruence"/>.

      <Example><![CDATA[
gap> S := Semigroup([
>   Transformation([2, 1, 1, 2, 1]),
>   Transformation([3, 4, 3, 4, 4]),
>   Transformation([3, 4, 3, 4, 3]),
>   Transformation([4, 3, 3, 4, 4])]);;
gap> pair1 := [Transformation([3, 4, 3, 4, 3]),
>              Transformation([1, 2, 1, 2, 1])];;
gap> pair2 := [Transformation([4, 3, 4, 3, 4]),
>              Transformation([3, 4, 3, 4, 3])];;
gap> cong := LeftSemigroupCongruence(S, [pair1, pair2]);
<left semigroup congruence over <transformation semigroup of degree 5
 with 4 generators> with 2 generating pairs>
gap> IsLeftSemigroupCongruence(cong);
true]]></Example>
    </Description>
  </ManSection>
<#/GAPDoc>

<#GAPDoc Label="IsRightSemigroupCongruence">
  <ManSection>
    <Prop Name="IsRightSemigroupCongruence" Arg="obj"/>
    <Description>
      A right semigroup congruence <C>cong</C> is an equivalence relation on a
      semigroup <C>S</C> which respects right multiplication. <P/>

      That is, if <M>(a,b)</M> is a pair in <C>cong</C>, and <M>x</M> is an
      element of <C>S</C>, then <M>(ax,bx)</M> is also in <C>cong</C>. <P/>

      The simplest way of creating a right congruence in &SEMIGROUPS; is by a set
      of <E>generating pairs</E>.  See <Ref Func="RightSemigroupCongruence"/>.

      <Example><![CDATA[
gap> S := Semigroup([
>   Transformation([2, 1, 1, 2, 1]),
>   Transformation([3, 4, 3, 4, 4]),
>   Transformation([3, 4, 3, 4, 3]),
>   Transformation([4, 3, 3, 4, 4])]);;
gap> pair1 := [Transformation([3, 4, 3, 4, 3]),
>              Transformation([1, 2, 1, 2, 1])];;
gap> pair2 := [Transformation([4, 3, 4, 3, 4]),
>              Transformation([3, 4, 3, 4, 3])];;
gap> RightSemigroupCongruence(S, [pair1, pair2]);
<right semigroup congruence over <transformation semigroup of
 degree 5 with 4 generators> with 2 generating pairs>
gap> IsRightSemigroupCongruence(cong);
true]]></Example>
    </Description>
  </ManSection>
<#/GAPDoc>

<#GAPDoc Label="SemigroupCongruence">
  <ManSection>
    <Func Name = "SemigroupCongruence" Arg = "S, pairs"/>
    <Returns>A semigroup congruence.</Returns>
    <Description>
      This function returns a semigroup congruence over the semigroup
      <A>S</A>.<P/>

      If <A>pairs</A> is a list of lists of size 2 with elements from <A>S</A>,
      then this function will return the semigroup congruence defined by these
      generating pairs.  The individual pairs may instead be given as separate
      arguments.<P/>

      <Example><![CDATA[
gap> S := Semigroup([
>   Transformation([2, 1, 1, 2, 1]),
>   Transformation([3, 4, 3, 4, 4]),
>   Transformation([3, 4, 3, 4, 3]),
>   Transformation([4, 3, 3, 4, 4])]);;
gap> pair1 := [Transformation([3, 4, 3, 4, 3]),
>              Transformation([1, 2, 1, 2, 1])];;
gap> pair2 := [Transformation([4, 3, 4, 3, 4]),
>              Transformation([3, 4, 3, 4, 3])];;
gap> SemigroupCongruence(S, [pair1, pair2]);
<semigroup congruence over <simple transformation semigroup of
 degree 5 with 4 generators> with linked triple (2,4,1)>
gap> SemigroupCongruence(S, pair1, pair2);
<semigroup congruence over <simple transformation semigroup of
 degree 5 with 4 generators> with linked triple (2,4,1)>]]></Example>
    </Description>
  </ManSection>
<#/GAPDoc>

<#GAPDoc Label="LeftSemigroupCongruence">
  <ManSection>
    <Func Name = "LeftSemigroupCongruence" Arg = "S, pairs"/>
    <Returns>A left semigroup congruence.</Returns>
    <Description>
      This function returns a left semigroup congruence over the semigroup
      <A>S</A>.<P/>

      If <A>pairs</A> is a list of lists of size 2 with elements from <A>S</A>,
      then this function will return the least left semigroup congruence on
      <A>S</A> which contains these generating pairs.  The individual pairs may
      instead be given as separate arguments.<P/>

      <Example><![CDATA[
gap> S := Semigroup([
>   Transformation([2, 1, 1, 2, 1]),
>   Transformation([3, 4, 3, 4, 4]),
>   Transformation([3, 4, 3, 4, 3]),
>   Transformation([4, 3, 3, 4, 4])]);;
gap> pair1 := [Transformation([3, 4, 3, 4, 3]),
>              Transformation([1, 2, 1, 2, 1])];;
gap> pair2 := [Transformation([4, 3, 4, 3, 4]),
>              Transformation([3, 4, 3, 4, 3])];;
gap> LeftSemigroupCongruence(S, [pair1, pair2]);
<left semigroup congruence over <transformation semigroup of degree 5
 with 4 generators> with 2 generating pairs>
gap> LeftSemigroupCongruence(S, pair1, pair2);
<left semigroup congruence over <transformation semigroup of degree 5
 with 4 generators> with 2 generating pairs>]]></Example>
    </Description>
  </ManSection>
<#/GAPDoc>

<#GAPDoc Label="RightSemigroupCongruence">
  <ManSection>
    <Func Name = "RightSemigroupCongruence" Arg = "S, pairs"/>
    <Returns>A right semigroup congruence.</Returns>
    <Description>
      This function returns a right semigroup congruence over the semigroup
      <A>S</A>.<P/>

      If <A>pairs</A> is a list of lists of size 2 with elements from <A>S</A>,
      then this function will return the least right semigroup congruence on
      <A>S</A> which contains these generating pairs.  The individual pairs may
      instead be given as separate arguments.<P/>

      <Example><![CDATA[
gap> S := Semigroup([
>   Transformation([2, 1, 1, 2, 1]),
>   Transformation([3, 4, 3, 4, 4]),
>   Transformation([3, 4, 3, 4, 3]),
>   Transformation([4, 3, 3, 4, 4])]);;
gap> pair1 := [Transformation([3, 4, 3, 4, 3]),
>              Transformation([1, 2, 1, 2, 1])];;
gap> pair2 := [Transformation([4, 3, 4, 3, 4]),
>              Transformation([3, 4, 3, 4, 3])];;
gap> RightSemigroupCongruence(S, [pair1, pair2]);
<right semigroup congruence over <transformation semigroup of
 degree 5 with 4 generators> with 2 generating pairs>
gap> RightSemigroupCongruence(S, pair1, pair2);
<right semigroup congruence over <transformation semigroup of
 degree 5 with 4 generators> with 2 generating pairs>]]></Example>
    </Description>
  </ManSection>
<#/GAPDoc>

  <!--
    <#GAPDoc Label="GeneratingPairsOfSemigroupCongruence">
    <ManSection>
    <Attr Name = "GeneratingPairsOfSemigroupCongruence" Arg = "cong"/>
    <Attr Name = "GeneratingPairsOfLeftSemigroupCongruence" Arg = "cong"/>
    <Attr Name = "GeneratingPairsOfRightSemigroupCongruence" Arg = "cong"/>
    <Returns>A list of lists.</Returns>
    <Description>
    If <A>cong</A> is a semigroup congruence, then
    <C>GeneratingPairsOfSemigroupCongruence</C> returns a list of pairs of
    elements from <C>Range(<A>cong</A>)</C> that <E>generates</E> the
    congruence; i.e. <A>cong</A> is the least congruence on the semigroup
    which contains all the pairs in the list. <P/>

    If <A>cong</A> is a left or right semigroup congruence, then
    <C>GeneratingPairsOfLeft/RightSemigroupCongruence</C> will instead give a
    list of pairs which generate it as a left or right congruence.  Note that,
    although a congruence is also a left and right congruence, its generating
    pairs as a left or right congruence may differ from its generating pairs
    as a two-sided congruence. <P/>

    A congruence can be defined using a set of generating pairs: see
    <Ref Func = "SemigroupCongruence"/>,
    <Ref Func = "LeftSemigroupCongruence"/>, and
    <Ref Func = "RightSemigroupCongruence"/>. <P/>

    <Example><![CDATA[
    gap> S := Semigroup([Transformation([3, 3, 2, 3]),
    >                    Transformation([3, 4, 4, 1])]);;
    gap> pairs :=
    >     [[Transformation([1, 1, 1, 1]), Transformation([2, 2, 2, 3])],
    >      [Transformation([2, 2, 3, 2]), Transformation([3, 3, 2, 3])]];;
    gap> cong := SemigroupCongruence(S, pairs);;
    gap> GeneratingPairsOfSemigroupCongruence(cong);
    [ [ Transformation( [ 1, 1, 1, 1 ] ),
    Transformation( [ 2, 2, 2, 3 ] ) ],
    [ Transformation( [ 2, 2, 3, 2 ] ),
    Transformation( [ 3, 3, 2, 3 ] ) ] ]
    ]]></Example>
    </Description>
    </ManSection>
    <#/GAPDoc>
-->

<#GAPDoc Label="CongruencesOfSemigroup">
  <ManSection>
    <Attr Name = "CongruencesOfSemigroup" Arg = "S"
          Label = "for a semigroup"/>
    <Attr Name = "LeftCongruencesOfSemigroup" Arg = "S"
          Label = "for a semigroup"/>
    <Attr Name = "RightCongruencesOfSemigroup" Arg = "S"
          Label = "for a semigroup"/>
    <Oper Name = "CongruencesOfSemigroup" Arg = "S, restriction"
          Label = "for a semigroup and a multiplicative element collection"/>
    <Oper Name = "LeftCongruencesOfSemigroup" Arg = "S, restriction"
          Label = "for a semigroup and a multiplicative element collection"/>
    <Oper Name = "RightCongruencesOfSemigroup" Arg = "S, restriction"
          Label = "for a semigroup and a multiplicative element collection"/>
    <Returns>The congruences of a semigroup.</Returns>
    <Description>
      This attribute gives a list of the left, right, or 2-sided congruences of
      the semigroup <A>S</A>. <P/>

      If <A>restriction</A> is specified and is a collection of elements from
      <A>S</A>, then the result will only include congruences generated by pairs
      of elements from <A>restriction</A>.  Otherwise, all congruences will be
      calculated.<P/>

      See also <Ref Attr = "LatticeOfCongruences" Label = "for a semigroup"/>.
      <P/>

      <Example><![CDATA[
gap> S := ReesZeroMatrixSemigroup(SymmetricGroup(3),
>                                 [[(), (1, 3, 2)], [(1, 2), 0]]);;
gap> congs := CongruencesOfSemigroup(S);;
gap> Length(congs);
4
gap> Set(congs, NrEquivalenceClasses);
[ 1, 5, 9, 25 ]
gap> pos := Position(congs, UniversalSemigroupCongruence(S));;
gap> congs[pos];
<universal semigroup congruence over
<Rees 0-matrix semigroup 2x2 over Sym( [ 1 .. 3 ] )>>]]></Example>
    </Description>
  </ManSection>
<#/GAPDoc>

<#GAPDoc Label="MinimalCongruencesOfSemigroup">
  <ManSection>
    <Attr Name = "MinimalCongruencesOfSemigroup" Arg = "S"
          Label = "for a semigroup"/>
    <Attr Name = "MinimalLeftCongruencesOfSemigroup" Arg = "S"
          Label = "for a semigroup"/>
    <Attr Name = "MinimalRightCongruencesOfSemigroup" Arg = "S"
          Label = "for a semigroup"/>
    <Oper Name = "MinimalCongruencesOfSemigroup" Arg = "S, restriction"
          Label = "for a semigroup and a multiplicative element collection"/>
    <Oper Name = "MinimalLeftCongruencesOfSemigroup" Arg = "S, restriction"
          Label = "for a semigroup and a multiplicative element collection"/>
    <Oper Name = "MinimalRightCongruencesOfSemigroup" Arg = "S, restriction"
          Label = "for a semigroup and a multiplicative element collection"/>
    <Returns>The congruences of a semigroup.</Returns>
    <Description>
      If <A>S</A> is a semigroup, then the attribute
      <C>MinimalCongruencesOfSemigroup</C> gives a list of all the congruences
      on <A>S</A> which are <E>minimal</E>.  A congruence is minimal iff it is
      non-trivial and contains no other congruences as subrelations (apart from
      the trivial congruence).
      <P/>

      <C>MinimalLeftCongruencesOfSemigroup</C> and
      <C>MinimalRightCongruencesOfSemigroup</C> do the same thing, but for left
      congruences and right congruences respectively.  Note that any congruence
      is also a left congruence, but that a minimal congruence may not be a
      minimal left congruence. <P/>

      If <A>restriction</A> is specified and is a collection of elements from
      <A>S</A>, then the result will only include congruences generated by pairs
      of elements from <A>restriction</A>.  Otherwise, all congruences will be
      calculated.<P/>

      See also <Ref Attr = "CongruencesOfSemigroup" Label = "for a semigroup"/> and
      <Ref Attr = "PrincipalCongruencesOfSemigroup" Label = "for a semigroup"/>.
      <P/>

      <Example><![CDATA[
gap> S := Semigroup(Transformation([1, 3, 2]),
>                   Transformation([3, 1, 3]));;
gap> min := MinimalCongruencesOfSemigroup(S);
[ <2-sided semigroup congruence over <transformation semigroup
     of size 13, degree 3 with 2 generators> with 1 generating pairs>
 ]
gap> minl := MinimalLeftCongruencesOfSemigroup(S);
[ <left semigroup congruence over <transformation semigroup
     of size 13, degree 3 with 2 generators> with 1 generating pairs>,
  <left semigroup congruence over <transformation semigroup
     of size 13, degree 3 with 2 generators> with 1 generating pairs>,
  <left semigroup congruence over <transformation semigroup
     of size 13, degree 3 with 2 generators> with 1 generating pairs>
 ]
]]></Example>
    </Description>
  </ManSection>
<#/GAPDoc>

<#GAPDoc Label="PrincipalCongruencesOfSemigroup">
  <ManSection>
    <Attr Name = "PrincipalCongruencesOfSemigroup" Arg = "S"
          Label = "for a semigroup"/>
    <Attr Name = "PrincipalLeftCongruencesOfSemigroup" Arg = "S"
          Label = "for a semigroup"/>
    <Attr Name = "PrincipalRightCongruencesOfSemigroup" Arg = "S"
          Label = "for a semigroup"/>
    <Oper Name = "PrincipalCongruencesOfSemigroup" Arg = "S, restriction"
          Label = "for a semigroup and a multiplicative element collection"/>
    <Oper Name = "PrincipalLeftCongruencesOfSemigroup" Arg = "S, restriction"
          Label = "for a semigroup and a multiplicative element collection"/>
    <Oper Name = "PrincipalRightCongruencesOfSemigroup" Arg = "S, restriction"
          Label = "for a semigroup and a multiplicative element collection"/>
    <Returns>A list.</Returns>
    <Description>
      If <A>S</A> is a semigroup, then the attribute
      <C>PrincipalCongruencesOfSemigroup</C> gives a list of all the congruences
      on <A>S</A> which are <E>principal</E>.  A congruence is principal if and
      only if it is non-trivial and can be defined by a single generating pair.
      <P/>

      <C>PrincipalLeftCongruencesOfSemigroup</C> and
      <C>PrincipalRightCongruencesOfSemigroup</C> do the same thing, but for
      left congruences and right congruences respectively.  Note that any
      congruence is a left congruence and a right congruence, but that a
      principal congruence may not be a principal left congruence or a principal
      right congruence. <P/>

      If <A>restriction</A> is specified and is a collection of elements from
      <A>S</A>, then the result will only include congruences generated by pairs
      of elements from <A>restriction</A>.  Otherwise, all congruences will be
      calculated.<P/>

      See also <Ref Attr = "CongruencesOfSemigroup" Label = "for a semigroup"/>
      and
      <Ref Attr = "MinimalCongruencesOfSemigroup" Label = "for a semigroup"/>.
      <P/>

      <Example><![CDATA[
gap> S := Semigroup(Transformation([1, 3, 2]),
>                   Transformation([3, 1, 3]));;
gap> congs := PrincipalCongruencesOfSemigroup(S);
[ <universal semigroup congruence over <transformation semigroup
     of size 13, degree 3 with 2 generators>>,
  <2-sided semigroup congruence over <transformation semigroup
     of size 13, degree 3 with 2 generators> with 1 generating pairs>,
  <2-sided semigroup congruence over <transformation semigroup
     of size 13, degree 3 with 2 generators> with 1 generating pairs>,
  <2-sided semigroup congruence over <transformation semigroup
     of size 13, degree 3 with 2 generators> with 1 generating pairs>,
  <2-sided semigroup congruence over <transformation semigroup
     of size 13, degree 3 with 2 generators> with 1 generating pairs>
 ]
]]></Example>
    </Description>
  </ManSection>
<#/GAPDoc>

<#GAPDoc Label="EquivalenceRelationLookup">
  <ManSection>
    <Attr Name="EquivalenceRelationLookup" Arg="equiv"
      Label="for an equivalence relation over a finite semigroup"/>
    <Returns>A list.</Returns>
    <Description>
      This attribute describes the equivalence relation <A>equiv</A>, defined
      over a finite semigroup, as a list of positive integers of length the size
      of the finite semigroup over which <A>equiv</A> is defined.<P/>

      Each position in the list corresponds to an element of the semigroup (in a
      consistent canonical order) and the integer at that position is a unique
      identifier for that element's equivalence class under <A>equiv</A>.  Two
      elements of the semigroup on which the equivalence is defined are related
      in the equivalence if and only if they have the same number at their
      respective positions in the lookup.<P/>

      Note that the order in which numbers appear in the list is
      non-deterministic, and two equivalence relations describing the same
      mathematical relation might therefore have different lookups.  Note also
      that the maximum value of the list may not be the number of classes of
      <A>equiv</A>, and that any integer might not be included.  However, see
      <Ref Attr="EquivalenceRelationCanonicalLookup"
           Label="for an equivalence relation over a finite semigroup"/>.
      <P/>

      See also <Ref Attr = "EquivalenceRelationPartition" BookName = "ref"/>.
      <Example><![CDATA[
gap> S := Monoid([
>  Transformation([1, 2, 2]), Transformation([3, 1, 3])]);;
gap> cong := SemigroupCongruence(S,
> [Transformation([1, 2, 1]), Transformation([2, 1, 2])]);;
gap> lookup := EquivalenceRelationLookup(cong);;
gap> lookup[3] = lookup[8];
true
gap> lookup[2] = lookup[9];
false]]></Example>
    </Description>
  </ManSection>
<#/GAPDoc>

<#GAPDoc Label="EquivalenceRelationCanonicalLookup">
  <ManSection>
    <Attr Name="EquivalenceRelationCanonicalLookup" Arg="equiv"
      Label="for an equivalence relation over a finite semigroup"/>
    <Returns>A list.</Returns>
    <Description>
      This attribute describes the equivalence relation <A>equiv</A>, defined
      over a finite semigroup, as a list of positive integers of length the size
      of the semigroup.<P/>

      Each position in the list corresponds to an element of the semigroup (in a
      consistent canonical order as defined by <Ref Oper =
        "PositionCanonical"/>) and the integer at that position is a unique
      identifier for that element's equivalence class under <A>equiv</A>.  The
      value of <C>EquivalenceRelationCanonicalLookup</C> has the property that
      the first appearance of the value <C>i</C> is strictly later than the
      first appearance of <C>i-1</C>, and that all entries in the list will be
      from the range <C>[1 .. NrEquivalenceClasses(<A>equiv</A>)]</C>.  As such,
      two equivalence relations on a given semigroup are equal if and only if
      their canonical lookups are equal.<P/>

      Two elements of the semigroup on which the equivalence relation is defined
      are related in the equivalence relation if and only if they have the same
      number at their respective positions in the lookup.
      <P/>

      See also <Ref Attr="EquivalenceRelationLookup"
        Label="for an equivalence relation over a finite semigroup"/> and
      <Ref Attr = "EquivalenceRelationPartition" BookName = "ref"/>.
      <Example><![CDATA[
gap> S := Monoid([
>  Transformation([1, 2, 2]), Transformation([3, 1, 3])]);;
gap> cong := SemigroupCongruence(S,
> [Transformation([1, 2, 1]), Transformation([2, 1, 2])]);;
gap> EquivalenceRelationCanonicalLookup(cong);
[ 1, 2, 3, 4, 5, 6, 2, 3, 6, 4, 5, 6 ]]]></Example>
    </Description>
  </ManSection>
<#/GAPDoc>

<#GAPDoc Label="EquivalenceRelationCanonicalPartition">
  <ManSection>
    <Attr Name = "EquivalenceRelationCanonicalPartition" Arg = "cong"/>
    <Returns>A list of lists.</Returns>
    <Description>
      This attribute returns a list of lists of elements of the underlying set
      of the semigroup congruence <A>cong</A>.  These lists are precisely the
      nontrivial equivalence classes of <A>cong</A>.  The order in which the
      classes appear is deterministic, and the order of the elements inside each
      class is also deterministic.  Hence, two congruence objects have the same
      <C>EquivalenceRelationCanonicalPartition</C> if and only if they describe
      the same relation. <P/>

      See also <Ref Attr = "EquivalenceRelationPartition" BookName = "ref"/>,
      a similar attribute which does not have canonical ordering, but which is
      likely to be faster. <P/>
      <Example><![CDATA[
gap> S := Semigroup(Transformation([1, 4, 3, 3]),
>                   Transformation([2, 4, 3, 3]));;
gap> cong := SemigroupCongruence(S, [Transformation([1, 4, 3, 3]),
>                                    Transformation([1, 3, 3, 3])]);;
gap> EquivalenceRelationCanonicalPartition(cong);
[ [ Transformation( [ 1, 4, 3, 3 ] ),
      Transformation( [ 1, 3, 3, 3 ] ) ],
  [ Transformation( [ 4, 3, 3, 3 ] ),
      Transformation( [ 3, 3, 3, 3 ] ) ] ]
]]></Example>
    </Description>
  </ManSection>
<#/GAPDoc>

<#GAPDoc Label="AsSemigroupCongruenceByGeneratingPairs">
  <ManSection>
    <Oper Name = "AsSemigroupCongruenceByGeneratingPairs" Arg = "cong"/>
    <Returns>A semigroup congruence.</Returns>
    <Description>
      This operation takes <A>cong</A>, a semigroup congruence, and returns the
      same congruence relation, but described by &GAP;'s default method of
      defining semigroup congruences: a set of generating pairs for the
      congruence.
      <Example><![CDATA[
gap> S := ReesZeroMatrixSemigroup(SymmetricGroup(3),
>                                 [[(), (1, 3, 2)], [(1, 2), 0]]);;
gap> cong := CongruencesOfSemigroup(S)[3];;
gap> AsSemigroupCongruenceByGeneratingPairs(cong);
<semigroup congruence over <Rees 0-matrix semigroup 2x2 over
  Sym( [ 1 .. 3 ] )> with linked triple (3,2,2)>]]></Example>
    </Description>
  </ManSection>
<#/GAPDoc>

<#GAPDoc Label="NonTrivialEquivalenceClasses">
  <ManSection>
    <Attr Name = "NonTrivialEquivalenceClasses" Arg = "eq"/>
    <Returns>A list of equivalence classes.</Returns>
    <Description>
      If <A>eq</A> is an equivalence relation, then this attribute returns a
      list of all equivalence classes of <A>eq</A> which contain more than one
      element. <P/>

      <Example><![CDATA[
gap> S := Monoid([Transformation([1, 2, 2]),
>                 Transformation([3, 1, 3])]);;
gap> cong := SemigroupCongruence(S, [Transformation([1, 2, 1]),
>                                    Transformation([2, 1, 2])]);;
gap> classes := NonTrivialEquivalenceClasses(cong);;
gap> Set(classes);
[ <2-sided congruence class of Transformation( [ 1, 2, 2 ] )>,
  <2-sided congruence class of Transformation( [ 3, 1, 3 ] )>,
  <2-sided congruence class of Transformation( [ 3, 1, 1 ] )>,
  <2-sided congruence class of Transformation( [ 2, 1, 2 ] )>,
  <2-sided congruence class of Transformation( [ 3, 3, 3 ] )> ]
gap> cong := RightSemigroupCongruence(S, [Transformation([1, 2, 1]),
>                                         Transformation([2, 1, 2])]);;
gap> classes := NonTrivialEquivalenceClasses(cong);;
gap> Set(classes);
[ <right congruence class of Transformation( [ 3, 1, 3 ] )>,
  <right congruence class of Transformation( [ 2, 1, 2 ] )> ]]]></Example>
    </Description>
  </ManSection>
<#/GAPDoc>

<#GAPDoc Label="IsCongruenceClass">
  <ManSection>
    <Filt Name="IsCongruenceClass" Arg="obj" Type="category"/>
    <Description>
      This category contains any object which is an equivalence class of a
      semigroup congruence (see <Ref Prop="IsSemigroupCongruence"/>).  An
      object will only be in this category if the relation is known to be a
      semigroup congruence when the congruence class is created.

      <Example><![CDATA[
gap> S := Monoid([
>  Transformation([1, 2, 2]), Transformation([3, 1, 3])]);;
gap> cong := SemigroupCongruence(S, [Transformation([1, 2, 1]),
>                                    Transformation([2, 1, 2])]);;
gap> class := EquivalenceClassOfElement(cong,
>                                       Transformation([3, 1, 1]));
<2-sided congruence class of Transformation( [ 3, 1, 1 ] )>
gap> IsCongruenceClass(class);
true]]></Example>
    </Description>
  </ManSection>
<#/GAPDoc>

<#GAPDoc Label="IsLeftCongruenceClass">
  <ManSection>
    <Filt Name="IsLeftCongruenceClass" Arg="obj" Type="category"/>
    <Description>
      This category contains any object which is an equivalence class of a
      left semigroup congruence (see <Ref Prop="IsLeftSemigroupCongruence"/>).
      An object will only be in this category if the relation is known to be a
      left semigroup congruence when the class is created.

      <Example><![CDATA[
gap> S := Monoid([
>  Transformation([1, 2, 2]), Transformation([3, 1, 3])]);;
gap> pairs := [Transformation([1, 2, 1]),
>              Transformation([2, 1, 2])];;
gap> cong := LeftSemigroupCongruence(S, pairs);;
gap> class := EquivalenceClassOfElement(cong,
>                                       Transformation([3, 1, 1]));
<left congruence class of Transformation( [ 3, 1, 1 ] )>
gap> IsLeftCongruenceClass(class);
true]]></Example>
    </Description>
  </ManSection>
<#/GAPDoc>

<#GAPDoc Label="IsRightCongruenceClass">
  <ManSection>
    <Filt Name="IsRightCongruenceClass" Arg="obj" Type="category"/>
    <Description>
      This category contains any object which is an equivalence class of a
      right semigroup congruence (see <Ref Prop="IsRightSemigroupCongruence"/>).
      An object will only be in this category if the relation is known to be a
      right semigroup congruence when the class is created.

      <Example><![CDATA[
gap> S := Monoid([
>  Transformation([1, 2, 2]), Transformation([3, 1, 3])]);;
gap> pairs := [Transformation([1, 2, 1]),
>              Transformation([2, 1, 2])];;
gap> cong := RightSemigroupCongruence(S, pairs);;
gap> class := EquivalenceClassOfElement(cong,
>                                       Transformation([3, 1, 1]));
<right congruence class of Transformation( [ 3, 1, 1 ] )>
gap> IsRightCongruenceClass(class);
true]]></Example>
    </Description>
  </ManSection>
<#/GAPDoc>

<#GAPDoc Label="IsSubrelation">
<ManSection>
  <Oper Name = "IsSubrelation" Arg = "cong1, cong2"/>
  <Returns>True or false.</Returns>
  <Description>
    If <A>cong1</A> and <A>cong2</A> are congruences over the same semigroup,
    then this operation returns whether <A>cong2</A> is a refinement of
    <A>cong1</A>, i.e. whether every pair in <A>cong2</A> is contained in
    <A>cong1</A>. <P/>

    <Example><![CDATA[
gap> S := ReesZeroMatrixSemigroup(SymmetricGroup(3),
> [[(), (1, 3, 2)], [(1, 2), 0]]);;
gap> cong1 := SemigroupCongruence(S, [RMSElement(S, 1, (1, 2, 3), 1),
>                                     RMSElement(S, 1, (), 1)]);;
gap> cong2 := SemigroupCongruence(S, []);;
gap> IsSubrelation(cong1, cong2);
true
gap> IsSubrelation(cong2, cong1);
false]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="IsSuperrelation">
<ManSection>
  <Oper Name = "IsSuperrelation" Arg = "cong1, cong2"/>
  <Returns>True or false.</Returns>
  <Description>
    If <A>cong1</A> and <A>cong2</A> are congruences over the same semigroup,
    then this operation returns whether <A>cong1</A> is a refinement of
    <A>cong2</A>, i.e. whether every pair in <A>cong1</A> is contained in
    <A>cong2</A>. <P/>

    See <Ref Oper="IsSubrelation"/>. <P/>

    <Example><![CDATA[
gap> S := ReesZeroMatrixSemigroup(SymmetricGroup(3),
> [[(), (1, 3, 2)], [(1, 2), 0]]);;
gap> cong1 := SemigroupCongruence(S, [RMSElement(S, 1, (1, 2, 3), 1),
>                                     RMSElement(S, 1, (), 1)]);;
gap> cong2 := SemigroupCongruence(S, []);;
gap> IsSuperrelation(cong1, cong2);
false
gap> IsSuperrelation(cong2, cong1);
true]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="MeetSemigroupCongruences">
<ManSection>
  <Oper Name = "MeetSemigroupCongruences" Arg = "c1, c2"/>
  <Oper Name = "MeetLeftSemigroupCongruences" Arg = "c1, c2"/>
  <Oper Name = "MeetRightSemigroupCongruences" Arg = "c1, c2"/>
  <Returns>A semigroup congruence.</Returns>
  <Description>
    This operation returns the <E>meet</E> of the two semigroup congruences
    <A>c1</A> and <A>c2</A> -- that is, the largest semigroup congruence
    contained in both <A>c1</A> and <A>c2</A>.<P/>

    <Example><![CDATA[
gap> S := ReesZeroMatrixSemigroup(SymmetricGroup(3),
> [[(), (1, 3, 2)], [(1, 2), 0]]);;
gap> cong1 := SemigroupCongruence(S, [RMSElement(S, 1, (1, 2, 3), 1),
>                                     RMSElement(S, 1, (), 1)]);;
gap> cong2 := SemigroupCongruence(S, []);;
gap> MeetSemigroupCongruences(cong1, cong2);
<semigroup congruence over <Rees 0-matrix semigroup 2x2 over
  Sym( [ 1 .. 3 ] )> with linked triple (1,2,2)>]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="JoinSemigroupCongruences">
<ManSection>
  <Oper Name = "JoinSemigroupCongruences" Arg = "c1, c2"/>
  <Oper Name = "JoinLeftSemigroupCongruences" Arg = "c1, c2"/>
  <Oper Name = "JoinRightSemigroupCongruences" Arg = "c1, c2"/>
  <Returns>A semigroup congruence.</Returns>
  <Description>
    This operation returns the <E>join</E> of the two semigroup congruences
    <A>c1</A> and <A>c2</A> -- that is, the smallest semigroup congruence
    containing all the relations in both <A>c1</A> and <A>c2</A>.<P/>

    <Example><![CDATA[
gap> S := ReesZeroMatrixSemigroup(SymmetricGroup(3),
> [[(), (1, 3, 2)], [(1, 2), 0]]);;
gap> cong1 := SemigroupCongruence(S, [RMSElement(S, 1, (1, 2, 3), 1),
>                                     RMSElement(S, 1, (), 1)]);;
gap> cong2 := SemigroupCongruence(S, []);;
gap> JoinSemigroupCongruences(cong1, cong2);
<semigroup congruence over <Rees 0-matrix semigroup 2x2 over
  Sym( [ 1 .. 3 ] )> with linked triple (3,2,2)>]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="OnLeftCongruenceClasses">
<ManSection>
  <Oper Name = "OnLeftCongruenceClasses" Arg = "class, elm"/>
  <Returns>A left congruence class.</Returns>
  <Description>
    If <A>class</A> is an equivalence class of the left semigroup congruence
    <C>cong</C> on the semigroup <C>S</C>, and <A>elm</A> is an element of
    <C>S</C>, then this operation returns the equivalence class of <C>cong</C>
    containing the element <C><A>elm</A> * x</C>, where <C>x</C> is any element
    of <A>class</A>.  The result is well-defined by the definition of a left
    congruence. <P/>

    See <Ref Prop="IsLeftSemigroupCongruence"/> and
    <Ref Filt="IsLeftCongruenceClass"/>. <P/>

    <Example><![CDATA[
gap> S := Semigroup([
>   Transformation([2, 1, 1, 2, 1]),
>   Transformation([3, 4, 3, 4, 4]),
>   Transformation([3, 4, 3, 4, 3]),
>   Transformation([4, 3, 3, 4, 4])]);;
gap> pair1 := [Transformation([3, 4, 3, 4, 3]),
>              Transformation([1, 2, 1, 2, 1])];;
gap> pair2 := [Transformation([4, 3, 4, 3, 4]),
>              Transformation([3, 4, 3, 4, 3])];;
gap> cong := LeftSemigroupCongruence(S, [pair1, pair2]);
<left semigroup congruence over <transformation semigroup of degree 5
 with 4 generators> with 2 generating pairs>
gap> x := Transformation([3, 4, 3, 4, 3]);;
gap> class := EquivalenceClassOfElement(cong, x);
<left congruence class of Transformation( [ 3, 4, 3, 4, 3 ] )>
gap> elm := Transformation([1, 2, 2, 1, 2]);;
gap> OnLeftCongruenceClasses(class, elm);
<left congruence class of Transformation( [ 3, 4, 4, 3, 4 ] )>
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="OnRightCongruenceClasses">
<ManSection>
  <Oper Name = "OnRightCongruenceClasses" Arg = "class, elm"/>
  <Returns>A right congruence class.</Returns>
  <Description>
    If <A>class</A> is an equivalence class of the right semigroup congruence
    <C>cong</C> on the semigroup <C>S</C>, and <A>elm</A> is an element of
    <C>S</C>, then this operation returns the equivalence class of <C>cong</C>
    containing the element <C>x * <A>elm</A></C>, where <C>x</C> is any element
    of <A>class</A>.  The result is well-defined by the definition of a right
    congruence. <P/>

    See <Ref Prop="IsRightSemigroupCongruence"/> and
    <Ref Filt="IsRightCongruenceClass"/>. <P/>

    <Example><![CDATA[
gap> S := Semigroup([
>   Transformation([2, 1, 1, 2, 1]),
>   Transformation([3, 4, 3, 4, 4]),
>   Transformation([3, 4, 3, 4, 3]),
>   Transformation([4, 3, 3, 4, 4])]);;
gap> pair1 := [Transformation([3, 4, 3, 4, 3]),
>              Transformation([1, 2, 1, 2, 1])];;
gap> pair2 := [Transformation([4, 3, 4, 3, 4]),
>              Transformation([3, 4, 3, 4, 3])];;
gap> cong := RightSemigroupCongruence(S, [pair1, pair2]);
<right semigroup congruence over <transformation semigroup of
 degree 5 with 4 generators> with 2 generating pairs>
gap> x := Transformation([3, 4, 3, 4, 3]);;
gap> class := EquivalenceClassOfElement(cong, x);
<right congruence class of Transformation( [ 3, 4, 3, 4, 3 ] )>
gap> elm := Transformation([1, 2, 2, 1, 2]);;
gap> OnRightCongruenceClasses(class, elm);
<right congruence class of Transformation( [ 2, 1, 2, 1, 2 ] )>
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>
