[arch-commits] Commit in gap/repos (5 files)

Antonio Rojas arojas at archlinux.org
Mon Jan 13 15:20:51 UTC 2020


    Date: Monday, January 13, 2020 @ 15:20:51
  Author: arojas
Revision: 552379

archrelease: copy trunk to community-staging-x86_64

Added:
  gap/repos/community-staging-x86_64/
  gap/repos/community-staging-x86_64/PKGBUILD
    (from rev 552378, gap/trunk/PKGBUILD)
  gap/repos/community-staging-x86_64/gap.sh
    (from rev 552378, gap/trunk/gap.sh)
  gap/repos/community-staging-x86_64/libsemigroups-1.0.patch
    (from rev 552378, gap/trunk/libsemigroups-1.0.patch)
  gap/repos/community-staging-x86_64/normalizinterface-missing-include.patch
    (from rev 552378, gap/trunk/normalizinterface-missing-include.patch)

-----------------------------------------+
 PKGBUILD                                |  142 +
 gap.sh                                  |    7 
 libsemigroups-1.0.patch                 | 2244 ++++++++++++++++++++++++++++++
 normalizinterface-missing-include.patch |   12 
 4 files changed, 2405 insertions(+)

Copied: gap/repos/community-staging-x86_64/PKGBUILD (from rev 552378, gap/trunk/PKGBUILD)
===================================================================
--- community-staging-x86_64/PKGBUILD	                        (rev 0)
+++ community-staging-x86_64/PKGBUILD	2020-01-13 15:20:51 UTC (rev 552379)
@@ -0,0 +1,142 @@
+# Maintainer: Antonio Rojas <arojas at archlinux.org>
+# Contributor:  TDY <tdy at archlinux.info>
+# Contributor: Rémy Oudompheng <oudomphe at clipper.ens.fr>
+
+pkgbase=gap
+pkgname=(gap gap-doc gap-packages)
+pkgver=4.10.2
+pkgrel=10
+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
+         git+https://github.com/gap-packages/NormalizInterface#commit=cd69a42
+         normalizinterface-missing-include.patch)
+sha256sums=('11175bed0234101643d510d4ab94c44db30bd303bfe63d86b9b86ae67cff9e49'
+            '143fb8a79a52c007903cce13407850df309ef803a9b00398d05169355917de46'
+            'ccd95de4f48d26b73d6df7c1847855f68ee70644d130d32f14213988c3e286e3'
+            'SKIP'
+            '2410dfc69f1f4d2f320e91590d55e59c7b557637f9f60b9e609b318cfc21c181')
+makedepends=(libxaw givaro mpfi normaliz boost libsemigroups c-xsc zeromq fplll polymake wget chrpath fmt git)
+
+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
+
+# Update NormalizInterface to support recent normaliz
+  rm -r pkg/NormalizInterface-1.0.2
+  cp -r ../NormalizInterface pkg
+  cd pkg/NormalizInterface
+  patch -p1 -i "$srcdir"/normalizinterface-missing-include.patch
+
+  cd ../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
+  export MAKEFLAGS="-j1"
+  ../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 552378, gap/trunk/gap.sh)
===================================================================
--- community-staging-x86_64/gap.sh	                        (rev 0)
+++ community-staging-x86_64/gap.sh	2020-01-13 15:20:51 UTC (rev 552379)
@@ -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 552378, gap/trunk/libsemigroups-1.0.patch)
===================================================================
--- community-staging-x86_64/libsemigroups-1.0.patch	                        (rev 0)
+++ community-staging-x86_64/libsemigroups-1.0.patch	2020-01-13 15:20:51 UTC (rev 552379)
@@ -0,0 +1,2244 @@
+From ff6e172a492af2465fd7465da64298353cc15cc5 Mon Sep 17 00:00:00 2001
+From: James Mitchell <jdm3 at 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);

Copied: gap/repos/community-staging-x86_64/normalizinterface-missing-include.patch (from rev 552378, gap/trunk/normalizinterface-missing-include.patch)
===================================================================
--- community-staging-x86_64/normalizinterface-missing-include.patch	                        (rev 0)
+++ community-staging-x86_64/normalizinterface-missing-include.patch	2020-01-13 15:20:51 UTC (rev 552379)
@@ -0,0 +1,12 @@
+diff --git a/src/normaliz.cc b/src/normaliz.cc
+index a2ef45d..9768988 100644
+--- a/src/normaliz.cc
++++ b/src/normaliz.cc
+@@ -27,6 +27,7 @@
+ 
+ #include "libnormaliz/cone.h"
+ #include "libnormaliz/map_operations.h"
++#include "libnormaliz/dynamic_bitset.h"
+ 
+ #include <vector>
+ 



More information about the arch-commits mailing list