2

I’m trying to number some objects on a per-page basis with a shared counter. The following example is close to minimal.

\documentclass{article}

\usepackage{zref-perpage}

\newcommand*{\tablecaption}[1]{%
  \setlength{\belowcaptionskip}{\abovecaptionskip}%
  \setlength{\abovecaptionskip}{0pt}%
  \caption{#1}%
}

\newcounter{maincounter}

\newtheorem{theorem}{Theorem}
\newtheorem{proposition}[theorem]{Proposition}

\makeatletter
\let\c@equation\c@maincounter
\let\c@figure\c@maincounter
\let\c@table\c@maincounter
\let\c@theorem\c@maincounter
\makeatother

\zmakeperpage{maincounter}
%\zmakeperpage{equation}
%\zmakeperpage{figure}
%\zmakeperpage{table}
%\zmakeperpage{theorem}

\renewcommand*{\themaincounter}{\arabic{zpage}.\arabic{maincounter}}
\renewcommand*{\theequation}{\themaincounter}
\renewcommand*{\thefigure}{\themaincounter}
\renewcommand*{\thetable}{\themaincounter}
\renewcommand*{\thetheorem}{\themaincounter}

\begin{document}
%
\begin{theorem}
Blah.
\end{theorem}
%
\begin{table}[h]
\centering
\tablecaption{A table}
\begin{tabular}{l | l}
1 & 2 \\
\hline
3 & 4
\end{tabular}
\end{table}
%
\begin{equation}
a = b
\end{equation}
%
\begin{figure}[b]
\centering
\rule{3cm}{2cm}
\caption{A black rectangle}
\end{figure}
%
\begin{proposition}
Blah.
\end{proposition}
%
\newpage
%
\begin{equation}
c = d
\end{equation}
%
\begin{table}[t]
\centering
\tablecaption{Another table}
\begin{tabular}{l | l}
a & b \\
\hline
c & d
\end{tabular}
\end{table}
%
\begin{theorem}
Blah.
\begin{equation}
e = f
\end{equation}
\end{theorem}
%
\end{document}

The problem is that the counter maincounter is not reset at each change of page and that the value of the counter zpage is always 0. If I uncomment the commented lines in the preamble, the per-page reset works and the counter zpage is incremented but the counters are not linked any longer.

As a bonus, I would like the different objects on each page to be numbered in their order of apparition (maybe something like the \MakeSorted command of the perpage package).


Update

Thanks to David Carlisle’s comment, I was able to use the code related to the perpage option from the footmisc package and make it work with any counter. One relatively constraining aspect of this solution is the need to patch the commands that print the number of the corresponding objects: we have to surround them with some code which checks whether there is a change of page or not and consequently sets the associated counter. Such patching hence depends on the loaded packages and their possible redefinitions. (Here, I am working with amsmath and amsthm.)

Linking the counters is very easy, then: I just need to load the per-page machinery for one ‘main’ counter and identify the others to that one.

As for the number of the current page within the numbering of the different objects, I tried to make a label before incrementing the counter and printing it (through patches, as previously) in order to then be able to use \pageref.

However, there is something wrong with those patches: they break the mechanism of references; some incorrect values of the counter and the page are sometimes — or is it always? — read and written.

Here is the code with some testing inside the document. The incorrect references are indicated with the command \wrong, which prints its argument in red.

\documentclass[a4paper, 11pt]{article}

% amsmath redefines the \label command, which messes up the mechanism that prints the current page number
\makeatletter
\let\label@original\label
\makeatother

\usepackage{etoolbox}
\usepackage{amsmath}
\usepackage{amsthm}
\usepackage{xcolor}

\allowdisplaybreaks

\makeatletter

\providecommand\protected@writeaux{%
  \protected@write\@auxout
}

% Get and print the current page number
\newcounter{currentpage@mark}
\def\theCurrentPageMark{%
  \global\advance\c@currentpage@mark\@ne
  \label@original{currentpage@mark\the\c@currentpage@mark}%
}
\def\theCurrentPageRef{%
  \expandafter\pageref{currentpage@mark\the\c@currentpage@mark}%
}

% Load some commands that reset a counter at each change of page
\def\load@PerPage@machinery#1{%
  \expandafter\newif\csname ifPerPage@#1@hint\endcsname
  \newcounter{PerPage@#1@next@reset}
  \expandafter\newif\csname ifPerPage@#1@towrite\endcsname
  \@nameuse{PerPage@#1@towritefalse}

  \global\@namedef{PerPage@#1@initial@stab}{\@addtoreset{#1}{page}}
  \AtBeginDocument{\@nameuse{PerPage@#1@initial@stab}}
  \newcounter{@#1@serial}
  \@namedef{PerPage@#1@cpage}{0}
  \@nameuse{PerPage@#1@hinttrue}

  \@namedef{PerPage@#1@hint}{%
    \setcounter{#1}{0}%
    \protected@writeaux\relax{\expandafter\protect\csname PerPage@#1@hinttrue\endcsname}%
    \@tempcnta\csname c@@#1@serial\endcsname%
    \advance\@tempcnta\@ne
    \global\expandafter\csname c@PerPage@#1@next@reset\endcsname\@tempcnta
  }

  \AtBeginDocument{%
    \protected@writeaux\relax{%
      \protect\providecommand{\expandafter\protect\csname PerPage@#1@hinttrue\endcsname}{}%
    }%
  }

  \@namedef{PerPage@#1@lastfoot}{-1}

  \@namedef{PerPage@#1@aux}##1##2{%
    \ifnum\csname PerPage@#1@lastfoot\endcsname<##1%
      \@nameuse{ifPerPage@#1@hint}%
        \@nameuse{PerPage@#1@reset}{##1}{##2}%
        \@nameuse{PerPage@#1@hintfalse}%
      \else
        \gdef\@tempa{##2}%
        {\expandafter}\expandafter\ifx\csname PerPage@#1@cpage\endcsname\@tempa
        \else
          \@nameuse{PerPage@#1@reset}{##1}{##2}%
        \fi
      \fi
      \@namedef{PerPage@#1@lastfoot}{##1}%
    \fi
    \global\cslet{PerPage@#1@initial@stab}{\relax}%
  }

  \@namedef{PerPage@#1@reset}##1##2{%
    \global\@namedef{PerPage@#1@cpage}{##2}%
    \expandafter\gdef
      \csname PerPage@#1@next-\@nameuse{PerPage@#1@prev@foot}\endcsname{##1}%
    \@namedef{PerPage@#1@prev@foot}{##1}%
    \expandafter\xdef
      \csname PerPage@#1@next-\@nameuse{PerPage@#1@prev@foot}\endcsname{\the\@MM}%
  }

  \@namedef{PerPage@#1@prev@foot}{root}

  \AtBeginDocument{%
    \protected@writeaux\relax{%
      \protect\providecommand{\expandafter\protect\csname PerPage@#1@aux\endcsname}[2]{}%
    }%
    \csname c@PerPage@#1@next@reset\endcsname\@ne
  }

  \AtEndDocument{%
    \csletcs{PerPage@#1@aux}{PerPage@#1@endaux}%
    \@namedef{PerPage@#1@lastfoot}{-1}%
    \@nameuse{PerPage@#1@hintfalse}%
    \@namedef{PerPage@#1@prev@foot}{root}%
  }

  \@namedef{PerPage@#1@endaux}##1##2{%
    \ifnum\csname PerPage@#1@lastfoot\endcsname<##1%
      \@nameuse{ifPerPage@#1@hint}%
        \@nameuse{PerPage@#1@reset@end}{##1}{##2}%
        \@nameuse{PerPage@#1@hintfalse}%
      \else
        \gdef\@tempa{##2}%
        {\expandafter}\expandafter\ifx\csname PerPage@#1@cpage\endcsname\@tempa
        \else
          \@nameuse{PerPage@#1@reset@end}{##1}{##2}%
        \fi
      \fi
      \@namedef{PerPage@#1@lastfoot}{##1}%
    \fi
  }

  \@namedef{PerPage@#1@reset@end}##1##2{%
    \def\@tempa{##1}%
    {\expandafter}\expandafter\ifx\csname PerPage@#1@next-\@nameuse{PerPage@#1@prev@foot}\endcsname\@tempa
    \else
      \@tempswatrue
    \fi
    \global\@namedef{PerPage@#1@prev@foot}{##1}%
    \global\@namedef{PerPage@#1@cpage}{##2}%
  }

  \pretocmd{\clearpage}{\@nameuse{PerPage@#1@hint}}{}{}

  \@namedef{PerPage@#1}{%
    \if@minipage\else
      \global\expandafter\advance\csname c@@#1@serial\endcsname\@ne
      \if@filesw
        \expandafter\xdef\csname PerPage@#1@writetemp\endcsname{%
          \noexpand\protected@writeaux\relax{%
            \expandafter\string\csname PerPage@#1@aux\endcsname%
              {\the\@nameuse{c@@#1@serial}}{\noexpand\thepage}%
          }%
        }%
        \@nameuse{PerPage@#1@towritetrue}%
      \fi
      \ifnum\csname c@PerPage@#1@next@reset\endcsname>\csname c@@#1@serial\endcsname
      \else
        \global\expandafter\csname c@#1\endcsname\@ne
        \expandafter\let\expandafter\@tempa
          \csname PerPage@#1@next-\number\csname c@PerPage@#1@next@reset\endcsname\endcsname
        \ifx\@tempa\relax
          \global\expandafter\csname c@PerPage@#1@next@reset\endcsname\@MM
        \else
          \global\expandafter\csname c@PerPage@#1@next@reset\endcsname\@tempa
        \fi
      \fi
    \fi
  }

  \@namedef{PerPage@#1@end}{%
    \@nameuse{ifPerPage@#1@towrite}%
      \@nameuse{PerPage@#1@writetemp}%
      \@nameuse{PerPage@#1@towritefalse}%
    \fi
  }
}

\newcounter{maincounter}
\load@PerPage@machinery{maincounter}

% Patch some numbering commands to take into account the page number and the resetting
\newtheoremstyle{thmstyle}%
  {\topsep}%
  {\topsep}%
  {\itshape}%
  {}%
  {\bfseries}%
  {.}%
  { }%
  {\thmname{#1}%
   \thmnumber{\@ifnotempty{#1}{ }%
              \theCurrentPageMark
              \PerPage@maincounter
              \@upn{#2}%
              \PerPage@maincounter@end}%
   \thmnote{ {\the\thm@notefont(#3)}}}

\theoremstyle{thmstyle}
\newtheorem{theorem}{Theorem}
\newtheorem{proposition}[theorem]{Proposition}

\pretocmd{\@footnotemark}{%
  \theCurrentPageMark
  \PerPage@maincounter
  \global\csname c@\@mpfn\endcsname\c@footnote
  \protected@xdef\@thefnmark{\thempfn}%
}{}{}
\apptocmd{\@footnotemark}{%
  \PerPage@maincounter@end
}{}{}

\pretocmd{\tagform@}{%
  \theCurrentPageMark
  \PerPage@maincounter
}{}{}
\apptocmd{\tagform@}{%
  \PerPage@maincounter@end
}{}{}

\pretocmd{\@caption}{%
  \theCurrentPageMark
  \PerPage@maincounter
}{}{}
\apptocmd{\@caption}{%
  \PerPage@maincounter@end
}{}{}

% Link the counters
\let\c@footnote\c@maincounter
\let\c@equation\c@maincounter
\let\c@theorem\c@maincounter
\let\c@figure\c@maincounter
\let\c@table\c@maincounter

\renewcommand{\thefootnote}{\theCurrentPageRef.\arabic{footnote}}
\renewcommand{\theequation}{\theCurrentPageRef.\arabic{equation}}
\renewcommand{\thetheorem}{\theCurrentPageRef.\arabic{theorem}}
\renewcommand{\thefigure}{\theCurrentPageRef.\arabic{figure}}
\renewcommand{\thetable}{\theCurrentPageRef.\arabic{table}}

\newcounter{rptcount}
\long\def\rpt#1#2{%
  \setcounter{rptcount}{#1}%
  \loop #2%
    \ifnum\therptcount>1 \addtocounter{rptcount}{-1}%
    \repeat
}

\def\brack@iden[#1]{#1}

\newcommand*{\blindtext}[1]{%
  \ifnum#1<\@ne
  \else\ifnum#1=\@ne
    Blah%
  \else
    Blah, %
    \rpt{\numexpr#1-2\relax}{blah, }%
    blah%
  \fi\fi
  \@ifnextchar[\brack@iden.%
}

\makeatother

\newcommand*{\tablecaption}[1]{%
  \setlength{\belowcaptionskip}{\abovecaptionskip}%
  \setlength{\abovecaptionskip}{0pt}%
  \caption{#1}%
}

\newcommand*{\wrong}[1]{%
  \textcolor{red}{#1}%
}

\begin{document}
%
\begin{theorem}\label{thm1}
Blah.
\end{theorem}
%
\begin{table}[h]
\centering
\tablecaption{A table}
\begin{tabular}{l | l}
1 & 2 \\
\hline
3 & 4
\end{tabular}
\end{table}
%
\begin{equation}\label{eq1}
a = b
\end{equation}
%
\begin{figure}[b]
\centering
\rule{3cm}{2cm}
\caption{A black rectangle}\label{fig1}
\end{figure}
%
\begin{proposition}
Blah.
\end{proposition}
%
Theorem~\wrong{\ref{thm1}}. Equation~\eqref{eq1}. \blindtext{301}\space Table~\ref{tbl1}. Equation~\eqref{eq2}.\par
%
\begin{equation}
c = d
\end{equation}
%
\begin{table}[t]
\centering
\tablecaption{Another table}\label{tbl1}
\begin{tabular}{l | l}
a & b \\
\hline
c & d
\end{tabular}
\end{table}
%
\begin{theorem}
Blah.
\begin{equation}
e = f
\end{equation}
\end{theorem}
%
Footnote~\ref{fn1}. \blindtext{398}[\footnotemark], blah\footnotemark, blah\footnote{\label{fn1}A footnote.}. Footnote~\ref{fn1}. Theorem~\wrong{\ref{thm1}}. Equations~\eqref{eq1} and~\eqref{eq2}. Figure~\ref{fig1}.\par
%
\blindtext{519}
%
\begin{align}
\alpha &= \beta \\
\gamma &= \delta \\
\varepsilon &= \zeta \label{eq2}
\end{align}
%
\blindtext{528}\space Figure~\wrong{\ref{fig2}}. Proposition~\wrong{\ref{prop1}}.\par
%
\begin{proposition}\label{prop1}
Blah.
\end{proposition}
%
Proposition~\wrong{\ref{prop1}}.
%
\begin{figure}[p]
\centering
\rule{4cm}{3cm}
\caption{Another black rectangle}\label{fig2}
\end{figure}
%
\end{document}
  • 1
    The page breaker works asynchronously with the execution of code on the main page so by the time you split one page you may have executed the counter for equations that will only be typeset pages ahead (due to insertion of figures, or simply long paragraphs) You need to use the \pageref system and correct the resetting on later runs. You should be able to reuse code from (say) footmisc package which has a per-page option for footnote counter – David Carlisle Sep 2 '13 at 20:41
  • It seems to work if \thepage is used instead of \thezpage; however, figures and tables not "here" will appear out of order. – egreg Sep 2 '13 at 22:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.