From 1344588713987f7b4ca834b95ce49f604530ab5d Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Mon, 14 Nov 2022 17:56:25 +0000 Subject: [PATCH] Fixup --- gap/congruences/conglatt.gd | 1 + gap/congruences/conglatt.gi | 372 +++++++++++++------------- gap/congruences/congsemigraph.gi | 1 - tst/standard/congruences/conglatt.tst | 9 +- 4 files changed, 195 insertions(+), 188 deletions(-) diff --git a/gap/congruences/conglatt.gd b/gap/congruences/conglatt.gd index e43f5f5a9..3dfc9f432 100644 --- a/gap/congruences/conglatt.gd +++ b/gap/congruences/conglatt.gd @@ -28,6 +28,7 @@ DeclareAttribute("CongruencesOfPoset", IsCongruencePoset); # Constructs the poset object consisting of the congruences given in the # argument. DeclareOperation("PosetOfCongruences", [IsListOrCollection]); +DeclareAttribute("JoinSemilatticeOfCongruences", IsListOrCollection); DeclareAttribute("GeneratingPairsOfPrincipalCongruences", IsSemigroup); DeclareAttribute("GeneratingPairsOfPrincipalLeftCongruences", IsSemigroup); diff --git a/gap/congruences/conglatt.gi b/gap/congruences/conglatt.gi index 3334e4f13..2742e4b2b 100644 --- a/gap/congruences/conglatt.gi +++ b/gap/congruences/conglatt.gi @@ -47,12 +47,8 @@ SEMIGROUPS.PrincipalXCongruencesNC := local total, words, congs, congs_discrim, nrcongs, last_collected, nr, keep, newcong, m, newcongdiscrim, i, old_pair, new_pair; - Assert(1, IsListOrCollection(pairs) or IsIterator(pairs)); - if IsListOrCollection(pairs) then - total := Size(pairs); - else - total := Binomial(Size(S), 2); - fi; + Assert(1, IsListOrCollection(pairs)); + total := Size(pairs); Info(InfoSemigroups, 1, "Finding principal congruences . . ."); words := List([1 .. Int(Log2(Float(Size(S))))], x -> Random(S)); @@ -122,39 +118,6 @@ end; ######################################################################## ######################################################################## -InstallMethod(PosetOfCongruences, "for a list or collection", -[IsListOrCollection], -function(coll) - local congs, nrcongs, children, parents, i, ignore, j, poset; - congs := AsList(coll); - nrcongs := Length(congs); - - # Setup children and parents lists - children := []; - parents := []; - for i in [1 .. nrcongs] do - children[i] := Set([i]); - parents[i] := Set([i]); - od; - - # Find children of each cong in turn - for i in [1 .. nrcongs] do - # Ignore known parents - ignore := BlistList([1 .. nrcongs], [parents[i]]); - for j in [1 .. nrcongs] do - if not ignore[j] and IsSubrelation(congs[i], congs[j]) then - AddSet(children[i], j); - AddSet(parents[j], i); - fi; - od; - od; - - # We are done: make the object and return - poset := Digraph(parents); - SetInNeighbours(poset, children); - return SEMIGROUPS.MakeCongruencePoset(poset, congs); -end); - # We declare the following for the sole purpose of being able to use the # Froidure-Pin (GAP implementation) algorithm for computing the join # semilattice of congruences. We could not just implement multiplication of @@ -329,6 +292,143 @@ function(S, obj) fi; end); +# Creates a poset object from a list of congruences, without generating any +# congruences. + +InstallMethod(PosetOfCongruences, "for a list or collection", +[IsListOrCollection], +function(coll) + local congs, nrcongs, children, parents, i, ignore, j, poset; + congs := AsList(coll); + nrcongs := Length(congs); + + # Setup children and parents lists + children := []; + parents := []; + for i in [1 .. nrcongs] do + children[i] := Set([i]); + parents[i] := Set([i]); + od; + + # Find children of each cong in turn + for i in [1 .. nrcongs] do + # Ignore known parents + ignore := BlistList([1 .. nrcongs], [parents[i]]); + for j in [1 .. nrcongs] do + if not ignore[j] and IsSubrelation(congs[i], congs[j]) then + AddSet(children[i], j); + AddSet(parents[j], i); + fi; + od; + od; + + # We are done: make the object and return + poset := Digraph(parents); + SetInNeighbours(poset, children); + return SEMIGROUPS.MakeCongruencePoset(poset, congs); +end); + +InstallMethod(JoinSemilatticeOfCongruences, "for a congruence poset", +[IsCongruencePoset], +function(C) + local S; + if IsEmpty(CongruencesOfPoset(C)) then + if not HasUnderlyingSemigroupOfCongruencePoset(C) then + ErrorNoReturn("cannot form the join semilattice of an empty congruence ", + "poset without the underlying semigroup being set"); + fi; + + S := UnderlyingSemigroupOfCongruencePoset(C); + return SEMIGROUPS.MakeCongruencePoset(Digraph([[1]]), + [TrivialCongruence(S)]); + fi; + return JoinSemilatticeOfCongruences(CongruencesOfPoset(C)); +end); + +InstallMethod(JoinSemilatticeOfCongruences, "for a congruence poset", +[IsListOrCollection], +function(gen_congs) + local S, D, all_congs, trivial; + # TODO(FasterJoins) arg checks + if IsEmpty(gen_congs) then + ErrorNoReturn("the argument must not be empty"); + fi; + S := Source(gen_congs[1]); + if ForAll(gen_congs, IsMagmaCongruence) then + D := _ClosureLattice(S, gen_congs, WrappedTwoSidedCongruence); + elif ForAll(gen_congs, IsLeftMagmaCongruence) then + D := _ClosureLattice(S, gen_congs, WrappedLeftCongruence); + else + Assert(1, ForAll(gen_congs, IsRightMagmaCongruence)); + D := _ClosureLattice(S, gen_congs, WrappedRightCongruence); + fi; + all_congs := CongruencesOfPoset(D); + D := DigraphMutableCopy(D); + DigraphRemoveAllMultipleEdges(D); + if not TrivialCongruence(S) in gen_congs then + all_congs := ShallowCopy(all_congs); + DigraphRemoveLoops(D); + trivial := DigraphSources(D)[1]; + DigraphRemoveVertex(D, trivial); + Remove(all_congs, trivial); + fi; + DigraphReflexiveTransitiveClosure(D); + MakeImmutable(D); + return SEMIGROUPS.MakeCongruencePoset(D, all_congs); +end); + +# This method exists because when we use the "Simple" option with +# LatticeOfCongruences etc the congruences themselves are not present (only the +# CayleyDigraphOfCongruences), so we use this method to reconstruct the +# congruences themselves. +InstallMethod(CongruencesOfPoset, "for a congruence poset", +[IsCayleyDigraphOfCongruences], +function(D) + local S, result, gen_congs, Q, q, genstoapply, seen, Join, current, n, i; + + S := UnderlyingSemigroupOfCongruencePoset(D); + result := [TrivialCongruence(S)]; + gen_congs := GeneratingCongruencesOfJoinSemilattice(D); + if IsEmpty(gen_congs) then + return result; + fi; + Append(result, gen_congs); + + # TODO(later): replace this with a Queue from the datastructures + # We do a simple BFS from the bottom of the lattice. + Q := [1]; + q := 1; + # We prepended the TrivialCongruence and this is not one of the generators + genstoapply := [1 .. Length(result) - 1]; + seen := BlistList([1 .. DigraphNrVertices(D)], []); + + if IsMagmaCongruence(gen_congs[1]) then + Join := JoinSemigroupCongruences; + elif IsRightMagmaCongruence(gen_congs[1]) then + Join := JoinRightSemigroupCongruences; + else + Assert(1, IsLeftMagmaCongruence(gen_congs[1])); + Join := JoinLeftSemigroupCongruences; + fi; + + while q <= Size(Q) do + current := Q[q]; + for i in genstoapply do + n := OutNeighbours(D)[current][i]; + if not seen[n] then + seen[n] := true; + result[n] := Join(result[current], result[i + 1]); + if n <> 1 then + Add(Q, n); + fi; + fi; + od; + q := q + 1; + od; + SetDigraphVertexLabels(D, result); + return result; +end); + ######################################################################## # GeneratingPairsOfPrincipalCongruences ######################################################################## @@ -660,6 +760,57 @@ function(S, pairs) return MinimalCongruences(PosetOfPrincipalLeftCongruences(S, pairs)); end); +######################################################################## +# PosetOfPrincipalRight/LeftCongruences +######################################################################## + +InstallMethod(PosetOfPrincipalCongruences, "for a semigroup", [IsSemigroup], +function(S) + if HasLatticeOfCongruences(S) then + return PosetOfPrincipalCongruences(LatticeOfCongruences(S)); + fi; + return PosetOfCongruences(PrincipalCongruencesOfSemigroup(S)); +end); + +InstallMethod(PosetOfPrincipalRightCongruences, "for a semigroup", +[IsSemigroup], +function(S) + if HasLatticeOfRightCongruences(S) then + return PosetOfPrincipalRightCongruences(LatticeOfRightCongruences(S)); + fi; + return PosetOfCongruences(PrincipalRightCongruencesOfSemigroup(S)); +end); + +InstallMethod(PosetOfPrincipalLeftCongruences, "for a semigroup", +[IsSemigroup], +function(S) + if HasLatticeOfLeftCongruences(S) then + return PosetOfPrincipalLeftCongruences(LatticeOfLeftCongruences(S)); + fi; + return PosetOfCongruences(PrincipalLeftCongruencesOfSemigroup(S)); +end); + +InstallMethod(PosetOfPrincipalCongruences, +"for a semigroup and list or collection", +[IsSemigroup, IsListOrCollection], +function(S, pairs) + return PosetOfCongruences(PrincipalCongruencesOfSemigroup(S, pairs)); +end); + +InstallMethod(PosetOfPrincipalRightCongruences, +"for a semigroup and list or collection", +[IsSemigroup, IsListOrCollection], +function(S, pairs) + return PosetOfCongruences(PrincipalRightCongruencesOfSemigroup(S, pairs)); +end); + +InstallMethod(PosetOfPrincipalLeftCongruences, +"for a semigroup and list or collection", +[IsSemigroup, IsListOrCollection], +function(S, pairs) + return PosetOfCongruences(PrincipalLeftCongruencesOfSemigroup(S, pairs)); +end); + ######################################################################## # Printing, viewing, dot strings etc ######################################################################## @@ -765,146 +916,3 @@ function(poset, opts) return str; end); -SEMIGROUPS.MakeJoinSemilattice := function(C) - local D, S, congs, trivial; - - D := DigraphMutableCopy(C); - DigraphRemoveAllMultipleEdges(D); - - S := UnderlyingSemigroupOfCongruencePoset(C); - congs := ShallowCopy(CongruencesOfPoset(C)); - if not TrivialCongruence(S) in GeneratingCongruencesOfJoinSemilattice(C) then - DigraphRemoveLoops(D); - trivial := DigraphSources(D)[1]; - DigraphRemoveVertex(D, trivial); - Remove(congs, trivial); - fi; - DigraphReflexiveTransitiveClosure(D); - MakeImmutable(D); - return SEMIGROUPS.MakeCongruencePoset(D, congs); -end; - -# TODO(FasterJoins) use this elsewhere rather than calling _ClosureLattice -# directly -# TODO(FasterJoins) version of this for IsListOrCollection -InstallMethod(JoinSemilatticeOfCongruences, "for a congruence poset", -[IsCongruencePoset], -function(D) - local C, S, Make; - C := CongruencesOfPoset(D); - if IsEmpty(C) then - return D; - fi; - S := Source(C[1]); - Make := SEMIGROUPS.MakeJoinSemilattice; - if ForAll(C, IsMagmaCongruence) then - return Make(_ClosureLattice(S, C, WrappedTwoSidedCongruence)); - elif ForAll(C, IsLeftMagmaCongruence) then - return Make(_ClosureLattice(S, C, WrappedLeftCongruence)); - fi; - Assert(1, ForAll(C, IsRightMagmaCongruence)); - return Make(_ClosureLattice(S, C, WrappedRightCongruence)); -end); - -# This method exists because when we use the "Simple" option with -# LatticeOfCongruences etc the congruences themselves are not present (only the -# CayleyDigraphOfCongruences), so we use this method to reconstruct the -# congruences themselves. -InstallMethod(CongruencesOfPoset, "for a congruence poset", -[IsCayleyDigraphOfCongruences], -function(D) - local S, result, gen_congs, Q, q, genstoapply, seen, Join, current, n, i; - - S := UnderlyingSemigroupOfCongruencePoset(D); - result := [TrivialCongruence(S)]; - gen_congs := GeneratingCongruencesOfJoinSemilattice(D); - if IsEmpty(gen_congs) then - return result; - fi; - Append(result, gen_congs); - - # TODO(later): replace this with a Queue from the datastructures - # We do a simple BFS from the bottom of the lattice. - Q := [1]; - q := 1; - # We prepended the TrivialCongruence and this is not one of the generators - genstoapply := [1 .. Length(result) - 1]; - seen := BlistList([1 .. DigraphNrVertices(D)], []); - - if IsMagmaCongruence(gen_congs[1]) then - Join := JoinSemigroupCongruences; - elif IsRightMagmaCongruence(gen_congs[1]) then - Join := JoinRightSemigroupCongruences; - else - Assert(1, IsLeftMagmaCongruence(gen_congs[1])); - Join := JoinLeftSemigroupCongruences; - fi; - - while q <= Size(Q) do - current := Q[q]; - for i in genstoapply do - n := OutNeighbours(D)[current][i]; - if not seen[n] then - seen[n] := true; - result[n] := Join(result[current], result[i + 1]); - if n <> 1 then - Add(Q, n); - fi; - fi; - od; - q := q + 1; - od; - SetDigraphVertexLabels(D, result); - return result; -end); - -######################################################################## -# PosetOfPrincipalRight/LeftCongruences -######################################################################## - -InstallMethod(PosetOfPrincipalCongruences, "for a semigroup", [IsSemigroup], -function(S) - if HasLatticeOfCongruences(S) then - return PosetOfPrincipalCongruences(LatticeOfCongruences(S)); - fi; - return PosetOfCongruences(PrincipalCongruencesOfSemigroup(S)); -end); - -InstallMethod(PosetOfPrincipalRightCongruences, "for a semigroup", -[IsSemigroup], -function(S) - if HasLatticeOfRightCongruences(S) then - return PosetOfPrincipalRightCongruences(LatticeOfRightCongruences(S)); - fi; - return PosetOfCongruences(PrincipalRightCongruencesOfSemigroup(S)); -end); - -InstallMethod(PosetOfPrincipalLeftCongruences, "for a semigroup", -[IsSemigroup], -function(S) - if HasLatticeOfLeftCongruences(S) then - return PosetOfPrincipalLeftCongruences(LatticeOfLeftCongruences(S)); - fi; - return PosetOfCongruences(PrincipalLeftCongruencesOfSemigroup(S)); -end); - -InstallMethod(PosetOfPrincipalCongruences, -"for a semigroup and list or collection", -[IsSemigroup, IsListOrCollection], -function(S, pairs) - return PosetOfCongruences(PrincipalCongruencesOfSemigroup(S, pairs)); -end); - -InstallMethod(PosetOfPrincipalRightCongruences, -"for a semigroup and list or collection", -[IsSemigroup, IsListOrCollection], -function(S, pairs) - return PosetOfCongruences(PrincipalRightCongruencesOfSemigroup(S, pairs)); -end); - -InstallMethod(PosetOfPrincipalLeftCongruences, -"for a semigroup and list or collection", -[IsSemigroup, IsListOrCollection], -function(S, pairs) - return PosetOfCongruences(PrincipalLeftCongruencesOfSemigroup(S, pairs)); -end); diff --git a/gap/congruences/congsemigraph.gi b/gap/congruences/congsemigraph.gi index 27aa6b379..ab9199ffd 100644 --- a/gap/congruences/congsemigraph.gi +++ b/gap/congruences/congsemigraph.gi @@ -276,7 +276,6 @@ InstallMethod(CayleyDigraphOfCongruences, "for a graph inverse semigroup", [IsGraphInverseSemigroup], function(S) - # TODO(FasterJoins) don't use _ClosureLattice directly return _ClosureLattice(S, GeneratingCongruencesOfLattice(S), WrappedTwoSidedCongruence); diff --git a/tst/standard/congruences/conglatt.tst b/tst/standard/congruences/conglatt.tst index fd05fad1d..efaf2d7a1 100644 --- a/tst/standard/congruences/conglatt.tst +++ b/tst/standard/congruences/conglatt.tst @@ -325,14 +325,12 @@ gap> pair3 := [PartialPerm([1, 2], [1, 2]), PartialPerm([1, 2], [2, 1])];; gap> coll := [RightSemigroupCongruence(S, pair1), > RightSemigroupCongruence(S, pair2), > RightSemigroupCongruence(S, pair3)];; -gap> l := JoinSemilatticeOfCongruences(PosetOfCongruences(coll)); +gap> l := JoinSemilatticeOfCongruences(coll); > gap> IsIsomorphicDigraph(l, DigraphFromDigraph6String("&ClRC")); true gap> JoinSemilatticeOfCongruences(coll); -Error, no method found! For debugging hints type ?Recovery from NoMethodFound -Error, no 1st choice method found for `JoinSemilatticeOfCongruences' on 1 argu\ -ments +> # MinimalCongruences gap> S := SymmetricInverseMonoid(2);; @@ -391,7 +389,8 @@ gap> CongruencesOfPoset(poset); gap> DigraphNrVertices(poset); 0 gap> JoinSemilatticeOfCongruences(poset); - +Error, cannot form the join semilattice of an empty congruence poset without t\ +he underlying semigroup being set gap> MinimalCongruences(poset); [ ]