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();;