diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index 6c48a057f..5542a0e59 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -5,4 +5,4 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: codespell-project/actions-codespell@v2.0 + - uses: codespell-project/actions-codespell@v2.1 diff --git a/doc/attr.xml b/doc/attr.xml index 986827a8c..284510215 100644 --- a/doc/attr.xml +++ b/doc/attr.xml @@ -1292,7 +1292,7 @@ true]]> NambooripadPartialOrder returns the Nambooripad partial order on the regular semigroup S as a list of sets of positive integers where - entry i in NaturalPartialOrder(S) is the set of + entry i in NambooripadPartialOrder(S) is the set of positions in Elements(S) of elements which are less than Elements(S)[i]. See also . diff --git a/etc/code-coverage-test-gap.py b/etc/code-coverage-test-gap.py index e50ea5a89..f52bbdf31 100755 --- a/etc/code-coverage-test-gap.py +++ b/etc/code-coverage-test-gap.py @@ -64,19 +64,29 @@ _DIR = tempfile.mkdtemp() print(f"{_INFO_PREFIX}Using temporary directory: {_DIR}\033[0m") -_COMMANDS = 'echo "' -_COMMANDS += "".join(rf"Test(\"{f}\");;\n" for f in _ARGS.tstfiles) -_COMMANDS += rf"""UncoverageLineByLine();; -LoadPackage(\"profiling\", false);; -filesdir := \"{getcwd()}{_PROFILE_DIR}\";;\n""" - -_COMMANDS += rf"outdir := \"{_DIR}\";;\n" -_COMMANDS += rf"x := ReadLineByLineProfile(\"{_DIR}/profile.gz\");;\n" -_COMMANDS += 'OutputAnnotatedCodeCoverageFiles(x, filesdir, outdir);"' +# Raw strings are used to correctly escape quotes " for input in another +# process, i.e. we explicitly need the string to contain \" instead of just " +# for each quote. +_GAP_COMMANDS = [rf"Test(\"{f}\");;" for f in _ARGS.tstfiles] +_GAP_COMMANDS.extend( + [ + "UncoverageLineByLine();;", + rf"LoadPackage(\"profiling\", false);;", + rf"filesdir := \"{getcwd()}{_PROFILE_DIR}\";;", + rf"outdir := \"{_DIR}\";;", + rf"x := ReadLineByLineProfile(\"{_DIR}/profile.gz\");;", + "OutputAnnotatedCodeCoverageFiles(x, filesdir, outdir);", + ] +) _RUN_GAP = f"{_ARGS.gap_root}/gap -A -m 1g -T --cover {_DIR}/profile.gz" -with subprocess.Popen(_COMMANDS, stdout=subprocess.PIPE, shell=True) as pro1: +# Commands are stored in a list and then joined with "\n" since including +# newlines directly in raw strings cause issues when piping into GAP on some +# platforms. +with subprocess.Popen( + 'echo "' + "\n".join(_GAP_COMMANDS) + '"', stdout=subprocess.PIPE, shell=True +) as pro1: try: with subprocess.Popen(_RUN_GAP, stdin=pro1.stdout, shell=True) as pro2: pro2.wait() diff --git a/gap/attributes/isomorph.gi b/gap/attributes/isomorph.gi index 5d28954a8..c785ec0eb 100644 --- a/gap/attributes/isomorph.gi +++ b/gap/attributes/isomorph.gi @@ -105,7 +105,65 @@ end); InstallMethod(IsIsomorphicSemigroup, "for semigroups", [IsSemigroup, IsSemigroup], -{S, T} -> IsomorphismSemigroups(S, T) <> fail); +function(R, S) + local uR, uS, map, mat, next, row, entry, isoR, rmsR, isoS, rmsS; + + if not (IsFinite(R) and IsSimpleSemigroup(R) + and IsFinite(S) and IsSimpleSemigroup(S)) then + return IsomorphismSemigroups(R, S) <> fail; + fi; + + # Note that when experimenting the method for IsomorphismSemigroups for Rees + # 0-matrix semigroups is faster than the analogue of the below code, and so + # we do not special case finite 0-simple semigroups. + + # Take an isomorphism of R to an RMS if appropriate + if not (IsReesMatrixSemigroup(R) and IsWholeFamily(R) + and IsPermGroup(UnderlyingSemigroup(R))) then + isoR := IsomorphismReesMatrixSemigroupOverPermGroup(R); + rmsR := Range(isoR); + else + rmsR := R; + fi; + # Take an isomorphism of S to an RMS if appropriate + if not (IsReesMatrixSemigroup(S) and IsWholeFamily(S) + and IsPermGroup(UnderlyingSemigroup(S))) then + isoS := IsomorphismReesMatrixSemigroupOverPermGroup(S); + rmsS := Range(isoS); + else + rmsS := S; + fi; + + if Length(Rows(rmsR)) <> Length(Rows(rmsS)) + or (Length(Columns(rmsR)) <> Length(Columns(rmsS))) then + return false; + fi; + + uR := UnderlyingSemigroup(rmsR); + uS := UnderlyingSemigroup(rmsS); + + # uS and uR must be groups because we made them so above. + map := IsomorphismGroups(uS, uR); + if map = fail then + return false; + fi; + + # Make sure underlying groups are the same, and then compare + # canonical Rees matrix semigroups of both R and S + mat := []; + for row in Matrix(rmsS) do + next := []; + for entry in row do + Add(next, entry ^ map); + od; + Add(mat, next); + od; + + rmsR := CanonicalReesMatrixSemigroup(rmsR); + rmsS := ReesMatrixSemigroup(uR, mat); + rmsS := CanonicalReesMatrixSemigroup(rmsS); + return Matrix(rmsR) = Matrix(rmsS); +end); InstallMethod(IsomorphismSemigroups, "for finite simple semigroups", [IsSimpleSemigroup and IsFinite, IsSimpleSemigroup and IsFinite], diff --git a/gap/attributes/isorms.gi b/gap/attributes/isorms.gi index 60e6e75b9..16eb327f8 100644 --- a/gap/attributes/isorms.gi +++ b/gap/attributes/isorms.gi @@ -1368,7 +1368,7 @@ function(S) end); InstallMethod(CanonicalReesMatrixSemigroup, -"for a Rees 0-matrix semigroup", +"for a Rees matrix semigroup", [IsReesMatrixSemigroup], function(S) local G, mat; diff --git a/tst/standard/attributes/isomorph.tst b/tst/standard/attributes/isomorph.tst index 92d9ae609..428e3dd2d 100644 --- a/tst/standard/attributes/isomorph.tst +++ b/tst/standard/attributes/isomorph.tst @@ -9,7 +9,7 @@ ## #@local A, BruteForceInverseCheck, BruteForceIsoCheck, F, G, S, T, U, V, inv -#@local map, x, y +#@local map, x, y, M, N, R, L gap> START_TEST("Semigroups package: standard/attributes/isomorph.tst"); gap> LoadPackage("semigroups", false);; @@ -118,6 +118,44 @@ gap> T := JonesMonoid(4); gap> IsIsomorphicSemigroup(S, T); false +# isomorph: IsIsomorphicSemigroup, for finite simple semigroups +gap> M := [[(1, 2, 3), ()], [(), ()], [(), ()]]; +[ [ (1,2,3), () ], [ (), () ], [ (), () ] ] +gap> N := [[(1, 3, 2), ()], [(), (1, 2, 3)], [(1, 3, 2), (1, 3, 2)]]; +[ [ (1,3,2), () ], [ (), (1,2,3) ], [ (1,3,2), (1,3,2) ] ] +gap> R := ReesMatrixSemigroup(AlternatingGroup([1 .. 3]), M); + +gap> S := ReesMatrixSemigroup(Group([(1, 2, 3)]), N); + +gap> IsIsomorphicSemigroup(R, S); +true +gap> R := SemigroupByMultiplicationTable(MultiplicationTable(R));; +gap> S := SemigroupByMultiplicationTable(MultiplicationTable(S));; +gap> IsIsomorphicSemigroup(R, S); +true +gap> L := [[(), ()], [(), ()], [(1, 2, 3), ()]]; +[ [ (), () ], [ (), () ], [ (1,2,3), () ] ] +gap> T := ReesMatrixSemigroup(SymmetricGroup([1 .. 3]), L); + +gap> IsIsomorphicSemigroup(S, T); +false +gap> IsIsomorphicSemigroup(T, T); +true +gap> M := [[(1, 2, 3), ()], [(), ()], [(), ()]]; +[ [ (1,2,3), () ], [ (), () ], [ (), () ] ] +gap> N := [[(1, 3, 2), ()], [(), (1, 2, 3)]]; +[ [ (1,3,2), () ], [ (), (1,2,3) ] ] +gap> R := ReesMatrixSemigroup(AlternatingGroup([1 .. 3]), M);; +gap> S := ReesMatrixSemigroup(AlternatingGroup([1 .. 3]), N);; +gap> IsIsomorphicSemigroup(R, S); +false +gap> R := ReesMatrixSemigroup(AlternatingGroup([1 .. 5]), +> [[(), ()], [(), (1, 3, 2, 4, 5)]]);; +gap> S := ReesMatrixSemigroup(AlternatingGroup([1 .. 5]), +> [[(1, 5, 4, 3, 2), ()], [(1, 4, 5), (1, 4)(3, 5)]]);; +gap> IsIsomorphicSemigroup(R, S); +false + # isomorph: IsomorphismSemigroups, for infinite semigroup(s) gap> S := FreeSemigroup(1);; gap> T := TrivialSemigroup();;