2602 lines
82 KiB
TeX
2602 lines
82 KiB
TeX
% \iffalse meta-comment
|
|
%<*internal>
|
|
\begingroup
|
|
\input docstrip.tex
|
|
\keepsilent
|
|
\usedir{tex/latex/mkessler/groupthm}
|
|
\askforoverwritefalse
|
|
\generate{\file{groupthm.sty}{\from{groupthm.dtx}{package}}}
|
|
\def\tmpa{plain}
|
|
\ifx\tmpa\fmtname\endgroup\expandafter\bye\fi
|
|
\endgroup
|
|
%</internal>
|
|
%
|
|
%% 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}
|
|
\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
|
|
%
|
|
% \begin{documentation}
|
|
%
|
|
%
|
|
%
|
|
% 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, \meta{theorem group}s,
|
|
% to structure theorems into groups that can subsequently easily altered,
|
|
% as well as a mechanism for easily generating \meta{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 \meta{theorem}s themselves.
|
|
%
|
|
% Thus, any styles supported by \pkg{thmtools} will be supported by \pkg{groupthm}
|
|
% as well, by passing them to \pkg{thmtools}.
|
|
%
|
|
%
|
|
% In this documentation, we first give a more detailed overview of the concepts
|
|
% provided, and then describe the usage in detail.
|
|
%
|
|
% \newpage
|
|
% \tableofcontents
|
|
% \newpage
|
|
%
|
|
% \section{Concepts}
|
|
%
|
|
% \subsection{Theorem groups}
|
|
% \label{sec:theorem-groups}
|
|
% A \meta{theorem group} is some named group holding some properties for
|
|
% the \meta{theorem}s that are contained in this group.
|
|
% Each \meta{theorem} can, when declared, be part of arbitrarily many \meta{theorem group}s,
|
|
% and will be subject to the styles these groups defined.
|
|
%
|
|
% This enables to group similar \meta{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 \meta{theorem group}, and not all \meta{theorem}s separately.
|
|
%
|
|
% The properties. Such a \meta{theorem group} can hold are as follows
|
|
%
|
|
%
|
|
% \begin{description}
|
|
% \item[\texttt{prefix}] A prefix (any \meta{token list}) that will be inserted
|
|
% before the theorem name of each member of this \meta{theorem group}.
|
|
% \item[\texttt{suffix}] A suffix (any \meta{token list}) that will be
|
|
% inserted before the theorem name for each member of this \meta{theorem group}.
|
|
% This could be e.g.~some \enquote{$\star$} appended to the name to indicate
|
|
% variants of environments.
|
|
% \item[\texttt{mapname}] A \meta{function} (some macro that takes exactly one argument)
|
|
% that is applied to the \texttt{name}.
|
|
% \item[\texttt{thmtools}] A \meta{clist} of key-value pairs that are passed to the underlying
|
|
% \pkg{thmtools} backend of the \meta{theorem}.
|
|
% This allows e.g.~to set the \texttt{topskip} of a certain class of \meta{theorem}s.
|
|
% \end{description}
|
|
%
|
|
% The most versatile key here is certainly the \texttt{thmtools} key,
|
|
% providing the most customization to an end user (like you).
|
|
%
|
|
% As mentioned, each \meta{theorem} can be member of arbitrary many \meta{theorem group}s,
|
|
% and will posses their corresponding properties.
|
|
%
|
|
% To adjust finer controlling of these \meta{theorem group}s, \meta{theorem group}s can inherit from each other, and \meta{theorem group}s are subject to a hierarchy that controls precedence in case
|
|
% of conflicting properties of different \meta{theorem group}s a \meta{theorem} may be part of.
|
|
%
|
|
% This hierarchy can of course be controlled by the user.
|
|
%
|
|
% \subsection{Grouped theorems}
|
|
%
|
|
% A \meta{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 \meta{theorem variant}s of some \meta{theorem}, the most typical
|
|
% example being \texttt{starred} version of \meta{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}
|
|
%
|
|
% \pkg{groupthm} extends this idea and provides a versatile mechanism to define a
|
|
% \meta{theorem family}, which is based on some \meta{theorem name} and
|
|
% parses additional arguments / syntax to control the \meta{theorem groups}
|
|
% that this environment is a part of.
|
|
%
|
|
% So, in addition the name of a \meta{theorem}, the corresponding environment will
|
|
% accept some options and toggle the membership of certain \meta{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}
|
|
%
|
|
% Providing this consists of two parts:
|
|
% declaring the \meta{theorem family} by listing the groups that can be toggled
|
|
% by this \meta{theorem family}, and declaring the actual option parsing
|
|
% of the \meta{theorem family}, which then controls the membership in these groups
|
|
% (and of course prior to this the definition of the desired \meta{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 \texttt{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 \texttt{foo} if not defined already.
|
|
% This emits an error in case it has been defined yet.
|
|
%
|
|
% \item[\cs{RenewFoo}]
|
|
%
|
|
% Redefines \texttt{foo} if defined already.
|
|
% This emits an error in case it has \emph{not} been defined yet.
|
|
%
|
|
% \item[\cs{ProvideFoo}]
|
|
%
|
|
% Defines \texttt{foo} if it is not defined already.
|
|
% This does not emit an error if \texttt{foo} is already defined
|
|
% (and has no effect in this case).
|
|
%
|
|
% \item[\cs{DeclareFoo}]
|
|
%
|
|
% Defines \texttt{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}
|
|
%
|
|
% \begin{danger}
|
|
% Paragraphs like this that begin with a dangerous bend sign give more details
|
|
% that could be used, but whose use is not recommended, as it does not apply
|
|
% to the usual naming conventions. Use at your own responsibility.
|
|
% \end{danger}
|
|
%
|
|
% \section{Theorem groups}
|
|
%
|
|
% \subsection{Defining theorem groups}
|
|
%
|
|
% \begin{function}{\NewTheoremGroup, \RenewTheoremGroup, \ProvideTheoremGroup, \DeclareTheoremGroup}
|
|
% \begin{syntax}
|
|
% \cs{NewTheoremGroup}\oarg{key=value list}\marg{theorem group}
|
|
% \end{syntax}
|
|
%
|
|
% This introduces a new \meta{theorem group} with the given name.
|
|
% The \meta{key=value list} available are the same as introduced in \autoref{sec:theorem-groups}:
|
|
%
|
|
% \begin{description}
|
|
% \item
|
|
%
|
|
% \texttt{prefix} = \meta{token list}.
|
|
% Insert the \meta{token list} in front of the theorem name.
|
|
%
|
|
% \item
|
|
%
|
|
% \texttt{suffix} = \meta{token list}.
|
|
% Insert the \meta{token list} after the theorem name.
|
|
%
|
|
% \item
|
|
%
|
|
% \texttt{mapname} = \meta{function}.
|
|
% Apply this \meta{function} to the theorem name.
|
|
%
|
|
% \item
|
|
%
|
|
% \texttt{thmtools} = $\{$\meta{clist}$\}$.
|
|
% Pass these options to \pkg{thmtools}.
|
|
%
|
|
% \end{description}
|
|
%
|
|
% For uniqueness of the given options, the \meta{clist} given to the \texttt{thmtools} key
|
|
% has to be surrounded by a pair of braces.
|
|
%
|
|
% \begin{texnote}
|
|
% The \texttt{mapname} is expected to be a function of \cs{fun:n}.
|
|
% The function call is subject to an \texttt{x}-type expansion prior
|
|
% to being passed further to \pkg{thmtools}.
|
|
% \end{texnote}
|
|
%
|
|
% \end{function}
|
|
%
|
|
% \subsection{Controlling theorem group precedence}
|
|
% \label{subsec: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 \meta{keyname} can be one of \texttt{prefix}, \texttt{suffix}, \texttt{mapname}, \texttt{thmtools}.
|
|
% If present, it declares the corresponding relation only for this subkey.
|
|
% This can lead to \meta{theorem group_} overwriting \meta{theorem group_2} when given
|
|
% contradictory \pkg{thmtools} options, but the \texttt{prefix} of \meta{theorem group_}
|
|
% being applied after the one of \meta{theorem group_2}.
|
|
% When the \meta{keyname} is not given, this applies to all keywords.
|
|
%
|
|
% \begin{texnote}
|
|
% The \meta{keyname} is just passed to the corresponding argument
|
|
% of the \texttt{lthooks} package.
|
|
% If the option argument is not present, \texttt{??} 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
|
|
% \pkg{lthooks} packages documentation for a list of the full keys.
|
|
% For us, the following list will suffice:
|
|
%
|
|
% \begin{description}
|
|
% \item[\texttt{higher} or \texttt{after} or \texttt{\string>}]
|
|
%
|
|
% \meta{theorem group_1} takes precedence over \meta{theorem group_2}.
|
|
% Its \texttt{prefix} is applied after the one of \meta{theorem group_2}.
|
|
%
|
|
% \item[\texttt{lower} or \texttt{before} or \texttt{\string<}]
|
|
%
|
|
% \meta{theorem group_2} takes precedence over \meta{theorem group_1}.
|
|
% Its \texttt{prefix} is applied after the one of \meta{theorem group_1}.
|
|
%
|
|
% \end{description}
|
|
%
|
|
% \begin{texnote}
|
|
% The \meta{relation} is first stripped,
|
|
% then checked if it matches either \texttt{higher} or \texttt{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 \meta{theorem group_1} to \enquote{inherit} all properties
|
|
% of \meta{theorem group_2}.
|
|
% In other words, \meta{theorem group_2} is a parent of \meta{theorem group_1}
|
|
% in a usual inheritance graph.
|
|
%
|
|
% The definitions of the groups themselves are unchanged,
|
|
% but each new theorem defined with \meta{theorem group_1} will also
|
|
% have the properties of \meta{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
|
|
% \autoref{subsec:theorem-group-precedence}.
|
|
% This can even yield situations, where \meta{theorem group_1} inherits
|
|
% from \meta{theorem group_2}, but \meta{theorem group_2} overwrites
|
|
% \meta{theorem group_1}.
|
|
% \end{function}
|
|
%
|
|
% \subsection{Appending to theorem groups}
|
|
% \begin{function}{\AppendToTheoremGroup}
|
|
% \begin{syntax}
|
|
% \cs{AppendToTheoremGroup}\oarg{key=value list}\marg{theorem group}
|
|
% \end{syntax}
|
|
% Adds the properties given as \meta{key=value list} to the theorem group.
|
|
% The syntax for the \meta{key=value list} is the same as in \cs{NewTheoremGroup}.
|
|
% \end{function}
|
|
%
|
|
% \subsection{Default theorem groups}
|
|
% \label{subsec: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.
|
|
% See the documentation for \cs{NewGroupedTheorem}, \cs{NewGroupedTheoremFamily}
|
|
% and \cs{NewGroupedTheoremFamilyOptions} how this group is treated.
|
|
%
|
|
% 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.
|
|
% Versions of all commands exist that add theorems to this group.
|
|
%
|
|
% 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 \texttt{starred} and \texttt{unnumbered}
|
|
% to both exist is that the \texttt{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
|
|
% \texttt{theorem} and \texttt{theorem*}, even if \texttt{theorem} is in the \texttt{unnumbered} group.
|
|
%
|
|
% So assuming that \texttt{theorem} is member of the \texttt{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 \texttt{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{key=value list}\marg{grouped theorem}
|
|
% \end{syntax}
|
|
% This defines \meta{grouped theorem} and \meta{grouped theorem*} as new theorem environments.
|
|
% Its properties can be set by the following keys:
|
|
%
|
|
% \begin{description}
|
|
%
|
|
% \item
|
|
%
|
|
% \texttt{name} $=$ \meta{displayed name}.
|
|
% If given, this is the displayed name of the environment in the document.
|
|
% If not present, the \meta{grouped theorem} is also used as the \meta{displayed name}
|
|
% in capitalized form.
|
|
%
|
|
% \item
|
|
%
|
|
% \texttt{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
|
|
%
|
|
% \texttt{thmtools} = \marg{clist}
|
|
%
|
|
% Passes these option to the \pkg{thmtools} environment that is declared internally.
|
|
%
|
|
% \end{description}
|
|
%
|
|
% The \meta{grouped theorem*} behaves the same as the \meta{grouped theorem},
|
|
% but additionally will be a member of the \texttt{starred} theorem group,
|
|
% see \autoref{subsec:default-theorem-groups}.
|
|
%
|
|
% \begin{danger}
|
|
% If you don't wish the \meta{grouped theorem*} variant to be generated,
|
|
% you can pass the additional option \texttt{starred version = false}.
|
|
% If you are not sure about this, you are probably fine without this option.
|
|
% \end{danger}
|
|
%
|
|
%
|
|
% \end{function}
|
|
%
|
|
% \begin{function}{\NewGroupedTheorem*,\ProvideGroupedTheorem*}
|
|
% \begin{syntax}
|
|
% \cs{NewGroupedTheorem*}\oarg{key=value list}\marg{grouped theorem}
|
|
% \end{syntax}
|
|
% Behaves the same as \cs{NewGroupedTheorem},
|
|
% but also adds the theorem(s) to the default \texttt{unnumbered} group,
|
|
% thus resulting in the environment not being numbered.
|
|
%
|
|
% This is thus equivalent to using \cs{NewGroupedTheorem} and adding the
|
|
% \texttt{unnumbered} group.
|
|
% \end{function}
|
|
%
|
|
%
|
|
% \subsection{Defining families of grouped theorems}
|
|
%
|
|
%
|
|
% \begin{function}{\NewGroupedTheoremFamily, \ProvideGroupedTheoremFamily}
|
|
% \begin{syntax}
|
|
% \cs{NewGroupedTheoremFamily}\oarg{key=value list}\marg{theorem family}
|
|
% \end{syntax}
|
|
%
|
|
% Defines a family of grouped theorems.
|
|
% The \meta{key=value list} 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 \texttt{GroupedTheoremFamilyOptions} have to specified,
|
|
% see \cs{NewGroupedTheoremFamilyOptions}.
|
|
%
|
|
% Also, to the given groups, the \texttt{starred} group is added automatically.
|
|
%
|
|
% \begin{danger}
|
|
% If you do not wish the \texttt{starred} versions,
|
|
% you can set the key \texttt{starred version = false}.
|
|
% \end{danger}
|
|
%
|
|
% \end{function}
|
|
%
|
|
% \begin{function}{\NewGroupedTheoremFamily*, \ProvideGroupedTheoremFamily*}
|
|
% Behaves the same as \cs{NewGroupedTheoremFamily}, but also adds each variant
|
|
% to the default \texttt{unnumbered} group, thus resulting in the environments not being
|
|
% numbered.
|
|
%
|
|
% This is \emph{almost} equivalent to calling \cs{NewGroupedTheoremFamily}
|
|
% with the \texttt{unnumbered} group being present, as it does not generate the variants
|
|
% where the \texttt{unnumbered} group is not present.
|
|
% \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 family}\marg{argument specifiation}%
|
|
% \marg{selection body}
|
|
% \end{syntax}
|
|
%
|
|
% Defines two new environment with options, given by \meta{theorem family}
|
|
% and \meta{theorem family*}.
|
|
% The \meta{argument specification} can be any valid \pkg{xparse} argument specification.
|
|
%
|
|
% The \meta{selection body} is there to process the options of
|
|
% the \meta{argument specification} and select which variant of the \meta{theorem family}
|
|
% to enter.
|
|
% The arguments are available as usual with \pkg{xparse} by \texttt{\#1}, \texttt{\#2}, \ldots
|
|
%
|
|
% The body may also call any number of \cs{AddTheoremToGroup} calls,
|
|
% which the enables the corresponding groups to be toggled.
|
|
%
|
|
% When the environment is called within the document, the options are parsed
|
|
% as with \pkg{xparse} and the \meta{selection body} is executed.
|
|
% Immediately after, the theorem variant of \meta{theorem family} with the specified groups
|
|
% by \cs{AddTheoremToGroup} is called.
|
|
%
|
|
% At the end of the environment, the \meta{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.
|
|
% \begin{danger}
|
|
% As always, if you do not wish the \meta{theorem family*} version to be generated,
|
|
% you can pass \texttt{starred version = false} as an additional key.
|
|
% \end{danger}
|
|
%
|
|
% \end{function}
|
|
%
|
|
% \begin{function}
|
|
% {
|
|
% \NewGroupedTheoremFamilyOptions*, \RenewGroupedTheoremFamilyOptions*,
|
|
% \ProvideGroupedTheoremFamilyOptions*, \DeclareGroupedTheoremFamilyOptions*
|
|
% }
|
|
% \begin{syntax}
|
|
% \cs{NewGroupedTheoremFamilyOptions*}\marg{theorem family}\marg{argument specifiation}%
|
|
% \marg{selection body}
|
|
% \end{syntax}
|
|
%
|
|
% Does the same as \cs{NewGroupedTheoremFamilyOptions},
|
|
% but calls the variants with the additional \texttt{unnumbered} group.
|
|
%
|
|
% The possible theorem variants have to be generated
|
|
% with the \cs{NewGroupedTheoremFamily*} 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 some cases.
|
|
%
|
|
% Most of the time, however, the document level commands will provide
|
|
% a better interface that just accepts more options than the
|
|
% underlying \LaTeX3 interface does.
|
|
% Feel free to just use these directly.
|
|
%
|
|
% 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}
|
|
%
|
|
%
|
|
% \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{key=value list}\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}
|
|
% \marg{suffix}\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}
|
|
%
|
|
%
|
|
%
|
|
% \begin{function}{\groupthm_add_parent:nn}
|
|
% \begin{syntax}
|
|
% \cs{groupthm_add_parent:nn}\marg{theorem group_1}\marg{theorem group_2}
|
|
% \end{syntax}
|
|
%
|
|
% \LaTeX3 version of \cs{AddTheoremGroupParent}.
|
|
%
|
|
% \end{function}
|
|
%
|
|
%
|
|
%
|
|
% \begin{function}{\groupthm_append_to_group:nn}
|
|
% \begin{syntax}
|
|
% \cs{groupthm_append_to_group:nn}\marg{key=value list}\marg{theorem group}
|
|
% \end{syntax}
|
|
%
|
|
% \LaTeX3 version of \cs{AppendToTheoremGroup}.
|
|
%
|
|
% \end{function}
|
|
% \subsection{Grouped theorems}
|
|
%
|
|
% \begin{function}{\groupthm_new_theorem:nnnn, \groupthm_provide_theorem:nnnn}
|
|
% \begin{syntax}
|
|
% \cs{groupthm_new_theorem:nnnn}\marg{grouped theorem}\marg{groups}
|
|
% \marg{name}\marg{thmtools keys}
|
|
% \end{syntax}
|
|
%
|
|
%
|
|
%
|
|
% \end{function}
|
|
% \begin{function}{\groupthm_new_theorem:nnn, \groupthm_provide_theorem:nnn}
|
|
% \begin{syntax}
|
|
% \cs{groupthm_new_theorem:nnn}\marg{key=value list}\marg{theorem group}\marg{bool}
|
|
% \end{syntax}
|
|
%
|
|
% \LaTeX3 version of \cs{NewGroupedTheorem}. The given \meta{bool} indicates the presence of
|
|
% the \enquote{*}, i.e.~if it is true, the new theorem will be additionally added to the
|
|
% \texttt{unnumbered} group.
|
|
%
|
|
% \end{function}
|
|
%
|
|
%
|
|
% \subsection{Theorem families}
|
|
%
|
|
%
|
|
% \begin{function}{\groupthm_new_family:nnn, \groupthm_provide_family:nnn}
|
|
% \begin{syntax}
|
|
% \cs{groupthm_new_family:nnn}\marg{key=value list}\marg{theorem family}\marg{bool}
|
|
% \end{syntax}
|
|
%
|
|
% \LaTeX3 version of \cs{NewGroupedTheoremFamily}. The given \meta{bool} indicates the presence of
|
|
% the \enquote{*}, i.e.~if it is true, the new theorem will be additionally added to the
|
|
% \texttt{unnumbered} group.
|
|
%
|
|
% \end{function}
|
|
%
|
|
%
|
|
%
|
|
% \begin{function}
|
|
% {
|
|
% \groupthm_new_family:nnnnn, \groupthm_provide_family:nnnnn,
|
|
% \groupthm_new_family:nVVVV, \groupthm_provide_family:nVVVV
|
|
% }
|
|
% \begin{syntax}
|
|
% \cs{groupthm_new_family:nnnnn}\marg{theorem family}\marg{groups_1}\marg{name}
|
|
% \marg{thmtools clist}\marg{groups_2}
|
|
% \end{syntax}
|
|
%
|
|
% Non-keyval version of \cs{groupthm_new_family:nnn}.
|
|
% The \meta{groups_2} will be added to each generated variant, i.e.~we generate a variant
|
|
% for the union of (the powerset of \meta{groups_1}) and \meta{groups_2}.
|
|
%
|
|
% \end{function}
|
|
%
|
|
%
|
|
%
|
|
% \begin{function}{\groupthm_add_theorem_to_group:n}
|
|
% \begin{syntax}
|
|
% \cs{groupthm_add_theorem_to_group:n}\marg{theorem group}
|
|
% \end{syntax}
|
|
%
|
|
% \LaTeX3 version of \cs{AddTheoremToGroup}
|
|
%
|
|
% \end{function}
|
|
%
|
|
% \end{documentation}
|
|
%
|
|
%
|
|
% \begin{function}
|
|
% {
|
|
% \groupthm_new_family_options:nnnn,
|
|
% \groupthm_renew_family_options:nnnn,
|
|
% \groupthm_provide_family_options:nnnn,
|
|
% \groupthm_declare_family_options:nnnn,
|
|
% }
|
|
% \begin{syntax}
|
|
% \cs{groupthm_new_family_options:nnnn}\marg{theorem family}\marg{arg spec}
|
|
% \marg{selection body}\marg{groups}
|
|
% \end{syntax}
|
|
%
|
|
% \LaTeX3 version of \cs{NewGroupedTheoremFamilyOptions}.
|
|
% The \meta{groups} is a comma separated list of groups that will always be added
|
|
% to the variants called.
|
|
%
|
|
% So, \cs{NewGroupedTheoremFamilyOptions*} will e.g.~add \texttt{unnumbered} to this list.
|
|
%
|
|
% \end{function}
|
|
%
|
|
%
|
|
%
|
|
%
|
|
% \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} \meta{theorem name}\meta{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}\meta{clist name}\meta{relation}\meta{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_starred_version_bool,
|
|
% \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}
|
|
\bool_new:N \l_@@_key_starred_version_bool
|
|
\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_@@_starred_version_bool,
|
|
% \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}
|
|
% \begin{variable}{\g_@@_append_groups_int}
|
|
%
|
|
% This counts the number of times we appended to a group.
|
|
%
|
|
% \begin{macrocode}
|
|
\int_new:N \g_@@_append_groups_int
|
|
% \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 / theorem ~ group }
|
|
{
|
|
prefix .tl_set:N = \l_@@_key_prefix_tl,
|
|
prefix .default:n = \c_empty_tl,
|
|
suffix .tl_set:N = \l_@@_key_suffix_tl,
|
|
suffix .default:n = \c_empty_tl,
|
|
suffix .groups:n = { theoremgroup },
|
|
map ~ name .clist_set:N = \l_@@_mapname_clist,
|
|
map ~ name .default:n = {},
|
|
map ~ name .groups:n = { theoremgroup },
|
|
thmtools .clist_set:N = \l_@@_key_thmtools_clist,
|
|
thmtools .default:n = {},
|
|
unknown .code:n =
|
|
\msg_error:nnx { groupthm } { unknown ~ key } { \str_use:N \l_keys_key_str }
|
|
}
|
|
\keys_define:nn { groupthm / grouped ~ theorem }
|
|
{
|
|
name .tl_set:N = \l_@@_key_name_tl,
|
|
name .default:n = \c_novalue_tl,
|
|
group .clist_set:N = \l_@@_key_group_clist,
|
|
group .default:n = {},
|
|
thmtools .clist_set:N = \l_@@_key_thmtools_clist,
|
|
thmtools .default:n = {},
|
|
starred ~ version .bool_set:N = \l_@@_key_starred_version_bool,
|
|
starred ~ version .default:n = { true },
|
|
unknown .code:n =
|
|
\msg_error:nnx { groupthm } { unknown ~ key } { \str_use:N \l_keys_key_str }
|
|
}
|
|
\keys_define:nn { groupthm / theorem ~ family }
|
|
{
|
|
name .tl_set:N = \l_@@_key_name_tl,
|
|
name .default:n = \c_novalue_tl,
|
|
group .clist_set:N = \l_@@_key_group_clist,
|
|
group .default:n = {},
|
|
thmtools .clist_set:N = \l_@@_key_thmtools_clist,
|
|
thmtools .default:n = {},
|
|
starred ~ version .bool_set:N = \l_@@_key_starred_version_bool,
|
|
starred ~ version .default:n = { true },
|
|
unknown .code:n =
|
|
\msg_error:nnx { groupthm } { unknown ~ key } { \str_use:N \l_keys_key_str }
|
|
}
|
|
\keys_define:nn { groupthm / theorem ~ family ~ options }
|
|
{
|
|
starred ~ version .bool_set:N = \l_@@_key_starred_version_bool,
|
|
starred ~ version .default:n = { true },
|
|
unknown .code:n =
|
|
\msg_error:nnx { groupthm } { unknown ~ key } { \str_use:N \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{key=value list}\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
|
|
% \meta{fallback name}.
|
|
%
|
|
% \begin{macrocode}
|
|
\cs_new:Npn \@@_set_normalized_keys:nnn #1 #2 #3
|
|
{
|
|
\keys_set:nn { groupthm / theorem ~ group }
|
|
{ prefix, suffix, thmtools, map ~ name }
|
|
\keys_set:nn { groupthm / grouped ~ theorem }
|
|
{ name, group, thmtools, starred ~ version }
|
|
\keys_set:nn { groupthm / theorem ~ family }
|
|
{ name, group, thmtools, starred ~ version }
|
|
\keys_set:nn { 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}
|
|
\bool_set_eq:NN \l_@@_starred_version_bool \l_@@_key_starred_version_bool
|
|
\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, 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}
|
|
% This ensures default priorities between groups.
|
|
% \begin{macrocode}
|
|
\hook_gset_rule:nnnn { ?? } { all } { before } { #1 }
|
|
\hook_gset_rule:nnnn { ?? } { unnumbered } { after } { #1 }
|
|
\hook_gset_rule:nnnn { ?? } { starred } { after } { #1 }
|
|
% \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'. }
|
|
\tl_log:n { Declarator ~ was ~ #1. }
|
|
#5 { #3 }
|
|
}
|
|
% \end{macrocode}
|
|
% Finally, define new version if not already defined
|
|
% (this check is necessary for the provide version.)
|
|
% \begin{macrocode}
|
|
\bool_if:nTF
|
|
{
|
|
\cs_if_exist_p:N #4
|
|
&&
|
|
\str_if_eq_p:nn { #1 } { provide }
|
|
}
|
|
{
|
|
\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:nnnnn},
|
|
% \cs{groupthm_renew_group:nnnnn},
|
|
% \cs{groupthm_provide_group:nnnnn} and \cs{groupthm_declare_group:nnnnn}
|
|
% 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:nnnnNNn},
|
|
% 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
|
|
{
|
|
\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{key=value list}\marg{theorem group}
|
|
% \end{syntax}
|
|
%
|
|
% \begin{macrocode}
|
|
\@@_wrap_multiple:nnn
|
|
{ new, renew, provide, declare }
|
|
{ groupthm_#1_group:nn }
|
|
{
|
|
\@@_set_normalized_keys:nnn { ##1 } { theorem ~ group } { ##2 }
|
|
\use:c { groupthm_#1_group:nVVVV }
|
|
{ ##2 }
|
|
\l_@@_prefix_tl
|
|
\l_@@_suffix_tl
|
|
\l_@@_mapname_clist
|
|
\l_@@_thmtools_clist
|
|
}
|
|
% \end{macrocode}
|
|
% Additional variant
|
|
% \begin{macrocode}
|
|
\cs_generate_variant:Nn \groupthm_new_group:nn { n x }
|
|
% \end{macro}
|
|
%
|
|
%
|
|
% Finally, we provide \LaTeX2e wrappers as document commands for these.
|
|
%
|
|
% \begin{macro}{\@@_new_document_command:Nnn, \@@_new_document_command:cnn}
|
|
%
|
|
% Private wrappers around \cs{NewDocumentCommand}.
|
|
%
|
|
% \begin{macrocode}
|
|
\cs_new:Npn \@@_new_document_command:Nnn #1 #2 #3
|
|
{
|
|
\NewDocumentCommand { #1 } { #2 } { #3 }
|
|
}
|
|
\cs_generate_variant:Nn \@@_new_document_command:Nnn { c n n }
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
%
|
|
%
|
|
%
|
|
% \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
|
|
{
|
|
\cs_set:Nn \@@_Declarator: { \text_titlecase_first:n { ##1 } }
|
|
\@@_new_document_command:cnn { #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_#1 _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 \meta{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_str { after }
|
|
}
|
|
\str_if_eq:VnT \l_tmpa_str { lower }
|
|
{
|
|
\str_set:Nn \l_tmpa_str { before }
|
|
}
|
|
\str_if_eq:nnTF { #1 } { ?? }
|
|
{
|
|
\hook_gset_rule:nnVn {??} {#2} \l_tmpa_str {#4}
|
|
}
|
|
{
|
|
\hook_gset_rule:nnVn { @@ / #1 } {#2} \l_tmpa_str {#4}
|
|
}
|
|
}
|
|
\cs_generate_variant:Nn \groupthm_declare_group_rule:nnnn { n n n x }
|
|
% \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}
|
|
%
|
|
%
|
|
%
|
|
% \begin{macro}{\groupthm_add_parent:nn}
|
|
% \begin{syntax}
|
|
% \cs{groupthm_add_parent:nn}\marg{theorem group_1}\marg{theorem group_2}
|
|
% \end{syntax}
|
|
%
|
|
% Declares \meta{theorem group_2} as a parent of \meta{theorem group_1}
|
|
%
|
|
% \begin{macrocode}
|
|
\cs_new:Npn \groupthm_add_parent:nn #1 #2
|
|
{
|
|
\@@_ensure_group_exists:n { #1 }
|
|
\@@_ensure_group_exists:n { #2 }
|
|
\clist_gput_left:cn { g_@@_parents_group__#1__clist } { #2 }
|
|
}
|
|
\cs_generate_variant:Nn \groupthm_add_parent:nn { n x }
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
%
|
|
% \begin{macro}{\AddTheoremGroupParent}
|
|
% \begin{syntax}
|
|
% \cs{AddTheoremGroupParent}\marg{theorem group_1}\marg{theorem group_2}
|
|
% \end{syntax}
|
|
%
|
|
% Document command version of \cs{groupthm_add_parent:nn}
|
|
%
|
|
% \begin{macrocode}
|
|
\NewDocumentCommand { \AddTheoremGroupParent } { m m }
|
|
{
|
|
\groupthm_add_parent:nn { #1 } { #2 }
|
|
}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
%
|
|
% \begin{macro}{\@@_push_tmpa_seq:n}
|
|
% \begin{syntax}
|
|
% \cs{@@_push_tmpa_seq:n}\marg{balanced text}
|
|
% \end{syntax}
|
|
%
|
|
%
|
|
%
|
|
% \begin{macrocode}
|
|
%
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\@@_flatten_groups_hierarchy:nN}
|
|
% \begin{syntax}
|
|
% \cs{@@_flatten_groups_hierarchy:nN}\marg{theorem groups}\marg{clist}
|
|
% \end{syntax}
|
|
%
|
|
% Expects a comma separated list of \meta{theorem group}s.
|
|
% The inheritance relation is flattened, and the set of
|
|
% obtained theorem groups is stored in \meta{clist}
|
|
%
|
|
% \begin{macrocode}
|
|
\cs_new:Npn \@@_push_tmpa_seq:n #1
|
|
{
|
|
\seq_push:Nn \l_tmpa_seq { #1 }
|
|
}
|
|
\cs_new:Npn \@@_flatten_groups_hierarchy:nN #1 #2
|
|
{
|
|
\clist_clear:N #2
|
|
\seq_set_from_clist:Nn \l_tmpa_seq { #1 }
|
|
\bool_until_do:nn
|
|
{
|
|
\seq_if_empty_p:N \l_tmpa_seq
|
|
}
|
|
{
|
|
\seq_pop:NN \l_tmpa_seq \l_tmpa_tl
|
|
\@@_ensure_group_exists:V \l_tmpa_tl
|
|
\clist_if_in:NVF #2 \l_tmpa_tl
|
|
{
|
|
\clist_put_left:NV #2 \l_tmpa_tl
|
|
\clist_map_function:cN
|
|
{ g_@@_parents_group__ \l_tmpa_tl __clist }
|
|
\@@_push_tmpa_seq:n
|
|
}
|
|
}
|
|
}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\groupthm_append_to_group:nn}
|
|
% \begin{syntax}
|
|
% \cs{groupthm_append_to_group:nn}\marg{key=value list}\marg{theorem group}
|
|
% \end{syntax}
|
|
%
|
|
% This works the same as defining a new group, except that we append to the group,
|
|
% overwriting the old group in case of conflicts.
|
|
%
|
|
% \begin{macrocode}
|
|
\cs_new:Npn \groupthm_append_to_group:nn #1 #2
|
|
{
|
|
\groupthm_new_group:nx { #1 } { __append__ \int_use:N \g_@@_append_groups_int }
|
|
\groupthm_add_parent:nx { #2 } { __append__ \int_use:N \g_@@_append_groups_int }
|
|
\groupthm_declare_group_rule:nnnx
|
|
{ ?? } { #2 } { before } { __append__ \int_use:N \g_@@_append_groups_int }
|
|
\int_gincr:N \g_@@_append_groups_int
|
|
}
|
|
% \end{macrocodel}
|
|
% \end{macro}
|
|
%
|
|
%
|
|
%
|
|
% \begin{macro}{\AppendToTheoremGroup}
|
|
% \begin{syntax}
|
|
% \cs{AppendToTheoremGroup} \marg{key=value list}\marg{theorem group}
|
|
% \end{syntax}
|
|
%
|
|
%
|
|
%
|
|
% \begin{macrocode}
|
|
\NewDocumentCommand { \AppendToTheoremGroup } { O{} m }
|
|
{
|
|
\groupthm_append_to_group:nn { #1 } { #2 }
|
|
}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
%
|
|
% We also provide the three default groups:
|
|
%
|
|
% \begin{macrocode}
|
|
\groupthm_new_group:nnnnn { all } { } { } { } { }
|
|
\groupthm_new_group:nnnnn { starred } { } { } { } { numbered = no }
|
|
\groupthm_new_group:nnnnn { unnumbered } { } { } { } { numbered = no }
|
|
% \end{macrocode}
|
|
%
|
|
% \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}\meta{clist}\marg{code}
|
|
% \end{syntax}
|
|
%
|
|
% Executes \meta{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 \meta{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 }
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\__powerset_clist_foreach_aux:Nn #1 {#2}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\seq_get:NN \l__powerset_saved_seq \l_tmpa_tl
|
|
\clist_put_left:NV #1 \l_tmpa_tl
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\__powerset_clist_foreach_aux:Nn #1 {#2}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\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, \@@_ensure_group_exists:V}
|
|
% \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 }
|
|
}
|
|
}
|
|
\cs_generate_variant:Nn \@@_ensure_group_exists:n { V }
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\@@_use_group:n}
|
|
% \begin{syntax}
|
|
% \cs{@@_use_group:n}\meta{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}\meta{function}
|
|
% \end{syntax}
|
|
%
|
|
% The \meta{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}
|
|
\@@_flatten_groups_hierarchy:nN { #2, all } \l_@@_group_clist
|
|
\clist_map_function:NN \l_@@_group_clist \@@_use_group:n
|
|
\tl_log:x { Flattened ~ groups ~ '#2' ~ to ~ '\clist_use:Nn \l_@@_group_clist {,}' ~ when ~
|
|
defining ~ theorem ~ '#1' }
|
|
% \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}
|
|
\tl_set:Nn \l_tmpa_tl { name = }
|
|
\tl_put_right:NV \l_tmpa_tl \l_@@_prefix_tl
|
|
\tl_put_right:NV \l_tmpa_tl \l_@@_name_tl
|
|
\tl_put_right:NV \l_tmpa_tl \l_@@_suffix_tl
|
|
\clist_put_right:NV \l_@@_thmtools_clist \l_tmpa_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_theorem:nnnn,
|
|
% \groupthm_new_theorem:nVVV,
|
|
% \groupthm_new_theorem:xVnn,
|
|
% \groupthm_provide_theorem:nnnn,
|
|
% \groupthm_provide_theorem:nVVV,
|
|
% \groupthm_provide_theorem:xVnn
|
|
% }
|
|
% \begin{syntax}
|
|
% \cs{groupthm_new_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_theorem:nnnn }
|
|
{ { ##1 } { ##2 } { ##3 } { ##4 } }
|
|
\cs_generate_variant:Nn \groupthm_new_theorem:nnnn { n V V V }
|
|
\cs_generate_variant:Nn \groupthm_provide_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_theorem:nnnn { x V n n }
|
|
\cs_generate_variant:Nn \groupthm_provide_theorem:nnnn { x V n n }
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
%
|
|
% \begin{macro}{\groupthm_new_theorem:nnn, \groupthm_provide_theorem:nnn}
|
|
% \begin{syntax}
|
|
% \cs{groupthm_new_theorem:nnn}\marg{key=value list}\marg{grouped theorem}
|
|
% \marg{bool}
|
|
% \end{syntax}
|
|
%
|
|
%
|
|
% The third argument indicates whether the generated theorem(s) will be added to the
|
|
% \texttt{unnumbered} group
|
|
%
|
|
% \begin{macrocode}
|
|
\@@_wrap_multiple:nnn
|
|
{ new, provide }
|
|
{ groupthm_#1_theorem:nnn }
|
|
{
|
|
\@@_set_normalized_keys:nnn { ##1 } { grouped ~ theorem } { ##2 }
|
|
\bool_if:nT { ##3 }
|
|
{
|
|
\clist_put_left:Nn \l_@@_group_clist { unnumbered }
|
|
}
|
|
\use:c { groupthm_#1_theorem:nVVV }
|
|
{ ##2 }
|
|
\l_@@_group_clist
|
|
\l_@@_name_tl
|
|
\l_@@_thmtools_clist
|
|
\bool_if:NT \l_@@_starred_version_bool
|
|
{
|
|
\clist_put_left:Nn \l_@@_group_clist { starred }
|
|
\use:c { groupthm_#1_theorem:nVVV }
|
|
{ ##2* }
|
|
\l_@@_group_clist
|
|
\l_@@_name_tl
|
|
\l_@@_thmtools_clist
|
|
}
|
|
}
|
|
% \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
|
|
%
|
|
%
|
|
% Now, we can wrap these into document commands
|
|
%
|
|
%
|
|
% \begin{macro}
|
|
% {
|
|
% \NewGroupedTheorem, \NewGroupedTheorem*,
|
|
% \ProvideGroupedTheorem, \ProvideGroupedTheorem*
|
|
% }
|
|
% \begin{syntax}
|
|
% \cs{NewGroupedTheorem}\oarg{key=value list}\marg{theorem name}
|
|
% \end{syntax}
|
|
%
|
|
% \begin{macrocode}
|
|
\@@_wrap_multiple_document:nnnn
|
|
{ new, provide }
|
|
{ \@@_Declarator: GroupedTheorem }
|
|
{ s O{} m }
|
|
{
|
|
\use:c { groupthm_#1_theorem:nnn }
|
|
{ ##2 }
|
|
{ ##3 }
|
|
{ ##1 }
|
|
}
|
|
% \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}{\@@_define_family:nnnnn}
|
|
% \begin{syntax}
|
|
% \cs{@@_define_family:nnnnn}\marg{family name}\marg{groups clist}
|
|
% \marg{name}\marg{thmtools clist}\marg{extra groups clist}
|
|
% \end{syntax}
|
|
%
|
|
% This will generate a new grouped theorem for each union of a subset of \meta{groups clist}
|
|
% and the extra set \meta{extra groups clist}, with the given properties, that is
|
|
% the \meta{nam} and \meta{thmtools clist} will be passed to the grouped theorem.
|
|
% The \meta{theorem name} of the grouped theorem will be an internal name that contains
|
|
% the \meta{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.
|
|
%
|
|
% \begin{macrocode}
|
|
\cs_new:Npn \@@_define_family:nnnnn #1 #2 #3 #4 #5
|
|
{
|
|
% \end{macrocode}
|
|
% Make a local copy of the \meta{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
|
|
% \begin{macrocode}
|
|
\use:c{groupthm_new_theorem:xVnn}
|
|
{__#1__groups_\clist_use:Nn \l_@@_group_clist {_}}
|
|
\l_@@_group_clist
|
|
{ #3 }
|
|
{ #4 }
|
|
}
|
|
% \end{macrocode}
|
|
% We save the set of variants we generated for later error checking:
|
|
% \begin{macrocode}
|
|
\clist_new:c { @@_family__#1__group_clist }
|
|
\clist_set_eq:cN {@@_family__#1__group_clist } \l_tmpa_clist
|
|
\clist_new:c { @@_family__#1__always_group_clist }
|
|
\clist_set:cn {@@_family__#1__always_group_clist } { #5 }
|
|
}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
%
|
|
% \begin{macro}{\groupthm_new_family:nnnnn,\groupthm_new_family:nVVVV}
|
|
% \begin{syntax}
|
|
% \cs{groupthm_new_family:nnnnn}\marg{theorem family}
|
|
% \marg{groups_1}\marg{name}\marg{thmtools clist}\marg{groups_2}
|
|
% \end{syntax}
|
|
%
|
|
%
|
|
% \begin{macrocode}
|
|
\@@_define_multiple:nnnNNnn
|
|
{ new, provide }
|
|
{ theorem ~ family }
|
|
{ @@_family__##1__group_clist }
|
|
\@@_error:
|
|
\@@_define_family:nnnnn
|
|
{ groupthm_#1_family:nnnnn }
|
|
{ { ##1 } { ##2 } { ##3 } { ##4 } { ##5 }}
|
|
\cs_generate_variant:Nn \groupthm_new_family:nnnnn { n V V V V }
|
|
\cs_generate_variant:Nn \groupthm_provide_family:nnnnn { n V V V V }
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
%
|
|
% \begin{macro}{\groupthm_new_family:nnn, \groupthm_provide_family:nnn}
|
|
% \begin{syntax}
|
|
% \cs{groupthm_new_family:nnn}\marg{key=value list}\marg{theorem family}\marg{bool}
|
|
% \end{syntax}
|
|
%
|
|
% The third argument indicates whether the generated theorem(s) will all be added to the
|
|
% \texttt{unnumbered} group.
|
|
%
|
|
% \begin{macrocode}
|
|
\@@_wrap_multiple:nnn
|
|
{ new, provide }
|
|
{ groupthm_#1_family:nnn }
|
|
{
|
|
\@@_set_normalized_keys:nnn { ##1 } { theorem ~ family } { ##2 }
|
|
\bool_if:nTF { ##3}
|
|
{
|
|
\clist_set:Nn \l_tmpa_clist { unnumbered }
|
|
}
|
|
{
|
|
\clist_clear:N \l_tmpa_clist
|
|
}
|
|
\bool_if:NT \l_@@_starred_version_bool
|
|
{
|
|
\clist_put_left:Nn \l_@@_group_clist { starred }
|
|
}
|
|
\use:c { groupthm_#1_family:nVVVV }
|
|
{ ##2 }
|
|
\l_@@_group_clist
|
|
\l_@@_name_tl
|
|
\l_@@_thmtools_clist
|
|
\l_tmpa_clist
|
|
}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
%
|
|
%
|
|
% Finally, we can provide document commands that make these available.
|
|
%
|
|
%
|
|
% \begin{macro}
|
|
% {
|
|
% \NewGroupedTheoremFamily,\NewGroupedTheoremFamily*,
|
|
% \ProvideGroupedTheoremFamily, \ProvideGroupedTheoremFamily*
|
|
% }
|
|
% \begin{syntax}
|
|
% \cs{NewGroupedTheoremFamily}\oarg{key=value list}\marg{family name}
|
|
% \end{syntax}
|
|
%
|
|
% \begin{macrocode}
|
|
\@@_wrap_multiple_document:nnnn
|
|
{ new, provide }
|
|
{ \@@_Declarator: GroupedTheoremFamily }
|
|
{ s O{} m }
|
|
{
|
|
\use:c { groupthm_#1_family:nnn }
|
|
{ ##2 }
|
|
{ ##3 }
|
|
{ ##1 }
|
|
}
|
|
% \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 \meta{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}{\@@_define_family_options:nnnn}
|
|
% \begin{syntax}
|
|
% \cs{@@_define_family_options:nnnn}\marg{theorem family}
|
|
% \marg{argument specification}\marg{selection body}\marg{extra groups}
|
|
% \end{syntax}
|
|
%
|
|
% This declares a new theorem variant option parser, i.e.~ introduces the environment
|
|
% \meta{theorem family} with signature \marg{argument specification}.
|
|
%
|
|
% The \meta{selection body} will be executed and selects some groups the environment shall have.
|
|
% The \meta{extra groups} will be added regardless of the arguments given
|
|
% to the \meta{theorem family}
|
|
% The \meta{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 \@@_define_family_options:nnnn #1 #2 #3 #4
|
|
{
|
|
\DeclareDocumentEnvironment
|
|
{ #1 }
|
|
{ #2 }
|
|
{
|
|
% \end{macrocode}
|
|
% We can now clear the group list and execute the \meta{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 \meta{extra groups} to them
|
|
%
|
|
% \begin{macro}
|
|
% {
|
|
% \groupthm_new_family_options:nnnn,
|
|
% \groupthm_renew_family_options:nnnn,
|
|
% \groupthm_provide_family_options:nnnn,
|
|
% \groupthm_declare_family_options:nnnn,
|
|
% }
|
|
% \begin{syntax}
|
|
% \cs{groupthm_new_family_options:nnnn}\marg{theorem family}
|
|
% \marg{signature}\marg{selection body}\marg{groups}
|
|
% \end{syntax}
|
|
%
|
|
% \begin{macrocode}
|
|
\@@_define_multiple:nnnNNnn
|
|
{ new, renew, provide, declare }
|
|
{ theorem ~ family ~ options }
|
|
{ ##1 }
|
|
\use_none:n
|
|
\@@_define_family_options:nnnn
|
|
{ groupthm_#1_family_options:nnnn }
|
|
{ { ##1 } { ##2 } { ##3 } { ##4 } }
|
|
\cs_generate_variant:Nn \groupthm_new_family_options:nnnn { n n n V }
|
|
\cs_generate_variant:Nn \groupthm_renew_family_options:nnnn { n n n V }
|
|
\cs_generate_variant:Nn \groupthm_provide_family_options:nnnn { n n n V }
|
|
\cs_generate_variant:Nn \groupthm_declare_family_options:nnnn { n n n V }
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
%
|
|
% It remains to wrap these into document commands
|
|
%
|
|
%
|
|
% \begin{macro}
|
|
% {
|
|
% \NewGroupedTheoremFamilyOptions,
|
|
% \NewGroupedTheoremFamilyOptions*,
|
|
% \RenewGroupedTheoremFamilyOptions,
|
|
% \RenewGroupedTheoremFamilyOptions*,
|
|
% \ProvideGroupedTheoremFamilyOptions,
|
|
% \ProvideGroupedTheoremFamilyOptions*,
|
|
% \DeclareGroupedTheoremFamilyOptions,
|
|
% \DeclareGroupedTheoremFamilyOptions*,
|
|
% }
|
|
% \begin{syntax}
|
|
% \cs{NewGroupedTheoremFamilyOptions}\marg{family name}\marg{signature}
|
|
% \marg{selection body}
|
|
% \end{syntax}
|
|
%
|
|
% \begin{macrocode}
|
|
\@@_wrap_multiple_document:nnnn
|
|
{ new, renew, provide, declare }
|
|
{ \@@_Declarator: GroupedTheoremFamilyOptions }
|
|
{ s O{} m m m }
|
|
{
|
|
\keys_set:nn { groupthm / theorem ~ family ~ options } { starred ~ version }
|
|
\keys_set:nn { groupthm / theorem ~ family ~ options } { ##2 }
|
|
\bool_if:nTF { ##1 }
|
|
{
|
|
\clist_set:Nn \l_tmpa_clist { unnumbered }
|
|
}
|
|
{
|
|
\clist_clear:N \l_tmpa_clist
|
|
}
|
|
\use:c { groupthm_#1_family_options:nnnV }
|
|
{ ##3 }
|
|
{ ##4 }
|
|
{ ##5 }
|
|
\l_tmpa_clist
|
|
\bool_if:NT \l_@@_starred_version_bool
|
|
{
|
|
\use:c { groupthm_#1_family_options:nnnV }
|
|
{ ##3* }
|
|
{ ##4 }
|
|
{
|
|
##5
|
|
\groupthm_add_theorem_to_group:n { starred }
|
|
}
|
|
\l_tmpa_clist
|
|
}
|
|
}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
%
|
|
%
|
|
%
|
|
%
|
|
% \begin{macrocode}
|
|
%</package>
|
|
% \end{macrocode}
|
|
%
|
|
% \end{implementation}
|
|
%
|
|
%
|
|
%
|
|
% \newpage
|
|
% \PrintIndex
|