% \iffalse meta-comment
%
%% File: groupthm.dtx
%
% Copyright (C) 2022 Maximilian Keßler
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
% license or (at your option) any later version.  The latest version
% of this license is in the file
%
%    https://www.latex-project.org/lppl.txt
%
% -----------------------------------------------------------------------
%<package>\ProvidesExplPackage{groupthm}{2022/01/17}{0.0.1}{Grouped theorems.}
%
%<*driver>
\documentclass[full,kernel]{l3doc}
\usepackage{mkessler-todo}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \title{^^A
%   The \pkg{groupthm} package^^A
% }
%
% \author{^^A
%      Maximilian Keßler
% }
%
% \date{Released 2022-01-12}
%
% \maketitle
%
%
% \NewDocumentCommand{\kw}{m}
% {%
%  \texttt{#1}%
% }
%
% \NewDocumentCommand{\vocab}{m}
% {%
%  \emph{#1}%
% }
% 
% \ExplSyntaxOn
% \NewDocumentCommand { \mymeta } { O{} m }
% {
%   \meta[#1]{#2}
%   \__codedoc_special_index_module:nnnnN { #2 } { #2 } { meta } { usage } { \c_false_bool}
% }
% \ExplSyntaxOff
%
%
%
% \begin{documentation}
% 
% \tableofcontents
% \listoftodos
% \newpage
% 
% \begin{itemize}
%   \item Inheritance
%   \item Appending to groups
%   \item default group integration
%   \item better error message to avoid low level tex errors in any case
%   \item potentially: detection of star / nonstar misuse
%   \item add command to define group rule for all existing groups
%   \item various info commands on defined groups?
%   \item debugging information?
% \end{itemize}
% A central thing in \LaTeX is the usage of \enquote{theorems}.
% With \enquote{theorems} we actually mean \enquote{environments} that typically
% have a title, some style applied to their contents and are numbered throughout 
% the document, often later referenced by number and / or name.
% 
% Mechanisms for generating such environments are packages like
% \pkg{amsthm}, \pkg{ntheorem}, \pkg{thmtools}.
% 
% While the mechanism in \pkg{thmtools} are pretty versatile and suffice
% for almost all needs, it is pretty time-consuming to largely change
% the behavior of environments, or have small variants of these.
% 
% This package aims at both providing a versatile mechanism, \mymeta{theorem group}s,
% to structure theorems into groups that can subsequently easily altered,
% as well as a mechanism for easily generating \mymeta{theorem families}.
% 
% As the author is of the opinion that of the mentioned theorem controlling packages
% \pkg{thmtools} provides the most versatile interface, the \pkg{groupthm}
% will be working on top of \pkg{thmtools} and use this as a backend for declaring
% the \mymeta{theorem}s themselves.
% 
% Thus, any styles supported by \pkg{thmtools} will be supported by \pkg{groupthm}
% as well, by passing them to \pkg{thmtools}.
% 
% \section{Concepts}
% 
% \subsection{Theorem groups}
% \label{sec:theorem-groups}
% A \mymeta{theorem group} is some named group holding some properties for
% the \mymeta{theorem}s that are contained in this group.
% Each \mymeta{theorem} can, when declared, be part of arbitrarily many \mymeta{theorem group}s,
% and will be subject to the styles these groups defined.
% 
% This enables to group similar \mymeta{theorem}s and alter them at a late stage of
% document development in a unique manner, by only having to change the
% definition of the \mymeta{theorem group}, and not all \mymeta{theorem}s separately.
% 
% The properties. such a \mymeta{theorem group} can hold are as follows
% 
% 
% \begin{description}
%   \item[\kw{prefix}] A prefix (any \mymeta{token list}) that will be inserted
%     before the theorem name of each member of this \mymeta{theorem group}.
%   \item[\kw{suffix}] A suffix (any \mymeta{token list}) that will be
%     inserted before the theorem name for each member of this \mymeta{theorem group}.
%     This could be e.g.~some \enquote{$\star$} appended to the name to indicate
%     variants of environments.
%   \item[\kw{mapname}] A \mymeta{function} (some macro that takes exactly one argument)
%     that is applied to the \kw{name}.
%   \item[\kw{thmtools}] A \mymeta{clist} of key-value pairs that are passed to the underlying
%     \pkg{thmtools} backend of the \mymeta{theorem}.
%     This allows e.g.~to set the \kw{topskip} of a certain class of \mymeta{theorem}s.
% \end{description}
% 
% The most versatile key here is certainly the \kw{thmtools} key,
% providing the most customization to an end user (like you).
% 
% As mentioned, each \mymeta{theorem} can be member of arbitrary many \mymeta{theorem group}s,
% and will posses their corresponding properties.
% 
% To adjust finer controlling of these \mymeta{theorem group}s, \mymeta{theorem group}s can inherit from each other, and \mymeta{theorem group}s are subject to a hierarchy that controls precedence in case
% of conflicting properties of different \mymeta{theorem group}s a \mymeta{theorem} may be part of.
% 
% This hierarchy can of course be controlled by the user.
% 
% \subsection{Grouped theorems}
% 
% A \mymeta{grouped theorem} is just a theorem that is a member of
% a given set of groups (possibly empty).
% It behaves just a regular theorem, except that by changing the definition of
% its theorem groups, we can alter its behavior.
% 
% 
% It is the core concept of the \pkg{groupthm} package.
% For brevity, we will often talk about \enquote{theorems},
% although in fact we mean \enquote{grouped theorems}.
% 
% \subsection{Theorem families}
% Often, one needs some small \mymeta{theorem variant}s of some \mymeta{theorem}, the most typical
% example being \vocab{starred} version of \mymeta{theorem}s that are not numbered
% in contrast to their counterparts.
% 
% \begin{verbatim}
%   \begin{theorem}
%     This theorem is numbered.
%   \end{theorem}
% 
%   \begin{theorem*}
%     This theorem is not numbered.
%     Probably because we do not want a reference to it.
%   \end{theorem*}
% \end{verbatim}
% \todo{insert code example output}
% 
% \pkg{groupthm} extends this idea and provides a versatile mechanism to define a
% \mymeta{theorem family}, which is based on some \mymeta{theorem name} and
% parses additional arguments / syntax to control the \mymeta{theorem groups}
% that this environment is a part of.
% 
% So, in addition the name of a \mymeta{theorem}, the corresponding environment will
% accept some options and toggle the membership of certain \mymeta{theorem groups},
% thus further customizing its appearance.
% 
% This can lead e.g.~to usages like the following:
% 
% \begin{verbatim}
%   \begin{theorem}*
%     This theorem has a visual * at its name.
%   \end{theorem}
% \end{verbatim}
% \todo{code}
% 
% Providing this consists of two parts:
% declaring the \mymeta{theorem family} by listing the groups that can be toggled
% by this \mymeta{theorem family}, and declaring the actual option parsing
% of the \mymeta{theorem family}, which then controls the membership in these groups
% (and of course prior to this the definition of the desired \mymeta{theorem group}s).
% 
% 
% 
% \subsection{General notions}
% 
% In many cases, there are a number of variants of some command,
% call it for example \cs{Foo}.
% Then the documentation will look like
% %
% \begin{function}{\NewFoo, \RenewFoo, \ProvideFoo, \DeclareFoo}
%   Defines some \kw{foo} \ldots
% \end{function}
% %
% and will not mention anything about the variants.
% This follows some general naming convention that also \pkg{xparse} uses,
% and is the following:
% 
%   \begin{description}
%     \item[\cs{NewFoo}]
% 
%       Defines \kw{foo} if not defined already.
%       This emits an error in case it has been defined yet.
% 
%     \item[\cs{RenewFoo}]
% 
%       Redefines \kw{foo} if defined already.
%       This emits an error in case it has \emph{not} been defined yet.
% 
%     \item[\cs{ProvideFoo}]
% 
%       Defines \kw{foo} if it is not defined already.
%       This does not emit an error if \kw{foo} is already defined
%       (and has no effect in this case).
% 
%     \item[\cs{DeclareFoo}]
% 
%       Defines \kw{foo} in disregard of any
%       existing definitions. Any old definition will be overwritten (if present).
%   \end{description}
% %
%   The documentation margin will list all variants that are available,
%   they follow their respective conventions.
% 
% 
%   \begin{texnote}
%     The \pkg{thmtools} package, unfortunately, dose not follow this convention,
%     as its \cs{declaretheorem} command actually behaves like a \cs{newtheorem}.
%     The reason for this is that \pkg{amsthm} already defines \cs{newtheorem}.
% 
%     Thus, actually, calls to \cs{NewGroupedTheorem} will have an underlying
%     \cs{declaretheorem}, but you do not have to bother with this.
%   \end{texnote}
% 
% \section{Theorem groups}
% 
% \subsection{Defining theorem groups}
% 
% \begin{function}{\NewTheoremGroup, \RenewTheoremGroup, \ProvideTheoremGroup, \DeclareTheoremGroup}
%   \begin{syntax}
%     \cs{NewTheoremGroup}\oarg{keys}\marg{theorem group}
%   \end{syntax}
%   
%   This introduces a new \mymeta{theorem group} with the given name.
%   The \mymeta{keys} available are the same as introduced in \autoref{sec:theorem-groups}:
% 
%   \begin{description}
%     \item
% 
%       \kw{prefix} = \mymeta{token list}.
%       Insert the \mymeta{token list} in front of the theorem name.
% 
%     \item
% 
%       \kw{suffix} = \mymeta{token list}.
%       Insert the \mymeta{token list} after the theorem name.
% 
%     \item
% 
%       \kw{mapname} = \mymeta{function}.
%       Apply this \mymeta{function} to the theorem name.
% 
%     \item
% 
%       \kw{thmtools} = $\{$\mymeta{clist}$\}$.
%       Pass these options to \pkg{thmtools}.
% 
%   \end{description}
% 
%   For uniqueness of the given options, the \mymeta{clist} given to the \kw{thmtools} key
%   has to be surrounded by a pair of braces.
% 
%   \begin{texnote}
%     The \kw{mapname} is expected to be a function of \cs{fun:n}.
%     It is subject to an \kw{x}-type expansion prior to being passed further to \pkg{thmtools}.
%   \end{texnote}
% 
% \end{function}
% 
% \subsection{Controlling theorem group precedence}
% 
% \begin{function}{\DeclareTheoremGroupRule}
%     \begin{syntax}
% \cs{DeclareTheoremGroupRule}\oarg{keyname}%
% \marg{theorem group 1}\marg{relation}\marg{theorem group 2}
%     \end{syntax}
%   
%   This declares some relation between the two theorem groups,
%   controlling their order of application in case a theorem is member
%   of both groups.
% 
%   The \mymeta{keyname} can be one of \kw{prefix}, \kw{suffix}, \kw{mapname}, \kw{thmtools}.
%   If present, it declares the corresponding relation only for this subkey.
%   This can lead to \mymeta{theorem group 1} overwriting \mymeta{theorem group 2} when given
%   contradictory \pkg{thmtools} options, but the \kw{prefix} of \mymeta{theorem group 1}
%   being applied after the one of \mymeta{theorem group 2}.
%   When the \mymeta{keyname} is not given, this applies to all keywords.
% 
%   \begin{texnote}
%     The \mymeta{keyname} is just passed to the corresponding argument
%     of the \kw{lthooks} package.
%     If the option argument is not present, \kw{??} is used, this has the described effect.
%   \end{texnote}
% 
%   The behavior of the relations is based on the \cs{DeclareHookRule} command
%   from the \pkg{xparse} package, and all respective keys are in fact available,
%   but typically not needed, so the reader of this manual is referred to the
%   \todoref{lthooks} packages documentation for a list of the full keys.
%   For us, the following list will suffice:
% 
%   \begin{description}
%     \item[\kw{higher} or \kw{after} or \kw{\string>}]
%       
%       \mymeta{theorem group 1} takes precedence over \mymeta{theorem group 2}.
%       Its \kw{prefix} is applied after the one of \mymeta{theorem group 2}.
% 
%     \item[\kw{lower} or \kw{before} or \kw{\string<}]
% 
%       \mymeta{theorem group 2} takes precedence over \mymeta{theorem group 1}.
%       Its \kw{prefix} is applied after the one of \mymeta{theorem group 1}.
% 
%   \end{description}
% 
%   \begin{texnote}
%     The \mymeta{relation} is first stripped,
%     then checked if it matches either \kw{higher} or \kw{lower}
%     and in this case replaced by the corresponding \pkg{lthooks} variant
%     of the relation.
%     The rest is passed as is to \pkg{lthooks} and thus subject to the usual
%     normalization process of \pkg{lthooks}.
%   \end{texnote}
% 
% \end{function}
% 
% 
% \subsection{Inheritance of theorem groups}
% \begin{function}{\AddTheoremGroupParent}
%   \begin{syntax}
%     \cs{AddTheoremGroupParent}\marg{theorem group 1}\marg{theorem group 2}
%   \end{syntax}
%   Declares \mymeta{theorem group 1} to \enquote{inherit} all properties
%   of \mymeta{theorem group 2}.
%   In other words, \mymeta{theorem group 2} is a parent of \mymeta{theorem group 1}
%   in a usual inheritance graph.
% 
%   The definitions of the groups themselves are unchanged,
%   but each new theorem defined with \mymeta{theorem group 1} will also
%   have the properties of \mymeta{theorem group 2}.
% 
%   Inheritance is transitive, when defining a new theorem, we just flatten out the
%   inheritance graph and apply all properties.
% 
%   Inheritance is subject to the usual theorem group hierarchies as discussed in \todoref.
%   This can even yield to situations, where \mymeta{theorem group 1} inherits
%   from \mymeta{theorem group 2}, but \mymeta{theorem group 2} overwrites
%   \mymeta{theorem group 1}.
% \end{function}
% 
% \subsection{Appending to theorem groups}
% \begin{function}{\AppendToTheoremGroup}
%   \begin{syntax}
%     \cs{AppendToTheoremGroup}\oarg{keys}\marg{theorem group}
%   \end{syntax}
%   Adds the properties given as \mymeta{keys} to the theorem group.
%   The syntax for the \mymeta{keys} is the same as in \cs{NewTheoremGroup}.
% \end{function}
% 
% \subsection{Default theorem groups}
% 
% There are a number of theorem groups that \pkg{groupthm} will initially declare
% and that have certain special treatment in some places.
% 
% \begin{function}{all}
%   Every declared grouped theorem is a member of this group.
% 
%   Initially, this group has no effect (i.e.~an empty property list).
%   It can be redefined by the user to alter the behavior of all grouped theorems
%   in a unified way.
% 
%   It is the lowest theorem group in the hierarchy by default.
% \end{function}
% 
% \begin{function}{starred}
%   This is group that shall represent the standard variant of theorems that
%   are called with a \enquote{*} in the environment name.
%   Theorems of this group are not numbered.
% 
%   The user should not add theorems to this group by hand,
%   as this is handled in a unified way by default.
%   \todoref{}
% 
%   It is the highest theorem group in the hierarchy by default,
%   except for \texttt{unnumbered},
%    with which it has no relation.
% \end{function}
% \addtocounter{footnote}{-1}
% 
% \begin{function}{unnumbered}
%   Theorems in this group are not numbered.
% 
%  It is the highest theorem group in the hierarchy by default,
%  except for \cs{starred},
%  with which it has no relation.
% \end{function}
% 
% The reason for the two groups \kw{starred} and \kw{unnumbered}
% to both exist is that the \kw{starred} group is \emph{meant} to be applied
% to theorems that were called with a \enquote{*} in their name (thus the name),
% whereas the \enquote{unnumbered} group \emph{means} that the environment
% is 'just unnumbered'.
% 
% This has two reasons:
% First, this enables more fine-tuning of the behavior of the theorems in post-processing
% of a document.
% Second, more importantly, this distinguishes semantically between the environments
% \kw{theorem} and \kw{theorem*}, even if \kw{theorem} is in the \kw{unnumbered} group.
% 
% So assuming that \kw{theorem} is member of the \kw{unnumbered} group, both calls
% 
% \begin{verbatim}
%   \begin{theorem}
%     This is not numbered.
%   \end{theorem}
%   \begin{theorem*}
%     This is not numbered.
%   \end{theorem*}
% \end{verbatim}
% 
% are defined and will produce the same result by default, but we could still
% change the definition of the \kw{starred} group later to do anything we want.
% 
% \begin{texnote}
%   The mentioned hierarchies are kept intact for newly defined theorem groups,
% i.e.~for each new such group, two theorem group rules are created.
% \end{texnote}
% 
% \section{Grouped Theorems}
% 
% \subsection{Defining grouped theorems}
% 
% \begin{function}{\NewGroupedTheorem, \ProvideGroupedTheorem}
%   \begin{syntax}
%     \cs{NewGroupedTheorem}\oarg{keys}\marg{theorem name}
%   \end{syntax}
%   This defines \mymeta{theorem name}  as a new theorem environment.
%   Its properties can be set by the following keys:
% 
%   \begin{description}
% 
%     \item
% 
%       \kw{name} $=$ \mymeta{displayed name}.
%       If given, this is the displayed name of the environment in the document.
%       If not present, the \mymeta{theorem name} is also used as the \mymeta{displayed name}
%       in capitalized form.
% 
%     \item
% 
%       \kw{group} $=$ \marg{clist}
% 
%       Makes this theorem a member of the listed groups.
%       It will inherit all respective properties of these groups.
% 
%       If groups are present more than one time, this has no (additional) effect.
% 
%     \item
% 
%       \kw{thmtools} = \marg{clist}
% 
%       Passes these option to the \pkg{thmtools} environment that is declared internally.
%     
%   \end{description}
% \end{function}
% 
% \begin{function}{\NewGroupedTheorem*,\ProvideGroupedTheorem*}
%   \begin{syntax}
%     \cs{NewGroupedTheorem*}\oarg{keys}\marg{theorem name}
%   \end{syntax}
%   Behaves the same as \cs{NewGroupedTheorem},
%   but also adds the theorem to the default \kw{unnumbered} group,
%   thus resulting in the environment not being numbered.
% 
%   This is thus equivalent to using \cs{NewGroupedTheorem} and adding the
%   \kw{unnumbered} group.
% \end{function}
% 
% \begin{function}{\NewTheorem, \ProvideTheorem}
%   \begin{syntax}
%     \cs{NewTheorem}\oarg{keys}\marg{theorem name}
%   \end{syntax}
% 
%   This behaves essentially the same as \cs{NewGroupedTheorem},
%   but will define two grouped theorems, namely \mymeta{theorem name} and \mymeta{theorem name*}.
% 
%   The \mymeta{theorem name*} environment has the same properties as the \mymeta{theorem name},
%   but will be member of the \kw{starred} theorem group.
%   It is thus not recommended to call \cs{NewTheorem}
%   with an actual \enquote{*} in the environment name, since both environments
%   will be generated.
% \end{function}
% 
% \begin{function}{\NewTheorem*, \ProvideTheorem*}
%   \begin{syntax}
%     \cs{NewTheorem}\oarg{keys}\marg{theorem name}
%   \end{syntax}
%   Combines the behavior of \cs{NewGroupedTheorem*} and \cs{NewTheorem}, thus
%   declaring \mymeta{theorem} to (additionally) be member of the \kw{unnumbered}
%   and \mymeta{theorem*} to (additionally) be member of the \kw{starred} group.
% 
%   As mentioned in \todoref, by default both environments will behave the same.
% \end{function}
% 
% \subsection{Defining families of grouped theorems}
% 
% \begin{function}{\NewGroupedTheoremFamily, \ProvideGroupedTheoremFamily}
%   \begin{syntax}
%     \cs{NewTheoremFamily}\oarg{keys}\marg{theorem name}
%   \end{syntax}
% 
%   Defines a family of grouped theorems.
%   The \mymeta{keys} accept the same arguments as the \cs{NewGroupedTheorem} macro.
%   However, for each \emph{subset} of the given groups,
%   a grouped theorem is defined.
% 
%   These grouped theorems are not meant to be accessed directly (but could),
%   so we omit their actual (internal) names here.
%   To call these, some \kw{GroupedTheoremFamilyOptions} have to specified,
%   see \cs{NewGroupedTheoremFamilyOptions}.
% \end{function}
% 
% \begin{function}{\NewGroupedTheoremFamily*, \ProvideGroupedTheoremFamily*}
%   Behaves the same as \cs{NewGroupedTheoremFamily}, but also adds each variant
%   to the default \kw{unnumbered} group, thus resulting in the environments not being
%   numbered.
% 
%   This is \emph{almost} equivalent to calling \cs{NewGroupedTheoremFamily}
%   with the \kw{unnumbered} group being present, as it does not generate the variants
%   where the \kw{unnumbered} group is not present.
% \end{function}
% 
% \begin{function}{\NewTheoremFamily, \ProvideTheoremFamily}
%   This behaves essentially the same as \cs{NewGroupedTheoremFamily},
%   but will add the \kw{starred} group to the list of groups and also generate variants
%   for these.
% 
%   It is thus not recommended to call \cs{NewTheoremFamily} with the \kw{starred}
%   group explicitly given, since this is added anyways.
% \end{function}
% 
% \begin{function}{\NewTheoremFamily*, \ProvideTheoremFamily*}
%   Combines the behavior of \cs{NewGroupedTheoremFamily*} and \cs{NewTheoremFamily}, thus
%   declaring all variants to (additionally) be member of the \kw{unnumbered}
%   group, and also generates definitions with and without the \kw{starred} group.
% 
%   As mentioned in \todoref, by default both environments will behave the same.
% \end{function}
% 
% 
% \begin{function}{\AddTheoremToGroup}
%   \begin{syntax}
%     \cs{AddTheoremToGroup}\marg{theorem group}
%   \end{syntax}
%   
%   Means that the current invocation of a theorem family should
%   call the theorem variant with the given group.
% 
%   Can only be used in the body of \cs{NewGroupedTheoremFamilyOptions} or similarly.
% \end{function}
% 
% \begin{function}
% {
%   \NewGroupedTheoremFamilyOptions, \RenewGroupedTheoremFamilyOptions,
%   \ProvideGroupedTheoremFamilyOptions, \DeclareGroupedTheoremFamilyOptions
% }
% \begin{syntax}
%   \cs{NewGroupedTheoremFamilyOptions}\marg{theorem name}\marg{argument specifiation}%
%   \marg{selection body}
% \end{syntax}
% 
% Defines a new environment with options, given by \mymeta{theorem name}.
% The \mymeta{argument specification} can be any valid \pkg{xparse} argument specification.
% 
% The \mymeta{selection body} is there to process the options of
% the \mymeta{argument specification} and select which variant of the \mymeta{theorem name}
% to enter.
% The arguments are available as usual with \pkg{xparse} by \kw{\#1}, \kw{\#2}, \ldots
% 
% The body may also call any number of \cs{AddTheoremToGroup} calls,
% which enables the corresponding groups.
% 
% When the environment is called within the document, the options are parsed
% as with \pkg{xparse} and the \mymeta{selection body} is executed.
% Immediately after, the theorem variant of \mymeta{theorem name} with the specified groups
% by \cs{AddTheoremToGroup} is called.
% 
% At the end of the environment, the \mymeta{selection body} is executed again and the
% called theorem variant is ended again.
% 
% The possible theorem variants that the newly declared environment will call
% \emph{have to be generated subsequently} by a call to the \cs{NewGroupedTheoremFamily}
% function.
%   
% \end{function}
% 
% \begin{function}
%   {
%     \NewGroupedTheoremFamilyOptions*, \RenewGroupedTheoremFamilyOptions*,
%     \ProvideGroupedTheoremFamilyOptions*, \DeclareGroupedTheoremFamilyOptions*
%   }
%   \begin{syntax}
%   \cs{NewGroupedTheoremFamilyOptions*}\marg{theorem name}\marg{argument specifiation}%
%   \marg{selection body}
%   \end{syntax}
%   
%   Does the same as \cs{NewGroupedTheoremFamilyOptions},
%   but calls the variants with the additional \kw{unnumbered} group.
% 
%   The possible theorem variants have to be generated
%   with the \cs{NewGroupedTheoremFamily*} command before.
% 
% \end{function}
% 
% \begin{function}
%   {
%     \NewTheoremFamilyOptions, \RenewTheoremFamilyOptions,
%     \ProvideTheoremFamilyOptions, \DeclareTheoremFamilyOptions
%   }
%   \begin{syntax}
%     \cs{NewTheoremFamilyOptions}\marg{theorem name}\marg{argument specifiation}%
%     \marg{selection body}
%   \end{syntax}
% 
%   This behaves essentially the same as \cs{NewGroupedTheoremFamilyOptions},
%   but also declares the environment \mymeta{theorem name*},
%   which behaves the same but calls the theorem variants with the additional \kw{starred}
%   subgroup.
% 
%   The possible theorem variants have to be generated with the \cs{NewTheoremFamily}
%   command before.
%   
% \end{function}
% 
% \begin{function}
%   {
%     \NewTheoremFamilyOptions*, \RenewTheoremFamilyOptions*,
%     \ProvideTheoremFamilyOptions*, \DeclareTheoremFamilyOptions*
%   }
%   \begin{syntax}
%     \cs{NewTheoremFamilyOptions*}\marg{theorem name}\marg{argument specifiation}%
%     \marg{selection body}
%   \end{syntax}
% 
%   Combines the behavior of \cs{NewGroupedTheoremFamilyOptions*} and \cs{NewTheoremFamilyOptions},
%   thus declaring both \mymeta{theorem name} and \mymeta{theorem name*} environments,
%   the latter calling the \kw{starred} variants of the theorem family,
%   and both of them calling \kw{unnumbered} variants of the family.
% 
%   The possible theorem variants have to be generated with the \cs{NewTheoremFamily*}
%   command before.
% 
% \end{function}
% 
% \section{\LaTeX3 interface}
%
% There is also an underlying \LaTeX3 interface provided by the package
% (and in fact, all prior documented macros are just wrappers around this
% internal programming interface.
%
% When building on top of this package, you can also use this interface,
% which is possibly easier to use.
%
% In general, for functions that use key-value syntax, there are typically
% three (public) versions of the command, namely
%
% \begin{itemize}
%   \item A \LaTeX3 command that requires all key-values as mandatory arguments,
%     so this does not use the key-value interface.
%     Use this if you already know with which keys you deal and know their
%     corresponding values.
%   \item A \LaTeX3 command having the first argument accepting the keys as a
%     comma-separated list.
%     Use this if you want to profit of the key-value syntax.
%   \item A \LaTeX2e document command. These were documented before,
%     and these just wrap the second type of command.
% \end{itemize}
% If the corresponding command would be something like \enquote{new foo},
% The syntax will typically be
% \begin{itemize}
%   \item \cs{groupthm_new_foo:mmm}\mymeta{mandatory args}\mymeta{optional args},
%     where the \mymeta{mandatory args} list the mandatory args of the \LaTeX2e
%     interface, and the \mymeta{optional args} list the optional args
%     of the key-value interface, but requiring them mandatory as well.
%   \item \cs{groupthm_new_foo_from_keys:mmm}\marg{keys}\mymeta{mandatory args}
%     where we pass a \texttt{clist} as the first argument and all mandatory args
%     as further mandatory arguments.
%   \item \cs{NewFoo}\oarg{keys}\mymeta{mandatory args},
%     where the keys can be passed optionally.
% \end{itemize}
% 
% \subsection{Theorem groups}
%
%
% \begin{function}
% {
%   \groupthm_new_group:nn,
%   \groupthm_renew_group:nn,
%   \groupthm_provide_group:nn,
%   \groupthm_declare_group:nn
% }
%   \begin{syntax}
%     \cs{groupthm_new_group:nn}\marg{keys}\marg{theorem group}
%   \end{syntax}
%
%    \LaTeX3 versions of \cs{NewTheoremGroup}, \cs{RenewTheoremGroup},
%    \cs{ProvideTheoremGroup} and \cs{DeclareTheoremGroup}
%
% \end{function}
% 
%
%
% \begin{function}
% {
%   \groupthm_new_group:nnnnn,
%   \groupthm_renew_group:nnnnn,
%   \groupthm_provide_group:nnnnn,
%   \groupthm_declare_group:nnnnn,
%   \groupthm_new_group:nVVVV,
%   \groupthm_renew_group:nVVVV,
%   \groupthm_provide_group:nVVVV,
%   \groupthm_declare_group:nVVVV
% }
%   \begin{syntax}
%     \cs{groupthm_new_group:nnnnn}\marg{theorem group}\marg{prefix tl}
%     \marg{suffix tl}\marg{mapname clist}\marg{thmtools clist}
%   \end{syntax}
%  
% Non-keyval versions of
% \cs{groupthm_new_group:nn},
% \cs{groupthm_renew_group:nn},
% \cs{groupthm_provide_group:nn}
% and
% \cs{groupthm_declare_group:nn}
%
% These take the individual values of the keyval keys directly, in the order
% indicated by the syntax specification.
% 
% \end{function}
% 
%
% \begin{function}{\groupthm_declare_group_rule:nnnn}
%    \begin{syntax}
%       \cs{groupthm_declare_group_rule:nnnn}\marg{keyname}\marg{theorem group 1}
%       \marg{relation}\marg{theorem group 2}
%    \end{syntax}
%
%  \LaTeX3 version of \cs{DeclareTheoremGroupRule}
%
% \end{function}
%
% 
% \subsection{Grouped theorems}
%
% \begin{function}{\groupthm_new_grouped_theorem_from_keys:nn, \groupthm_provide_grouped_theorem_from_keys:nn}
%    \begin{syntax}
%       \cs{groupthm_provide_grouped_theorem_from_keys:nn}\marg{keys}\marg{environment name}
%    \end{syntax}
%   
%   \LaTeX3 version of \cs{NewGroupedTheorem}, \cs{ProvideGroupedTheorem}
% 
%
% \end{function}
%
% \begin{function}
% {
%   \groupthm_new_grouped_theorem_star_from_keys:nn,
%   \groupthm_provide_grouped_theorem_star_from_keys:nn
% }
%    \begin{syntax}
%       \cs{groupthm_new_grouped_theorem_star_from_keys:nn}\marg{keys}\marg{environment name}
%    \end{syntax}
%
% 
%   \LaTeX3 version of \cs{NewGroupedTheorem*}, \cs{ProvideGroupedTheorem*}
%
%
% \end{function}
%
%
%
% \begin{function}{\groupthm_new_theorem_from_keys:nn, \groupthm_provide_theorem_from_keys:nn}
%    \begin{syntax}
%       \cs{groupthm_provide_theorem_from_keys:nn}\marg{keys}\marg{environment name}
%    \end{syntax}
%   
%   \LaTeX3 version of \cs{NewTheorem}, \cs{ProvideTheorem}
% 
%
% \end{function}
%
% \begin{function}{\groupthm_new_theorem_star_from_keys:nn, \groupthm_provide_theorem_star_from_keys:nn}
%    \begin{syntax}
%       \cs{groupthm_new_theorem_star_from_keys:nn}\marg{keys}\marg{environment name}
%    \end{syntax}
%
%   \LaTeX3 version of \cs{NewTheorem*}, \cs{ProvideTheorem*}
%
% \end{function}
%
% 
% \begin{function}
% {
%   \groupthm_new_grouped_theorem:nnnn,
%   \groupthm_provide_grouped_theorem:nnnn,
%   \groupthm_new_grouped_theorem_star:nnnn,
%   \groupthm_provide_grouped_theorem_star:nnnn,
%   \groupthm_new_theorem:nnnn,
%   \groupthm_provide_theorem:nnnn,
%   \groupthm_new_theorem_star:nnnn,
%   \groupthm_provide_theorem_star:nnnn
% }
%    \begin{syntax}
%       \cs{groupthm_new_theorem:nnnn}\marg{environment name}\marg{groups clist}
%       \marg{theorem name}\marg{thmtools keys}
%    \end{syntax}
% 
%   Non-keyval versions of above macros.
%
% \end{function}
% 
% 
% \subsection{Theorem families}
% 
%
% \begin{function}
%   {
%     \groupthm_new_grouped_theorem_family_from_keys:nn,
%     \groupthm_provide_grouped_theorem_family_from_keys:nn
%   }
%   \begin{syntax}
%     \cs{groupthm_new_grouped_theorem_family_from_keys:nn}\marg{keys}\marg{theorem family}
%   \end{syntax}
%
%   The \LaTeX3 versions of \cs{NewGroupedTheoremFamily} and \cs{ProvideGroupedTheoremFamily}
%
% \end{function}
% 
% 
% 
% \begin{function}
%   {
%     \groupthm_new_grouped_theorem_family_star_from_keys:nn,
%     \groupthm_provide_grouped_theorem_family_star_from_keys:nn
%   }
%   \begin{syntax}
%     \cs{groupthm_new_grouped_theorem_family_star_from_keys:nn}\marg{keys}\marg{theorem family}
%   \end{syntax}
%
%   The \LaTeX3 versions of \cs{NewGroupedTheoremFamily*} and \cs{ProvideGroupedTheoremFamily*}
%
% \end{function}
% 
% 
%
% \begin{function}
%   {
%     \groupthm_new_theorem_family_from_keys:nn,
%     \groupthm_provide_theorem_family_from_keys:nn
%   }
%   \begin{syntax}
%     \cs{groupthm_new_theorem_family_from_keys:nn}\marg{keys}\marg{theorem family}
%   \end{syntax}
%
%   The \LaTeX3 versions of \cs{NewTheoremFamily} and \cs{ProvideTheoremFamily}
%
% \end{function}
% 
% 
% 
% \begin{function}
%   {
%     \groupthm_new_theorem_family_star_from_keys:nn,
%     \groupthm_provide_theorem_family_star_from_keys:nn
%   }
%   \begin{syntax}
%     \cs{groupthm_new_theorem_family_star_from_keys:nn}\marg{keys}\marg{theorem family}
%   \end{syntax}
%
%   The \LaTeX3 versions of \cs{NewTheoremFamily*} and \cs{ProvideTheoremFamily*}
%
% \end{function}
% 
%
% \begin{function}
% {
%   \groupthm_new_grouped_theorem_family:nnnn,
%   \groupthm_provide_grouped_theorem_family:nnnn,
%   \groupthm_new_grouped_theorem_family_star:nnnn,
%   \groupthm_provide_grouped_theorem_family_star:nnnn,
%   \groupthm_new_theorem_family:nnnn,
%   \groupthm_provide_theorem_family:nnnn,
%   \groupthm_new_theorem_family_star:nnnn,
%   \groupthm_provide_theorem_family_star:nnnn
% }
%   \begin{syntax}
%     \cs{groupthm_new_grouped_theorem_family:nnnn}\marg{theorem family}     
%     \marg{groups}\marg{name}\marg{thmtools clist}
%   \end{syntax}
%
%  The non-key-value versions of the prior macros.
%
% \end{function}
% 
% \end{documentation}
% 
% 
% 
% 
% 
% 
% 
% 
% 
% 
% 
% 
% 
% \begin{implementation}
% 
% \section{\pkg{groupthm} implementation}
%
%    \begin{macrocode}
%<*package>
%    \end{macrocode}
%
%    \begin{macrocode}
%<@@=groupthm>
%    \end{macrocode}
%
%
%
%
% \subsection{Dependencies}
%
%
%
% First, we import other packages on which we rely on, and
% set up some private wrappers around these.
%    \begin{macrocode}
\RequirePackage{amsthm}
\RequirePackage{thmtools}
%    \end{macrocode}
%
% \begin{macro}{\@@_thmtools_declare_theorem:nn, \@@_thmtools_declare_theorem:Vn}
%   \begin{syntax}
%     \cs{@@_thmtools_declare_theorem:nn} \mymeta{theorem name}\mymeta{thmtools keyval args}
%   \end{syntax}
% 
%  This is just a private wrapper around \cs{declaretheorem} of the \pkg{thmtools} package.
% 
%    \begin{macrocode}
\cs_new:Npn \@@_thmtools_declare_theorem:nn #1 #2
{
  \tl_log:n { Declaring ~ thmtools ~ theorem ~ #2 }
  \declaretheorem [ #1 ] { #2 }
}
\cs_generate_variant:Nn \@@_thmtools_declare_theorem:nn { V n }
%    \end{macrocode}
% \end{macro}
%
%
%
% It also comes in handy to have a stronger version of the 
% hook role setting mechanism:
% \begin{macro}{\@@_hook_gset_rule_foreach:nNnn}
%    \begin{syntax}
%       \cs{@@_hook_gset_rule_foreach:nNnn}\marg{hook}\mymeta{clist name}\mymeta{relation}\mymeta{label}
%    \end{syntax}
%		 
%   This is a wrapper around the \cs{hook_gset_rule:nnnn} macro
%   that takes a clist name of labels, and executes the corresponding
%   command for each such label.
%
%    \begin{macrocode}
\cs_new:Npn \@@_hook_gset_rule_foreach:nNnn #1 #2 #3 #4
  {
    \cs_set:Npn \@@_map_aux:n ##1
    {
      \hook_gset_rule:nnnn { #1 } { ##1 } { #3 } { #4 }
    }
    \clist_map_function:NN #2 \@@_map_aux:n
  }
%    \end{macrocode}
% \end{macro}
%
%
%
% \subsection{Messages}
% These are  messages that we might emit.
%
% When an unknown group is used somwhere:
%    \begin{syntax}
%      \cs{msg_error:nnn}\{ groupthm \}\{ unknown group \}\marg{groupname}
%    \end{syntax}
%    \begin{macrocode}
\msg_new:nnn { groupthm } { unknown ~ group }
{
  Unknown  ~ group ~ '#1' ~ supplied ~ \msg_line_context:
}
%    \end{macrocode}
%
% When an unknown key has been used:
% \begin{syntax}
%   \cs{msg_error:nnn}\{ groupthm \}\{ unknown key \}\marg{key}
% \end{syntax}
%    \begin{macrocode}
\msg_new:nnn { groupthm } { unknown ~ key }
{
  Unknown ~  key ~ '#1' ~ supplied ~ \msg_line_context:
}
%    \end{macrocode}
%
% Some data structure is already defined or not defined yet.
% \begin{syntax}
%   \cs{msg_error:nnnnn}\{ groupthm \}\{ wrong definition \}
%   \marg{type}\marg{name}\marg{already $\|$ not}
% \end{syntax}
%    \begin{macrocode}
\msg_new:nnn { groupthm } { wrong ~ definition }
{
  Bad ~ definition ~ of ~ #1 ~ '#2' ~ \msg_line_context:, ~ #1 ~ is ~ #3 ~ defined.
}
%    \end{macrocode}
%
% 
% When the special \cs{AddTheoremToGroup} macro is issued outside a theorem family options
% body.
% \begin{syntax}
%   \cs{msg_error:nn} \{ groupthm \}\{ misuse add theorem to group \}
% \end{syntax}
%    \begin{macrocode}
\msg_new:nnn { groupthm } { misuse ~ add ~ theorem ~ to ~ group }
  {
    Bad ~ usage ~ of ~ 'AddTheoremToGroup' ~ macro ~ outside ~ theorem ~
    family ~ options ~ \msg_line_context:
  }
%    \end{macrocode}
% 
% 
% 
%  When a theorem family is invoked, but has not been generated yet.
% \begin{syntax}
%   \cs{msg_error:nn} \{ groupthm \}\{ undefined theorem variant \}
% \end{syntax}
%    \begin{macrocode}
\msg_new:nnnn { groupthm } { undefined ~ theorem ~ variant }
  {
    Bad ~ call ~ of ~ theorem ~ variant ~ of ~ '#1' ~ \msg_line_context:
  }
  {
    You ~ wanted ~ to ~ call ~ the ~ variant ~ with ~ group(s) ~
    '#2' ~ of ~ theorem ~ family ~ '#1', ~ but ~ it ~ has ~ not ~ been ~
    generated ~ yet. ~
    Probably ~ you ~ forgot ~ this. ~
    \msg_see_documentation_text:n { groupthm }
  }
%    \end{macrocode}
%
% \subsection{Allocation and initialization}
%
% We use hooks at several places. However, these are not intended for outer use,
% and we thus mark them with a preceding \texttt{__}.
%
%    \begin{macrocode}
\hook_new:n { @@/prefix   }
\hook_new:n { @@/suffix  }
\hook_new:n { @@/mapname   }
\hook_new:n { @@/thmtools  }
%    \end{macrocode}
%    \begin{macrocode}
\hook_new:n { @@/groupsort }
%    \end{macrocode}
%
% \begin{macro}{\hook_gset_rule:nnVn}
%    \begin{syntax}
%       \cs{hook_gset_rule:nnVn}\marg{hook}\marg{label 1}\marg{relation}\marg{label 2}
%    \end{syntax}
%
%		 Just a variant of the usual \cs{hook_gset_rule:nnnn} macro that we use.
%
%    \begin{macrocode}
\cs_generate_variant:Nn \hook_gset_rule:nnnn { n n V n }
%    \end{macrocode}
% \end{macro}
% 
%
%
% \begin{variable}
% {
%   \l_@@_key_prefix_tl, \l_@@_key_name_tl, \l_@@_key_suffix_tl,
%   \l_@@_key_group_clist, \l_@@_key_mapname_clist, \l_@@_key_thmtools_clist
% }
% These variables will be set by the key-value interface provided by
% \pkg{l3keys} and are used in various places in the package.
%    \begin{macrocode}
\tl_new:N    \l_@@_key_prefix_tl
\tl_new:N    \l_@@_key_name_tl
\tl_new:N    \l_@@_key_suffix_tl
\clist_new:N \l_@@_key_group_clist
\clist_new:N \l_@@_key_mapname_clist
\clist_new:N \l_@@_key_thmtools_clist
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%   {
%     \l_@@_prefix_tl,
%     \l_@@_name_tl,
%     \l_@@_suffix_tl,
%     \l_@@_mapname_clist,
%     \l_@@_thmtools_clist,
%     \l_@@_group_clist
%   }
%
%   General local variables.
%   Will typically be used to extract the variables set by the \pkg{l3keys} interface,
%   but also in just a local variable sense.
%     
%    \begin{macrocode}
\tl_new:N    \l_@@_prefix_tl
\tl_new:N    \l_@@_name_tl
\tl_new:N    \l_@@_suffix_tl
\clist_new:N \l_@@_mapname_clist
\clist_new:N \l_@@_thmtools_clist
\clist_new:N \l_@@_group_clist
%    \end{macrocode}
% \end{variable}
% 
% 
% 
% \begin{variable}{\g_@@_defined_groups_clist}
%		 
%     This variable will hold a global list of declared theorem groups
%
%    \begin{macrocode}
\clist_new:N \g_@@_defined_groups_clist
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_in_family_options_environment_bool}
%  This variable indicates whether we are in the special environment
%  used to parse a set of groups out of options given to a theorem
%  family.
%
%  This bool toggles the availability of the special \cs{AddTheoremToGroup} macro.
%    \begin{macrocode}
\bool_new:N  \l_@@_in_family_options_environment_bool
%    \end{macrocode}
% \end{variable}
% 
%
% \subsection{Key interface}
% As mentioned, all keys will set their corresponding local variables
% (containing \enquote{\texttt{_key_}} in their name) and store the
% user input in these.
% 
% Additionally, we group these keys by use cases,
% and provide defaults that in most cases will not require further handling.
%
% 
%
%    \begin{macrocode}
\keys_define:nn { groupthm }
  {
    prefix      .tl_set:N      = \l_@@_key_prefix_tl,
    prefix      .default:n     = \c_empty_tl,
    prefix      .groups:n      = { theoremgroup },
    name         .tl_set:N      = \l_@@_key_name_tl,
    name         .default:n     = \c_novalue_tl,
    name         .groups:n      = { groupedtheorem, theoremvariants },
    suffix     .tl_set:N      = \l_@@_key_suffix_tl,
    suffix     .default:n     = \c_empty_tl,
    suffix     .groups:n      = { theoremgroup },
    group        .clist_set:N   = \l_@@_key_group_clist,
    group        .default:n     = {},
    group        .groups:n      = { groupedtheorem, theoremvariants },
    mapname      .clist_set:N   = \l_@@_mapname_clist,
    mapname      .default:n     = {},
    mapname      .groups:n      = { theoremgroup },
    thmtools     .clist_set:N   = \l_@@_key_thmtools_clist,
    thmtools     .default:n     = {},
    thmtools     .groups:n      =
      { theoremgroup, groupedtheorem, theoremvariants },
    unknown      .code:n        =
      \msg_error:nnn { groupthm } { unknown ~ group } { \l_keys_key_str }
  }
%    \end{macrocode}
% 
%
% The only key whose default requires such handling is the \enquote{\texttt{name}} key,
% which will be set to a capitalized version of the environment name
% when not specified.
%
%
% \begin{macro}{\@@_set_normalized_keys:nnn}
%    \begin{syntax}
%       \cs{@@_set_normalized_keys:nnn}\marg{keys}\marg{key group}\marg{fallback name}
%    \end{syntax}
%		 
% Sets the packages keys and normalizes the retrieved values, that is,
% clears old set keys, stores all keys in local variables,
% and replaces the \cs{l_@@_name_tl} with the capitalized version of the
% \mymeta{fallback name}.
%
%    \begin{macrocode}
\cs_new:Npn \@@_set_normalized_keys:nnn #1 #2 #3
  {
    \keys_set:nn { groupthm } { prefix, name, suffix, group, mapname, thmtools }
    \keys_set_groups:nnn { groupthm } { #2 } { #1 }
%    \end{macrocode}
%
% Normalize given name
%
%    \begin{macrocode}
    \tl_if_eq:NnTF \l_@@_key_name_tl { \c_novalue_tl }
      {
        \tl_set:Nx \l_@@_name_tl
          {
            \text_titlecase_first:n {#3}
          }
      }
      {
        \tl_set_eq:NN \l_@@_name_tl \l_@@_key_name_tl
      }
%    \end{macrocode}
% 
% Copy set keys into local variables 
% 
%    \begin{macrocode}
    \tl_set_eq:NN    \l_@@_prefix_tl     \l_@@_key_prefix_tl
    \tl_set_eq:NN    \l_@@_suffix_tl    \l_@@_key_suffix_tl
    \clist_set_eq:NN \l_@@_group_clist    \l_@@_key_group_clist
    \clist_set_eq:NN \l_@@_mapname_clist  \l_@@_key_mapname_clist
    \clist_set_eq:NN \l_@@_thmtools_clist \l_@@_key_thmtools_clist
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \subsection{Theorem groups}
%
% For technical reasons explained in the \todoref section, we need to 
% some arbitrary, but unique total ordering on the set of all defined theorem groups.
%
% Since unfortunately (by now) there is no standard mechanism for sorting strings
% in \LaTeX3 directly, we use an ugly hack to achieve what we want:
%
% We will use an internal hook, and apply hook rules to each pair of internal groups
% such that the resulting relation is a total order.
% Whenever we want to sort a list of groups now, we do the following:
% First, for each group element in the list, insert into the hook the function
% \enquote{put this group back into the list}, using the group itself as a label.
% Then we clear the list, and finally execute the hook.
% 
% Essentially, we thus split up the hook in the single groups, let the \LaTeX3 hook
% mechanism take care of the sorting, and restore the sorted single pieces into our list.
% Of course, this is very inefficient, but for now it seems to be the simplest solution,
% without having to implement an own string sorting function.
% 
% Once there is such a proper mechanism, the author will likely update this to proper
% string sorting.
%
% \begin{macro}{\@@_add_to_group_ordering:n}
%    \begin{syntax}
%       \cs{@@_add_to_group_ordering:n}\marg{theorem group}
%    \end{syntax}
%		 
%    Sets hook relations for this group and all already defined theorem groups.     
%
%    \begin{macrocode}
\cs_new:Npn \@@_add_to_group_ordering:n #1
  {
    \@@_hook_gset_rule_foreach:nNnn
      { @@/groupsort }
      \g_@@_defined_groups_clist
      { before }
      { #1 }
  }
%    \end{macrocode}
% \end{macro}
%
% 
% 
% \begin{macro}{\@@_remove_from_group_ordering:n}
%    \begin{syntax}
%       \cs{@@_remove_from_group_ordering:n}\marg{theorem group}
%    \end{syntax}
%		 
%    Removes all relations of this theorem group with the currently defined theorem groups.
%
%    \begin{macrocode}
\cs_new:Npn \@@_remove_from_group_ordering:n #1
  {
    \@@_hook_gset_rule_foreach:nNnn
      { @@/groupsort }
      \g_@@_defined_groups_clist
      { unrelated }
      { #1 }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
%
% \begin{macro}{\@@_add_to_sort_hook:n}
%    \begin{syntax}
%       \cs{@@_add_to_sort_hook:n}\marg{theorem group}
%    \end{syntax}
%		 
%    Adds the theorem group into the sort hook to be restored later from it.
%    This already uses the assumption, that we want to use the \cs{l_@@_group_clist}
%    variable (which we do).
%
%    \begin{macrocode}
\cs_new:Npn \@@_add_to_sort_hook:n #1
{
  \hook_gput_code:nnn { @@/groupsort }
  { #1 }
  {
    \clist_put_left:Nn \l_@@_group_clist { #1 }
  }
}
%    \end{macrocode}
% \end{macro}
% 
%
% \begin{macro}{\@@_sort_group_names:}
%		 
%     As explained briefly before, we first insert all theorems
%     into the hook, clear the list, and then use the hook again.
%     
%     This then sorts the \cs{l_@@_group_clist} variable,
%     which is also assumed to hold only defined theorem group names.
%
%    \begin{macrocode}
\cs_new:Npn \@@_sort_group_names:
  {
    \hook_gremove_code:nn { @@/groupsort  }{*}
    \clist_map_function:NN \l_@@_group_clist \@@_add_to_sort_hook:n
    \clist_clear:N \l_@@_group_clist
    \hook_use:n { @@/groupsort }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\@@_define_group:nnnnn}
%    \begin{syntax}
%       \cs{@@_define_group:nnnnn}\marg{theorem group}\marg{prefix tl}
%       \marg{suffix tl}\marg{mapname clist}\marg{thmtools clist}
%    \end{syntax}
%		 
% This creates a new theorem group out of the given parameters.
% We store all given contents in our (private) hooks, using the group name as the key
% so that we can later retrieve the components of each group separately.
%
% This is an internal function and assumes that the group is currently not defined,
% and also removed from all hooks.
%
%
%    \begin{macrocode}
\cs_new:Npn \@@_define_group:nnnnn #1#2#3#4#5
  {
%    \end{macrocode}
%
% \begin{macro}{\@@_use_group__\meta{theorem group}:}
%
% This is the internal macro that will be called when retrieving contents of a group.
% We define this here to store the properties of the group.
%
%    \begin{macrocode}
  \cs_new:cpn { @@_use_group__#1: }
    {
      \hook_gput_code:nnn { @@/prefix } { #1 }
        {
            \tl_put_left:Nx \l_@@_prefix_tl { #2 }
        }
      \hook_gput_code:nnn { @@/suffix } { #1 }
        {
            \tl_put_right:Nx \l_@@_suffix_tl { #3 }
        }
      \hook_gput_code:nnn { @@/mapname } { #1 }
        {
          \clist_put_right:Nn \l_@@_mapname_clist { #4 }
        }
      \hook_gput_code:nnn { @@/thmtools } { #1 }
        {
          \clist_put_right:Nn \l_@@_thmtools_clist { #5 }
        }
    }
%    \end{macrocode}
% \end{macro}
%
% This ensures the ordering hacks explained before.
%
%    \begin{macrocode}
    \@@_add_to_group_ordering:n { #1 }
%    \end{macrocode}
% \begin{variable}{ \g_@@_parents_group__\meta{theorem group}__clist }
%     
% This variable will accumulate the parents of this group:
%    \begin{macrocode}
    \clist_new:c { g_@@_parents_group__#1__clist }
%    \end{macrocode}
% \end{variable}
% Add defined group to corresponding list 
%
%    \begin{macrocode}
    \clist_gput_left:Nn \g_@@_defined_groups_clist { #1 }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\@@_undefine_group:n}
%    \begin{syntax}
%       \cs{@@_undefine_group:n}\marg{theorem group}
%    \end{syntax}
%		 
% Undeclares / undefines the given theorem group.
% This means removing its hook code in the \texttt{prefix}, \texttt{suffix},
% \texttt{mapname} and \texttt{thmtools} hooks,
% and removing all relations with other theorem groups globally
% as well as for each hook individually.
%
% This macro assumes that the group was defined prior to calling.
%
%    \begin{macrocode}
\cs_new:Npn \@@_undefine_group:n #1
  {
    \tl_log:n { Undefining ~ theorem ~ group ~ '#1' }
    \cs_undefine:c { @@_use_group__#1:   }
%    \end{macrocode}
% 
% Remove properties from hooks
%
%    \begin{macrocode}
    \hook_gremove_code:nn { @@/prefix  } { #1 }
    \hook_gremove_code:nn { @@/suffix } { #1 }
    \hook_gremove_code:nn { @@/mapname  } { #1 }
    \hook_gremove_code:nn { @@/thmtools } { #1 }
%    \end{macrocode}
%
% Remove theorem group from list of defined theorems
%
%    \begin{macrocode}
    \clist_gremove_all:Nn  \g_@@_defined_groups_clist { #1 }
%    \end{macrocode}
%  
%   Delete the known parents of this group:
%    \begin{macrocode}
    \cs_undefine:c { g_@@_parents_group__#1__clist }
%    \end{macrocode}
%
% Now, unset all relations with all defined theorem groups in the internal hooks.
%
%    \begin{macrocode}
    \@@_hook_gset_rule_foreach:nNnn
      { ?? }
      \g_@@_defined_groups_clist
      { unrelated }
      { #1 }
    \@@_hook_gset_rule_foreach:nNnn
      { @@/prefix }
      \g_@@_defined_groups_clist
      { unrelated }
      { #1 }
    \@@_hook_gset_rule_foreach:nNnn
      { @@/suffix }
      \g_@@_defined_groups_clist
      { unrelated }
      { #1 }
    \@@_hook_gset_rule_foreach:nNnn
      { @@/mapname }
      \g_@@_defined_groups_clist
      { unrelated }
      { #1 }
    \@@_hook_gset_rule_foreach:nNnn
      { @@/thmtools }
      \g_@@_defined_groups_clist
      { unrelated }
      { #1 }
%    \end{macrocode}
%
% Also clear all sorting relations
%
%    \begin{macrocode}
    \@@_remove_from_group_ordering:n { #1 }
  }
%    \end{macrocode}
% \end{macro}
% 
% \begin{macro}{\@@_define:nnnNNNn, \@@_define:nnncNNn}
%    \begin{syntax}
%       \cs{@@_define:nnnNNNn}\marg{declarator}\marg{type}\marg{instance}\marg{existence cs}\marg{undefine function}\marg{define function}\marg{definition args}
%    \end{syntax}
%		 
%   A general definition macro that is used to implement the \texttt{new},
%   \texttt{renew}, \texttt{provide} and \texttt{declare} definition variants of \meta{type}s.
%   For the purpose of this package, \meta{type} will be one of
%   \enquote{theorem group}, \enquote{grouped theorem}, \enquote {theorem family}
%   and\enquote{theorem family options}, but could technically be anything.
% 
%   The \meta{instance} is the actual thing that will be defined by this function.
%   The \meta{declarator} is one of \texttt{new}, \texttt{renew},
%   \texttt{provide} and \texttt{declare} and indicates the definition behavior:
%   \texttt{new} only defines
%   if \meta{instance} does not yet exist and throws an error otherwise,
%   \texttt{renew} only (re)defines
%   if \meta{instance} does exist yet and throws an error otherwise,
%   \texttt{provides} defines if \meta{instance} does not exist yet,
%   but does nothing otherwise
%   and
%   \texttt{declare} defines \meta{instance} in any case,
%   possibly by overwriting the old definition.
% 
%   The \meta{existence cs} is the one whose existence will be checked to
%   determine whether the \meta{instance} already exists.
% 
%   The \meta{undefine function} will be called in case \meta{instance} has to be undefined.
%   It is assumed to have argument type \texttt{n} and will be given the \meta{instance}
%   as an argument in this case.
% 
%   The \meta{define function} will be called with the arguments
%   given as \meta{definition args} in case no error occurs and \meta{instance} should be defined.
% 
%
%    \begin{macrocode}
\cs_new:Npn \@@_define:nnnNNNn #1 #2 #3 #4 #5 #6 #7
  {
%    \end{macrocode}
%    We first check for wrong usage of \texttt{new}
%    \begin{macrocode}
    \bool_if:nT
      {
        \str_if_eq_p:nn { #1 } { new }
        &&
        \cs_if_exist_p:N #4
      }
      {
        \tl_log:n { Wrong ~ 'new' ~ definition ~ of ~ #2 ~ '#3' ~ detected. }
        \msg_error:nnnnn { groupthm } { wrong ~ definition }
          { #2 } { #3 } { already }
      }
%    \end{macrocode}
% Then check for wrong usage of \texttt{renew}
%    \begin{macrocode}
    \bool_if:nT
      {
        \str_if_eq_p:nn { #1 } { renew }
        &&
        ! \cs_if_exist_p:N #4
      }
      {
        \tl_log:n { Wrong ~ 'renew' ~ definition ~ of ~ #2 ~ '#3' ~ detected. }
        \msg_error:nnnnn { groupthm } { wrong ~ definition }
          { #2 } { #3 } { not }
      }
%    \end{macrocode}
% Now, remove the old definition if necessary
%    \begin{macrocode}
    \bool_if:nT
      {
        (
          \str_if_eq_p:nn { #1 } { declare } ||
          \str_if_eq_p:nn { #1 } { renew } 
        ) &&
        \cs_if_exist_p:N #4
      }
      {
        \tl_log:n { Removing ~ definition ~ of ~ #2 ~ '#3'. }
        #5 { #3 }
      }
%    \end{macrocode}
% Finally, define new version if not already defined
% (this check is necessary for the provide version.)
%    \begin{macrocode}
    \cs_if_exist:NTF #4
      {
        \tl_log:n { Providing ~ #2 ~ '#3' ~ skipped: ~ '#3' ~ already ~ defined. }
      }
      {
        \tl_log:n { Defining ~ #2 ~ '#3'. }
        #6 #7
      }
  }
\cs_generate_variant:Nn \@@_define:nnnNNNn { n n n c N N n }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_define_multiple:nnnNNnn}
%    \begin{syntax}
%     \cs{@@_define_multiple:nnnNNnn} \marg{declarator list} \marg{type} \marg{existence cs}
%     \marg{undefine function}\marg{define function}\marg{function name}\marg{definition args}
%    \end{syntax}
%		 
%  This is a wrapper around the \cs{@@_define:nnnNNNn} macro.
%  It is intended to wrap the multiple variants of it into a family of macros indicating
%  the variant in their name, e.g.~to define \cs{groupthm_new_group}, \cs{groupthm_renew_group},
%  \cs{groupthm_provide_group} and \cs{groupthm_declare_group} in the same way except for their
%  indicated declaration behavior, to avoid repetition when defining these.
%
%  The first five arguments work the same way as in \cs{@@_define:nnnNNn},
%  except that \meta{declarator list} is now a comma separated list.
%  In \meta{existence cs}, \texttt{\#\#1} is used to denote the \meta{instance}
%  that has currently been called to define.
%  
%  The \meta{function name} is expected to contain \texttt{\#1},
%  for which the current \meta{declarator} is inserted.
%  These control sequences will then be defined.
%
%  The \meta{definition args} denote the arguments passed to the \meta{define function}
%  and may contain \texttt{\#\#1}, \texttt{\#\#2}, etc. for the arguments that the
%  \meta{function name} received as arguments on expansion.
%
%
%    \begin{macrocode}
\cs_new:Npn \@@_define_multiple:nnnNNnn #1 #2 #3 #4 #5 #6 #7
  {
    \cs_set:Npn \@@_map_aux:n ##1
      {
        \cs_new:cn { #6 }
          {
            \@@_define:nnncNNn
              { ##1 }
              { #2 }
              { ####1 }
              { #3 }
              #4
              #5
              { #7 }
          }
      }
    \clist_map_function:nN { #1 } \@@_map_aux:n
  }
%    \end{macrocode}
% \end{macro}
%
%
% With these helper functions, we can now easily generate the
% \texttt{new}, \texttt{renew}, \texttt{provide} and \texttt{declare} variants
% of the theorem group macro:
% 
% \begin{macro}
%   {
%     \groupthm_new_group:nnnnn,     \groupthm_new_group:nVVVV,
%     \groupthm_renew_group:nnnnn,   \groupthm_renew_group:nVVVV,
%     \groupthm_provide_group:nnnnn, \groupthm_provide_group:nVVVV,
%     \groupthm_declare_group:nnnnn, \groupthm_declare_group:nVVVV
%   }
%		 
%    \begin{macrocode}
\@@_define_multiple:nnnNNnn
  { new, renew, provide, declare }
  { theorem group }
  { @@_use_group__##1: }
  \@@_undefine_group:n
  \@@_define_group:nnnnn
  { groupthm_#1_group:nnnnn }
  { { ##1 } { ##2 } { ##3 } { ##4 } { ##5 } }
%    \end{macrocode}
%
% Finally, generate some extra variants
%
%    \begin{macrocode}
\cs_generate_variant:Nn \groupthm_new_group:nnnnn     { n V V V V }
\cs_generate_variant:Nn \groupthm_renew_group:nnnnn   { n V V V V }
\cs_generate_variant:Nn \groupthm_provide_group:nnnnn { n V V V V }
\cs_generate_variant:Nn \groupthm_declare_group:nnnnn { n V V V V }
%    \end{macrocode}
% \end{macro}
% 
% 
% With the \cs{@@_set_normalized_keys:nnn} macro at hand,
% it is also easy to provide key-value interfaces for these commands:
%


% \begin{macro}{\@@_wrap_multiple:nnn}
%    \begin{syntax}
%       \cs{@@_wrap_multiple:nnn}\marg{declarator list}\marg{function name}\marg{code}
%    \end{syntax}
%		 
%    Defines \meta{function name}, which is assumed to contain \cs{declarator}
%    by \meta{code} for each declarator in \meta{declarator list}.
%
%    \begin{macrocode}
\cs_new:Npn \@@_wrap_multiple:nnn #1 #2 #3
  {
    \cs_set:Npn \@@_map_aux:n ##1
      {
        \def \declarator { ##1 }
        \cs_new:cn { #2 }
          {
            #3
          }
      }
    \clist_map_function:nN { #1 } \@@_map_aux:n
  }
%    \end{macrocode}
% \end{macro}

% \begin{macro}
%   {
%     \groupthm_new_group:nn,
%     \groupthm_renew_group:nn,
%     \groupthm_provide_group:nn,
%     \groupthm_declare_group:nn
%   }
%    \begin{syntax}
%       \cs{groupthm_new_group:nn}\marg{keys}\marg{theorem group}
%    \end{syntax}
%		 
%    \begin{macrocode}
\@@_wrap_multiple:nnn
  { new, renew, provide, declare }
  { groupthm_ \declarator _group:nn }
  {
    \@@_set_normalized_keys:nnn { ##1 } { theoremgroup } { ##2 }
    \use:c { groupthm_#1_group:nVVVV }
      { ##2 }
      \l_@@_prefix_tl
      \l_@@_suffix_tl
      \l_@@_mapname_clist
      \l_@@_thmtools_clist
  }
%    \end{macrocode}
% \end{macro}
%
%
%  Finally, we provide \LaTeX2e wrappers as document commands for these.
%
% \begin{macro}{\@@_wrap_multiple_document:nnnn}
%    \begin{syntax}
%       \cs{@@_wrap_multiple_document:nnnn}\marg{declarator list}\marg{function name}\marg{arg spec}\marg{code}
%    \end{syntax}
%		 
%     This is very similar to \cs{@@_wrap_multiple:nnn}, except that it produces document commands.
%     For this reason, \cs{declarator} and \cs{Declarator} are available to refer to the lower
%     and upper-case versions of the current declarator.
%
%    \begin{macrocode}
\cs_new:Npn \@@_wrap_multiple_document:nnnn #1 #2 #3 #4
  {
    \cs_set:Npn \@@_map_aux:n ##1
      {
        \def \declarator { ##1 }
        \def \Declarator { \text_titlecase_first:n { ##1 } }
        \exp_args:Nc \NewDocumentCommand { #2 } { #3 }
          {
            #4
          }
      }
    \clist_map_function:nN { #1 } \@@_map_aux:n
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\NewTheoremGroup, \RenewTheoremGroup, \ProvideTheoremGroup, \DeclareTheoremGroup}
%
%  These just wrap the \cs{groupthm_\meta{declarator}_group:nn}  macros.
%
%    \begin{macrocode}
\@@_wrap_multiple_document:nnnn
  { new, renew, provide, declare }
  { \Declarator TheoremGroup }
  { O{} m }
  {
    \use:c { groupthm_ \declarator _group:nn } { ##1 } { ##2 }
  }
%    \end{macrocode}
% \end{macro}
%
%
% We also provide the interface for declaring the precedence rules for theorem groups.
%
%
% \begin{macro}{\groupthm_declare_group_rule:nnnn}
%    \begin{syntax}
%       \cs{groupthm_declare_group_rule:nnnn}\marg{keyname}\marg{theorem group 1}
%       \marg{relation}\marg{theorem group 2}
%    \end{syntax}
%		 
% We have to normalize the arguments a little bit, namely replacing \texttt{higher}
% and \texttt{lower} with \texttt{before} \texttt{after} respectively,
% and prefix the \mymeta{keyname} with \texttt{__groupthm}
% in case it is not the general hook \enquote{\texttt{??}}.
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_declare_group_rule:nnnn #1 #2 #3 #4
  {
    \str_set:Nx \l_tmpa_str { \tl_trim_spaces:n { #3 } }
    \str_if_eq:VnT \l_tmpa_str { higher }
      {
        \str_set:Nn \l_tmpa_tl { after }
      }
    \str_if_eq:VnT \l_tmpa_str { lower }
      {
        \str_set:Nn \l_tmpa_tl { before }
      }
    \str_if_eq:nnTF { #1 } { ?? }
      {
        \hook_gset_rule:nnVn {??} {#2} \l_tmpa_tl {#4}
      }
      {
        \hook_gset_rule:nnVn { @@ / #1 } {#2} \l_tmpa_tl {#4}
      }
  }
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\DeclareTheoremGroupRule}
%    \begin{syntax}
%      \cs{DeclareTheoremGroupRule}\oarg{keyname}%
%      \marg{theorem group 1}\marg{relation}\marg{theorem group 2}
%    \end{syntax}
%
%    \begin{macrocode}
\NewDocumentCommand { \DeclareTheoremGroupRule } { O{??} m m m }
  {
    \groupthm_declare_group_rule:nnnn {#1} {#2} {#3} {#4}
  }
%    \end{macrocode}
% \end{macro}
% 
% \subsection{Iterating over powersets}
% For generating the different variants of a theorem family,
% we need to iterate over over the powerset of some list.
% This is a collection of hacks that perform exactly this,
% but these are poorly documented for now.
% 
%
% \begin{macro}{\@@_powerset_clist_foreach:Nn}
%    \begin{syntax}
%       \cs{@@_powerset_clist_foreach:Nn}\mymeta{clist}\marg{code}
%    \end{syntax}
%		 
%   Executes \mymeta{code} for each subset of the given clist variable.
%   The value of the (local) variable is changes throughout the iteration,
%   and is thus available regularly in \mymeta{code}.
%   Its value is restored at the end of the iteration.
%
%    \begin{macrocode}
\clist_new:N  \l__powerset_copied_clist
\seq_new:N    \l__powerset_saved_seq
\cs_generate_variant:Nn \clist_remove_all:Nn { N V }
\cs_new:Npn \__powerset_clist_foreach_aux:Nn #1 #2 
  {
    \clist_if_empty:NTF \l__powerset_copied_clist
      {
        #2
      }
      {
        \clist_get:NN \l__powerset_copied_clist \l_tmpa_tl
        \seq_push:NV  \l__powerset_saved_seq \l_tmpa_tl
        \clist_pop:NN \l__powerset_copied_clist { \l_tmpa_tl }

        \__powerset_clist_foreach_aux:Nn #1 {#2}
        
        \seq_get:NN \l__powerset_saved_seq \l_tmpa_tl
        \clist_put_left:NV #1 \l_tmpa_tl

        \__powerset_clist_foreach_aux:Nn #1 {#2}

        \seq_get:NN \l__powerset_saved_seq \l_tmpa_tl
        \clist_remove_all:NV #1 \l_tmpa_tl
        \clist_push:NV \l__powerset_copied_clist \l_tmpa_tl
        \seq_pop:NN \l__powerset_saved_seq \l_tmpa_tl
      }
  }
\cs_new:Npn \powerset_clist_foreach:Nn #1 #2
  {
    \clist_set_eq:NN \l__powerset_copied_clist #1
    \clist_clear:N #1
    \clist_remove_duplicates:N \l__powerset_copied_clist
    \__powerset_clist_foreach_aux:Nn #1 {#2}
    \clist_set_eq:NN #1 \l__powerset_copied_clist
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% 
% \subsection{Grouped Theorems} 
% 
%
%
% \begin{macro}{\@@_ensure_group_exists:n}
%    \begin{syntax}
%       \cs{@@_ensure_group_exists:n}\meta{theorem group}
%    \end{syntax}
%		 
%    Checks if this group exists.
%    If not, produces an error message.
%
%    \begin{macrocode}
\cs_new:Npn \@@_ensure_group_exists:n #1
  {
    \cs_if_exist:cF { @@_use_group__#1: }
    {
      \msg_error:nnn { groupthm } { unknown ~ group } { #1 }
    }
  }
%    \end{macrocode}
% \end{macro}
% 
% \begin{macro}{\@@_use_group:n}
%    \begin{syntax}
%       \cs{@@_use_group:n}\mymeta{theorem group}
%    \end{syntax}
%		 
%    Uses this theorem group, i.e.~applies its definition by writing
%    to the internal hooks.
%    A proper error message is emitted if the group is not defined.
%
%    \begin{macrocode}
\cs_new:Npn \@@_use_group:n #1
  {
    \@@_ensure_group_exists:n { #1 }
    \use:c { @@_use_group__#1: }
  }
%    \end{macrocode}
% \end{macro} 
%
% 
%
% \begin{macro}{\@@_use_function_on_name:n}
%    \begin{syntax}
%       \cs{@@_use_function_on_name:n}\mymeta{function}
%    \end{syntax}
%		 
%    The \mymeta{function} is expected to be of type \texttt{:n},
%    This applies the function to the \cs{l_@@_name_tl}
%
%    \begin{macrocode}
\cs_new:Npn \@@_use_function_on_name:n #1
  {
    \tl_set:Nx \l_@@_name_tl
      {
        #1 { \tl_use:N \l_@@_name_tl }
      }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
%
% \begin{macro}{\@@_define_theorem:nnnn}
%    \begin{syntax}
%       \cs{@@_define_theorem:nnnn}\marg{environment name}
%       \marg{groups clist}\marg{theorem name}\marg{thmtools keys}
%    \end{syntax}
%		 
%   This is the internal backend that declares a grouped theorem
%   by retrieving all the group properties and issuing a (single) \cs{declaretheorem}
%   command of \pkg{thmtools}.
%
%    \begin{macrocode}
\cs_new:Npn \@@_define_theorem:nnnn #1 #2 #3 #4
  {
%    \end{macrocode}
% First, set local variables to default values and store current name.
%    \begin{macrocode}
    \tl_clear:N     \l_@@_prefix_tl
    \tl_set:Nn      \l_@@_name_tl        { #3 }
    \tl_clear:N     \l_@@_suffix_tl
    \clist_clear:N  \l_@@_mapname_clist
    \clist_clear:N  \l_@@_thmtools_clist
%    \end{macrocode}
% Clear all hooks
%    \begin{macrocode}
    \hook_gremove_code:nn { @@/prefix  }{*}
    \hook_gremove_code:nn { @@/suffix }{*}
    \hook_gremove_code:nn { @@/mapname  }{*}
    \hook_gremove_code:nn { @@/thmtools }{*}
%    \end{macrocode}
% Now, retrieve the group properties, by writing these into the hooks
%    \begin{macrocode}
    \clist_map_function:nN { #2 } \@@_use_group:n
%    \end{macrocode}
% Execute the hooks, so that local variables will get modified according to the groups
% and in the order that were specified for the hooks.
%    \begin{macrocode}
    \hook_use:n { @@/prefix }
    \hook_use:n { @@/suffix }
    \hook_use:n { @@/mapname }
    \hook_use:n { @@/thmtools }
%    \end{macrocode}
% We are left with dealing with the obtained data.
% We first map on the name, before appending to it.
%    \begin{macrocode}
    \clist_map_function:NN \l_@@_mapname_clist \map_use_on_name:n
%    \end{macrocode}
% We now glue the name together of its three parts,
% and pass this key directly to the \pkg{thmtools} arguments
%    \begin{macrocode}
    \clist_put_right:Nx \l_@@_thmtools_clist
      {
        name = \tl_use:N \l_@@_prefix_tl
               \tl_use:N \l_@@_name_tl
               \tl_use:N \l_@@_suffix_tl
      }
%    \end{macrocode}
% Finally, apply the additional \pkg{thmtools} keys for this specific theorem.
% Putting them last will overwrite keys that were given by the groups.
%    \begin{macrocode}
    \clist_put_right:Nn \l_@@_thmtools_clist { #4 }
%    \end{macrocode}
% We can now pass our list to \pkg{thmtools}, declaring the theorem.
%    \begin{macrocode}
    \@@_thmtools_declare_theorem:Vn
      \l_@@_thmtools_clist
      { #1 }
  }
%    \end{macrocode}
% \end{macro}
%
%
% As usual, we provide a \texttt{new} and a \texttt{provide} variant wrapped
% around this that do proper error checking.
% 
% 
% \begin{macro}
% {
%   \groupthm_new_grouped_theorem:nnnn,
%   \groupthm_new_grouped_theorem:nVVV,
%   \groupthm_new_grouped_theorem:xVnn
%   \groupthm_provide_grouped_theorem:nnnn,
%   \groupthm_provide_grouped_theorem:nVVV,
%   \groupthm_provide_grouped_theorem:xVnn
% }
%    \begin{syntax}
%       \cs{groupthm_new_grouped_theorem:nnnn}\marg{environment name}
%       \marg{groups clist}\marg{theorem name}\marg{thmtools keys}
%    \end{syntax}
%		 
%    \begin{macrocode}
\@@_define_multiple:nnnNNnn
  { new, provide }
  { grouped ~ theorem }
  { ##1 }
  \error
  \@@_define_theorem:nnnn 
  { groupthm_#1_grouped_theorem:nnnn }
  { { ##1 } { ##2 } { ##3 } { ##4 } }
\cs_generate_variant:Nn \groupthm_new_grouped_theorem:nnnn { n V V V }
%    \end{macrocode}
% We need this extra variant here for the generation of theorem families later:
%    \begin{macrocode}
\cs_generate_variant:Nn \groupthm_new_grouped_theorem:nnnn { x V n n }
%    \end{macrocode}
% \end{macro}
% 
%
%   The star variants of these that add the \texttt{unnumbered} group
%   are straightforward:
%
% \begin{macro}{\groupthm_new_grouped_theorem_star:nnnn}
%		 
%    \begin{macrocode}
\cs_new:Npn \groupthm_new_grouped_theorem_star:nnnn #1 #2 #3 #4
  {
    \groupthm_new_grouped_theorem:nnnn
      { #1 } { #2, unnumbered } { #3 } { #4 }
  }
%    \end{macrocode}
% \end{macro}
%
% 
% \begin{macro}{\groupthm_provide_grouped_theorem_star:nnnn}
%    \begin{syntax}
%       \cs{groupthm_provide_grouped_theorem_star:nnnn}\marg{environment name}
%       \marg{groups clist}\marg{theorem name}\marg{thmtools keys}
%    \end{syntax}
%		 
%    \begin{macrocode}
\cs_new:Npn \groupthm_provide_grouped_theorem_star:nnnn #1 #2 #3 #4
  {
    \groupthm_provide_grouped_theorem:nnnn
      { #1 } { #2, unnumbered } { #3 } { #4 }
  }
%    \end{macrocode}
% \end{macro}
% 
%  
% On top of these, we can provide the shorter versions that will generate
% two theorems each, one with and one without a \enquote{*} in its 
% environment name
% 
% 
% 
% \begin{macro}{\groupthm_new_theorem:nnnn,\groupthm_new_theorem:nVVV}
%    \begin{syntax}
%       \cs{groupthm_new_theorem:nnnn}\marg{environment name}
%       \marg{groups clist}\marg{theorem name}\marg{thmtools keys}
%    \end{syntax}
%		 
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_new_theorem:nnnn #1 #2 #3 #4
  {
    \groupthm_new_grouped_theorem:nnnn
      { #1 } { #2 } { #3 } { #4 }
    \groupthm_new_grouped_theorem:nnnn
      { #1* } { #2, starred } { #3 } { #4 }
  }
\cs_generate_variant:Nn \groupthm_new_theorem:nnnn { n V V V }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% \begin{macro}{\groupthm_provide_theorem:nnnn,\groupthm_provide_theorem:nVVV}
%    \begin{syntax}
%       \cs{groupthm_provide_theorem:nnnn}\marg{environment name}
%       \marg{groups clist}\marg{theorem name}\marg{thmtools keys}
%    \end{syntax}
%		 
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_provide_theorem:nnnn #1 #2 #3 #4
  {
    \groupthm_provide_grouped_theorem:nnnn
      { #1 } { #2 } { #3 } { #4 }
    \groupthm_provide_grouped_theorem:nnnn
      { #1* } { #2, starred } { #3 } { #4 }
  }
\cs_generate_variant:Nn \groupthm_provide_theorem:nnnn { n V V V }
%    \end{macrocode}
% \end{macro}
% 
% 
% Combining these is also not difficult:
% 
% 
% 
% 
% \begin{macro}{\groupthm_new_theorem_star:nnnn}
%    \begin{syntax}
%       \cs{groupthm_new_theorem_star:nnnn}\marg{environment name}
%       \marg{groups clist}\marg{theorem name}\marg{thmtools keys}
%    \end{syntax}
%		 
%    \begin{macrocode}
\cs_new:Npn \groupthm_new_theorem_star:nnnn #1 #2 #3 #4
  {
    \groupthm_new_theorem:nnnn
      { #1 } { #2, unnumbered } { #3 } { #4 }
  }
%    \end{macrocode}
% \end{macro}
%
%
% 
% \begin{macro}{\groupthm_provide_theorem_star:nnnn}
%    \begin{syntax}
%       \cs{groupthm_provide_theorem_star:nnnn}\marg{environment name}
%       \marg{groups clist}\marg{theorem name}\marg{thmtools keys}
%    \end{syntax}
%		 
%    \begin{macrocode}
\cs_new:Npn \groupthm_provide_theorem_star:nnnn #1 #2 #3 #4
  {
    \groupthm_provide_theorem:nnnn
      { #1 } { #2, unnumbered } { #3 } { #4 }
  }
%    \end{macrocode}
% \end{macro}
% 
% We now provide the corresponding key-valued interfaces around these.
% All of these work in the same way:
% We set the normalized keys, and then pass these by value to the
% previously defined macros
% 
%
% \begin{macro}{\groupthm_new_grouped_theorem_from_keys:nn}
%    \begin{macrocode}
\cs_new:Npn \groupthm_new_grouped_theorem_from_keys:nn #1 #2
  {
    \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 }

    \groupthm_new_grouped_theorem:nVVV
      { #1 }
      \l_@@_key_group_clist
      \l_@@_name_tl
      \l_@@_key_thmtools_clist
  }
%    \end{macrocode}
% \end{macro}
% 
%
% \begin{macro}{\groupthm_provide_grouped_theorem_from_keys:nn}
%    \begin{macrocode}
\cs_new:Npn \groupthm_provide_grouped_theorem_from_keys:nn #1 #2
  {
    \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 }

    \groupthm_provide_grouped_theorem:nVVV
      { #1 }
      \l_@@_key_group_clist
      \l_@@_name_tl
      \l_@@_key_thmtools_clist
  }
%    \end{macrocode}
% \end{macro}
% 
%
% \begin{macro}{\groupthm_new_grouped_theorem_star_from_keys:nn}
%    \begin{macrocode}
\cs_new:Npn \groupthm_new_grouped_theorem_star_from_keys:nn #1 #2
  {
    \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 }

    \groupthm_new_grouped_theorem_star:nVVV
      { #2 }
      \l_@@_key_group_clist
      \l_@@_name_tl
      \l_@@_key_thmtools_clist
  }
%    \end{macrocode}
% \end{macro}
% 
%
% \begin{macro}{\groupthm_provide_grouped_theorem_star_from_keys:nn}
%    \begin{macrocode}
\cs_new:Npn \groupthm_provide_grouped_theorem_star_from_keys:nn #1 #2
  {
    \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 }

    \groupthm_provide_grouped_theorem_star:nVVV
      { #2 }
      \l_@@_key_group_clist
      \l_@@_name_tl
      \l_@@_key_thmtools_clist
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% \begin{macro}{\groupthm_new_theorem_from_keys:nn}
%    \begin{macrocode}
\cs_new:Npn \groupthm_new_theorem_from_keys:nn #1 #2
  {
    \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 }

    \groupthm_new_theorem:nVVV
      { #2 }
      \l_@@_key_group_clist
      \l_@@_name_tl
      \l_@@_key_thmtools_clist
  }
%    \end{macrocode}
% \end{macro}
% 
%
% \begin{macro}{\groupthm_provide_theorem_from_keys:nn}
%    \begin{macrocode}
\cs_new:Npn \groupthm_provide_theorem_from_keys:nn #1 #2
  {
    \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 }

    \groupthm_provide_theorem:nVVV
      { #2 }
      \l_@@_key_group_clist
      \l_@@_name_tl
      \l_@@_key_thmtools_clist
  }
%    \end{macrocode}
% \end{macro}
% 
%
% \begin{macro}{\groupthm_new_theorem_star_from_keys:nn}
%    \begin{macrocode}
\cs_new:Npn \groupthm_new_theorem_star_from_keys:nn #1 #2
  {
    \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 }

    \groupthm_new_theorem_star:nVVV
      { #1 }
      \l_@@_key_group_clist
      \l_@@_name_tl
      \l_@@_key_thmtools_clist
  }
%    \end{macrocode}
% \end{macro}
% 
%
% \begin{macro}{\groupthm_provide_theorem_star_from_keys:nn}
%    \begin{macrocode}
\cs_new:Npn \groupthm_provide_theorem_star_from_keys:nn #1 #2
  {
    \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 }

    \groupthm_provide_theorem_star:nVVV
      { #1 }
      \l_@@_key_group_clist
      \l_@@_name_tl
      \l_@@_key_thmtools_clist
  }
%    \end{macrocode}
% \end{macro}
%
%  
%
% Now, we can wrap these into document commands
% 
%
% \begin{macro}{\NewGroupedTheorem, \NewGroupedTheorem*}
%    \begin{syntax}
%       \cs{NewGroupedTheorem}\oarg{keys}\marg{theorem name}
%    \end{syntax}
%
%    \begin{macrocode}
\NewDocumentCommand{\NewGroupedTheorem}{s O{} m}
  {
    \IfBooleanTF{#1}
    {
      \groupthm_new_grouped_theorem_star_from_keys:nn { #2 } { #3 }
    }
    {
      \groupthm_new_grouped_theorem_from_keys:nn { #2 } { #3 }
    }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\ProvideGroupedTheorem, \ProvideGroupedTheorem*}
%    \begin{syntax}
%       \cs{ProvideGroupedTheorem}\oarg{keys}\marg{theorem name}
%    \end{syntax}
%
%    \begin{macrocode}
\ProvideDocumentCommand{\NewGroupedTheorem}{s O{} m}
  {
    \IfBooleanTF{#1}
    {
      \groupthm_provide_grouped_theorem_star_from_keys:nn { #2 } { #3 }
    }
    {
      \groupthm_provide_grouped_theorem_from_keys:nn { #2 } { #3 }
    }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% \begin{macro}{\NewTheorem, \NewTheorem*}
%    \begin{syntax}
%       \cs{NewTheorem}\oarg{keys}\marg{theorem name}
%    \end{syntax}
%
%    \begin{macrocode}
\NewDocumentCommand{\NewTheorem}{s O{} m}
  {
    \IfBooleanTF{#1}
    {
      \groupthm_new_theorem_star_from_keys:nn { #2 } { #3 }
    }
    {
      \groupthm_new_theorem_from_keys:nn { #2 } { #3 }
    }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\ProvideTheorem, \ProvideTheorem*}
%    \begin{syntax}
%       \cs{ProvideTheorem}\oarg{keys}\marg{theorem name}
%    \end{syntax}
%
%    \begin{macrocode}
\ProvideDocumentCommand{\NewTheorem}{s O{} m}
  {
    \IfBooleanTF{#1}
    {
      \groupthm_provide_theorem_star_from_keys:nn { #2 } { #3 }
    }
    {
      \groupthm_provide_theorem_from_keys:nn { #2 } { #3 }
    }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% 
% \subsection{Theorem families}
%
%
% We now want to implement the generation of theorem families and their
% corresponding options.
% As a backend, we use the following auxiliary function
% 
%
% \begin{macro}{\@@_declare_grouped_theorem_family_aux:nnnnnn}
%    \begin{syntax}
%       \cs{@@_declare_grouped_theorem_family_aux:nnnnnn}\marg{family name}\marg{groups clist}
%       \marg{name}\marg{name}\marg{thmtools clist}\marg{extra groups clist}\marg{generation type}
%    \end{syntax}
%		 
%   This will generate a new grouped theorem for each union of a subset of \mymeta{groups clist}
%   and the extra set \mymeta{extra groups clist}, with the given properties, that is
%   the \mymeta{nam} and \mymeta{thmtools clist} will be passed to the grouped theorem.
%   The \mymeta{theorem name} of the grouped theorem will be an internal name that contains
%   the \mymeta{family name} and the list of groups of this variant, that will be generated
%   in a unique manner to later retrieve the generated theorems when parsing theorem families.
%    
%  The \mymeta{generation type} can be either \texttt{new} or \texttt{provide},
%  depending on which backend for grouped theorem generation to use
%    \begin{macrocode}
\cs_new:Npn \@@_declare_grouped_theorem_family_aux:nnnnnn #1 #2 #3 #4 #5 #6
  {
%    \end{macrocode}
% Make a local copy of the \mymeta{groups clist} argument,
% and iterate over its powerset
%    \begin{macrocode}
    \clist_set:Nn \l_tmpa_clist { #2 }
    \powerset_clist_foreach:Nn \l_tmpa_clist
      {
%    \end{macrocode}
% We read out the current value of the list, and append the extra groups
% This ensures that now \cs{l_@@_group_clist} iterates over the proper subsets
%    \begin{macrocode}
        \clist_set_eq:NN \l_@@_group_clist \l_tmpa_clist
        \clist_put_right:Nn \l_@@_group_clist { #5 }
%    \end{macrocode}
% This sorting is necessary so that for each theorem family and set of groups,
% the generated name will be unique:
%    \begin{macrocode}
        \@@_sort_group_names:
%    \end{macrocode}
% Now just declare the grouped theorem, passing the corresponding arguments and using
% specified \texttt{\#6} as backend.
%    \begin{macrocode}
        \use:c{groupthm_#6_grouped_theorem:xVnn}
          {__#1__groups_\clist_use:Nn \l_@@_group_clist {_}}
          \l_@@_group_clist
          { #3 }
          { #4 }
      }
  }
%    \end{macrocode}
% \end{macro}
% 
%
% \begin{macro}{\groupthm_new_grouped_theorem_family:nnnn,\groupthm_new_grouped_theorem_family:nVVV}
%    \begin{syntax}
%       \cs{groupthm_new_grouped_theorem_family:nnnn}\marg{family name}
%       \marg{groups}\marg{name}\marg{thmtools clist}
%    \end{syntax}
%		 
%    Just pass the arguments to the auxiliary function, with no additional groups
%    and the \texttt{new} backend.
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_new_grouped_theorem_family:nnnn #1 #2 #3 #4
  {
    \@@_declare_grouped_theorem_family_aux:nnnnnn
      { #1 } { #2 } { #3 } { #4 } { } { new }
  }
\cs_generate_variant:Nn \groupthm_new_grouped_theorem_family:nnnn { n V V V }
%    \end{macrocode}
% \end{macro}
% 
% 
%
% \begin{macro}{\groupthm_provide_grouped_theorem_family:nnnn,\groupthm_provide_grouped_theorem_family:nVVV}
%    \begin{syntax}
%       \cs{groupthm_provide_grouped_theorem_family:nnnn}\marg{family name}
%       \marg{groups}\marg{name}\marg{thmtools clist}
%    \end{syntax}
%		 
%    Just pass the arguments to the auxiliary function, with no additional groups
%    and the \texttt{provide} backend.
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_provide_grouped_theorem_family:nnnn #1 #2 #3 #4
  {
    \@@_declare_grouped_theorem_family_aux:nnnnnn
      { #1 } { #2 } { #3 } { #4 } { } { provide }
  }
\cs_generate_variant:Nn \groupthm_provide_grouped_theorem_family:nnnn { n V V V }
%    \end{macrocode}
% \end{macro}
% 
% 
% The starred variants that add the \texttt{unnumbered} group are straightforward:
% 
% 
% 
% \begin{macro}{\groupthm_new_grouped_theorem_family_star:nnnn,\groupthm_new_grouped_theorem_family_star:nVVV}
%    \begin{syntax}
%       \cs{groupthm_new_grouped_theorem_family_star:nnnn}\marg{family name}
%       \marg{groups}\marg{name}\marg{thmtools clist}
%    \end{syntax}
%		 
%    Just pass the arguments to the auxiliary function, with the additional
%    \texttt{unnumbered group} and the \texttt{new} backend.
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_new_grouped_theorem_family_star:nnnn #1 #2 #3 #4
  {
    \@@_declare_grouped_theorem_family_aux:nnnnnn
      { #1 } { #2 } { #3 } { #4 } { unnumbered } { new }
  }
\cs_generate_variant:Nn \groupthm_new_grouped_theorem_family_star:nnnn { n V V V }
%    \end{macrocode}
% \end{macro}
% 
% 
%
% \begin{macro}{\groupthm_provide_grouped_theorem_family_star:nnnn,\groupthm_provide_grouped_theorem_family_star:nVVV}
%    \begin{syntax}
%       \cs{groupthm_provide_grouped_theorem_family_star:nnnn}\marg{family name}
%       \marg{groups}\marg{name}\marg{thmtools clist}
%    \end{syntax}
%		 
%    Just pass the arguments to the auxiliary function, with the additional
%    \texttt{unnumbered group} and the \texttt{provide} backend.
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_provide_grouped_theorem_family_star:nnnn #1 #2 #3 #4
  {
    \@@_declare_grouped_theorem_family_aux:nnnnnn
      { #1 } { #2 } { #3 } { #4 } { } { provide }
  }
\cs_generate_variant:Nn \groupthm_provide_grouped_theorem_family_star:nnnn { n V V V }
%    \end{macrocode}
% \end{macro}
% 
% 
% Now define the variants that also generate the starred and unstarred family versions.
% 
% 
% \begin{macro}{\groupthm_new_theorem_family:nnnn,\groupthm_new_theorem_family:nVVV}
%    \begin{syntax}
%       \cs{groupthm_new_theorem_family:nnnn}\marg{family name}
%       \marg{groups}\marg{name}\marg{thmtools clist}
%    \end{syntax}
%		 
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_new_theorem_family:nnnn #1 #2 #3 #4
  {
    \@@_declare_grouped_theorem_family_aux:nnnnnn
      { #1 } { #2, starred } { #3 } { #4 } { } { new }
  }
\cs_generate_variant:Nn \groupthm_new_theorem_family:nnnn { n V V V }
%    \end{macrocode}
% \end{macro}
% 
% 
%
% \begin{macro}{\groupthm_provide_theorem_family:nnnn,\groupthm_provide_theorem_family:nVVV}
%    \begin{syntax}
%       \cs{groupthm_provide_theorem_family:nnnn}\marg{family name}
%       \marg{groups}\marg{name}\marg{thmtools clist}
%    \end{syntax}
%		 
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_provide_theorem_family:nnnn #1 #2 #3 #4
  {
    \@@_declare_grouped_theorem_family_aux:nnnnnn
      { #1 } { #2, starred } { #3 } { #4 } { } { provide }
  }
\cs_generate_variant:Nn \groupthm_provide_theorem_family:nnnn { n V V V }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\groupthm_new_theorem_family_star:nnnn,\groupthm_new_theorem_family_star:nVVV}
%    \begin{syntax}
%       \cs{groupthm_new_theorem_family_star:nnnn}\marg{family name}
%       \marg{groups}\marg{name}\marg{thmtools clist}
%    \end{syntax}
%		 
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_new_theorem_family_star:nnnn #1 #2 #3 #4
  {
    \@@_declare_grouped_theorem_family_aux:nnnnnn
      { #1 } { #2, starred } { #3 } { #4 } { unnumbered } { new }
  }
\cs_generate_variant:Nn \groupthm_new_theorem_family_star:nnnn { n V V V }
%    \end{macrocode}
% \end{macro}
% 
% 
%
% \begin{macro}{\groupthm_provide_theorem_family_star:nnnn,\groupthm_provide_theorem_family_star:nVVV}
%    \begin{syntax}
%       \cs{groupthm_provide_theorem_family_star:nnnn}\marg{family name}
%       \marg{groups}\marg{name}\marg{thmtools clist}
%    \end{syntax}
%		 
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_provide_theorem_family_star:nnnn #1 #2 #3 #4
  {
    \@@_declare_grouped_theorem_family_aux:nnnnnn
      { #1 } { #2, starred } { #3 } { #4 } { } { provide }
  }
\cs_generate_variant:Nn \groupthm_provide_theorem_family_star:nnnn { n V V V }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% We now make the key variants available of these, all of the work in the same way
% as we just have to set the normalized keys and pass to our non-key-value versions.
%  
% 
% 
%
% \begin{macro}{\groupthm_new_grouped_theorem_family_from_keys:nn}
%    \begin{syntax}
%       \cs{groupthm_new_grouped_theorem_family_from_keys:nn}\marg{keys}\marg{family name}
%    \end{syntax}
%		 
%   Just retrieve the normalized keys and pass on arguments.
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_new_grouped_theorem_family_from_keys:nn #1 #2
  {
    \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 }
    \groupthm_new_grouped_theorem_family:nVVV
      { #2 }
      \l_@@_group_clist
      \l_@@_name_tl
      \l_@@_thmtools_clist
  }
%    \end{macrocode}
% \end{macro}
% 
% 
%
% \begin{macro}{\groupthm_provide_grouped_theorem_family_from_keys:nn}
%    \begin{syntax}
%       \cs{groupthm_provide_grouped_theorem_family_from_keys:nn}\marg{keys}\marg{family name}
%    \end{syntax}
%		 
%   Just retrieve the normalized keys and pass on arguments.
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_provide_grouped_theorem_family_from_keys:nn #1 #2
  {
    \@@_set_normalized_keys:nnn { #1 } {groupedtheorem} { #2 }
    \groupthm_provide_grouped_theorem_family:nVVV
      { #2 }
      \l_@@_group_clist
      \l_@@_name_tl
      \l_@@_thmtools_clist
  }
%    \end{macrocode}
% \end{macro}
% 
% 
%
% \begin{macro}{\groupthm_new_grouped_theorem_family_star_from_keys:nn}
%    \begin{syntax}
%       \cs{groupthm_new_grouped_theorem_family_star_from_keys:nn}\marg{keys}\marg{family name}
%    \end{syntax}
%		 
%   Just retrieve the normalized keys and pass on arguments.
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_new_grouped_theorem_family_star_from_keys:nn #1 #2
  {
    \@@_set_normalized_keys:nnn { #1 } { groupedtheorem }{ #2 }
    \groupthm_new_grouped_theorem_family_star:nVVV
      { #2 }
      \l_@@_group_clist
      \l_@@_name_tl
      \l_@@_thmtools_clist
  }
%    \end{macrocode}
% \end{macro}
% 
% 
%
% \begin{macro}{\groupthm_provide_grouped_theorem_family_star_from_keys:nn}
%    \begin{syntax}
%       \cs{groupthm_provide_grouped_theorem_family_star_from_keys:nn}\marg{keys}\marg{family name}
%    \end{syntax}
%		 
%   Just retrieve the normalized keys and pass on arguments.
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_provide_grouped_theorem_family_star_from_keys:nn #1 #2
  {
    \@@_set_normalized_keys:nnn { #1 } { groupedtheorem }{ #2 }
    \groupthm_provide_grouped_theorem_family_star:nVVV
      { #2 }
      \l_@@_group_clist
      \l_@@_name_tl
      \l_@@_thmtools_clist
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% \begin{macro}{\groupthm_new_theorem_family_from_keys:nn}
%    \begin{syntax}
%       \cs{groupthm_new_theorem_family_from_keys:nn}\marg{keys}\marg{family name}
%    \end{syntax}
%		 
%   Just retrieve the normalized keys and pass on arguments.
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_new_theorem_family_from_keys:nn #1 #2
  {
    \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 }
    \groupthm_new_theorem_family:nVVV
      { #2 }
      \l_@@_group_clist
      \l_@@_name_tl
      \l_@@_thmtools_clist
  }
%    \end{macrocode}
% \end{macro}
% 
% 
%
% \begin{macro}{\groupthm_provide_theorem_family_from_keys:nn}
%    \begin{syntax}
%       \cs{groupthm_provide_theorem_family_from_keys:nn}\marg{keys}\marg{family name}
%    \end{syntax}
%		 
%   Just retrieve the normalized keys and pass on arguments.
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_provide_theorem_family_from_keys:nn #1 #2
  {
    \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 }
    \groupthm_provide_theorem_family:nVVV
      { #2 }
      \l_@@_group_clist
      \l_@@_name_tl
      \l_@@_thmtools_clist
  }
%    \end{macrocode}
% \end{macro}
% 
% 
%
% \begin{macro}{\groupthm_new_theorem_family_star_from_keys:nn}
%    \begin{syntax}
%       \cs{groupthm_new_theorem_family_star_from_keys:nn}\marg{keys}\marg{family name}
%    \end{syntax}
%		 
%   Just retrieve the normalized keys and pass on arguments.
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_new_theorem_family_star_from_keys:nn #1 #2
  {
    \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 }
    \groupthm_new_theorem_family_star:nVVV
      { #2 }
      \l_@@_group_clist
      \l_@@_name_tl
      \l_@@_thmtools_clist
  }
%    \end{macrocode}
% \end{macro}
% 
% 
%
% \begin{macro}{\groupthm_provide_theorem_family_star_from_keys:nn}
%    \begin{syntax}
%       \cs{groupthm_provide_theorem_family_star_from_keys:nn}\marg{keys}\marg{family name}
%    \end{syntax}
%		 
%   Just retrieve the normalized keys and pass on arguments.
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_provide_theorem_family_star_from_keys:nn #1 #2
  {
    \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 }
    \groupthm_provide_theorem_family_star:nVVV
      { #2 }
      \l_@@_group_clist
      \l_@@_name_tl
      \l_@@_thmtools_clist
  }
%    \end{macrocode}
% \end{macro}
% 
% 
%
% Finally, we can provide document commands that make these available.
% 
%
% \begin{macro}{\NewGroupedTheoremFamily,\NewGroupedTheoremFamily*}
%    \begin{syntax}
%       \cs{NewGroupedTheoremFamily}\oarg{keys}\marg{family name}
%    \end{syntax}
%		 
%     
%
%    \begin{macrocode}
\NewDocumentCommand{\NewGroupedTheoremFamily}{s O{} m}
  {
    \IfBooleanTF { #1 }
      {
        \groupthm_new_grouped_theorem_family_star_from_keys:nn { #2 } { #3 }
      }
      {
        \groupthm_new_grouped_theorem_family_from_keys:nn { #2 } { #3 }
      }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
%
% \begin{macro}{\ProvideGroupedTheoremFamily,\ProvideGroupedTheoremFamily*}
%    \begin{syntax}
%       \cs{ProvideGroupedTheoremFamily}\oarg{keys}\marg{family name}
%    \end{syntax}
%		 
%     
%
%    \begin{macrocode}
\NewDocumentCommand{\ProvideGroupedTheoremFamily}{s O{} m}
  {
    \IfBooleanTF { #1 }
      {
        \groupthm_provide_grouped_theorem_family_star_from_keys:nn { #2 } { #3 }
      }
      {
        \groupthm_provide_grouped_theorem_family_from_keys:nn { #2 } { #3 }
      }
  }
%    \end{macrocode}
% \end{macro}
% 
%
% \begin{macro}{\NewTheoremFamily,\NewTheoremFamily*}
%    \begin{syntax}
%       \cs{NewTheoremFamily}\oarg{keys}\marg{family name}
%    \end{syntax}
%		 
%     
%
%    \begin{macrocode}
\NewDocumentCommand{\NewTheoremFamily}{s O{} m}
  {
    \IfBooleanTF { #1 }
      {
        \groupthm_new_theorem_family_star_from_keys:nn { #2 } { #3 }
      }
      {
        \groupthm_new_theorem_family_from_keys:nn { #2 } { #3 }
      }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
%
% \begin{macro}{\ProvideTheoremFamily,\ProvideTheoremFamily*}
%    \begin{syntax}
%       \cs{ProvideTheoremFamily}\oarg{keys}\marg{family name}
%    \end{syntax}
%		 
%     
%
%    \begin{macrocode}
\NewDocumentCommand{\ProvideTheoremFamily}{s O{} m}
  {
    \IfBooleanTF { #1 }
      {
        \groupthm_provide_theorem_family_star_from_keys:nn { #2 } { #3 }
      }
      {
        \groupthm_provide_theorem_family_from_keys:nn { #2 } { #3 }
      }
  }
%    \end{macrocode}
% \end{macro}
% 
%
% \subsection{Theorem family options}
% 
% 
%
% \begin{macro}{\groupthm_add_theorem_to_group:n}
%    \begin{syntax}
%       \cs{groupthm_add_theorem_to_group:n}\marg{theorem group}
%    \end{syntax}
%		 
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_add_theorem_to_group:n #1
  {
%    \end{macrocode}
% As mentioned earlier, this bool will indicate whether we are 
% executing a \mymeta{selection body} from some family options.
% If used outside, we emit an error message.
%    \begin{macrocode}
    \bool_if:NTF \l_@@_in_family_options_environment_bool
      {
        \clist_put_left:Nn \l_@@_group_clist { #1 }
      }
      {
        \msg_error:nn { groupthm } { misuse ~ add ~ theorem ~ to ~ group }
      }
  }
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\AddTheoremToGroup}
%    \begin{syntax}
%       \cs{AddTheoremToGroup}\marg{theorem group}
%    \end{syntax}
%		 
%     
%
%    \begin{macrocode}
  \NewDocumentCommand { \AddTheoremToGroup } { m }
  {
    \groupthm_add_theorem_to_group:n { #1 }
  }
%    \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\@@_declare_theorem_family_options_aux:nnnnn}
%    \begin{syntax}
%       \c{@@_declare_theorem_family_options_aux:nnnnn}\marg{theorem family}
%        \marg{argument specification}\marg{selection body}\marg{extra groups}\marg{declaring backend}
%    \end{syntax}
%		 
%     This declares a new theorem variant option parser, i.e.~ introduces the environment
%     \mymeta{theorem family} with signature \marg{argument specification}.
% 
%     The \mymeta{selection body} will be executed and selects some groups the environment shall have.
%     The \mymeta{extra groups} will be added regardless of the arguments given
%     to the \mymeta{theorem family}
%     The \mymeta{declaring backend} is one of \texttt{New}, \texttt{Renew}, \texttt{Provide}
%     and \texttt{Declare} and is given to the \texttt{DocumentEnvironment} command from \pkg{xpars}.
%
%    \begin{macrocode}
\cs_new:Npn \@@_declare_theorem_family_options_aux:nnnnn #1 #2 #3 #4 #5
  {
    \use:c{ #5 DocumentEnvironment }
      { #1 }
      { #2 }
      {
%    \end{macrocode}
% We can now clear the group list and execute the \mymeta{selection body}
% that populates this list again.
% Additionally, we add the groups that should always be present and activate the
% \cs{AddTheoremToGroup} macro by setting the bool.
%    \begin{macrocode}
        \clist_clear:N \l_@@_group_clist
        \bool_set_true:N \l_@@_in_family_options_environment_bool
        #3
        \bool_set_false:N \l_@@_in_family_options_environment_bool
        \clist_put_right:Nn \l_@@_group_clist { #4 }
%    \end{macrocode}
% We now got the list of groups parsed. We sort this and start the corresponding
% environment that has been generated by a \cs{NewGroupedTheoremFamily} command
% or similar.
%    \begin{macrocode}
        \@@_sort_group_names:
        \cs_if_exist:cTF { __#1__groups_ \clist_use:Nn \l_@@_group_clist { _ } }
        {
          \begin { __#1__groups_ \clist_use:Nn \l_@@_group_clist { _ } }
        }
        {
          \msg_error:nnxx { groupthm } { undefined ~ theorem ~ variant }
            { #1 }
            { \clist_use:Nnnn \l_@@_group_clist { ~ and ~ } {, ~} { , ~ and ~ } }
        }
      }
      {
%    \end{macrocode}
% At the end of the environment, we have to do the same parsing again.
%    \begin{macrocode}
        \clist_clear:N \l_@@_group_clist
        \bool_set_true:N \l_@@_in_family_options_environment_bool
        #3
        \bool_set_false:N \l_@@_in_family_options_environment_bool
        \clist_put_right:Nn \l_@@_group_clist { #4 }
%    \end{macrocode}
% End the corresponding environment.
%    \begin{macrocode}
        \@@_sort_group_names:
        \end { __#1__groups_ \clist_use:Nn \l_@@_group_clist { _ } }
      }
  }
%    \end{macrocode}
% \end{macro}
% 
%
%  All other macros are now essentially wrappers around this aux macro,
%  passing different \mymeta{extra groups} to them
%
% \begin{macro}{\groupthm_new_grouped_theorem_family_options:nnn}
%    \begin{syntax}
%       \cs{groupthm_new_grouped_theorem_family_options:nnn}\marg{theorem family}
%       \marg{signature}\marg{selection body}
%    \end{syntax}
%		 
%    \begin{macrocode}
\cs_new:Npn \groupthm_new_grouped_theorem_family_options:nnn #1 #2 #3
{
  \@@_declare_theorem_family_options_aux:nnnnn
    { #1 } { #2 } { #3 } { } { New }
}
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% \begin{macro}{\groupthm_renew_grouped_theorem_family_options:nnn}
%    \begin{syntax}
%       \cs{groupthm_renew_grouped_theorem_family_options:nnn}\marg{theorem family}
%       \marg{signature}\marg{selection body}
%    \end{syntax}
%		 
%    \begin{macrocode}
\cs_new:Npn \groupthm_renew_grouped_theorem_family_options:nnn #1 #2 #3
{
  \@@_declare_theorem_family_options_aux:nnnnn
    { #1 } { #2 } { #3 } { } { Renew }
}
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% \begin{macro}{\groupthm_provide_grouped_theorem_family_options:nnn}
%    \begin{syntax}
%       \cs{groupthm_provide_grouped_theorem_family_options:nnn}\marg{theorem family}
%       \marg{signature}\marg{selection body}
%    \end{syntax}
%		 
%    \begin{macrocode}
\cs_new:Npn \groupthm_provide_grouped_theorem_family_options:nnn #1 #2 #3
{
  \@@_declare_theorem_family_options_aux:nnnnn
    { #1 } { #2 } { #3 } { } { Provide }
}
%    \end{macrocode}
% \end{macro}
%
% 
% 
% \begin{macro}{\groupthm_declare_grouped_theorem_family_options:nnn}
%    \begin{syntax}
%       \cs{groupthm_declare_grouped_theorem_family_options:nnn}\marg{theorem family}
%       \marg{signature}\marg{selection body}
%    \end{syntax}
%		 
%    \begin{macrocode}
\cs_new:Npn \groupthm_declare_grouped_theorem_family_options:nnn #1 #2 #3
{
  \@@_declare_theorem_family_options_aux:nnnnn
    { #1 } { #2 } { #3 } { } { Declare }
}
%    \end{macrocode}
% \end{macro}
%
% 
% 
% The variants without \enquote{grouped} in their name will just issue two commands,
% one with and one without the \texttt{starred} group, and add a \enquote{*} to the name.
% 
% \begin{macro}{\groupthm_new_theorem_family_options:nnn}
%    \begin{syntax}
%       \cs{groupthm_new_theorem_family_options:nnn}\marg{theorem family}
%       \marg{signature}\marg{selection body}
%    \end{syntax}
%		 
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_new_theorem_family_options:nnn #1 #2 #3
{
  \@@_declare_theorem_family_options_aux:nnnnn
    { #1 } { #2 } { #3 } { } { New }
  \@@_declare_theorem_family_options_aux:nnnnn
    { #1* } { #2 } { #3 } { starred } { New }
}
%    \end{macrocode}
% \end{macro}
% 
% \begin{macro}{\groupthm_renew_theorem_family_options:nnn}
%    \begin{syntax}
%       \cs{groupthm_renew_theorem_family_options:nnn}\marg{theorem family}
%       \marg{signature}\marg{selection body}
%    \end{syntax}
%		 
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_renew_theorem_family_options:nnn #1 #2 #3
{
  \@@_declare_theorem_family_options_aux:nnnnn
    { #1 } { #2 } { #3 } { } { Renew }
  \@@_declare_theorem_family_options_aux:nnnnn
    { #1* } { #2 } { #3 } { starred } { Renew }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\groupthm_provide_theorem_family_options:nnn}
%    \begin{syntax}
%       \cs{groupthm_provide_theorem_family_options:nnn}\marg{theorem family}
%       \marg{signature}\marg{selection body}
%    \end{syntax}
%		 
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_provide_theorem_family_options:nnn #1 #2 #3
{
  \@@_declare_theorem_family_options_aux:nnnnn
    { #1 } { #2 } { #3 } { } { Provide }
  \@@_declare_theorem_family_options_aux:nnnnn
    { #1* } { #2 } { #3 } { starred } { Provide }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\groupthm_declare_theorem_family_options:nnn}
%    \begin{syntax}
%       \cs{groupthm_declare_theorem_family_options:nnn}\marg{theorem family}
%       \marg{signature}\marg{selection body}
%    \end{syntax}
%		 
%
%    \begin{macrocode}
\cs_new:Npn \groupthm_declare_theorem_family_options:nnn #1 #2 #3
{
  \@@_declare_theorem_family_options_aux:nnnnn
    { #1 } { #2 } { #3 } { } { Declare }
  \@@_declare_theorem_family_options_aux:nnnnn
    { #1* } { #2 } { #3 } { starred } { Declare }
}
%    \end{macrocode}
% \end{macro}
%
% 
% It remains to wrap these into document commands 
% 
%
% \begin{macro}{\NewGroupedTheoremFamilyOptions, \NewGroupedTheoremFamilyOptions*}
%    \begin{syntax}
%       \cs{NewGroupedTheoremFamilyOptions}\marg{family name}\marg{signature}
%       \marg{selection body}
%    \end{syntax}
%		 
%    \begin{macrocode}
\NewDocumentCommand { \NewGroupedTheoremFamilyOptions } { s m m m }
{
  \IfBooleanTF { #1 }
  {
    \groupthm_new_grouped_theorem_family_options:nnn
      { #2 }
      { #3 }
      {
        #4
        \groupthm_add_theorem_to_group:n { unnumbered }
      }
  }
  {
    \groupthm_new_grouped_theorem_family_options:nnn
      { #2 }
      { #3 }
      { #4 }
  }
}
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% \begin{macro}{\RenewGroupedTheoremFamilyOptions, \RenewGroupedTheoremFamilyOptions*}
%    \begin{syntax}
%       \cs{RenewGroupedTheoremFamilyOptions}\marg{family name}\marg{signature}
%       \marg{selection body}
%    \end{syntax}
%		 
%    \begin{macrocode}
\NewDocumentCommand { \RenewGroupedTheoremFamilyOptions } { s m m m }
{
  \IfBooleanTF { #1 }
  {
    \groupthm_renew_grouped_theorem_family_options:nnn
      { #2 }
      { #3 }
      {
        #4
        \groupthm_add_theorem_to_group:n { unnumbered }
      }
  }
  {
    \groupthm_renew_grouped_theorem_family_options:nnn
      { #2 }
      { #3 }
      { #4 }
  }
}
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\ProvideGroupedTheoremFamilyOptions, \ProvideGroupedTheoremFamilyOptions*}
%    \begin{syntax}
%       \cs{ProvideGroupedTheoremFamilyOptions}\marg{family name}\marg{signature}
%       \marg{selection body}
%    \end{syntax}
%		 
%    \begin{macrocode}
\NewDocumentCommand { \ProvideGroupedTheoremFamilyOptions } { s m m m }
{
  \IfBooleanTF { #1 }
  {
    \groupthm_provide_grouped_theorem_family_options:nnn
      { #2 }
      { #3 }
      {
        #4
        \groupthm_add_theorem_to_group:n { unnumbered }
      }
  }
  {
    \groupthm_provide_grouped_theorem_family_options:nnn
      { #2 }
      { #3 }
      { #4 }
  }
}
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\DeclareGroupedTheoremFamilyOptions, \DeclareGroupedTheoremFamilyOptions*}
%    \begin{syntax}
%       \cs{DeclareGroupedTheoremFamilyOptions}\marg{family name}\marg{signature}
%       \marg{selection body}
%    \end{syntax}
%		 
%    \begin{macrocode}
\NewDocumentCommand { \DeclareGroupedTheoremFamilyOptions } { s m m m }
{
  \IfBooleanTF { #1 }
  {
    \groupthm_declare_grouped_theorem_family_options:nnn
      { #2 }
      { #3 }
      {
        #4
        \groupthm_add_theorem_to_group:n { unnumbered }
      }
  }
  {
    \groupthm_declare_grouped_theorem_family_options:nnn
      { #2 }
      { #3 }
      { #4 }
  }
}
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% 
%
% \begin{macro}{\NewTheoremFamilyOptions, \NewTheoremFamilyOptions*}
%    \begin{syntax}
%       \cs{NewTheoremFamilyOptions}\marg{family name}\marg{signature}
%       \marg{selection body}
%    \end{syntax}
%		 
%    \begin{macrocode}
\NewDocumentCommand { \NewTheoremFamilyOptions } { s m m m }
{
  \IfBooleanTF { #1 }
  {
    \groupthm_new_theorem_family_options:nnn
      { #2 }
      { #3 }
      {
        #4
        \groupthm_add_theorem_to_group:n { unnumbered }
      }
  }
  {
    \groupthm_new_theorem_family_options:nnn
      { #2 }
      { #3 }
      { #4 }
  }
}
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% \begin{macro}{\RenewTheoremFamilyOptions, \RenewTheoremFamilyOptions*}
%    \begin{syntax}
%       \cs{RenewTheoremFamilyOptions}\marg{family name}\marg{signature}
%       \marg{selection body}
%    \end{syntax}
%		 
%    \begin{macrocode}
\NewDocumentCommand { \RenewTheoremFamilyOptions } { s m m m }
{
  \IfBooleanTF { #1 }
  {
    \groupthm_renew_theorem_family_options:nnn
      { #2 }
      { #3 }
      {
        #4
        \groupthm_add_theorem_to_group:n { unnumbered }
      }
  }
  {
    \groupthm_renew_theorem_family_options:nnn
      { #2 }
      { #3 }
      { #4 }
  }
}
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\ProvideTheoremFamilyOptions, \ProvideTheoremFamilyOptions*}
%    \begin{syntax}
%       \cs{ProvideTheoremFamilyOptions}\marg{family name}\marg{signature}
%       \marg{selection body}
%    \end{syntax}
%		 
%    \begin{macrocode}
\NewDocumentCommand { \ProvideTheoremFamilyOptions } { s m m m }
{
  \IfBooleanTF { #1 }
  {
    \groupthm_provide_theorem_family_options:nnn
      { #2 }
      { #3 }
      {
        #4
        \groupthm_add_theorem_to_group:n { unnumbered }
      }
  }
  {
    \groupthm_provide_theorem_family_options:nnn
      { #2 }
      { #3 }
      { #4 }
  }
}
%    \end{macrocode}
% \end{macro}
% 
% 
% \begin{macro}{\DeclareTheoremFamilyOptions, \DeclareTheoremFamilyOptions*}
%    \begin{syntax}
%       \cs{DeclareTheoremFamilyOptions}\marg{family name}\marg{signature}
%       \marg{selection body}
%    \end{syntax}
%		 
%    \begin{macrocode}
\NewDocumentCommand { \DeclareTheoremFamilyOptions } { s m m m }
{
  \IfBooleanTF { #1 }
  {
    \groupthm_declare_theorem_family_options:nnn
      { #2 }
      { #3 }
      {
        #4
        \groupthm_add_theorem_to_group:n { unnumbered }
      }
  }
  {
    \groupthm_declare_theorem_family_options:nnn
      { #2 }
      { #3 }
      { #4 }
  }
}
%    \end{macrocode}
% \end{macro}
% 
% 
% 
% 
% 
% 
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
%   \end{implementation}
% 
% 
% 
% 
% \ExplSyntaxOn
% \__codedoc_special_index_module:nnnnN { key } { macro } { module } { main } { \c_false_bool}
% \__codedoc_special_index_module:nnnnN { l } { bla } { module } { usage } { \c_false_bool}
% \ExplSyntaxOff
% 
% \newpage
% \PrintIndex
