Reference an environment counter through label in another counter
This is based on Christian Hupfer's answer, but tries to adhere to the guidelines for working with expl3
code and issues warnings in case an implication context has not been defined.
It reimplements the two environments as xparse
wrappers around expl3
functions, which adhere to the standard syntax. It also uses \cs_new_protected_nopar
in preference to \cs_new
, and tries to use more efficient options for handling property lists, where possible.
The implementation no longer relies on the \label
/\ref
system provided by LaTeX 2e. Instead, a tag can be given as an optional argument to the impl
environment, and must be given as a mandatory argument to the hypo
one.
Two property lists are used: one for each type of environment. If an implication context is not defined, zeroes will be used in the output and warnings written to the console with details.
One standard, as I understand it, is that user-level commands and environments should be defined using \NewDocumentEnvironment
etc. rather than \newenvironment
etc., and that this should be minimal wrappers which simply parse user input and pass it to lower-level expl3
functions.
However, I'm not sure I've understood all this correctly, especially since people seem generally not to do this. So this could be all wrong.
Caveat emptor
\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}
% based on ateb Christian Hupfer: https://tex.stackexchange.com/a/375209/
\ExplSyntaxOn
\prop_new:N \g_milo_hypcounter_prop
\prop_new:N \g_milo_implcounter_prop
% these are the counters
\int_new:N \g_milo_hypo_int
\int_new:N \g_milo_impl_int
\msg_new:nnn { milo } { undef }
{
milo ~::~reference~#1~is~unknown.~0~will~be~used~instead.~\msg_line_context:.
}
\cs_new_protected_nopar:Nn \milo_storehypcounter:n {
\prop_gput:Nnx \g_milo_implcounter_prop { #1 } { \int_to_arabic:n { \g_milo_impl_int } }
\prop_gput:Nnn \g_milo_hypcounter_prop { #1 } { 0 }
}
\cs_new_protected_nopar:Nn \milo_extracthypcounter:n {
\prop_get:NnNTF \g_milo_implcounter_prop { #1 } \l_tmpa_tl
{
\l_tmpa_tl
}
{
0
\msg_warning:nnn { milo } { undef } { #1 }
}
.
\prop_get:NnNTF \g_milo_hypcounter_prop { #1 } \l_tmpa_tl
{
\prop_gput:Nnx \g_milo_hypcounter_prop { #1 } { \int_eval:n { \l_tmpa_tl + 1 } }
\prop_item:Nn \g_milo_hypcounter_prop { #1 }
}
{
0
\msg_warning:nnn { milo } { undef } { #1 }
}
}
\NewDocumentEnvironment { impl } { o }
{
\int_gincr:N \g_milo_impl_int
\IfValueT { #1 }
{
\milo_storehypcounter:n { #1 }
}
\textbf{Implication ~ \int_to_arabic:n {\g_milo_impl_int} : }
}{
\par
}
\NewDocumentEnvironment { hypo } { m }
{
\textbf{ Hypothesis ~ \milo_extracthypcounter:n { #1 } }
}{
\par
}
\ExplSyntaxOff
\begin{document}
This is one implication:
\begin{impl}[impl:a]
Hello
\end{impl}
This is another implication:
\begin{impl}[impl:b]
Bye bye
\end{impl}
But then:
\begin{hypo}{impl:a}
Foo a
\end{hypo}
\begin{hypo}{impl:a}
Impl a cont.
\end{hypo}
\begin{hypo}{impl:b}
Foo b
\end{hypo}
\begin{hypo}{impl:a}
Foo a cont.
\end{hypo}
\begin{hypo}{impl:u}
Undefined case.
\end{hypo}
\end{document}
Note the last case is undefined, so produces warnings and zeroes:
Try this:
\documentclass{article}
\usepackage{amsmath}
%% Implications
\newcounter{implcounter}
\newenvironment{impl}{
\refstepcounter{implcounter}
\textbf{Implication \theimplcounter:}
}{\par}
%% Hypotheses
\newcounter{hypcounter}
\newenvironment{hypo}[1][\theimplcounter]{
\refstepcounter{hypcounter}
\textbf{Hypothesis #1.\thehypcounter:}
}{\par}
\begin{document}
This is one implication:
\begin{impl} \label{impl:a}
Hello
\end{impl}
This is another implication:
\begin{impl}
Bye bye
\end{impl}
But then:
\begin{hypo}[\ref{impl:a}]
Not the numberwithin I would like!
% I would like for this to be implication 1.1
\end{hypo}
\end{document}
You just need a second parameter (optional) in your environment to refer to the Implication you choose to refer... If you don't give the parameter it will refer to the last one impl
Edit:
What you want can be done like this:
\documentclass{article}
\usepackage{amsmath}
\usepackage{verbatim}
\usepackage{refcount}
\usepackage{stringstrings}
\usepackage{xstring}
%% Implications
\newcounter{implcounter}
\newenvironment{impl}{
\refstepcounter{implcounter}
\textbf{Implication \theimplcounter:}
}{\par}
%% Hypotheses
\makeatletter
\newcommand\andrea@test@count[1]{%
\@ifundefined{c@#1}
{% the counter doesn't exist so I define it
\expandafter\newcounter{#1}
}
{% the counter exists and I do nothing
\relax
}%
}
\newenvironment{hypo}[1][\theimplcounter]{
\ifnum #1=\theimplcounter
{ %this is the default case for not given argument
\andrea@test@count{counter\theimplcounter}
\refstepcounter{counter\theimplcounter}
\textbf{Hypothesis \theimplcounter.\csname thecounter\theimplcounter\endcsname:}
}
\else
{ %this is tha case with given argument
\andrea@test@count{counter#1}
\refstepcounter{counter#1}
\textbf{Hypothesis #1.\csname thecounter#1\endcsname:}
}
\fi
}{\par}
\makeatother
\begin{document}
This is one implication:
\begin{impl} \label{impl:a}
Hello this Implication has label \getrefnumber{impl:a}
\end{impl}\quad
This is another implication:
\begin{impl} \label{impl:b}
Hello this Implication has label \getrefnumber{impl:b}
\end{impl}\quad
This is a third implication without label:
\begin{impl}
Bye bye
\end{impl}\quad
And then:\par
\begin{hypo}[\getrefnumber{impl:b}]
This hypothesis is refered to label \getrefnumber{impl:b}.
So I want 2.1
\end{hypo}\quad
\begin{hypo}
This Hypothesis is refered to no label.
So I want it 3.1
\end{hypo}\quad
\begin{hypo}[\getrefnumber{impl:a}]
This hypothesis is refered to label \getrefnumber{impl:a}.
I want it 1.1
\end{hypo}\quad
\begin{hypo}[\getrefnumber{impl:a}]
This hypothesis is refered to label \getrefnumber{impl:a}.
I want 1.2
\end{hypo}\quad
\begin{hypo}
This last hypothesis has no label. So I want it 3.2
\end{hypo}
\end{document}
You have this result:
An expl3
way by storing the number of hypo
calls for a specific label in an expl3
\prop
list.
It does not check whether the label is valid, however.
Just define the label, say, \label{foo}
as usual and say \begin{hypo}{foo}...\end{hypo}
.
This can be done at any time in the document, even before the relevant implication has been defined, the first compilation run will give ??
and some warnings about the undefined references, however then.
\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}
\makeatletter
\ExplSyntaxOn
\prop_new:N \g_milo_hypcounter_prop% The global prop list
\cs_new:Npn \storehypcounter#1 {
% Test if the label #1 is contained already, if so, increase the current number by one
\prop_if_in:NnTF \g_milo_hypcounter_prop {#1} {
\prop_gput:Nnx \g_milo_hypcounter_prop {#1} {\int_eval:n {\prop_item:Nn \g_milo_hypcounter_prop {#1} +1}}
}{
% First call, set the per label - specific counting value to 1
\prop_gput:Nnn \g_milo_hypcounter_prop {#1} {1}
}
}
\cs_new:Npn \extracthypcounter#1 {%
% Extract the current value of the property (i.e. the label #1)
\prop_item:Nn \g_milo_hypcounter_prop {#1}
}
\ExplSyntaxOff
\makeatother
\usepackage{refcount}
%% Implications
\newcounter{implcounter}
\newenvironment{impl}{%
\refstepcounter{implcounter}
\textbf{Implication \theimplcounter:}
}{\par}
%% Hypotheses
\newenvironment{hypo}[1]{%
\storehypcounter{#1}%
\textbf{Hypothesis \ref{#1}.\extracthypcounter{#1}}
}{\par}
\begin{document}
This is one implication:
\begin{impl} \label{impl:a}
Hello
\end{impl}
This is another implication:
\begin{impl} \label{impl:b}
Bye bye
\end{impl}
But then:
\begin{hypo}{impl:a}
Foo a
\end{hypo}
\begin{hypo}{impl:a}
Impl a cont.
\end{hypo}
\begin{hypo}{impl:b}
Foo b
\end{hypo}
\begin{hypo}{impl:a}
Foo a cont.
\end{hypo}
\end{document}