Date: Thursday, November 28, 2019 @ 07:14:22 Author: arojas Revision: 534255
archrelease: copy trunk to community-staging-x86_64 Added: gap/repos/community-staging-x86_64/ gap/repos/community-staging-x86_64/PKGBUILD (from rev 534254, gap/trunk/PKGBUILD) gap/repos/community-staging-x86_64/gap.sh (from rev 534254, gap/trunk/gap.sh) gap/repos/community-staging-x86_64/libsemigroups-1.0.patch (from rev 534254, gap/trunk/libsemigroups-1.0.patch) -------------------------+ PKGBUILD | 131 ++ gap.sh | 7 libsemigroups-1.0.patch | 2244 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 2382 insertions(+) Copied: gap/repos/community-staging-x86_64/PKGBUILD (from rev 534254, gap/trunk/PKGBUILD) =================================================================== --- community-staging-x86_64/PKGBUILD (rev 0) +++ community-staging-x86_64/PKGBUILD 2019-11-28 07:14:22 UTC (rev 534255) @@ -0,0 +1,131 @@ +# Maintainer: Antonio Rojas <aro...@archlinux.org> +# Contributor: TDY <t...@archlinux.info> +# Contributor: Rémy Oudompheng <oudom...@clipper.ens.fr> + +pkgbase=gap +pkgname=(gap gap-doc gap-packages) +pkgver=4.10.2 +pkgrel=8 +pkgdesc="Groups, Algorithms, Programming: a system for computational discrete algebra" +arch=(x86_64) +url="https://www.gap-system.org/" +license=(GPL) +source=("https://www.gap-system.org/pub/gap/gap-${pkgver%.*}/tar.gz/gap-$pkgver.tar.gz" gap.sh + libsemigroups-1.0.patch) +sha256sums=('11175bed0234101643d510d4ab94c44db30bd303bfe63d86b9b86ae67cff9e49' + '143fb8a79a52c007903cce13407850df309ef803a9b00398d05169355917de46' + 'ccd95de4f48d26b73d6df7c1847855f68ee70644d130d32f14213988c3e286e3') +makedepends=(libxaw givaro mpfi normaliz boost libsemigroups c-xsc zeromq fplll polymake wget chrpath fmt) + +prepare() { + cd gap-$pkgver + +# Use system normaliz + sed -e '/build-normaliz.sh/d' -i bin/BuildPackages.sh +# Use system libsemigroups + sed -e 's|test "$with_external_libsemigroups" = yes|true|' -i pkg/semigroups-*/configure +# Disable anupq package, it's i686 only + rm -r pkg/anupq-* +# Fix https://bugs.archlinux.org/task/55174 + sed -e '/xgap/d' -i pkg/sonata-*/PackageInfo.g + sed -e '/XGAP/d' -i pkg/cryst/PackageInfo.g + + cd pkg/semigroups-* + patch -p1 -i "$srcdir"/libsemigroups-1.0.patch # Fix build with libsemigroups 1.0 +} + +build() { + cd gap-$pkgver + ./configure --prefix=/usr --with-gmp=system + + # https://bugzilla.gnome.org/show_bug.cgi?id=655517 + sed -i -e 's/ -shared / -Wl,-O1,--as-needed\0/g' libtool + + make + make libgap.la + + # Install libgap so we can link packages against it + mkdir -p tmp-install + libtool --mode=install install libgap.la "$srcdir"/gap-$pkgver/tmp-install + + cd pkg + export CXXFLAGS+=" -I/usr/include/cxsc" # Find c-xsc headers + export LDFLAGS+=" -L$srcdir/gap-$pkgver/tmp-install -lgap" # See https://trac.sagemath.org/ticket/27372 + export LD_LIBRARY_PATH="$srcdir"/gap-$pkgver/tmp-install + ../bin/BuildPackages.sh +} + +_standardpkgs=(GAPDoc-* primgrp-* SmallGrp-* transgrp atlasrep autpgrp-* alnuth-* crisp-* ctbllib FactInt-* fga irredsol-* laguna-* + polenta-* polycyclic-* resclasses-* sophus-* tomlib-*) + +package_gap() { + depends=(gmp zlib) + optdepends=('gap-packages: extra packages' 'gap-doc: documentation') + conflicts=(libgap) + replaces=(gap-data libgap gap-4.8 gap-4.8-data) + cd gap-$pkgver + + install -Dm644 src/*.h -t "$pkgdir"/usr/include/gap + install -Dm644 gen/config.h -t "$pkgdir"/usr/include/gap + install -Dm644 src/hpc/*.h -t "$pkgdir"/usr/include/gap/hpc + + install -d "$pkgdir"/usr/lib + libtool --mode=install install libgap.la "$pkgdir"/usr/lib + + mkdir -p "$pkgdir"/usr/{bin,lib/gap/pkg} + cp -r grp lib "$pkgdir"/usr/lib/gap + for _pkg in ${_standardpkgs[@]}; do + cp -r pkg/$_pkg "$pkgdir"/usr/lib/gap/pkg + done + install -Dm755 gap -t "$pkgdir"/usr/lib/gap +# Install launcher script + install -Dm755 "$srcdir"/gap.sh "$pkgdir"/usr/bin/gap + + mkdir -p "$pkgdir"/usr/share + ln -s /usr/lib/gap -t "$pkgdir"/usr/share # expected by sagemath +} + +package_gap-doc() { + depends=(gap) + replaces=(gap-4.8-doc) + pkgdesc="Documentation for GAP" + cd gap-$pkgver + + mkdir -p "$pkgdir"/usr/lib/gap + cp -r doc "$pkgdir"/usr/lib/gap +} + +package_gap-packages() { + depends=(gap) + replaces=(gap-4.8-packages) + optdepends=('normaliz: Normaliz interface package' 'libxaw: xgap package' 'c-xsc: float package' 'mpfi: float package' + 'libmpc: float package' 'fplll: float package' 'zeromq: ZeroMQ interface package' 'planarity: digraph package' + 'polymake: Polymake interface package' 'curl: curl interface package' 'libsemigroups: semigroups package') + pkgdesc="Extra packages for GAP" + cd gap-$pkgver + + mkdir -p "$pkgdir"/usr/{bin,lib/gap} + cp -r pkg "$pkgdir"/usr/lib/gap + +# fix xgap launch script + sed -e 's|/build/gap/src/gap-4.10.2|/usr/lib/gap|g' -e 's|^GAP=.*|GAP=/usr/lib/gap/gap|g' \ + "$pkgdir"/usr/lib/gap/pkg/xgap-*/xgap.sh > "$pkgdir"/usr/bin/xgap + chmod 755 "$pkgdir"/usr/bin/xgap + rm "$pkgdir"/usr/lib/gap/pkg/xgap-*/xgap.sh* + +# provided by main gap package + for _pkg in ${_standardpkgs[@]}; do + rm -r "$pkgdir"/usr/lib/gap/pkg/$_pkg + done + +# fix RPATH + find "$pkgdir"/usr/lib/gap/pkg/ -name '*.so' | xargs chrpath -d + +# remove bundled planarity + rm -r "$pkgdir"/usr/lib/gap/pkg/digraphs-*/bin/lib/ + +# remove leftover binaries and source files + find "$pkgdir"/usr/lib/gap/pkg -name .libs -o -name '*.o' | xargs rm -fr + find "$pkgdir"/usr/lib/gap/pkg -type d -name src | xargs rm -fr + rm -fr "$pkgdir"/usr/lib/gap/pkg/log +} Copied: gap/repos/community-staging-x86_64/gap.sh (from rev 534254, gap/trunk/gap.sh) =================================================================== --- community-staging-x86_64/gap.sh (rev 0) +++ community-staging-x86_64/gap.sh 2019-11-28 07:14:22 UTC (rev 534255) @@ -0,0 +1,7 @@ +#!/bin/sh + +GAP_ROOT="/usr/lib/gap" +GAP_DIR=$GAP_ROOT +GAP_EXE=$GAP_ROOT + +exec "$GAP_EXE/gap" -l "$GAP_DIR" "$@" Copied: gap/repos/community-staging-x86_64/libsemigroups-1.0.patch (from rev 534254, gap/trunk/libsemigroups-1.0.patch) =================================================================== --- community-staging-x86_64/libsemigroups-1.0.patch (rev 0) +++ community-staging-x86_64/libsemigroups-1.0.patch 2019-11-28 07:14:22 UTC (rev 534255) @@ -0,0 +1,2244 @@ +From ff6e172a492af2465fd7465da64298353cc15cc5 Mon Sep 17 00:00:00 2001 +From: James Mitchell <j...@st-and.ac.uk> +Date: Wed, 2 May 2018 10:45:40 +0200 +Subject: [PATCH] Update for libsemigroups v1.0.0 + +--- + .LIBSEMIGROUPS_VERSION | 2 +- + Makefile.am | 16 +- + gap/main/fropin.gi | 19 ++- + m4/ax_check_libsemigroup.m4 | 4 +- + scripts/travis-test.sh | 10 +- + src/.clang-format | 10 +- + src/bipart.cc | 133 ++++++++-------- + src/bipart.h | 9 +- + src/congpairs.cc | 235 ++++++++++++++-------------- + src/converter.cc | 21 ++- + src/converter.h | 50 +++--- + src/fropin.cc | 29 ++-- + src/pkg.cc | 22 +-- + src/pkg.h | 5 +- + src/semigrp.cc | 294 +++++++++++++++++++----------------- + src/semigrp.h | 63 ++++---- + src/uf.cc | 8 +- + tst/standard/congfpmon.tst | 17 +-- + 18 files changed, 484 insertions(+), 463 deletions(-) + +diff --git a/.LIBSEMIGROUPS_VERSION b/.LIBSEMIGROUPS_VERSION +index 2228cad41..3eefcb9dd 100644 +--- a/.LIBSEMIGROUPS_VERSION ++++ b/.LIBSEMIGROUPS_VERSION +@@ -1 +1 @@ +-0.6.7 ++1.0.0 +diff --git a/Makefile.am b/Makefile.am +index b5ee5ea8b..6998d563e 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -11,7 +11,7 @@ if WITH_INCLUDED_LIBSEMIGROUPS + # the following triggers "make install" on libsemigroups + # note that making it a concrete file prevents this target + # to be needlessly re-run if libsemigroups/ is not changed. +- BUILT_SOURCES = bin/include/libsemigroups/blocks.h ++ BUILT_SOURCES = bin/include/libsemigroups/libsemigroups.hpp + endif + + AM_CPPFLAGS = @LIBSEMIGROUPS_CFLAGS@ +@@ -28,6 +28,18 @@ semigroups_la_SOURCES += src/semigrp.cc + semigroups_la_CXXFLAGS = $(GAP_CFLAGS) @LIBSEMIGROUPS_CFLAGS@ -std=gnu++11 -O3 -g -march=native + semigroups_la_CPPFLAGS = $(GAP_CPPFLAGS) @LIBSEMIGROUPS_CFLAGS@ + semigroups_la_CFLAGS = $(GAP_CFLAGS) ++ ++semigroups_la_CPPFLAGS += -I$(top_srcdir)/libsemigroups/extern/HPCombi/include ++semigroups_la_CPPFLAGS += -I$(top_srcdir)/libsemigroups/extern/HPCombi/include/fallback ++semigroups_la_CPPFLAGS += -I$(top_srcdir)/libsemigroups/extern/fmt-5.3.0/include ++semigroups_la_CPPFLAGS += -DFMT_HEADER_ONLY ++ ++if KERNEL_DEBUG ++semigroups_la_CPPFLAGS += -DDEBUG ++else ++semigroups_la_CPPFLAGS += -DNDEBUG ++endif ++ + semigroups_la_LDFLAGS = $(GAP_LDFLAGS) -module -avoid-version + + semigroups_la_LIBADD = @LIBSEMIGROUPS_LIBS@ +@@ -37,7 +49,7 @@ semigroups_la_LDFLAGS += -no-undefined -version-info 0:0:0 -Wl,$(GAPROOT)/bin/$( + endif + + # the following is only run if BUILT_SOURCES is wound up +-bin/include/libsemigroups/blocks.h: ++bin/include/libsemigroups/libsemigroups.hpp: + $(MAKE) -C libsemigroups install + + all-local: semigroups.la +diff --git a/gap/main/fropin.gi b/gap/main/fropin.gi +index 49ff8ed7e..cdbb79b5c 100644 +--- a/gap/main/fropin.gi ++++ b/gap/main/fropin.gi +@@ -259,7 +259,9 @@ function(S) + enum := rec(); + + enum.NumberElement := function(enum, x) +- return EN_SEMI_POSITION_SORTED(S, x); ++ # Don't call EN_SEMI_POSITION_SORTED directly because then we pass elements ++ # of too high degree which causes an exception in Libsemigroups ++ return PositionSortedOp(S, x); + end; + + enum.ElementNumber := function(enum, nr) +@@ -348,6 +350,8 @@ function(S) + enum := rec(); + + enum.NumberElement := function(enum, x) ++ # Don't call EN_SEMI_POSITION directly since we may then pass too large ++ # degree pperms or transformations which cause a libsemigroups exception. + return PositionCanonical(S, x); + end; + +@@ -475,7 +479,8 @@ function(S, x) + or (IsTransformation(x) + and DegreeOfTransformation(x) > DegreeOfTransformationSemigroup(S)) + or (IsPartialPerm(x) +- and DegreeOfPartialPerm(x) > DegreeOfPartialPermSemigroup(S)) then ++ and (DegreeOfPartialPerm(x) > DegreeOfPartialPermSemigroup(S) ++ or CodegreeOfPartialPerm(x) > CodegreeOfPartialPermSemigroup(S))) then + return fail; + fi; + +@@ -487,6 +492,9 @@ InstallMethod(PositionCanonical, + [IsPermGroup and HasGeneratorsOfGroup and IsEnumerableSemigroupRep, + IsMultiplicativeElement], + function(G, x) ++ if (not IsPerm(x)) or LargestMovedPointPerm(x) > LargestMovedPoint(G) then ++ return fail; ++ fi; + return EN_SEMI_POSITION(G, x); + end); + +@@ -513,7 +521,8 @@ function(S, x, n) + or (IsTransformation(x) + and DegreeOfTransformation(x) > DegreeOfTransformationSemigroup(S)) + or (IsPartialPerm(x) +- and DegreeOfPartialPerm(x) > DegreeOfPartialPermSemigroup(S)) then ++ and (DegreeOfPartialPerm(x) > DegreeOfPartialPermSemigroup(S) ++ or CodegreeOfPartialPerm(x) > CodegreeOfPartialPermSemigroup(S))) then + return fail; + fi; + +@@ -529,13 +538,13 @@ function(S, x) + or (IsTransformation(x) + and DegreeOfTransformation(x) > DegreeOfTransformationSemigroup(S)) + or (IsPartialPerm(x) +- and DegreeOfPartialPerm(x) > DegreeOfPartialPermSemigroup(S)) then ++ and (DegreeOfPartialPerm(x) > DegreeOfPartialPermSemigroup(S) ++ or CodegreeOfPartialPerm(x) > CodegreeOfPartialPermSemigroup(S))) then + return fail; + elif not IsFinite(S) then + ErrorNoReturn("Semigroups: PositionSortedOp: usage,\n", + "the first argument (a semigroup) must be finite,"); + fi; +- + return EN_SEMI_POSITION_SORTED(S, x); + end); + +diff --git a/m4/ax_check_libsemigroup.m4 b/m4/ax_check_libsemigroup.m4 +index ae1f6f40c..23e498b4a 100644 +--- a/m4/ax_check_libsemigroup.m4 ++++ b/m4/ax_check_libsemigroup.m4 +@@ -21,9 +21,9 @@ AC_DEFUN([AX_CHECK_LIBSEMIGROUPS], [ + if test "$need_included_libsemigroups" = yes; then + AC_MSG_NOTICE([using included libsemigroups...]) + AC_CHECK_FILE( +- [libsemigroups/src/semigroups.h], ++ [libsemigroups/libsemigroups.hpp], + [], +- [AC_MSG_ERROR([libsemigroups is required, clone or download the repo from https://github.com/james-d-mitchell/libsemigroups into this directory])]) ++ [AC_MSG_ERROR([libsemigroups is required, clone or download the repo from https://github.com/libsemigroups/libsemigroups into this directory])]) + + AC_CHECK_FILE( + [libsemigroups/VERSION], +diff --git a/src/.clang-format b/src/.clang-format +index 7de2cef03..8d5699d47 100644 +--- a/src/.clang-format ++++ b/src/.clang-format +@@ -4,7 +4,7 @@ AccessModifierOffset: -1 + AlignAfterOpenBracket: Align + AlignConsecutiveAssignments: true + AlignConsecutiveDeclarations: true +-AlignEscapedNewlines: Left ++AlignEscapedNewlinesLeft: true + AlignOperands: true + AlignTrailingComments: true + AllowAllParametersOfDeclarationOnNextLine: false +@@ -15,7 +15,7 @@ AllowShortIfStatementsOnASingleLine: false + AllowShortLoopsOnASingleLine: false + AlwaysBreakAfterReturnType: None + AlwaysBreakBeforeMultilineStrings: false +-AlwaysBreakTemplateDeclarations: false ++AlwaysBreakTemplateDeclarations: true + BinPackArguments: false + BinPackParameters: false + BraceWrapping: +@@ -79,12 +79,8 @@ PenaltyBreakComment: 300 + PenaltyBreakFirstLessLess: 200 + PenaltyBreakString: 1000 + PenaltyExcessCharacter: 1000000 +-PenaltyReturnTypeOnItsOwnLine: 600 ++PenaltyReturnTypeOnItsOwnLine: 60 + PointerAlignment: Left +-RawStringFormats: +- - Delimiter: pb +- Language: TextProto +- BasedOnStyle: google + ReflowComments: true + SortIncludes: true + SpaceAfterCStyleCast: true +diff --git a/src/bipart.cc b/src/bipart.cc +index 2db351952..83c3a3996 100644 +--- a/src/bipart.cc ++++ b/src/bipart.cc +@@ -28,12 +28,15 @@ + #include <utility> + #include <vector> + +-#include "libsemigroups/semigroups.h" ++#include "libsemigroups/blocks.hpp" ++#include "libsemigroups/froidure-pin.hpp" ++ + #include "src/compiled.h" + ++using libsemigroups::Blocks; + using libsemigroups::Element; +-using libsemigroups::glob_reporter; +-using libsemigroups::Timer; ++using libsemigroups::REPORTER; ++using libsemigroups::detail::Timer; + + // Global variables + +@@ -97,7 +100,7 @@ inline Obj blocks_new_obj(Blocks* x) { + + Obj BIPART_NC(Obj self, Obj gap_blocks) { + SEMIGROUPS_ASSERT(IS_LIST(gap_blocks)); +- std::vector<u_int32_t>* blocks = new std::vector<u_int32_t>(); ++ std::vector<u_int32_t> blocks; + + size_t degree = 0; + size_t nr_left_blocks = 0; +@@ -110,7 +113,7 @@ Obj BIPART_NC(Obj self, Obj gap_blocks) { + SEMIGROUPS_ASSERT(IS_LIST(ELM_LIST(gap_blocks, i))); + degree += LEN_LIST(ELM_LIST(gap_blocks, i)); + } +- blocks->resize(degree); ++ blocks.resize(degree); + + degree /= 2; + +@@ -120,21 +123,21 @@ Obj BIPART_NC(Obj self, Obj gap_blocks) { + SEMIGROUPS_ASSERT(IS_INTOBJ(ELM_LIST(block, j))); + int jj = INT_INTOBJ(ELM_LIST(block, j)); + if (jj < 0) { +- (*blocks)[-jj + degree - 1] = i - 1; ++ blocks[-jj + degree - 1] = i - 1; + } else { +- nr_left_blocks = i; +- (*blocks)[jj - 1] = i - 1; ++ nr_left_blocks = i; ++ blocks[jj - 1] = i - 1; + } + } + } + } else { // gap_blocks is the internal rep of a bipartition +- blocks->reserve(LEN_LIST(gap_blocks)); ++ blocks.reserve(LEN_LIST(gap_blocks)); + for (size_t i = 1; i <= static_cast<size_t>(LEN_LIST(gap_blocks)) / 2; + i++) { + SEMIGROUPS_ASSERT(IS_INTOBJ(ELM_LIST(gap_blocks, i)) + && INT_INTOBJ(ELM_LIST(gap_blocks, i)) > 0); + u_int32_t index = INT_INTOBJ(ELM_LIST(gap_blocks, i)) - 1; +- blocks->push_back(index); ++ blocks.push_back(index); + nr_blocks = (index > nr_blocks ? index : nr_blocks); + } + nr_left_blocks = nr_blocks + 1; +@@ -144,7 +147,7 @@ Obj BIPART_NC(Obj self, Obj gap_blocks) { + SEMIGROUPS_ASSERT(IS_INTOBJ(ELM_LIST(gap_blocks, i)) + && INT_INTOBJ(ELM_LIST(gap_blocks, i)) > 0); + u_int32_t index = INT_INTOBJ(ELM_LIST(gap_blocks, i)) - 1; +- blocks->push_back(index); ++ blocks.push_back(index); + nr_blocks = (index > nr_blocks ? index : nr_blocks); + } + nr_blocks++; +@@ -168,8 +171,8 @@ Obj BIPART_EXT_REP(Obj self, Obj x) { + Bipartition* xx = bipart_get_cpp(x); + size_t n = xx->degree(); + +- Obj ext_rep = NEW_PLIST(n == 0 ? T_PLIST_EMPTY : T_PLIST_TAB, +- xx->nr_blocks()); ++ Obj ext_rep ++ = NEW_PLIST(n == 0 ? T_PLIST_EMPTY : T_PLIST_TAB, xx->nr_blocks()); + SET_LEN_PLIST(ext_rep, (Int) xx->nr_blocks()); + + for (size_t i = 0; i < 2 * n; i++) { +@@ -198,8 +201,7 @@ Obj BIPART_INT_REP(Obj self, Obj x) { + Bipartition* xx = bipart_get_cpp(x); // get C++ bipartition pointer + size_t n = xx->degree(); + +- Obj int_rep +- = NEW_PLIST_IMM(n == 0 ? T_PLIST_EMPTY : T_PLIST_CYC, 2 * n); ++ Obj int_rep = NEW_PLIST_IMM(n == 0 ? T_PLIST_EMPTY : T_PLIST_CYC, 2 * n); + SET_LEN_PLIST(int_rep, (Int) 2 * n); + + for (size_t i = 0; i < 2 * n; i++) { +@@ -347,18 +349,17 @@ Obj BIPART_LEFT_PROJ(Obj self, Obj x) { + -1); + _BUFFER_size_t.resize(2 * deg, -1); + +- std::vector<u_int32_t>* blocks = new std::vector<u_int32_t>(); +- blocks->resize(2 * deg, -1); ++ std::vector<u_int32_t> blocks(2 * deg, -1); + + for (size_t i = 0; i < deg; i++) { +- (*blocks)[i] = xx->at(i); ++ blocks[i] = xx->at(i); + if (xx->is_transverse_block(xx->at(i))) { +- (*blocks)[i + deg] = xx->at(i); ++ blocks[i + deg] = xx->at(i); + } else if (_BUFFER_size_t[xx->at(i)] != static_cast<size_t>(-1)) { +- (*blocks)[i + deg] = _BUFFER_size_t[xx->at(i)]; ++ blocks[i + deg] = _BUFFER_size_t[xx->at(i)]; + } else { + _BUFFER_size_t[xx->at(i)] = next; +- (*blocks)[i + deg] = next; ++ blocks[i + deg] = next; + next++; + } + } +@@ -384,8 +385,7 @@ Obj BIPART_RIGHT_PROJ(Obj self, Obj x) { + auto buf1 = _BUFFER_size_t.begin(); + auto buf2 = _BUFFER_size_t.begin() + 2 * deg; + +- std::vector<u_int32_t>* blocks = new std::vector<u_int32_t>(); +- blocks->resize(2 * deg, -1); ++ std::vector<u_int32_t> blocks(2 * deg, -1); + + for (size_t i = deg; i < 2 * deg; i++) { + if (buf2[xx->at(i)] == static_cast<size_t>(-1)) { +@@ -396,8 +396,8 @@ Obj BIPART_RIGHT_PROJ(Obj self, Obj x) { + buf1[xx->at(i)] = l_block++; + } + } +- (*blocks)[i - deg] = buf1[xx->at(i)]; +- (*blocks)[i] = buf2[xx->at(i)]; ++ blocks[i - deg] = buf1[xx->at(i)]; ++ blocks[i] = buf2[xx->at(i)]; + } + + Bipartition* out = new Bipartition(blocks); +@@ -418,17 +418,16 @@ Obj BIPART_STAR(Obj self, Obj x) { + -1); + _BUFFER_size_t.resize(2 * deg, -1); + +- std::vector<u_int32_t>* blocks = new std::vector<u_int32_t>(); +- blocks->resize(2 * deg, -1); ++ std::vector<u_int32_t> blocks(2 * deg, -1); + + size_t next = 0; + + for (size_t i = 0; i < deg; i++) { + if (_BUFFER_size_t[xx->at(i + deg)] != static_cast<size_t>(-1)) { +- (*blocks)[i] = _BUFFER_size_t[xx->at(i + deg)]; ++ blocks[i] = _BUFFER_size_t[xx->at(i + deg)]; + } else { + _BUFFER_size_t[xx->at(i + deg)] = next; +- (*blocks)[i] = next; ++ blocks[i] = next; + next++; + } + } +@@ -437,10 +436,10 @@ Obj BIPART_STAR(Obj self, Obj x) { + + for (size_t i = 0; i < deg; i++) { + if (_BUFFER_size_t[xx->at(i)] != static_cast<size_t>(-1)) { +- (*blocks)[i + deg] = _BUFFER_size_t[xx->at(i)]; ++ blocks[i + deg] = _BUFFER_size_t[xx->at(i)]; + } else { + _BUFFER_size_t[xx->at(i)] = next; +- (*blocks)[i + deg] = next; ++ blocks[i + deg] = next; + next++; + } + } +@@ -563,8 +562,7 @@ Obj BIPART_STAB_ACTION(Obj self, Obj x, Obj p) { + size_t deg = xx->degree(); + size_t nr_blocks = xx->nr_blocks(); + +- std::vector<u_int32_t>* blocks = new std::vector<u_int32_t>(); +- blocks->resize(2 * deg); ++ std::vector<u_int32_t> blocks(2 * deg); + + _BUFFER_size_t.clear(); + _BUFFER_size_t.resize(2 * nr_blocks + std::max(deg, pdeg), -1); +@@ -604,8 +602,8 @@ Obj BIPART_STAB_ACTION(Obj self, Obj x, Obj p) { + } + + for (size_t i = 0; i < deg; i++) { +- (*blocks)[i] = xx->at(i); +- (*blocks)[i + deg] = tab2[tab1[xx->at(i + deg)]]; ++ blocks[i] = xx->at(i); ++ blocks[i + deg] = tab2[tab1[xx->at(i + deg)]]; + } + + return bipart_new_obj(new Bipartition(blocks)); +@@ -722,8 +720,8 @@ Obj BLOCKS_EXT_REP(Obj self, Obj x) { + Blocks* xx = blocks_get_cpp(x); + size_t n = xx->degree(); + +- Obj ext_rep = NEW_PLIST(n == 0 ? T_PLIST_EMPTY : T_PLIST_TAB, +- xx->nr_blocks()); ++ Obj ext_rep ++ = NEW_PLIST(n == 0 ? T_PLIST_EMPTY : T_PLIST_TAB, xx->nr_blocks()); + SET_LEN_PLIST(ext_rep, (Int) xx->nr_blocks()); + + for (size_t i = 0; i < n; i++) { +@@ -793,21 +791,20 @@ Obj BLOCKS_PROJ(Obj self, Obj x) { + _BUFFER_size_t.clear(); + _BUFFER_size_t.resize(blocks->nr_blocks(), -1); + +- std::vector<u_int32_t>* out = new std::vector<u_int32_t>(); +- out->resize(2 * blocks->degree()); +- u_int32_t nr_blocks = blocks->nr_blocks(); ++ std::vector<u_int32_t> out(2 * blocks->degree()); ++ u_int32_t nr_blocks = blocks->nr_blocks(); + + for (u_int32_t i = 0; i < blocks->degree(); i++) { + u_int32_t index = blocks->block(i); +- (*out)[i] = index; ++ out[i] = index; + if (blocks->is_transverse_block(index)) { +- (*out)[i + blocks->degree()] = index; ++ out[i + blocks->degree()] = index; + } else { + if (_BUFFER_size_t[index] == static_cast<size_t>(-1)) { + _BUFFER_size_t[index] = nr_blocks; + nr_blocks++; + } +- (*out)[i + blocks->degree()] = _BUFFER_size_t[index]; ++ out[i + blocks->degree()] = _BUFFER_size_t[index]; + } + } + return bipart_new_obj(new Bipartition(out)); +@@ -920,22 +917,21 @@ Obj BLOCKS_E_CREATOR(Obj self, Obj left_gap, Obj right_gap) { + } + } + +- std::vector<u_int32_t>* blocks = new std::vector<u_int32_t>(); +- blocks->resize(2 * left->degree()); ++ std::vector<u_int32_t> blocks(2 * left->degree()); + + size_t next = right->nr_blocks(); + + for (size_t i = 0; i < left->degree(); i++) { +- (*blocks)[i] = right->block(i); +- size_t j = left->block(i); ++ blocks[i] = right->block(i); ++ size_t j = left->block(i); + if (left->is_transverse_block(j)) { +- (*blocks)[i + left->degree()] = tab1[fuse_it(j)]; ++ blocks[i + left->degree()] = tab1[fuse_it(j)]; + } else { + if (tab2[j] == static_cast<size_t>(-1)) { + tab2[j] = next; + next++; + } +- (*blocks)[i + left->degree()] = tab2[j]; ++ blocks[i + left->degree()] = tab2[j]; + } + } + +@@ -1071,14 +1067,13 @@ Obj BLOCKS_INV_LEFT(Obj self, Obj blocks_gap, Obj x_gap) { + x->nr_blocks(), + false); + SEMIGROUPS_ASSERT(_BUFFER_size_t.size() +- == blocks->nr_blocks() + x->nr_blocks()); ++ == blocks->nr_blocks() + x->nr_blocks()); + +- std::vector<u_int32_t>* out_blocks = new std::vector<u_int32_t>(); +- out_blocks->resize(2 * x->degree()); ++ std::vector<u_int32_t> out_blocks(2 * x->degree()); + + _BUFFER_size_t.resize(2 * blocks->nr_blocks() + x->nr_blocks(), -1); + SEMIGROUPS_ASSERT(_BUFFER_size_t.size() +- == 2 * blocks->nr_blocks() + x->nr_blocks()); ++ == 2 * blocks->nr_blocks() + x->nr_blocks()); + SEMIGROUPS_ASSERT(std::all_of( + _BUFFER_size_t.cbegin() + blocks->nr_blocks() + x->nr_blocks(), + _BUFFER_size_t.cend(), +@@ -1096,12 +1091,12 @@ Obj BLOCKS_INV_LEFT(Obj self, Obj blocks_gap, Obj x_gap) { + + // find the left blocks of the output + for (u_int32_t i = 0; i < blocks->degree(); i++) { +- (*out_blocks)[i] = blocks->block(i); +- u_int32_t j = fuse_it(x->at(i) + blocks->nr_blocks()); ++ out_blocks[i] = blocks->block(i); ++ u_int32_t j = fuse_it(x->at(i) + blocks->nr_blocks()); + if (j >= blocks->nr_blocks() || tab[j] == static_cast<size_t>(-1)) { +- (*out_blocks)[i + x->degree()] = blocks->nr_blocks(); // junk ++ out_blocks[i + x->degree()] = blocks->nr_blocks(); // junk + } else { +- (*out_blocks)[i + x->degree()] = tab[j]; ++ out_blocks[i + x->degree()] = tab[j]; + } + } + +@@ -1175,8 +1170,7 @@ Obj BLOCKS_INV_RIGHT(Obj self, Obj blocks_gap, Obj x_gap) { + u_int32_t junk = -1; + u_int32_t next = 0; + +- std::vector<u_int32_t>* out_blocks = new std::vector<u_int32_t>(); +- out_blocks->resize(2 * x->degree()); ++ std::vector<u_int32_t> out_blocks(2 * x->degree()); + + _BUFFER_size_t.resize(3 * blocks->nr_blocks() + 2 * x->nr_blocks(), -1); + auto tab1 = _BUFFER_size_t.begin() + blocks->nr_blocks() + x->nr_blocks(); +@@ -1192,7 +1186,7 @@ Obj BLOCKS_INV_RIGHT(Obj self, Obj blocks_gap, Obj x_gap) { + tab1[j] = next; + next++; + } +- (*out_blocks)[i] = tab1[j]; ++ out_blocks[i] = tab1[j]; + continue; + } + } +@@ -1200,7 +1194,7 @@ Obj BLOCKS_INV_RIGHT(Obj self, Obj blocks_gap, Obj x_gap) { + junk = next; + next++; + } +- (*out_blocks)[i] = junk; ++ out_blocks[i] = junk; + } + + u_int32_t out_nr_left_blocks = next; +@@ -1210,13 +1204,13 @@ Obj BLOCKS_INV_RIGHT(Obj self, Obj blocks_gap, Obj x_gap) { + for (u_int32_t i = blocks->degree(); i < 2 * blocks->degree(); i++) { + u_int32_t j = blocks->block(i - blocks->degree()); + if (blocks->is_transverse_block(j)) { +- (*out_blocks)[i] = tab1[fuse_it(j)]; ++ out_blocks[i] = tab1[fuse_it(j)]; + } else { + if (tab2[j] == static_cast<size_t>(-1)) { + tab2[j] = next; + next++; + } +- (*out_blocks)[i] = tab2[j]; ++ out_blocks[i] = tab2[j]; + } + } + +@@ -1390,10 +1384,11 @@ class IdempotentCounter { + } + + std::vector<size_t> count() { +- glob_reporter.reset_thread_ids(); +- glob_reporter.set_report(_report); +- REPORT("using " << _nr_threads << " / " +- << std::thread::hardware_concurrency() << " threads"); ++ libsemigroups::THREAD_ID_MANAGER.reset(); ++ auto rg = libsemigroups::ReportGuard(_report); ++ REPORT_DEFAULT("using %llu / %llu additional threads", ++ _nr_threads, ++ std::thread::hardware_concurrency()); + Timer timer; + + for (size_t i = 0; i < _nr_threads; i++) { +@@ -1405,7 +1400,7 @@ class IdempotentCounter { + _threads[i].join(); + } + +- REPORT(timer); ++ REPORT_TIME(timer); + + size_t max = *max_element(_ranks.begin(), _ranks.end()) + 1; + std::vector<size_t> out = std::vector<size_t>(max, 0); +@@ -1441,7 +1436,7 @@ class IdempotentCounter { + } + } + } +- REPORT("finished in " << timer.string()); ++ REPORT_DEFAULT("finished in %llu", timer.string()); + } + + // This is basically the same as BLOCKS_E_TESTER, but is required because we +diff --git a/src/bipart.h b/src/bipart.h +index 8c09b7548..d8d192486 100644 +--- a/src/bipart.h ++++ b/src/bipart.h +@@ -19,10 +19,15 @@ + #ifndef SEMIGROUPS_SRC_BIPART_H_ + #define SEMIGROUPS_SRC_BIPART_H_ + +-#include "libsemigroups/elements.h" ++// libsemigroups headers ++#include "libsemigroups/element.hpp" ++ ++// GAP headers ++#include "src/compiled.h" ++ ++// Semigroups pkg headers + #include "pkg.h" + #include "semigroups-debug.h" +-#include "src/compiled.h" + + using libsemigroups::Bipartition; + using libsemigroups::Blocks; +diff --git a/src/congpairs.cc b/src/congpairs.cc +index 29457859c..de99163ac 100644 +--- a/src/congpairs.cc ++++ b/src/congpairs.cc +@@ -27,16 +27,34 @@ + #include "rnams.h" + #include "semigrp.h" + +-#include "libsemigroups/cong.h" +- +-using libsemigroups::Congruence; +-using libsemigroups::Partition; +-using libsemigroups::RecVec; +-using libsemigroups::relation_t; +-using libsemigroups::word_t; ++#include "libsemigroups/cong.hpp" ++#include "libsemigroups/fpsemi.hpp" ++#include "libsemigroups/report.hpp" ++ ++using libsemigroups::FpSemigroup; ++using libsemigroups::detail::DynamicArray2; ++using libsemigroups::relation_type; ++using libsemigroups::ReportGuard; ++using libsemigroups::word_type; ++using Congruence = libsemigroups::Congruence; ++using congruence_type = libsemigroups::congruence_type; ++ ++static inline congruence_type cstring_to_congruence_t(char const* type) { ++ std::string stype = std::string(type); ++ if (stype == "left") { ++ return congruence_type::left; ++ } else if (stype == "right") { ++ return congruence_type::right; ++ } else if (stype == "twosided") { ++ return congruence_type::twosided; ++ } else { ++ ErrorQuit("Unrecognised type %s", (Int) type, 0L); ++ return congruence_type::left; ++ } ++} + +-static inline word_t plist_to_word_t(gap_list_t plist) { +- word_t word; ++static inline word_type plist_to_word_type(gap_list_t plist) { ++ word_type word; + for (size_t i = 1; i <= (size_t) LEN_PLIST(plist); i++) { + Obj j = ELM_PLIST(plist, i); + SEMIGROUPS_ASSERT(IS_INTOBJ(j)); +@@ -45,7 +63,7 @@ static inline word_t plist_to_word_t(gap_list_t plist) { + return word; + } + +-static inline gap_list_t word_t_to_plist(word_t* w) { ++static inline gap_list_t word_type_to_plist(word_type const* w) { + gap_list_t plist = NEW_PLIST_IMM(T_PLIST_CYC, w->size()); + SET_LEN_PLIST(plist, w->size()); + for (size_t i = 0; i < w->size(); i++) { +@@ -66,13 +84,13 @@ static inline gap_semigroup_t cong_obj_get_range_obj(gap_cong_t o) { + return ElmPRec(o, RNam_range); + } + +-static inline Semigroup* cong_obj_get_range(gap_cong_t o) { ++static inline FroidurePin<Element const*>* cong_obj_get_range(gap_cong_t o) { + return semi_obj_get_semi_cpp(cong_obj_get_range_obj(o)); + } + + static inline bool cong_obj_get_range_type(gap_cong_t o) { + initRNams(); +- // SEMIGROUPS_ASSERT(IsSemigroupCongruenceByGeneratingPairsRep(o)); ++ // SEMIGROUPS_ASSERT(IsSemigroup<>CongruenceByGeneratingPairsRep(o)); + return semi_obj_get_type(cong_obj_get_range_obj(o)); + } + +@@ -82,82 +100,67 @@ static inline bool cong_obj_is_fp_cong(gap_cong_t cong) { + } + + static void cong_obj_init_cpp_cong(gap_cong_t o) { +- // SEMIGROUPS_ASSERT(IsSemigroupCongruenceByGeneratingPairsRep(o)); ++ // SEMIGROUPS_ASSERT(IsSemigroup<>CongruenceByGeneratingPairsRep(o)); + SEMIGROUPS_ASSERT(!cong_obj_has_cpp_cong(o)); +- + initRNams(); +- +- gap_list_t genpairs = ElmPRec(o, RNam_genpairs); +- gap_semigroup_t range_obj = cong_obj_get_range_obj(o); +- std::string type = std::string(CSTR_STRING(ElmPRec(o, RNam_type))); +- Congruence* cong; +- bool report = semi_obj_get_report(range_obj); ++ gap_list_t genpairs = ElmPRec(o, RNam_genpairs); ++ gap_semigroup_t range_obj = cong_obj_get_range_obj(o); ++ congruence_type type ++ = cstring_to_congruence_t(CSTR_STRING(ElmPRec(o, RNam_type))); ++ Congruence* cong = nullptr; ++ bool report = semi_obj_get_report(range_obj); ++ auto rg = ReportGuard(report); + + if (cong_obj_is_fp_cong(o)) { + size_t nrgens = INT_INTOBJ(ElmPRec(o, RNam_fp_nrgens)); + ++ auto S = libsemigroups::detail::make_unique<FpSemigroup>(); ++ S->set_alphabet(nrgens); ++ + // Get the fp semigroup's rels +- gap_list_t gap_rels = ElmPRec(o, RNam_fp_rels); +- word_t lhs, rhs; +- std::vector<relation_t> rels; +- rels.reserve(LEN_PLIST(gap_rels)); ++ gap_list_t gap_rels = ElmPRec(o, RNam_fp_rels); + for (size_t i = 1; i <= (size_t) LEN_PLIST(gap_rels); i++) { + gap_list_t rel = ELM_PLIST(gap_rels, i); +- lhs = plist_to_word_t(ELM_PLIST(rel, 1)); +- rhs = plist_to_word_t(ELM_PLIST(rel, 2)); +- rels.push_back(make_pair(lhs, rhs)); ++ S->add_rule(plist_to_word_type(ELM_PLIST(rel, 1)), ++ plist_to_word_type(ELM_PLIST(rel, 2))); + } + ++ cong = new Congruence(type, *S); ++ + // Get the extra pairs +- gap_list_t gap_extra = ElmPRec(o, RNam_fp_extra); +- std::vector<relation_t> extra; +- extra.reserve(LEN_PLIST(gap_extra)); ++ gap_list_t gap_extra = ElmPRec(o, RNam_fp_extra); + for (size_t i = 1; i <= (size_t) LEN_PLIST(gap_extra); i++) { + gap_list_t pair = ELM_PLIST(gap_extra, i); +- lhs = plist_to_word_t(ELM_PLIST(pair, 1)); +- rhs = plist_to_word_t(ELM_PLIST(pair, 2)); +- extra.push_back(make_pair(lhs, rhs)); ++ cong->add_pair(plist_to_word_type(ELM_PLIST(pair, 1)), ++ plist_to_word_type(ELM_PLIST(pair, 2))); + } +- +- cong = new Congruence(type, nrgens, rels, extra); +- cong->set_report(report); + } else if (cong_obj_get_range_type(o) != UNKNOWN) { +- Semigroup* range = cong_obj_get_range(o); +- range->set_report(report); +- +- std::vector<relation_t> extra; +- word_t lhs, rhs; ++ FroidurePin<Element const*>* range = cong_obj_get_range(o); + ++ cong = new Congruence(type, *range); + for (size_t i = 1; i <= (size_t) LEN_PLIST(genpairs); i++) { + Obj lhs_obj = ELM_PLIST(ELM_PLIST(genpairs, i), 1); + Obj rhs_obj = ELM_PLIST(ELM_PLIST(genpairs, i), 2); +- +- range->factorisation( +- lhs, INT_INTOBJ(EN_SEMI_POSITION(0L, range_obj, lhs_obj)) - 1); +- range->factorisation( +- rhs, INT_INTOBJ(EN_SEMI_POSITION(0L, range_obj, rhs_obj)) - 1); +- +- extra.push_back(make_pair(lhs, rhs)); +- lhs.clear(); +- rhs.clear(); ++ cong->add_pair( ++ range->factorisation( ++ INT_INTOBJ(EN_SEMI_POSITION(0L, range_obj, lhs_obj)) - 1), ++ range->factorisation( ++ INT_INTOBJ(EN_SEMI_POSITION(0L, range_obj, rhs_obj)) - 1)); + } +- cong = new Congruence(type, range, extra); +- cong->set_report(report); + } else { +- gap_rec_t data = fropin(range_obj, INTOBJ_INT(-1), 0, False); +- gap_list_t rules = ElmPRec(data, RNam_rules); +- gap_list_t words = ElmPRec(data, RNam_words); +- std::vector<relation_t> rels; +- std::vector<relation_t> extra; +- +- // convert the rules (i.e. relations) to relation_t's +- for (size_t i = 1; i <= (size_t) LEN_PLIST(rules); i++) { +- word_t lhs = plist_to_word_t(ELM_PLIST(ELM_PLIST(rules, i), 1)); +- word_t rhs = plist_to_word_t(ELM_PLIST(ELM_PLIST(rules, i), 2)); +- rels.push_back(make_pair(lhs, rhs)); +- } ++ gap_rec_t data = fropin(range_obj, INTOBJ_INT(-1), 0, False); ++ // gap_list_t rules = ElmPRec(data, RNam_rules); ++ gap_list_t words = ElmPRec(data, RNam_words); + +- // convert the generating pairs to relation_t's ++ size_t nrgens = LEN_PLIST(semi_obj_get_gens(range_obj)); ++ ++ cong = new Congruence(type, Congruence::policy::runners::none); ++ cong->set_nr_generators(nrgens); ++ ++ auto tc = new libsemigroups::congruence::ToddCoxeter(type); ++ tc->set_nr_generators(nrgens); ++ ++ // convert the generating pairs to relation_type's + for (size_t i = 1; i <= (size_t) LEN_PLIST(genpairs); i++) { + Obj lhs_obj = ELM_PLIST(ELM_PLIST(genpairs, i), 1); + Obj rhs_obj = ELM_PLIST(ELM_PLIST(genpairs, i), 2); +@@ -166,40 +169,33 @@ static void cong_obj_init_cpp_cong(gap_cong_t o) { + INT_INTOBJ(EN_SEMI_POSITION(0L, range_obj, lhs_obj))); + Obj rhs = ELM_PLIST(words, + INT_INTOBJ(EN_SEMI_POSITION(0L, range_obj, rhs_obj))); +- +- extra.push_back(make_pair(plist_to_word_t(lhs), plist_to_word_t(rhs))); ++ tc->add_pair(plist_to_word_type(lhs), plist_to_word_type(rhs)); + } + +- size_t nrgens = LEN_PLIST(semi_obj_get_gens(range_obj)); +- + Obj graph; + +- if (type == "left") { ++ if (type == congruence_type::left) { + // the left Cayley graph + graph = ElmPRec(data, RNam_left); + } else { +- SEMIGROUPS_ASSERT(type == "right" || type == "twosided"); ++ SEMIGROUPS_ASSERT(type == congruence_type::right ++ || type == congruence_type::twosided); + // the right Cayley graph + graph = ElmPRec(data, RNam_right); + } + +- RecVec<size_t> prefill(nrgens, LEN_PLIST(graph) + 1); +- +- Obj genslookup = ElmPRec(data, RNam_genslookup); +- for (size_t i = 0; i < nrgens; i++) { +- prefill.set(0, i, INT_INTOBJ(ELM_PLIST(genslookup, i + 1))); +- } ++ DynamicArray2<size_t> table(nrgens, LEN_PLIST(graph)); + + for (size_t i = 1; i <= (size_t) LEN_PLIST(graph); i++) { + Obj next = ELM_PLIST(graph, i); + for (size_t j = 1; j <= nrgens; j++) { +- prefill.set(i, j - 1, INT_INTOBJ(ELM_PLIST(next, j))); ++ table.set(i - 1, j - 1, INT_INTOBJ(ELM_PLIST(next, j)) - 1); + } + } +- cong = new Congruence(type, nrgens, std::vector<relation_t>(), extra); +- cong->set_report(report); +- cong->set_prefill(prefill); ++ tc->prefill(table); ++ cong->add_runner(*tc); + } ++ SEMIGROUPS_ASSERT(cong != nullptr); + AssPRec(o, RNam_cong_pairs_congruence, OBJ_CLASS(cong, T_SEMI_SUBTYPE_CONG)); + } + +@@ -221,17 +217,17 @@ Obj CONG_PAIRS_NR_CLASSES(Obj self, gap_cong_t o) { + Obj CONG_PAIRS_IN(Obj self, gap_cong_t o, Obj elm1, Obj elm2) { + initRNams(); + +- word_t lhs, rhs; ++ word_type lhs, rhs; + + if (cong_obj_is_fp_cong(o)) { +- lhs = plist_to_word_t(elm1); +- rhs = plist_to_word_t(elm2); ++ lhs = plist_to_word_type(elm1); ++ rhs = plist_to_word_type(elm2); + } else { + gap_semigroup_t S = cong_obj_get_range_obj(o); + size_t lhs_pos = INT_INTOBJ(EN_SEMI_POSITION(0L, S, elm1)); + size_t rhs_pos = INT_INTOBJ(EN_SEMI_POSITION(0L, S, elm2)); +- SEMIGROUPS_ASSERT(lhs_pos != Semigroup::UNDEFINED); +- SEMIGROUPS_ASSERT(rhs_pos != Semigroup::UNDEFINED); ++ SEMIGROUPS_ASSERT(lhs_pos != UNDEFINED); ++ SEMIGROUPS_ASSERT(rhs_pos != UNDEFINED); + + if (IsbPRec(o, RNam_fin_cong_lookup)) { + // TODO(JDM) use FindPRec and GET_ELM_PREC +@@ -241,7 +237,7 @@ Obj CONG_PAIRS_IN(Obj self, gap_cong_t o, Obj elm1, Obj elm2) { + } + + if (cong_obj_get_range_type(o) != UNKNOWN) { +- Semigroup* range = cong_obj_get_range(o); ++ FroidurePin<Element const*>* range = cong_obj_get_range(o); + + range->factorisation(lhs, lhs_pos - 1); + range->factorisation(rhs, rhs_pos - 1); +@@ -249,13 +245,13 @@ Obj CONG_PAIRS_IN(Obj self, gap_cong_t o, Obj elm1, Obj elm2) { + gap_rec_t data = fropin(S, INTOBJ_INT(-1), 0, False); + gap_list_t words = ElmPRec(data, RNam_words); + +- lhs = plist_to_word_t(ELM_PLIST(words, lhs_pos)); +- rhs = plist_to_word_t(ELM_PLIST(words, rhs_pos)); ++ lhs = plist_to_word_type(ELM_PLIST(words, lhs_pos)); ++ rhs = plist_to_word_type(ELM_PLIST(words, rhs_pos)); + } + } + + Congruence* cong = cong_obj_get_cpp(o); +- return (cong->test_equals(lhs, rhs) ? True : False); ++ return (cong->contains(lhs, rhs) ? True : False); + } + + // This describes a total ordering on the classes of the congruence. +@@ -266,18 +262,18 @@ Obj CONG_PAIRS_LESS_THAN(Obj self, + gap_list_t rep2) { + initRNams(); + +- word_t lhs, rhs; ++ word_type lhs, rhs; + + if (cong_obj_is_fp_cong(o)) { +- lhs = plist_to_word_t(rep1); +- rhs = plist_to_word_t(rep2); ++ lhs = plist_to_word_type(rep1); ++ rhs = plist_to_word_type(rep2); + } else { + gap_semigroup_t S = cong_obj_get_range_obj(o); + size_t lhs_pos = INT_INTOBJ(EN_SEMI_POSITION(0L, S, rep1)); + size_t rhs_pos = INT_INTOBJ(EN_SEMI_POSITION(0L, S, rep2)); + + if (cong_obj_get_range_type(o) != UNKNOWN) { +- Semigroup* range = cong_obj_get_range(o); ++ FroidurePin<Element const*>* range = cong_obj_get_range(o); + + range->factorisation(lhs, lhs_pos - 1); + range->factorisation(rhs, rhs_pos - 1); +@@ -285,13 +281,13 @@ Obj CONG_PAIRS_LESS_THAN(Obj self, + gap_rec_t data = fropin(S, INTOBJ_INT(-1), 0, False); + gap_list_t words = ElmPRec(data, RNam_words); + +- lhs = plist_to_word_t(ELM_PLIST(words, lhs_pos)); +- rhs = plist_to_word_t(ELM_PLIST(words, rhs_pos)); ++ lhs = plist_to_word_type(ELM_PLIST(words, lhs_pos)); ++ rhs = plist_to_word_type(ELM_PLIST(words, rhs_pos)); + } + } + + Congruence* cong = cong_obj_get_cpp(o); +- return (cong->test_less_than(lhs, rhs) ? True : False); ++ return (cong->less(lhs, rhs) ? True : False); + } + + Obj CONG_PAIRS_LOOKUP_PART(Obj self, gap_cong_t o) { +@@ -323,13 +319,13 @@ Obj CONG_PAIRS_LOOKUP_PART(Obj self, gap_cong_t o) { + Obj lookup; + + if (cong_obj_get_range_type(o) != UNKNOWN) { +- Semigroup* range = cong_obj_get_range(o); +- range->set_report(report); ++ FroidurePin<Element const*>* range = cong_obj_get_range(o); ++ auto rg = ReportGuard(report); + + lookup = NEW_PLIST_IMM(T_PLIST_CYC, range->size()); + SET_LEN_PLIST(lookup, range->size()); + +- word_t word; ++ word_type word; + for (size_t i = 0; i < range->size(); i++) { + range->factorisation(word, i); // changes word in place + size_t class_index = cong->word_to_class_index(word); +@@ -359,7 +355,7 @@ Obj CONG_PAIRS_LOOKUP_PART(Obj self, gap_cong_t o) { + + for (size_t i = 1; i <= (size_t) LEN_PLIST(words); i++) { + size_t class_index +- = cong->word_to_class_index(plist_to_word_t(ELM_PLIST(words, i))); ++ = cong->word_to_class_index(plist_to_word_type(ELM_PLIST(words, i))); + + auto it = class_dictionary.find(class_index); + if (it == class_dictionary.end()) { +@@ -395,13 +391,12 @@ Obj CONG_PAIRS_ELM_COSET_ID(Obj self, gap_cong_t cong_obj, Obj elm) { + } else if (cong_obj_is_fp_cong(cong_obj)) { + // elm should be a gap_list_t representing a word + Congruence* cong = cong_obj_get_cpp(cong_obj); +- return INTOBJ_INT(cong->word_to_class_index(plist_to_word_t(elm)) + 1); ++ return INTOBJ_INT(cong->word_to_class_index(plist_to_word_type(elm)) + 1); + } else if (cong_obj_get_range_type(cong_obj) != UNKNOWN) { +- Congruence* cong = cong_obj_get_cpp(cong_obj); +- Semigroup* range = cong_obj_get_range(cong_obj); +- range->set_report(report); +- +- word_t word; ++ Congruence* cong = cong_obj_get_cpp(cong_obj); ++ FroidurePin<Element const*>* range = cong_obj_get_range(cong_obj); ++ auto rg = ReportGuard(report); ++ word_type word; + range->factorisation( + word, INT_INTOBJ(EN_SEMI_POSITION(self, range_obj, elm)) - 1); + return INTOBJ_INT(cong->word_to_class_index(word) + 1); +@@ -412,7 +407,7 @@ Obj CONG_PAIRS_ELM_COSET_ID(Obj self, gap_cong_t cong_obj, Obj elm) { + Obj word = ELM_PLIST(ElmPRec(data, RNam_words), + INT_INTOBJ(EN_SEMI_POSITION(self, range_obj, elm))); + +- return INTOBJ_INT(cong->word_to_class_index(plist_to_word_t(word)) + 1); ++ return INTOBJ_INT(cong->word_to_class_index(plist_to_word_type(word)) + 1); + } + } + +@@ -420,26 +415,22 @@ gap_list_t CONG_PAIRS_NONTRIVIAL_CLASSES(Obj self, gap_cong_t o) { + initRNams(); + Congruence* cong = cong_obj_get_cpp(o); + +- Partition<word_t>* nt_classes = cong->nontrivial_classes(); +- + // Initialise gap_lists +- gap_list_t gap_lists = NEW_PLIST_IMM(T_PLIST_TAB, nt_classes->size()); +- SET_LEN_PLIST(gap_lists, nt_classes->size()); ++ gap_list_t gap_lists ++ = NEW_PLIST_IMM(T_PLIST_TAB, cong->nr_non_trivial_classes()); ++ SET_LEN_PLIST(gap_lists, cong->nr_non_trivial_classes()); + + // Convert the words to plists +- for (size_t c = 0; c < nt_classes->size(); c++) { +- gap_list_t next_class +- = NEW_PLIST_IMM(T_PLIST_TAB, (*nt_classes)[c]->size()); +- SET_LEN_PLIST(next_class, (*nt_classes)[c]->size()); +- for (size_t e = 0; e < (*nt_classes)[c]->size(); e++) { +- SET_ELM_PLIST(next_class, e + 1, word_t_to_plist((*(*nt_classes)[c])[e])); ++ for (auto it1 = cong->cbegin_ntc(); it1 < cong->cend_ntc(); ++it1) { ++ gap_list_t next_class = NEW_PLIST_IMM(T_PLIST_TAB, it1->size()); ++ SET_LEN_PLIST(next_class, it1->size()); ++ size_t pos = 0; ++ for (auto it2 = it1->cbegin(); it2 < it1->cend(); ++it2) { ++ SET_ELM_PLIST(next_class, ++pos, word_type_to_plist(&(*it2))); + CHANGED_BAG(next_class); + } +- SET_ELM_PLIST(gap_lists, c + 1, next_class); ++ SET_ELM_PLIST(gap_lists, (it1 - cong->cbegin_ntc()) + 1, next_class); + CHANGED_BAG(gap_lists); + } +- +- delete nt_classes; +- + return gap_lists; + } +diff --git a/src/converter.cc b/src/converter.cc +index 5f9fa93aa..95e411fa5 100644 +--- a/src/converter.cc ++++ b/src/converter.cc +@@ -36,16 +36,15 @@ BooleanMat* BoolMatConverter::convert(Obj o, size_t n) const { + SEMIGROUPS_ASSERT(CALL_1ARGS(IsBooleanMat, o)); + SEMIGROUPS_ASSERT(IS_BLIST_REP(ELM_PLIST(o, 1))); + +- size_t m = LEN_BLIST(ELM_PLIST(o, 1)); +- std::vector<bool>* x(new std::vector<bool>()); +- x->resize(m * m, false); ++ size_t m = LEN_BLIST(ELM_PLIST(o, 1)); ++ std::vector<bool> x(m * m, false); + + for (size_t i = 0; i < m; i++) { + Obj row = ELM_PLIST(o, i + 1); + SEMIGROUPS_ASSERT(IS_BLIST_REP(row)); + for (size_t j = 0; j < m; j++) { + if (ELM_BLIST(row, j + 1) == True) { +- x->at(i * m + j) = true; ++ x.at(i * m + j) = true; + } + } + } +@@ -89,12 +88,11 @@ Obj BoolMatConverter::unconvert(Element const* x) const { + + Bipartition* BipartConverter::convert(Obj o, size_t n) const { + SEMIGROUPS_ASSERT(TNUM_OBJ(o) == T_BIPART); +- return static_cast<Bipartition*>( +- static_cast<Element*>(bipart_get_cpp(o))->really_copy()); ++ return new Bipartition(*bipart_get_cpp(o)); + } + + Obj BipartConverter::unconvert(Element const* x) const { +- return bipart_new_obj(static_cast<Bipartition*>(x->really_copy())); ++ return bipart_new_obj(new Bipartition(*static_cast<Bipartition const*>(x))); + } + + //////////////////////////////////////////////////////////////////////////////// +@@ -115,10 +113,9 @@ Obj PBRConverter::get_gap_type(size_t deg) const { + + PBR* PBRConverter::convert(Obj o, size_t n) const { + SEMIGROUPS_ASSERT(CALL_1ARGS(IsPBR, o)); +- size_t m = INT_INTOBJ(ELM_PLIST(o, 1)); +- std::vector<std::vector<u_int32_t>>* pbr( +- new std::vector<std::vector<u_int32_t>>()); +- pbr->reserve(m); ++ size_t m = INT_INTOBJ(ELM_PLIST(o, 1)); ++ std::vector<std::vector<u_int32_t>> pbr; ++ pbr.reserve(m); + + for (u_int32_t i = 0; i < 2 * m; i++) { + Obj adj = ELM_PLIST(o, i + 2); +@@ -128,7 +125,7 @@ PBR* PBRConverter::convert(Obj o, size_t n) const { + // assumes that adj is duplicate-free + } + std::sort(next.begin(), next.end()); +- pbr->push_back(next); ++ pbr.push_back(next); + } + return new PBR(pbr); + } +diff --git a/src/converter.h b/src/converter.h +index b8f29f798..c4892a4b5 100644 +--- a/src/converter.h ++++ b/src/converter.h +@@ -37,15 +37,15 @@ + #include "src/compiled.h" + + #include "pkg.h" +- + #include "semigroups-debug.h" + +-#include "libsemigroups/elements.h" ++#include "libsemigroups/element.hpp" ++#include "libsemigroups/semiring.hpp" + + using libsemigroups::Bipartition; + using libsemigroups::BooleanMat; + using libsemigroups::Element; +-using libsemigroups::MatrixOverSemiringBase; ++using libsemigroups::detail::MatrixOverSemiringBase; + using libsemigroups::NaturalSemiring; + using libsemigroups::PartialPerm; + using libsemigroups::PBR; +@@ -53,6 +53,7 @@ using libsemigroups::ProjectiveMaxPlusMatrix; + using libsemigroups::Semiring; + using libsemigroups::SemiringWithThreshold; + using libsemigroups::Transformation; ++using libsemigroups::UNDEFINED; + + //////////////////////////////////////////////////////////////////////////////// + // Abstract base class +@@ -69,24 +70,25 @@ class Converter { + // Transformations + //////////////////////////////////////////////////////////////////////////////// + +-template <typename T> class TransConverter : public Converter { ++template <typename T> ++class TransConverter : public Converter { + public: + Transformation<T>* convert(Obj o, size_t n) const override { + SEMIGROUPS_ASSERT(IS_TRANS(o)); + +- auto x = new std::vector<T>(); +- x->reserve(n); ++ std::vector<T> x; ++ x.reserve(n); + + size_t i = 0; + if (TNUM_OBJ(o) == T_TRANS2) { + UInt2* pto2 = ADDR_TRANS2(o); + for (i = 0; i < std::min((size_t) DEG_TRANS2(o), n); i++) { +- x->push_back(pto2[i]); ++ x.push_back(pto2[i]); + } + } else if (TNUM_OBJ(o) == T_TRANS4) { + UInt4* pto4 = ADDR_TRANS4(o); + for (i = 0; i < std::min((size_t) DEG_TRANS4(o), n); i++) { +- x->push_back(pto4[i]); ++ x.push_back(pto4[i]); + } + } else { + // in case of future changes to transformations in GAP +@@ -94,7 +96,7 @@ template <typename T> class TransConverter : public Converter { + } + + for (; i < n; i++) { +- x->push_back(i); ++ x.push_back(i); + } + return new Transformation<T>(x); + } +@@ -115,31 +117,32 @@ template <typename T> class TransConverter : public Converter { + // Partial perms + //////////////////////////////////////////////////////////////////////////////// + +-template <typename T> class PPermConverter : public Converter { ++template <typename T> ++class PPermConverter : public Converter { + public: + PartialPerm<T>* convert(Obj o, size_t n) const override { + SEMIGROUPS_ASSERT(IS_PPERM(o)); + +- auto x = new std::vector<T>(); +- x->reserve(n); ++ std::vector<T> x; ++ x.reserve(n); + + size_t i = 0; + if (TNUM_OBJ(o) == T_PPERM2) { + UInt2* pto2 = ADDR_PPERM<UInt2>(o); + for (i = 0; i < std::min((size_t) DEG_PPERM2(o), n); i++) { + if (pto2[i] == 0) { +- x->push_back(UNDEFINED); ++ x.push_back(UNDEFINED); + } else { +- x->push_back(pto2[i] - 1); ++ x.push_back(pto2[i] - 1); + } + } + } else if (TNUM_OBJ(o) == T_PPERM4) { + UInt4* pto4 = ADDR_PPERM<UInt4>(o); + for (i = 0; i < std::min((size_t) DEG_PPERM4(o), n); i++) { + if (pto4[i] == 0) { +- x->push_back(UNDEFINED); ++ x.push_back(UNDEFINED); + } else { +- x->push_back(pto4[i] - 1); ++ x.push_back(pto4[i] - 1); + } + } + } else { +@@ -148,7 +151,7 @@ template <typename T> class PPermConverter : public Converter { + } + + for (; i < n; i++) { +- x->push_back(UNDEFINED); ++ x.push_back(UNDEFINED); + } + return new PartialPerm<T>(x); + } +@@ -186,11 +189,10 @@ template <typename T> class PPermConverter : public Converter { + } + } + +- template <typename UIntT> inline UIntT* ADDR_PPERM(Obj x) const { ++ template <typename UIntT> ++ inline UIntT* ADDR_PPERM(Obj x) const { + return reinterpret_cast<UIntT*>(static_cast<Obj*>(ADDR_OBJ(x)) + 2) + 1; + } +- +- T UNDEFINED = (T) -1; + }; + + //////////////////////////////////////////////////////////////////////////////// +@@ -226,17 +228,17 @@ class MatrixOverSemiringConverter : public Converter { + + size_t m = LEN_PLIST(ELM_PLIST(o, 1)); + +- std::vector<int64_t>* matrix(new std::vector<int64_t>()); +- matrix->reserve(m); ++ std::vector<int64_t> matrix; ++ matrix.reserve(m); + + for (size_t i = 0; i < m; i++) { + Obj row = ELM_PLIST(o, i + 1); + for (size_t j = 0; j < m; j++) { + Obj entry = ELM_PLIST(row, j + 1); + if (EQ(_gap_zero, entry)) { +- matrix->push_back(_semiring->zero()); ++ matrix.push_back(_semiring->zero()); + } else { +- matrix->push_back(INT_INTOBJ(entry)); ++ matrix.push_back(INT_INTOBJ(entry)); + } + } + } +diff --git a/src/fropin.cc b/src/fropin.cc +index 2de1dbca6..9918cad6c 100644 +--- a/src/fropin.cc ++++ b/src/fropin.cc +@@ -21,13 +21,11 @@ + #include <algorithm> + #include <iostream> + +-#include "libsemigroups/report.h" + #include "rnams.h" + #include "semigroups-debug.h" + #include "semigrp.h" + +-using libsemigroups::glob_reporter; +-using libsemigroups::Timer; ++using libsemigroups::detail::Timer; + + // Macros for the GAP version of the algorithm + +@@ -112,9 +110,9 @@ Obj fropin(Obj obj, Obj limit, Obj lookfunc, Obj looking) { + return data; + } + int_limit = std::max((size_t) INT_INTOBJ(limit), (size_t)(nr + batch_size)); +- +- glob_reporter.set_report(report); +- REPORT_FROM_FUNC("limit = " << int_limit); ++ if (report) { ++ std::cout << "limit = " << int_limit << "\n"; ++ } + + Timer timer; + +@@ -313,15 +311,16 @@ Obj fropin(Obj obj, Obj limit, Obj lookfunc, Obj looking) { + len++; + AssPlist(lenindex, len, INTOBJ_INT(i)); + } +- if (i <= nr) { +- REPORT_FROM_FUNC("found " << nr << " elements, " << nrrules +- << " rules, max word length " << len + 1 +- << ", so far"); +- } else { +- REPORT_FROM_FUNC("found " << nr << " elements, " << nrrules +- << " rules, max word length " << len + 1 +- << ", finished!"); +- REPORT_FROM_FUNC("elapsed time = " << timer); // NOLINT() ++ if (report) { ++ if (i <= nr) { ++ std::cout << "found " << nr << " elements, " << nrrules ++ << " rules, max word length " << len + 1 << ", so far,\n"; ++ } else { ++ std::cout << "found " << nr << " elements, " << nrrules ++ << " rules, max word length " << len + 1 << ", finished!\n"; ++ // NOLINTNEXTLINE(build/include_what_you_use) ++ std::cout << "elapsed time = " << timer.string() << "\n"; ++ } + } + } + +diff --git a/src/pkg.cc b/src/pkg.cc +index c4e38c8e1..9399770b0 100644 +--- a/src/pkg.cc ++++ b/src/pkg.cc +@@ -32,12 +32,13 @@ + #include "semigrp.h" + #include "uf.h" + +-#include "libsemigroups/cong.h" +-#include "libsemigroups/semigroups.h" +-#include "libsemigroups/uf.h" ++#include "libsemigroups/blocks.hpp" ++#include "libsemigroups/cong.hpp" ++#include "libsemigroups/froidure-pin.hpp" ++#include "libsemigroups/uf.hpp" + + using libsemigroups::Congruence; +-using libsemigroups::UF; ++using libsemigroups::detail::UF; + + #if !defined(SIZEOF_VOID_P) + #error Something is wrong with this GAP installation: SIZEOF_VOID_P not defined +@@ -111,7 +112,7 @@ void TSemiObjFreeFunc(Obj o) { + // don't use functions to access these since they have too many + // side effects + delete CLASS_OBJ<Converter*>(o, 4); +- delete CLASS_OBJ<Semigroup*>(o, 5); ++ delete CLASS_OBJ<FroidurePin<Element const*>*>(o, 5); + } + break; + } +@@ -121,7 +122,6 @@ void TSemiObjFreeFunc(Obj o) { + + void TBipartObjFreeFunc(Obj o) { + SEMIGROUPS_ASSERT(TNUM_OBJ(o) == T_BIPART); +- bipart_get_cpp(o)->really_delete(); + delete bipart_get_cpp(o); + } + +@@ -207,7 +207,7 @@ void TSemiObjLoadFunc(Obj o) { + ADDR_OBJ(o)[2] = LoadSubObj(); // semigroup Obj + ADDR_OBJ(o)[3] = reinterpret_cast<Obj>(LoadUInt4()); // degree + ADDR_OBJ(o)[4] = static_cast<Obj>(nullptr); // Converter* +- ADDR_OBJ(o)[5] = static_cast<Obj>(nullptr); // Semigroup* ++ ADDR_OBJ(o)[5] = static_cast<Obj>(nullptr); // FroidurePin* + CHANGED_BAG(o); + } + break; +@@ -247,12 +247,12 @@ void TBipartObjSaveFunc(Obj o) { + } + + void TBipartObjLoadFunc(Obj o) { +- UInt4 deg = LoadUInt4(); +- std::vector<u_int32_t>* blocks = new std::vector<u_int32_t>(); +- blocks->reserve(2 * deg); ++ UInt4 deg = LoadUInt4(); ++ std::vector<u_int32_t> blocks; ++ blocks.reserve(2 * deg); + + for (size_t i = 0; i < 2 * deg; i++) { +- blocks->push_back(LoadUInt4()); ++ blocks.push_back(LoadUInt4()); + } + ADDR_OBJ(o)[0] = reinterpret_cast<Obj>(new Bipartition(blocks)); + SEMIGROUPS_ASSERT(ADDR_OBJ(o)[1] == NULL && ADDR_OBJ(o)[2] == NULL); +diff --git a/src/pkg.h b/src/pkg.h +index 715e12eb6..d32cea002 100644 +--- a/src/pkg.h ++++ b/src/pkg.h +@@ -51,7 +51,7 @@ + #if !defined(GAP_KERNEL_MAJOR_VERSION) || GAP_KERNEL_MAJOR_VERSION < 3 + // compatibility with GAP <= 4.9 + static inline Obj NEW_PLIST_IMM(UInt type, Int plen) { +- return NEW_PLIST(type | IMMUTABLE, plen); ++ return NEW_PLIST(type | IMMUTABLE, plen); + } + #endif + +@@ -101,7 +101,8 @@ inline Obj OBJ_CLASS(Class* cpp_class, t_semi_subtype_t type, size_t size = 2) { + + // Get a pointer to a C++ object of type Class from GAP Obj of type T_SEMI + +-template <typename Class> inline Class CLASS_OBJ(Obj o, size_t pos = 1) { ++template <typename Class> ++inline Class CLASS_OBJ(Obj o, size_t pos = 1) { + return reinterpret_cast<Class>(ADDR_OBJ(o)[pos]); + } + +diff --git a/src/semigrp.cc b/src/semigrp.cc +index fd9c6fec8..026eaca83 100644 +--- a/src/semigrp.cc ++++ b/src/semigrp.cc +@@ -26,19 +26,20 @@ + #include "bipart.h" + #include "converter.h" + #include "fropin.h" ++#include "libsemigroups/froidure-pin-base.hpp" + #include "pkg.h" + #include "src/compiled.h" + +-using libsemigroups::cayley_graph_t; + using libsemigroups::Integers; ++using libsemigroups::LIMIT_MAX; + using libsemigroups::MatrixOverSemiring; + using libsemigroups::MaxPlusSemiring; + using libsemigroups::MinPlusSemiring; + using libsemigroups::NaturalSemiring; +-using libsemigroups::really_delete_cont; + using libsemigroups::TropicalMaxPlusSemiring; + using libsemigroups::TropicalMinPlusSemiring; +-using libsemigroups::word_t; ++using libsemigroups::UNDEFINED; ++using libsemigroups::word_type; + + #ifdef SEMIGROUPS_KERNEL_DEBUG + #define ERROR(obj, message) \ +@@ -78,12 +79,18 @@ using libsemigroups::word_t; + #define CHECK_POS_INTOBJ(obj) + #endif + +-std::vector<Element const*>* plist_to_vec(Converter* converter, +- gap_list_t elements, +- size_t degree) { ++template <class TElementType> ++void delete_vec(std::vector<TElementType*>* vec) { ++ for (auto x : *vec) { ++ delete x; ++ } ++} ++ ++std::vector<Element*>* ++plist_to_vec(Converter* converter, gap_list_t elements, size_t degree) { + SEMIGROUPS_ASSERT(IS_PLIST(elements)); + +- auto out = new std::vector<Element const*>(); ++ auto out = new std::vector<Element*>(); + + for (size_t i = 0; i < (size_t) LEN_PLIST(elements); i++) { + out->push_back(converter->convert(ELM_LIST(elements, i + 1), degree)); +@@ -92,9 +99,8 @@ std::vector<Element const*>* plist_to_vec(Converter* converter, + } + + template <typename T> +-static inline gap_list_t iterator_to_plist(Converter* converter, +- T first, +- T last) { ++static inline gap_list_t ++iterator_to_plist(Converter* converter, T first, T last) { + gap_list_t out + = NEW_PLIST((first == last ? T_PLIST_EMPTY : T_PLIST_HOM), last - first); + SET_LEN_PLIST(out, last - first); +@@ -106,7 +112,7 @@ static inline gap_list_t iterator_to_plist(Converter* converter, + return out; + } + +-gap_list_t word_t_to_plist(word_t const& word) { ++gap_list_t word_type_to_plist(word_type const& word) { + SEMIGROUPS_ASSERT(!word.empty()); + gap_list_t out = NEW_PLIST_IMM(T_PLIST_CYC, word.size()); + // IMMUTABLE since it should not be altered on the GAP level +@@ -248,7 +254,7 @@ static inline size_t semi_obj_get_period(gap_semigroup_t so) { + // 2: gap_semigroup_t so, + // 3: size_t degree, + // 4: Converter*, +-// 5: Semigroup* ++// 5: FroidurePin* + // + // To call en_semi_init_converter positions 0 to 3 must already be set, and 4 + // and 5 must be nullptrs. To call en_semi_init_semigroup, +@@ -347,9 +353,9 @@ Converter* en_semi_init_converter(en_semi_obj_t es) { + return converter; + } + +-Semigroup* en_semi_init_semigroup(en_semi_obj_t es) { ++FroidurePin<Element const*>* en_semi_init_semigroup(en_semi_obj_t es) { + SEMIGROUPS_ASSERT(en_semi_get_type(es) != UNKNOWN); +- SEMIGROUPS_ASSERT(CLASS_OBJ<Semigroup*>(es, 5) == nullptr); ++ SEMIGROUPS_ASSERT(CLASS_OBJ<FroidurePin<Element const*>*>(es, 5) == nullptr); + initRNams(); + + if (en_semi_get_converter(es) == nullptr) { +@@ -361,9 +367,9 @@ Semigroup* en_semi_init_semigroup(en_semi_obj_t es) { + size_t deg = en_semi_get_degree(es); + gap_list_t plist = semi_obj_get_gens(so); + auto gens = plist_to_vec(converter, plist, deg); +- Semigroup* semi_cpp = new Semigroup(gens); +- semi_cpp->set_batch_size(semi_obj_get_batch_size(so)); +- really_delete_cont(gens); ++ FroidurePin<Element const*>* semi_cpp = new FroidurePin<Element const*>(gens); ++ semi_cpp->batch_size(semi_obj_get_batch_size(so)); ++ delete_vec(gens); + ADDR_OBJ(es)[5] = reinterpret_cast<Obj>(semi_cpp); + + return semi_cpp; +@@ -462,11 +468,11 @@ Converter* en_semi_get_converter(en_semi_obj_t es) { + return (converter != nullptr ? converter : en_semi_init_converter(es)); + } + +-Semigroup* en_semi_get_semi_cpp(en_semi_obj_t es) { ++FroidurePin<Element const*>* en_semi_get_semi_cpp(en_semi_obj_t es) { + SEMIGROUPS_ASSERT(TNUM_OBJ(es) == T_SEMI + && SUBTYPE_OF_T_SEMI(es) == T_SEMI_SUBTYPE_ENSEMI); + SEMIGROUPS_ASSERT(en_semi_get_type(es) != UNKNOWN); +- Semigroup* semi_cpp = CLASS_OBJ<Semigroup*>(es, 5); ++ FroidurePin<Element const*>* semi_cpp = CLASS_OBJ<FroidurePin<Element const*>*>(es, 5); + return (semi_cpp != nullptr ? semi_cpp : en_semi_init_semigroup(es)); + } + +@@ -497,7 +503,7 @@ en_semi_t semi_obj_get_type(gap_semigroup_t so) { + return en_semi_get_type(semi_obj_get_en_semi(so)); + } + +-Semigroup* semi_obj_get_semi_cpp(gap_semigroup_t so) { ++FroidurePin<Element const*>* semi_obj_get_semi_cpp(gap_semigroup_t so) { + CHECK_SEMI_OBJ(so); + return en_semi_get_semi_cpp(semi_obj_get_en_semi(so)); + } +@@ -532,9 +538,9 @@ gap_list_t EN_SEMI_AS_LIST(Obj self, gap_semigroup_t so) { + en_semi_obj_t es = semi_obj_get_en_semi(so); + + if (en_semi_get_type(es) != UNKNOWN) { +- Semigroup* semi_cpp = en_semi_get_semi_cpp(es); +- semi_cpp->set_report(semi_obj_get_report(so)); +- semi_cpp->enumerate(); ++ FroidurePin<Element const*>* semi_cpp = en_semi_get_semi_cpp(es); ++ auto rg = libsemigroups::ReportGuard(semi_obj_get_report(so)); ++ semi_cpp->run(); + return iterator_to_plist( + en_semi_get_converter(es), semi_cpp->cbegin(), semi_cpp->cend()); + } else { +@@ -547,8 +553,8 @@ gap_list_t EN_SEMI_AS_SET(Obj self, gap_semigroup_t so) { + en_semi_obj_t es = semi_obj_get_en_semi(so); + + if (en_semi_get_type(es) != UNKNOWN) { +- Semigroup* semi_cpp = en_semi_get_semi_cpp(es); +- semi_cpp->set_report(semi_obj_get_report(so)); ++ FroidurePin<Element const*>* semi_cpp = en_semi_get_semi_cpp(es); ++ auto rg = libsemigroups::ReportGuard(semi_obj_get_report(so)); + Converter* converter = en_semi_get_converter(es); + // The T_PLIST_HOM_SSORTED makes a huge difference to performance!! + gap_list_t out = NEW_PLIST_IMM(T_PLIST_HOM_SSORT, semi_cpp->size()); +@@ -573,9 +579,8 @@ gap_list_t EN_SEMI_CAYLEY_TABLE(Obj self, gap_semigroup_t so) { + CHECK_SEMI_OBJ(so); + en_semi_obj_t es = semi_obj_get_en_semi(so); + if (en_semi_get_type(es) != UNKNOWN) { +- Semigroup* semi_cpp = en_semi_get_semi_cpp(es); +- semi_cpp->set_report(semi_obj_get_report(so)); +- ++ FroidurePin<Element const*>* semi_cpp = en_semi_get_semi_cpp(es); ++ auto rg = libsemigroups::ReportGuard(semi_obj_get_report(so)); + size_t n = semi_cpp->size(); + SEMIGROUPS_ASSERT(n != 0); + gap_list_t out = NEW_PLIST(T_PLIST_TAB_RECT, n); +@@ -644,7 +649,7 @@ gap_semigroup_t EN_SEMI_CLOSURE(Obj self, + Converter* converter = en_semi_get_converter(es); + auto coll = plist_to_vec(converter, plist, deg); + +- Semigroup* old_semi_cpp = semi_obj_get_semi_cpp(old_so); ++ FroidurePin<Element const*>* old_semi_cpp = semi_obj_get_semi_cpp(old_so); + + // CAUTION: copy_closure always copies old_semi_cpp regardless of whether or + // not every element in coll belongs to old_semi_cpp!! Only call this +@@ -654,26 +659,26 @@ gap_semigroup_t EN_SEMI_CLOSURE(Obj self, + #ifdef SEMIGROUPS_KERNEL_DEBUG + bool valid = false; + for (auto const& x : *coll) { +- if (!old_semi_cpp->test_membership(x)) { ++ if (!old_semi_cpp->contains(x)) { + valid = true; + break; + } + } + SEMIGROUPS_ASSERT(valid); + #endif +- old_semi_cpp->set_report(semi_obj_get_report(new_so)); +- Semigroup* new_semi_cpp = old_semi_cpp->copy_closure(coll); +- really_delete_cont(coll); ++ auto rg = libsemigroups::ReportGuard(semi_obj_get_report(new_so)); ++ FroidurePin<Element const*>* new_semi_cpp = old_semi_cpp->copy_closure(*coll); ++ delete_vec(coll); + +- new_semi_cpp->set_batch_size(semi_obj_get_batch_size(new_so)); ++ new_semi_cpp->batch_size(semi_obj_get_batch_size(new_so)); + ADDR_OBJ(es)[5] = reinterpret_cast<Obj>(new_semi_cpp); + CHANGED_BAG(es); + + // Reset the generators of the new semigroup +- gap_list_t gens = NEW_PLIST(T_PLIST_HOM, new_semi_cpp->nrgens()); ++ gap_list_t gens = NEW_PLIST(T_PLIST_HOM, new_semi_cpp->nr_generators()); + +- for (size_t i = 0; i < new_semi_cpp->nrgens(); i++) { +- AssPlist(gens, i + 1, converter->unconvert(new_semi_cpp->gens(i))); ++ for (size_t i = 0; i < new_semi_cpp->nr_generators(); i++) { ++ AssPlist(gens, i + 1, converter->unconvert(new_semi_cpp->generator(i))); + } + AssPRec(new_so, RNam_GeneratorsOfMagma, gens); + +@@ -690,9 +695,8 @@ gap_semigroup_t EN_SEMI_CLOSURE(Obj self, + // the elements in <so>. If this is not the case, then this should not be + // called but ClosureSemigroup should be instead, on the GAP level. + +-gap_semigroup_t EN_SEMI_CLOSURE_DEST(Obj self, +- gap_semigroup_t so, +- gap_list_t plist) { ++gap_semigroup_t ++EN_SEMI_CLOSURE_DEST(Obj self, gap_semigroup_t so, gap_list_t plist) { + CHECK_SEMI_OBJ(so); + CHECK_PLIST(plist); + +@@ -705,19 +709,19 @@ gap_semigroup_t EN_SEMI_CLOSURE_DEST(Obj self, + SEMIGROUPS_ASSERT(IS_PLIST(plist)); + SEMIGROUPS_ASSERT(LEN_PLIST(plist) > 0); + +- Semigroup* semi_cpp = en_semi_get_semi_cpp(es); ++ FroidurePin<Element const*>* semi_cpp = en_semi_get_semi_cpp(es); + size_t const deg = semi_cpp->degree(); + Converter* converter = en_semi_get_converter(es); + + auto coll = plist_to_vec(converter, plist, deg); +- semi_cpp->set_report(semi_obj_get_report(so)); +- semi_cpp->closure(coll); +- really_delete_cont(coll); ++ auto rg = libsemigroups::ReportGuard(semi_obj_get_report(so)); ++ semi_cpp->closure(*coll); ++ delete_vec(coll); + + gap_list_t gens = ElmPRec(so, RNam_GeneratorsOfMagma); + +- for (size_t i = 0; i < semi_cpp->nrgens(); i++) { +- AssPlist(gens, i + 1, converter->unconvert(semi_cpp->gens(i))); ++ for (size_t i = 0; i < semi_cpp->nr_generators(); i++) { ++ AssPlist(gens, i + 1, converter->unconvert(semi_cpp->generator(i))); + } + + // Reset the fropin data since none of it is valid any longer +@@ -752,7 +756,7 @@ gap_int_t EN_SEMI_CURRENT_NR_RULES(Obj self, gap_semigroup_t so) { + if (es == 0L) { + return INTOBJ_INT(0); + } else if (en_semi_get_type(es) != UNKNOWN) { +- return INTOBJ_INT(en_semi_get_semi_cpp(es)->current_nrrules()); ++ return INTOBJ_INT(en_semi_get_semi_cpp(es)->current_nr_rules()); + } else { + gap_rec_t fp = semi_obj_get_fropin(so); + // TODO(JDM) could write a function return_if_not_bound_prec(prec, rnam, +@@ -785,9 +789,8 @@ gap_int_t EN_SEMI_CURRENT_SIZE(Obj self, gap_semigroup_t so) { + + // Get the <pos> element of <S> this is not cached anywhere for cpp semigroups + +-gap_element_t EN_SEMI_ELEMENT_NUMBER(Obj self, +- gap_semigroup_t so, +- gap_int_t pos) { ++gap_element_t ++EN_SEMI_ELEMENT_NUMBER(Obj self, gap_semigroup_t so, gap_int_t pos) { + CHECK_SEMI_OBJ(so); + CHECK_POS_INTOBJ(pos); + +@@ -796,10 +799,18 @@ gap_element_t EN_SEMI_ELEMENT_NUMBER(Obj self, + + if (en_semi_get_type(es) != UNKNOWN) { + nr--; +- Semigroup* semi_cpp = en_semi_get_semi_cpp(es); +- semi_cpp->set_report(semi_obj_get_report(so)); +- Element const* x = semi_cpp->at(nr); +- return (x == nullptr ? Fail : en_semi_get_converter(es)->unconvert(x)); ++ FroidurePin<Element const*>* semi_cpp = en_semi_get_semi_cpp(es); ++ auto rg = libsemigroups::ReportGuard(semi_obj_get_report(so)); ++ try { ++ return en_semi_get_converter(es)->unconvert(semi_cpp->at(nr)); ++ } catch (std::out_of_range& e) { ++#ifdef SEMIGROUPS_KERNEL_DEBUG ++ std::cerr << "exception std::out_of_range thrown " ++ "by libsemigroups::FroidurePin::at(" ++ << nr << "): " << e.what() << std::endl; ++#endif ++ return Fail; ++ } + } else { + gap_rec_t fp = semi_obj_get_fropin(so); + if (IsbPRec(fp, RNam_elts)) { +@@ -819,21 +830,27 @@ gap_element_t EN_SEMI_ELEMENT_NUMBER(Obj self, + } + } + +-gap_element_t EN_SEMI_ELEMENT_NUMBER_SORTED(Obj self, +- gap_semigroup_t so, +- gap_int_t pos) { ++gap_element_t ++EN_SEMI_ELEMENT_NUMBER_SORTED(Obj self, gap_semigroup_t so, gap_int_t pos) { + CHECK_SEMI_OBJ(so); + CHECK_POS_INTOBJ(pos); + + en_semi_obj_t es = semi_obj_get_en_semi(so); + + if (en_semi_get_type(es) != UNKNOWN) { +- size_t nr = INT_INTOBJ(pos) - 1; +- Semigroup* semi_cpp = en_semi_get_semi_cpp(es); +- semi_cpp->set_report(semi_obj_get_report(so)); +- Element const* x = semi_cpp->sorted_at(nr); +- +- return (x == nullptr ? Fail : en_semi_get_converter(es)->unconvert(x)); ++ size_t nr = INT_INTOBJ(pos) - 1; ++ FroidurePin<Element const*>* semi_cpp = en_semi_get_semi_cpp(es); ++ auto rg = libsemigroups::ReportGuard(semi_obj_get_report(so)); ++ try { ++ return en_semi_get_converter(es)->unconvert(semi_cpp->sorted_at(nr)); ++ } catch (std::out_of_range& e) { ++#ifdef SEMIGROUPS_KERNEL_DEBUG ++ std::cerr << "exception std::out_of_range thrown " ++ "by libsemigroups::FroidurePin::sorted_at(" ++ << nr << "): " << e.what() << std::endl; ++#endif ++ return Fail; ++ } + } else { + ErrorQuit("EN_SEMI_ELEMENT_NUMBER_SORTED: this shouldn't happen!", 0L, 0L); + return 0L; +@@ -853,7 +870,7 @@ gap_list_t EN_SEMI_ELMS_LIST(Obj self, gap_semigroup_t so, gap_list_t poslist) { + SET_LEN_PLIST(out, len); + + if (en_semi_get_type(es) != UNKNOWN) { +- Semigroup* semi_cpp = en_semi_get_semi_cpp(es); ++ FroidurePin<Element const*>* semi_cpp = en_semi_get_semi_cpp(es); + for (size_t i = 1; i <= len; i++) { + gap_int_t pos = ELM_LIST(poslist, i); + if (pos == 0 || !IS_INTOBJ(pos) || INT_INTOBJ(pos) <= 0) { +@@ -862,16 +879,24 @@ gap_list_t EN_SEMI_ELMS_LIST(Obj self, gap_semigroup_t so, gap_list_t poslist) { + (Int) i, + 0L); + } +- semi_cpp->set_report(semi_obj_get_report(so)); +- Element const* x = semi_cpp->at(INT_INTOBJ(pos) - 1); +- if (x == nullptr) { ++ auto rg = libsemigroups::ReportGuard(semi_obj_get_report(so)); ++ try { ++ SET_ELM_PLIST(out, ++ i, ++ en_semi_get_converter(es)->unconvert( ++ semi_cpp->at(INT_INTOBJ(pos) - 1))); ++ CHANGED_BAG(out); ++ } catch (std::out_of_range& e) { ++#ifdef SEMIGROUPS_KERNEL_DEBUG ++ std::cerr << "exception std::out_of_range thrown " ++ "by libsemigroups::FroidurePin::at(" ++ << (INT_INTOBJ(pos) - 1) << "): " << e.what() << std::endl; ++#endif + ErrorQuit("Semigroups: ELMS_LIST: List Elements, <list>[%d] " + "must be at most %d,", + (Int) i, + (Int) semi_cpp->size()); + } +- SET_ELM_PLIST(out, i, en_semi_get_converter(es)->unconvert(x)); +- CHANGED_BAG(out); + } + } else { + for (size_t i = 1; i <= len; i++) { +@@ -896,17 +921,15 @@ gap_list_t EN_SEMI_ELMS_LIST(Obj self, gap_semigroup_t so, gap_list_t poslist) { + return out; + } + +-gap_semigroup_t EN_SEMI_ENUMERATE(Obj self, +- gap_semigroup_t so, +- gap_int_t limit) { ++gap_semigroup_t ++EN_SEMI_ENUMERATE(Obj self, gap_semigroup_t so, gap_int_t limit) { + CHECK_SEMI_OBJ(so); + CHECK_INTOBJ(limit); +- size_t c_limit +- = (INT_INTOBJ(limit) < 0 ? Semigroup::LIMIT_MAX : INT_INTOBJ(limit)); ++ size_t c_limit = (INT_INTOBJ(limit) < 0 ? LIMIT_MAX : INT_INTOBJ(limit)); + en_semi_obj_t es = semi_obj_get_en_semi(so); + if (en_semi_get_type(es) != UNKNOWN) { +- Semigroup* semi_cpp = en_semi_get_semi_cpp(es); +- semi_cpp->set_report(semi_obj_get_report(so)); ++ FroidurePin<Element const*>* semi_cpp = en_semi_get_semi_cpp(es); ++ auto rg = libsemigroups::ReportGuard(semi_obj_get_report(so)); + semi_cpp->enumerate(c_limit); + } else { + fropin(so, limit, 0, False); +@@ -927,8 +950,8 @@ gap_list_t EN_SEMI_FACTORIZATION(Obj self, gap_semigroup_t so, gap_int_t pos) { + 0L); + return 0L; // keep compiler happy + } else if (en_semi_get_type(es) != UNKNOWN) { +- gap_list_t words; +- Semigroup* semi_cpp = en_semi_get_semi_cpp(es); ++ gap_list_t words; ++ FroidurePin<Element const*>* semi_cpp = en_semi_get_semi_cpp(es); + + if (pos_c > semi_cpp->current_size()) { + ErrorQuit("the 2nd argument must be at most %d not %d", +@@ -939,13 +962,13 @@ gap_list_t EN_SEMI_FACTORIZATION(Obj self, gap_semigroup_t so, gap_int_t pos) { + gap_rec_t fp = semi_obj_get_fropin(so); + if (!IsbPRec(fp, RNam_words)) { + // TODO(JDM) Use FindPRec instead +- word_t w; // changed in place by the next line +- semi_cpp->set_report(semi_obj_get_report(so)); ++ word_type w; // changed in place by the next line ++ auto rg = libsemigroups::ReportGuard(semi_obj_get_report(so)); + semi_cpp->factorisation(w, pos_c - 1); + words = NEW_PLIST_IMM(T_PLIST, pos_c); + // IMMUTABLE since it should not be altered on the GAP level + SET_LEN_PLIST(words, pos_c); +- SET_ELM_PLIST(words, pos_c, word_t_to_plist(w)); ++ SET_ELM_PLIST(words, pos_c, word_type_to_plist(w)); + CHANGED_BAG(words); + AssPRec(fp, RNam_words, words); + CHANGED_BAG(so); +@@ -961,7 +984,8 @@ gap_list_t EN_SEMI_FACTORIZATION(Obj self, gap_semigroup_t so, gap_int_t pos) { + gap_list_t new_word + = NEW_PLIST_IMM(T_PLIST_CYC, LEN_PLIST(old_word) + 1); + // IMMUTABLE since it should not be altered on the GAP level +- memcpy(ADDR_OBJ(new_word) + 1, CONST_ADDR_OBJ(old_word) + 1, ++ memcpy(ADDR_OBJ(new_word) + 1, ++ CONST_ADDR_OBJ(old_word) + 1, + (size_t)(LEN_PLIST(old_word) * sizeof(Obj))); + SET_ELM_PLIST(new_word, + LEN_PLIST(old_word) + 1, +@@ -976,7 +1000,8 @@ gap_list_t EN_SEMI_FACTORIZATION(Obj self, gap_semigroup_t so, gap_int_t pos) { + gap_list_t new_word + = NEW_PLIST_IMM(T_PLIST_CYC, LEN_PLIST(old_word) + 1); + // IMMUTABLE since it should not be altered on the GAP level +- memcpy(ADDR_OBJ(new_word) + 2, CONST_ADDR_OBJ(old_word) + 1, ++ memcpy(ADDR_OBJ(new_word) + 2, ++ CONST_ADDR_OBJ(old_word) + 1, + (size_t)(LEN_PLIST(old_word) * sizeof(Obj))); + SET_ELM_PLIST( + new_word, 1, INTOBJ_INT(semi_cpp->first_letter(pos_c - 1) + 1)); +@@ -985,10 +1010,10 @@ gap_list_t EN_SEMI_FACTORIZATION(Obj self, gap_semigroup_t so, gap_int_t pos) { + CHANGED_BAG(fp); + CHANGED_BAG(so); + } else { +- word_t w; // changed in place by the next line +- semi_cpp->set_report(semi_obj_get_report(so)); ++ word_type w; // changed in place by the next line ++ auto rg = libsemigroups::ReportGuard(semi_obj_get_report(so)); + semi_cpp->factorisation(w, pos_c - 1); +- AssPlist(words, pos_c, word_t_to_plist(w)); ++ AssPlist(words, pos_c, word_type_to_plist(w)); + CHANGED_BAG(fp); + CHANGED_BAG(so); + } +@@ -1010,17 +1035,17 @@ gap_list_t EN_SEMI_LEFT_CAYLEY_GRAPH(Obj self, gap_semigroup_t so) { + CHECK_SEMI_OBJ(so); + en_semi_obj_t es = semi_obj_get_en_semi(so); + if (en_semi_get_type(es) != UNKNOWN) { +- Semigroup* semi_cpp = en_semi_get_semi_cpp(es); +- semi_cpp->set_report(semi_obj_get_report(so)); ++ FroidurePin<Element const*>* semi_cpp = en_semi_get_semi_cpp(es); ++ auto rg = libsemigroups::ReportGuard(semi_obj_get_report(so)); + gap_list_t out = NEW_PLIST(T_PLIST_TAB_RECT, semi_cpp->size()); + // this is intentionally not IMMUTABLE + SET_LEN_PLIST(out, semi_cpp->size()); + + for (size_t i = 0; i < semi_cpp->size(); ++i) { +- gap_list_t next = NEW_PLIST(T_PLIST_CYC, semi_cpp->nrgens()); ++ gap_list_t next = NEW_PLIST(T_PLIST_CYC, semi_cpp->nr_generators()); + // this is intentionally not IMMUTABLE +- SET_LEN_PLIST(next, semi_cpp->nrgens()); +- for (size_t j = 0; j < semi_cpp->nrgens(); ++j) { ++ SET_LEN_PLIST(next, semi_cpp->nr_generators()); ++ for (size_t j = 0; j < semi_cpp->nr_generators(); ++j) { + SET_ELM_PLIST(next, j + 1, INTOBJ_INT(semi_cpp->left(i, j) + 1)); + } + SET_ELM_PLIST(out, i + 1, next); +@@ -1037,8 +1062,8 @@ gap_int_t EN_SEMI_LENGTH_ELEMENT(Obj self, gap_semigroup_t so, gap_int_t pos) { + CHECK_POS_INTOBJ(pos); + en_semi_obj_t es = semi_obj_get_en_semi(so); + if (en_semi_get_type(es) != UNKNOWN) { +- Semigroup* semi_cpp = en_semi_get_semi_cpp(es); +- semi_cpp->set_report(semi_obj_get_report(so)); ++ FroidurePin<Element const*>* semi_cpp = en_semi_get_semi_cpp(es); ++ auto rg = libsemigroups::ReportGuard(semi_obj_get_report(so)); + return INTOBJ_INT(semi_cpp->length_non_const(INT_INTOBJ(pos) - 1)); + } else { + return INTOBJ_INT(LEN_PLIST(EN_SEMI_FACTORIZATION(self, so, pos))); +@@ -1049,11 +1074,11 @@ gap_list_t EN_SEMI_IDEMPOTENTS(Obj self, gap_semigroup_t so) { + CHECK_SEMI_OBJ(so); + en_semi_obj_t es = semi_obj_get_en_semi(so); + if (en_semi_get_type(es) != UNKNOWN) { +- Semigroup* semi_cpp = en_semi_get_semi_cpp(es); +- Converter* converter = en_semi_get_converter(es); ++ FroidurePin<Element const*>* semi_cpp = en_semi_get_semi_cpp(es); ++ Converter* converter = en_semi_get_converter(es); + +- semi_cpp->set_report(semi_obj_get_report(so)); +- semi_cpp->set_max_threads(semi_obj_get_nr_threads(so)); ++ auto rg = libsemigroups::ReportGuard(semi_obj_get_report(so)); ++ semi_cpp->max_threads(semi_obj_get_nr_threads(so)); + return iterator_to_plist(converter, + semi_cpp->cbegin_idempotents(), + semi_cpp->cend_idempotents()); +@@ -1097,9 +1122,9 @@ gap_int_t EN_SEMI_IDEMS_SUBSET(Obj self, gap_semigroup_t so, gap_list_t list) { + size_t len = 0; + + if (en_semi_get_type(es) != UNKNOWN) { +- Semigroup* semi_cpp = en_semi_get_semi_cpp(es); +- semi_cpp->set_report(semi_obj_get_report(so)); +- semi_cpp->set_max_threads(semi_obj_get_nr_threads(so)); ++ FroidurePin<Element const*>* semi_cpp = en_semi_get_semi_cpp(es); ++ auto rg = libsemigroups::ReportGuard(semi_obj_get_report(so)); ++ semi_cpp->max_threads(semi_obj_get_nr_threads(so)); + + for (size_t pos = 1; pos <= (size_t) LEN_LIST(list); pos++) { + gap_int_t ent = ELM_LIST(list, pos); +@@ -1143,7 +1168,7 @@ gap_bool_t EN_SEMI_IS_DONE(Obj self, gap_semigroup_t so) { + if (es == 0L) { + return False; + } else if (en_semi_get_type(es) != UNKNOWN) { +- return (en_semi_get_semi_cpp(es)->is_done() ? True : False); ++ return (en_semi_get_semi_cpp(es)->finished() ? True : False); + } + + gap_rec_t fp = semi_obj_get_fropin(so); +@@ -1157,11 +1182,11 @@ gap_int_t EN_SEMI_NR_IDEMPOTENTS(Obj self, gap_semigroup_t so) { + CHECK_SEMI_OBJ(so); + en_semi_obj_t es = semi_obj_get_en_semi(so); + if (en_semi_get_type(es) != UNKNOWN) { +- Semigroup* semi_cpp = en_semi_get_semi_cpp(es); +- semi_cpp->set_report(semi_obj_get_report(so)); +- semi_cpp->set_max_threads(semi_obj_get_nr_threads(so)); ++ FroidurePin<Element const*>* semi_cpp = en_semi_get_semi_cpp(es); ++ auto rg = libsemigroups::ReportGuard(semi_obj_get_report(so)); ++ semi_cpp->max_threads(semi_obj_get_nr_threads(so)); + +- return INTOBJ_INT(semi_cpp->nridempotents()); ++ return INTOBJ_INT(semi_cpp->nr_idempotents()); + } else { + // This could probably be better but is also probably not worth the effort + // of improving +@@ -1191,14 +1216,13 @@ Obj EN_SEMI_POSITION(Obj self, gap_semigroup_t so, gap_element_t x) { + en_semi_obj_t es = semi_obj_get_en_semi(so); + + if (en_semi_get_type(es) != UNKNOWN) { +- size_t deg = en_semi_get_degree(es); +- Element* xx = en_semi_get_converter(es)->convert(x, deg); +- Semigroup* semi_cpp = en_semi_get_semi_cpp(es); +- semi_cpp->set_report(semi_obj_get_report(so)); ++ size_t deg = en_semi_get_degree(es); ++ Element* xx = en_semi_get_converter(es)->convert(x, deg); ++ FroidurePin<Element const*>* semi_cpp = en_semi_get_semi_cpp(es); ++ auto rg = libsemigroups::ReportGuard(semi_obj_get_report(so)); + size_t pos = semi_cpp->position(xx); +- xx->really_delete(); + delete xx; +- return (pos == Semigroup::UNDEFINED ? Fail : INTOBJ_INT(pos + 1)); ++ return (pos == UNDEFINED ? Fail : INTOBJ_INT(pos + 1)); + } else { + gap_rec_t data = semi_obj_get_fropin(so); + Obj ht = ElmPRec(data, RNam_ht); +@@ -1220,9 +1244,8 @@ Obj EN_SEMI_POSITION(Obj self, gap_semigroup_t so, gap_element_t x) { + + // Get the position of <x> with out any further enumeration + +-gap_int_t EN_SEMI_CURRENT_POSITION(Obj self, +- gap_semigroup_t so, +- gap_element_t x) { ++gap_int_t ++EN_SEMI_CURRENT_POSITION(Obj self, gap_semigroup_t so, gap_element_t x) { + CHECK_SEMI_OBJ(so); + + en_semi_obj_t es = semi_obj_get_en_semi_no_init(so); +@@ -1232,17 +1255,15 @@ gap_int_t EN_SEMI_CURRENT_POSITION(Obj self, + size_t deg = en_semi_get_degree(es); + Element* xx = en_semi_get_converter(es)->convert(x, deg); + size_t pos = en_semi_get_semi_cpp(es)->current_position(xx); +- xx->really_delete(); + delete xx; +- return (pos == Semigroup::UNDEFINED ? Fail : INTOBJ_INT(pos + 1)); ++ return (pos == UNDEFINED ? Fail : INTOBJ_INT(pos + 1)); + } else { + return CALL_2ARGS(HTValue, ElmPRec(semi_obj_get_fropin(so), RNam_ht), x); + } + } + +-gap_int_t EN_SEMI_POSITION_SORTED(Obj self, +- gap_semigroup_t so, +- gap_element_t x) { ++gap_int_t ++EN_SEMI_POSITION_SORTED(Obj self, gap_semigroup_t so, gap_element_t x) { + CHECK_SEMI_OBJ(so); + + en_semi_obj_t es = semi_obj_get_en_semi(so); +@@ -1251,14 +1272,13 @@ gap_int_t EN_SEMI_POSITION_SORTED(Obj self, + ErrorQuit("EN_SEMI_POSITION_SORTED: this shouldn't happen!", 0L, 0L); + return 0L; + } else { +- size_t deg = en_semi_get_degree(es); +- Semigroup* semi_cpp = en_semi_get_semi_cpp(es); +- semi_cpp->set_report(semi_obj_get_report(so)); ++ size_t deg = en_semi_get_degree(es); ++ FroidurePin<Element const*>* semi_cpp = en_semi_get_semi_cpp(es); ++ auto rg = libsemigroups::ReportGuard(semi_obj_get_report(so)); + Element* xx = en_semi_get_converter(es)->convert(x, deg); + size_t pos = semi_cpp->sorted_position(xx); +- xx->really_delete(); + delete xx; +- return (pos == Semigroup::UNDEFINED ? Fail : INTOBJ_INT(pos + 1)); ++ return (pos == UNDEFINED ? Fail : INTOBJ_INT(pos + 1)); + } + } + +@@ -1270,12 +1290,11 @@ gap_list_t EN_SEMI_RELATIONS(Obj self, gap_semigroup_t so) { + + if (en_semi_get_type(es) != UNKNOWN) { + if (!IsbPRec(fp, RNam_rules) || LEN_PLIST(ElmPRec(fp, RNam_rules)) == 0) { +- Semigroup* semi_cpp = en_semi_get_semi_cpp(es); +- semi_cpp->set_report(semi_obj_get_report(so)); +- gap_list_t rules +- = NEW_PLIST_IMM(T_PLIST_TAB_RECT, semi_cpp->nrrules()); ++ FroidurePin<Element const*>* semi_cpp = en_semi_get_semi_cpp(es); ++ auto rg = libsemigroups::ReportGuard(semi_obj_get_report(so)); ++ gap_list_t rules = NEW_PLIST_IMM(T_PLIST_TAB_RECT, semi_cpp->nr_rules()); + // IMMUTABLE since it should not be altered on the GAP level +- SET_LEN_PLIST(rules, semi_cpp->nrrules()); ++ SET_LEN_PLIST(rules, semi_cpp->nr_rules()); + size_t nr = 0; + + semi_cpp->reset_next_relation(); +@@ -1306,7 +1325,8 @@ gap_list_t EN_SEMI_RELATIONS(Obj self, gap_semigroup_t so) { + gap_list_t new_word + = NEW_PLIST_IMM(T_PLIST_CYC, LEN_PLIST(old_word) + 1); + // IMMUTABLE since it should not be altered on the GAP level +- memcpy(ADDR_OBJ(new_word) + 1, CONST_ADDR_OBJ(old_word) + 1, ++ memcpy(ADDR_OBJ(new_word) + 1, ++ CONST_ADDR_OBJ(old_word) + 1, + (size_t)(LEN_PLIST(old_word) * sizeof(Obj))); + SET_ELM_PLIST( + new_word, LEN_PLIST(old_word) + 1, INTOBJ_INT(relation[1] + 1)); +@@ -1341,18 +1361,18 @@ gap_list_t EN_SEMI_RIGHT_CAYLEY_GRAPH(Obj self, gap_semigroup_t so) { + en_semi_obj_t es = semi_obj_get_en_semi(so); + + if (en_semi_get_type(es) != UNKNOWN) { +- Semigroup* semi_cpp = en_semi_get_semi_cpp(es); +- semi_cpp->set_report(semi_obj_get_report(so)); ++ FroidurePin<Element const*>* semi_cpp = en_semi_get_semi_cpp(es); ++ auto rg = libsemigroups::ReportGuard(semi_obj_get_report(so)); + + gap_list_t out = NEW_PLIST(T_PLIST_TAB_RECT, semi_cpp->size()); + // this is intentionally not IMMUTABLE + SET_LEN_PLIST(out, semi_cpp->size()); + + for (size_t i = 0; i < semi_cpp->size(); ++i) { +- gap_list_t next = NEW_PLIST(T_PLIST_CYC, semi_cpp->nrgens()); ++ gap_list_t next = NEW_PLIST(T_PLIST_CYC, semi_cpp->nr_generators()); + // this is intentionally not IMMUTABLE +- SET_LEN_PLIST(next, semi_cpp->nrgens()); +- for (size_t j = 0; j < semi_cpp->nrgens(); ++j) { ++ SET_LEN_PLIST(next, semi_cpp->nr_generators()); ++ for (size_t j = 0; j < semi_cpp->nr_generators(); ++j) { + SET_ELM_PLIST(next, j + 1, INTOBJ_INT(semi_cpp->right(i, j) + 1)); + } + SET_ELM_PLIST(out, i + 1, next); +@@ -1370,8 +1390,8 @@ gap_int_t EN_SEMI_SIZE(Obj self, gap_semigroup_t so) { + en_semi_obj_t es = semi_obj_get_en_semi(so); + + if (en_semi_get_type(es) != UNKNOWN) { +- Semigroup* semi_cpp = en_semi_get_semi_cpp(es); +- semi_cpp->set_report(semi_obj_get_report(so)); ++ FroidurePin<Element const*>* semi_cpp = en_semi_get_semi_cpp(es); ++ auto rg = libsemigroups::ReportGuard(semi_obj_get_report(so)); + return INTOBJ_INT(semi_cpp->size()); + } else { + gap_rec_t fp = fropin(so, INTOBJ_INT(-1), 0, False); +diff --git a/src/semigrp.h b/src/semigrp.h +index 1b99accf9..e5427e138 100644 +--- a/src/semigrp.h ++++ b/src/semigrp.h +@@ -21,13 +21,16 @@ + #ifndef SEMIGROUPS_SRC_SEMIGRP_H_ + #define SEMIGROUPS_SRC_SEMIGRP_H_ + ++#include "libsemigroups/froidure-pin.hpp" ++ ++#include "src/compiled.h" // GAP headers ++ + #include "converter.h" +-#include "libsemigroups/semigroups.h" + #include "pkg.h" ++ + #include "rnams.h" +-#include "src/compiled.h" // GAP headers + +-using libsemigroups::Semigroup; ++using libsemigroups::FroidurePin; + + // Typedef for readability, an en_semi_obj_t should be an Obj of TNUM_OBJ = + // T_SEMI and SUBTYPE_OF_T_SEMI = T_SEMI_SUBTYPE_ENSEMI +@@ -57,12 +60,12 @@ enum en_semi_t { + + // C++ functions + +-size_t semi_obj_get_batch_size(gap_semigroup_t so); +-bool semi_obj_get_report(gap_semigroup_t so); +-gap_list_t semi_obj_get_gens(gap_semigroup_t so); +-gap_rec_t semi_obj_get_fropin(gap_semigroup_t so); +-en_semi_t semi_obj_get_type(gap_semigroup_t so); +-Semigroup* semi_obj_get_semi_cpp(gap_semigroup_t so); ++size_t semi_obj_get_batch_size(gap_semigroup_t so); ++bool semi_obj_get_report(gap_semigroup_t so); ++gap_list_t semi_obj_get_gens(gap_semigroup_t so); ++gap_rec_t semi_obj_get_fropin(gap_semigroup_t so); ++en_semi_t semi_obj_get_type(gap_semigroup_t so); ++FroidurePin<Element const*>* semi_obj_get_semi_cpp(gap_semigroup_t so); + + static inline en_semi_t en_semi_get_type(en_semi_obj_t es) { + SEMIGROUPS_ASSERT(TNUM_OBJ(es) == T_SEMI +@@ -84,37 +87,32 @@ static inline size_t en_semi_get_degree(en_semi_obj_t es) { + return CLASS_OBJ<size_t>(es, 3); + } + +-Converter* en_semi_get_converter(en_semi_obj_t es); +-Semigroup* en_semi_get_semi_cpp(en_semi_obj_t es); ++Converter* en_semi_get_converter(en_semi_obj_t es); ++FroidurePin<Element const*>* en_semi_get_semi_cpp(en_semi_obj_t es); + + // GAP level functions for IsEnumerableSemigroupRep + +-gap_list_t EN_SEMI_AS_LIST(Obj self, gap_semigroup_t so); +-gap_list_t EN_SEMI_AS_SET(Obj self, gap_semigroup_t so); +-gap_int_t EN_SEMI_CURRENT_MAX_WORD_LENGTH(Obj self, gap_semigroup_t so); +-gap_int_t EN_SEMI_CURRENT_NR_RULES(Obj self, gap_semigroup_t so); +-gap_int_t EN_SEMI_CURRENT_POSITION(Obj self, +- gap_semigroup_t so, +- gap_element_t x); ++gap_list_t EN_SEMI_AS_LIST(Obj self, gap_semigroup_t so); ++gap_list_t EN_SEMI_AS_SET(Obj self, gap_semigroup_t so); ++gap_int_t EN_SEMI_CURRENT_MAX_WORD_LENGTH(Obj self, gap_semigroup_t so); ++gap_int_t EN_SEMI_CURRENT_NR_RULES(Obj self, gap_semigroup_t so); ++gap_int_t ++ EN_SEMI_CURRENT_POSITION(Obj self, gap_semigroup_t so, gap_element_t x); + gap_int_t EN_SEMI_CURRENT_SIZE(Obj self, gap_semigroup_t so); + gap_list_t EN_SEMI_CAYLEY_TABLE(Obj self, gap_semigroup_t so); + gap_semigroup_t EN_SEMI_CLOSURE(Obj self, + gap_semigroup_t new_so, + gap_semigroup_t old_so, + gap_list_t plist); +-gap_semigroup_t EN_SEMI_CLOSURE_DEST(Obj self, +- gap_semigroup_t so, +- gap_list_t coll); +-gap_element_t EN_SEMI_ELEMENT_NUMBER(Obj self, +- gap_semigroup_t so, +- gap_int_t pos); +-gap_element_t EN_SEMI_ELEMENT_NUMBER_SORTED(Obj self, +- gap_semigroup_t so, +- gap_int_t pos); ++gap_semigroup_t ++EN_SEMI_CLOSURE_DEST(Obj self, gap_semigroup_t so, gap_list_t coll); ++gap_element_t ++EN_SEMI_ELEMENT_NUMBER(Obj self, gap_semigroup_t so, gap_int_t pos); ++gap_element_t ++ EN_SEMI_ELEMENT_NUMBER_SORTED(Obj self, gap_semigroup_t so, gap_int_t pos); + gap_list_t EN_SEMI_ELMS_LIST(Obj self, gap_semigroup_t so, gap_list_t poslist); +-gap_semigroup_t EN_SEMI_ENUMERATE(Obj self, +- gap_semigroup_t so, +- gap_int_t limit); ++gap_semigroup_t ++ EN_SEMI_ENUMERATE(Obj self, gap_semigroup_t so, gap_int_t limit); + gap_list_t EN_SEMI_FACTORIZATION(Obj self, gap_semigroup_t so, gap_int_t pos); + gap_list_t EN_SEMI_LEFT_CAYLEY_GRAPH(Obj self, gap_semigroup_t so); + gap_int_t EN_SEMI_LENGTH_ELEMENT(Obj self, gap_semigroup_t so, gap_int_t pos); +@@ -123,9 +121,8 @@ gap_list_t EN_SEMI_IDEMS_SUBSET(Obj self, gap_semigroup_t so, gap_list_t list); + gap_bool_t EN_SEMI_IS_DONE(Obj self, gap_semigroup_t so); + gap_int_t EN_SEMI_NR_IDEMPOTENTS(Obj self, gap_semigroup_t so); + gap_int_t EN_SEMI_POSITION(Obj self, gap_semigroup_t so, gap_element_t x); +-gap_int_t EN_SEMI_POSITION_SORTED(Obj self, +- gap_semigroup_t so, +- gap_element_t x); ++gap_int_t ++ EN_SEMI_POSITION_SORTED(Obj self, gap_semigroup_t so, gap_element_t x); + gap_list_t EN_SEMI_RELATIONS(Obj self, gap_semigroup_t so); + gap_list_t EN_SEMI_RIGHT_CAYLEY_GRAPH(Obj self, gap_semigroup_t so); + gap_int_t EN_SEMI_SIZE(Obj self, gap_semigroup_t so); +diff --git a/src/uf.cc b/src/uf.cc +index ae663c7a8..63643dd4d 100644 +--- a/src/uf.cc ++++ b/src/uf.cc +@@ -26,9 +26,9 @@ + #include "semigroups-debug.h" + #include "src/compiled.h" + +-#include "libsemigroups/uf.h" ++#include "libsemigroups/uf.hpp" + +-using libsemigroups::UF; ++using libsemigroups::detail::UF; + + // GAP level functions + +@@ -67,7 +67,7 @@ Obj UF_FLATTEN(Obj self, Obj uf) { + } + + Obj UF_TABLE(Obj self, Obj uf) { +- UF::table_t* table = CLASS_OBJ<UF*>(uf)->get_table(); ++ UF::table_type* table = CLASS_OBJ<UF*>(uf)->get_table(); + size_t size = table->size(); + Obj gap_table = NEW_PLIST_IMM(T_PLIST_CYC, size); + // IMMUTABLE since it should not be altered on the GAP level +@@ -79,7 +79,7 @@ Obj UF_TABLE(Obj self, Obj uf) { + } + + Obj UF_BLOCKS(Obj self, Obj uf) { +- UF::blocks_t const* blocks = CLASS_OBJ<UF*>(uf)->get_blocks(); ++ UF::blocks_type const* blocks = CLASS_OBJ<UF*>(uf)->get_blocks(); + size_t size = blocks->size(); + size_t i, j; + +diff --git a/tst/standard/congfpmon.tst b/tst/standard/congfpmon.tst +index c69ad7356..33b51b1d1 100644 +--- a/tst/standard/congfpmon.tst ++++ b/tst/standard/congfpmon.tst +@@ -96,12 +96,9 @@ false + gap> class1 = class2; + false + gap> enum := Enumerator(class1);; +-gap> enum[3]; +-(m2*m1)^2 +-gap> enum[11]; +-m2*m1*m2 +-gap> Position(enum, M.2 * M.1 * M.2 * M.1); +-3 ++gap> AsSSortedList(enum); ++[ m2, m1^2, m1*m2, m2*m1, m1^2*m2, m1*m2*m1, m2*m1*m2, m1^2*m2*m1, (m1*m2)^2, ++ (m2*m1)^2, (m1*m2)^2*m1 ] + gap> Size(enum); + 11 + gap> class1 * class2 = EquivalenceClassOfElement(cong, M.2 ^ 20 * M.1 ^ 42); +@@ -164,11 +161,11 @@ gap> class1 = class2; + false + gap> enum := Enumerator(class1);; + gap> enum[3]; +-m1^2 ++m2*m1 + gap> enum[11]; +-m2^2*m1^2 ++m2*m1^3 + gap> Position(enum, M.2 * M.1 * M.2 * M.1); +-13 ++12 + gap> Size(enum); + 30 + +@@ -232,7 +229,7 @@ gap> class1 = class2; + false + gap> enum := Enumerator(class1);; + gap> enum[3]; +-m1*m2 ++m2^2 + gap> enum[11]; + m1*(m1*m2)^2*m1^3 + gap> Position(enum, M.1 * (M.1 * M.2) ^ 2 * M.1 ^ 3);