From 07a4968d4be8ccd16e39195e3dfef657133dc804 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sun, 13 Sep 2026 10:00:28 +0200 Subject: [PATCH] Add PreImagesRepresentativeNC method for SHBI GAP 4.17 splits PreImagesRepresentative into a checked operation and PreImagesRepresentativeNC, and the library calls the latter. Semigroup homomorphisms by images only had a method for the checked operation, so PreImagesRepresentativeNC fell through to the library method for s.p. general mappings, which signals "no default method". Install the unchecked computation for PreImagesRepresentativeNC as well, keeping the checked method and its error message. On older GAP both names are the same operation, so the extra method is only installed when they differ. The inverse function of AsSemigroupIsomorphismByFunction used PreImages, which returns a list of preimages rather than an element, in every GAP version. Use PreImagesRepresentativeNC instead; the argument lies in the range of an isomorphism. The automorphism group computations for Rees (0-)matrix semigroups call PreImagesRepresentative on elements known to be in the image. Call PreImagesRepresentativeNC there, skipping the range and image membership tests that the checked operation performs in GAP 4.17. Assisted-by: Claude Code (Opus 5) --- gap/attributes/homomorph.gi | 31 ++++++++++++++++++++------- gap/attributes/isorms.gi | 4 ++-- tst/standard/attributes/homomorph.tst | 5 +++++ 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/gap/attributes/homomorph.gi b/gap/attributes/homomorph.gi index 12418ce8f..5ef07fe71 100644 --- a/gap/attributes/homomorph.gi +++ b/gap/attributes/homomorph.gi @@ -328,7 +328,8 @@ InstallMethod(AsSemigroupIsomorphismByFunction, hom -> SemigroupIsomorphismByFunctionNC(Source(hom), Range(hom), x -> ImageElm(hom, x), - y -> PreImages(hom, y))); + y -> + PreImagesRepresentativeNC(hom, y))); # Methods for SHBI/SIBI/SHBF InstallMethod(IsSurjective, "for a semigroup homomorphism", @@ -364,6 +365,17 @@ InstallMethod(ImagesSource, "for SHBI", [IsSemigroupHomomorphismByImages], hom -> Semigroup(MappingGeneratorsImages(hom)[2])); +# must lie in ImagesSource(hom). +SEMIGROUPS.PreImagesRepresentativeSHBI := function(hom, x) + # Use MinimalFactorization rather than Factorization because + # MinimalFactorization is guaranteed to return a list of positive integers, + # but Factorization is not (i.e. if S is an inverse acting semigroup. + # Also since we require an IsomorphismFpSemigroup, there's no additional + # cost to using MinimalFactorization instead of Factorization. + return EvaluateWord(MappingGeneratorsImages(hom)[1], + MinimalFactorization(ImagesSource(hom), x)); +end; + InstallMethod(PreImagesRepresentative, "for a semigroup homom. by images and an element in the range", [IsSemigroupHomomorphismByImages, IsMultiplicativeElement], @@ -374,15 +386,18 @@ function(hom, x) elif not x in ImagesSource(hom) then return fail; fi; - # Use MinimalFactorization rather than Factorization because - # MinimalFactorization is guaranteed to return a list of positive integers, - # but Factorization is not (i.e. if S is an inverse acting semigroup. - # Also since we require an IsomorphismFpSemigroup, there's no additional - # cost to using MinimalFactorization instead of Factorization. - return EvaluateWord(MappingGeneratorsImages(hom)[1], - MinimalFactorization(ImagesSource(hom), x)); + return SEMIGROUPS.PreImagesRepresentativeSHBI(hom, x); end); +# GAP >= 4.17 calls PreImagesRepresentativeNC internally; in older versions it +# is the same operation as PreImagesRepresentative, see init.g. +if not IsIdenticalObj(PreImagesRepresentative, PreImagesRepresentativeNC) then + InstallMethod(PreImagesRepresentativeNC, + "for a semigroup homom. by images and an element in the image", + [IsSemigroupHomomorphismByImages, IsMultiplicativeElement], + SEMIGROUPS.PreImagesRepresentativeSHBI); +fi; + InstallMethod(ImagesRepresentative, "for a semigroup homom. by images and an element in the source", [IsSemigroupHomomorphismByImages, IsMultiplicativeElement], diff --git a/gap/attributes/isorms.gi b/gap/attributes/isorms.gi index 16eb327f8..97fcef71c 100644 --- a/gap/attributes/isorms.gi +++ b/gap/attributes/isorms.gi @@ -324,7 +324,7 @@ function(R) tester := function(x) local y, found, g, i, tmp, map; - y := PreImagesRepresentative(hom, x ^ Projection(V, 2)); + y := PreImagesRepresentativeNC(hom, x ^ Projection(V, 2)); x := x ^ Projection(V, 1); tmp := []; found := false; @@ -514,7 +514,7 @@ function(R) tester := function(x) local y, map, g; - y := PreImagesRepresentative(hom, x ^ Projection(V, 2)); + y := PreImagesRepresentativeNC(hom, x ^ Projection(V, 2)); x := x ^ Projection(V, 1); for g in T do map := RMSInducedFunction(R, R, x, y, g); diff --git a/tst/standard/attributes/homomorph.tst b/tst/standard/attributes/homomorph.tst index 83a302faf..ed05456c5 100644 --- a/tst/standard/attributes/homomorph.tst +++ b/tst/standard/attributes/homomorph.tst @@ -385,6 +385,11 @@ gap> x := ConstantTransformation(2, 1); Transformation( [ 1, 1 ] ) gap> x ^ map; Transformation( [ 1, 1 ] ) +gap> iso := AsSemigroupIsomorphismByFunction(hom2);; +gap> x ^ InverseGeneralMapping(iso); +Transformation( [ 1, 1 ] ) +gap> PreImagesRepresentativeNC(hom2, x); +Transformation( [ 1, 1 ] ) gap> imgs2 := [gens[2], gens[2], gens[1], gens[3]];; gap> hom3 := SemigroupHomomorphismByImages(S, S, gens, imgs2); fail