I have a small custom style file/package which contains a bunch of macros useful for a subfield of Computer Science I operate in (see here for the latest complete version of the package). A major part of the writing that I do involves setting out numbered "rules". For that, I use an array
, wrapped in a newenvironment
(which itself is wrapped in a newfloat
to get floating behaviour, but I doubt that's relevant here).
Each rule is itself written out using another macro, to ensure that they are all specified the same way, and provide me with automatic sequential numbering of the rules. I would like to be able to label and cross-reference the rules like many other types of countable things in LaTeX. I tried including an optional parameter for the rules macro, and writing a label
if the optional parameter was non-empty (you can see this in the MWE below). This seemingly worked well at first when I was trying to create a minimal working example, but I did not see the same behaviour when applying it to some of my completed old papers. Instead, I got error messages that I didn't really understand.
Eventually, after hours of trying to get the MWE and an old paper to produce the same outputs, I discovered that the problem appears to be with amsmath. Specifically, when amsmath is included via usepackage, it doesn't like my attempt at custom labelling. I guess that this is to do with how the rules environment works using an array
, and that amsmath somehow redefines array
in a way that makes the labelling stop working. Given that amsmath is pretty much a certainty for inclusion in any paper my package is likely to be relevant for, this obviously is not an acceptable situation.
The MWE is below, and was more or less constructed by copy-pasting the relevant bits out of the .sty file and wrapping them in makeatletter
/makeatother
. I have also included all the packages that are included in the sty file using RequirePackage
, just in case that makes any difference.
\documentclass[10pt,a4paper]{article}
\usepackage{amsmath,newfloat,array,framed,etoolbox,perfectcut,trimspaces,changepage}
\usepackage{hyperref}
\usepackage{cleveref}
\makeatletter
\newcounter{cpsystems@RuleNum}
\DeclareFloatingEnvironment[name=Ruleset,within=none]{cprulesetfloat}
\newenvironment{cpruleset}
{\begin{framed}\begin{adjustwidth}{-1.0em}{-1.0em}
\renewcommand{\arraystretch}{1.1}\[\begin{array}{lllllr}}
{\end{array}\]\end{adjustwidth}\end{framed}}
\newcommand{\cprule}[6][]{
\refstepcounter{cpsystems@RuleNum}
\notblank{#1}{\label{#1}}{}
\cpsystems@basecprule{#2}{#3}{#4}{#5}{#6}{\hspace{1.5em}(\arabic{cpsystems@RuleNum})}
}
\newcommand{\cpsystems@basecprule}[6]{
\trim@spaces@noexp{#1 & #2 & \rightarrow_{#3} & #4 & #5 & #6\\}
}
\newcommand*{\cpfunc}[2]{
\trim@spaces@noexp{#1\perfectunary{IncreaseHeight}{(}{)}{#2}}
}
\makeatother
\begin{document}
\section{Intro}
See Ruleset~\ref{rules}.
\section{The rules}
\begin{cprulesetfloat}
\begin{cpruleset}
\cprule[rule1]{s_1}{\cpfunc{a}{B}}{{\scriptstyle 1}}{s_2}{\cpfunc{f}{G}}
\cprule{s_2}{\cpfunc{c}{D}}{{\scriptstyle +}}{s_3}{\cpfunc{h}{I}}
\cprule[rule2]{s_2}{\cpfunc{c}{D}}{{\scriptstyle +}}{s_3}{\cpfunc{h}{I}}
\end{cpruleset}
\caption{\label{rules}My fancy ruleset}
\end{cprulesetfloat}
I'm particularly proud of rule~\ref{rule3}. That's \ref{rule3}.
\begin{cprulesetfloat}
\begin{cpruleset}
\cprule[rule3]{s_1}{\cpfunc{a}{B}}{{\scriptstyle 1}}{s_2}{\cpfunc{f}{G}}
\cprule{s_2}{\cpfunc{c}{D}}{{\scriptstyle +}}{s_3}{\cpfunc{h}{I}}
\cprule{s_2}{\cpfunc{c}{D}}{{\scriptstyle +}}{s_3}{\cpfunc{h}{I}}
\end{cpruleset}
\caption{\label{rules2}My fancy ruleset 2}
\end{cprulesetfloat}
\end{document}
A correctly built ruleset environment should look something like:
There are two problems with the MWE. Firstly, there's a compilation error if both of the optional parameters (intended labels) in the first cpruleset
are left in. This seems to be the issue with amsmath - it apparently thinks they're both labels for the array or something, and so complains that there are multiple labels defined for the same thing. Secondly, and for reasons entirely unclear to me, no matter what I try the ref
command I use to reference the rules (after ensuring there is only label per cpruleset
), it always gives back the number 2.
My question is: How should I change the definition of the cpruleset
environment and/or the cprule
macro, to enable labelling and cross-referencing of rule numbers? I have tried everything I can think of, and at this point I am completely stumped. My best guess is that I need to move to a different environment from array
, but despite looking around a bit (at, e.g. align
, gather
, etc. in the amsmath and mathtools packages), I couldn't find anything that seemed to enable me to achieve the same results without regard to cross-referencing. It is preferable, but not vital, that any solution plays nicely with hyperref and/or cleveref and would enable something like \autoref{rule2}
or \cref{rule2}
to get output similar to "Rule 2".