3

I'd like to typeset 5 rows x 2 cols of equations. I'd like the equation number to be automatically incremented for the rows. For the columns, I'd like to automatically append a) and b) to the row's equation number. Is this possible?

I have tried to visualise my desired output in the ascii text below

Reference case   Modified Case
--------------   -------------
a = k b   (1a)   a' = 3 b.  (1b)
x = y^k   (2a)   y' = y^0.5 (2b)
z = e^(k) (3a)   z' = e^1.1 (3b)

Additionally, all the = signs within each column need to be vertically aligned. As a bonus, it would be great if the code is flexible to handle 2-4 columns with automatic column suffixes b), c) and d) correctly applied. For the moment, I am happy with a $5 \times n$ equation-grid, but ideally, this numbering scheme should work across page-breaks to facilitate extension to multiple pages.

How can this be achieved?. I am happy to accept a LuaTeX solution if that is what it takes.

  • As a start, something like https://tex.stackexchange.com/questions/239755/individual-equations-in-multiple-columns-with-individual-numbering ? – Willie Wong Mar 14 '20 at 04:33
  • Does the question aim at the creation of an interface for specifying equations and at implementing an algorithm for parsing the specifications and having LaTeX create a table or whatever automatically from the specifications? If so: What kind of "specification-interface for specifying the single equations" would suit your workflow best? Does the question aim at providing an example of how to code a nice table using LaTeX's facilities for designing nice tables? Perhaps you could treat single equations as components of a database. If so, Dr. Nicola Talbot's datatool-package might be of interest – Ulrich Diez Mar 20 '20 at 21:23

2 Answers2

5

This is a very good chance to showoff the great potential of pgfplotstable

\documentclass{article}

\usepackage{pgfplotstable,booktabs,colortbl}

\pgfplotsset{compat=1.13}

\begin{document}

    \def\noteqnarrayskip{$\mkern\thickmuskip$}
    \def\printlabel{printlabel}
    \pgfplotstableread[col sep=&,row sep=\\]{
        alhs    &       arhs    &       blhs    &       brhs        \\
        a_1     &   =   A^{11}  &       b_1     &   =   B^{11}      \\
        a_2     &   =   A^{22}  &       b_2     &   =   B^{22}      \\
        a_3     &   =   A^{33}  &       b_3     &   =   B^{33}      \\
    }\excelatequations
    \pgfplotstableset{
        create on use/placeholder4label/.style={
            create col/set={labels fail}, % you will see `labels fail`
                % if one day the mechanism of assigning labels breaks
        }
    }
    \begin{table}
        \caption{Everyone can excel.}
        $$\pgfplotstabletypeset[
            % booktabs-related
            every head row/.style={before row=\toprule,after row=\midrule},
            every last row/.style={after row=\bottomrule},
            % arrange the columns into a table % notice the repetition
            columns={alhs,arhs,placeholder4label,blhs,brhs,placeholder4label},
            % put cell content into math $ $
            assign cell content/.style={@cell content/.initial={$#1$}},
            % compute and format label
            columns/placeholder4label/.style={assign cell content/.code={
                \pgfmathtruncatemacro\rowint{\pgfplotstablerow+1}%123...
                \pgfmathtruncatemacro\colascii{(\pgfplotstablecol+1)/3+96}%abc...
                \edef\equationlabel{(\rowint\char\colascii)}%\char97 = a
                \pgfkeyslet{/pgfplots/table/@cell content}\equationlabel
            }},
            % set spaces properly
            columns/alhs/.style={
                column type={ r@\noteqnarrayskip }
            },
            columns/arhs/.style={
                column type={ @{}l }
            },
            columns/blhs/.style={
                column type={ r@\noteqnarrayskip }
            },
            columns/brhs/.style={
                column type={ @{}l }
            },
            % set multicol % uncommon to hide implementation details
%           every head row/.style=output empty row,
%           every row no 0/.style={
%               before row={
%               \toprule
%               \multicolumn 3c{big col A} & \multicolumn 3c{fat col B}\\
%               \midrule}
%           },
        ]\excelatequations$$
    \end{table}

\end{document}

After uncommon

Symbol 1
  • 36,855
  • typo: uncommon -> uncomment. – Symbol 1 Mar 20 '20 at 23:36
  • Thank you for the very detailed answer. Indeed, it is a very skillfully crafted solution and truth be told, I am in awe. Also, a tip of the hat to the masterful pgfplots package. In the end, it was a tough decision to award the bounty to the other answer. This is solely due to my inability to comprehend the heavy markup for the table construction. If it can be tucked away in the preamble somehow, like the equationgrid environment proposed in the accepted answer, it might make the sheer power of pgfplots accessible to non-power latex users like me. Once again, thank you so much! – Dr Krishnakumar Gopalakrishnan Mar 27 '20 at 00:02
3

The code below implements the equationgrid environment that allows the following syntax for these types of equations:

\begin{equationgrid}[Reference case,   Modified Case]{one}%
  a &= kb,  a' &= 3b\\
  x &= y^k, y' &= y^{0.5} \\
  z &= e^k, z' &= e^{1.1}
\end{equationgrid}

The equations are numbered using the equation counter together with a "column" counter a, b, c, ... :

enter image description here

The equationgrid environment accepts two arguments:

  1. An optional header line that is a comma separated list of column headers.
  2. A required label for the equations -- because I strongly believe that you should not label an equation unless you intend to refer to it later. In the example above, the subequations can be referred to using \ref{one-1a}, \ref{one-1b}, \ref{one-2a} and \ref{one-2b}.

Notice that the equations themselves are separated using commas, with \\ being used to mark the end of the equation line. The number of columns is, in principle, arbitrary. For example, you can use

\begin{equationgrid}{two}%
  a &= kb,  a' &= 3 b,     a &= k b, a' &= 3 b\\
  x &= y^k, y' &= y^{0.5}, x &= y^k, y' &= y^{0.5} \\
  z &= e^k, z' &= e^{1.1}, z &= e^k, z' &= e^{1.1}
\end{equationgrid}

to produce

enter image description here

(The equation references for these equations are two-1a, two-1b, ..., two-3d.) These equations are typeset in an align* environment, so this environment and the page width limit how many columns can actually be used.

The code uses LaTex3 sequences in an essential way. First, the contents of the gridequation environment are split into rows using the newline separators \\ and then the rows are further split into columns using the commas. Once this is done the equations are reassembled with equation numbers and labels being added at the same time.

Here is the code:

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}
% two counters for the keeping track of grid rows and columns
\newcounter{GridEqnCol}[equation]
\newcounter{GridEqnRow}
\renewcommand\theGridEqnCol{(\theequation\alph{GridEqnCol})}
\renewcommand\theGridEqnRow{\arabic{GridEqnRow}\alph{GridEqnCol}}
\ExplSyntaxOn
\int_new:N \l_grid_row_int   % grid row number
\seq_new:N \l_grid_col_seq   % the column entries in one row
\seq_new:N \l_grid_head_seq  % the optional column headers
\seq_new:N \l_grid_row_seq   % the rows of the equation
\tl_new:N  \l_grid_hline_tl  % a hack to adjust the columns
\tl_new:N  \l_grid_label_tl  % for construction equation labels
% \begin{equationgrid}[column headers as csv]{label}...\end{equationgrid}
\NewDocumentEnvironment{equationgrid}{ o m b }{
    % split the environment body into rows using the \\
    \tl_clear:N \l_grid_hline_tl
    \int_zero:N \l_grid_row_int
    \setcounter{GridEqnRow}{0}
    \tl_set:Nn \l_grid_label_tl {#2-}
    \seq_set_split:Nnn \l_grid_row_seq { \\ } { #3 }
    \IfNoValueTF{#1}{ \seq_clear:N \l_grid_head_seq }
    {
      \seq_set_split:Nnn \l_grid_head_seq {,} {#1}
      \tl_put_right:Nx \l_grid_hline_tl {
          \noexpand\cline{1-\int_eval:n{2+4*\seq_count:N \l_grid_head_seq} }
      }
    }
    \begin{align*}
      \seq_if_empty:NF \l_grid_head_seq {
         \seq_map_function:NN \l_grid_head_seq \__grid_head:n
         \\\tl_use:N \l_grid_hline_tl
      }
      \seq_map_inline:Nn \l_grid_row_seq { \__grid_row:n {##1} }
    \end{align*}
}{}
% typeset an entry of the header row
\cs_new:Npn \__grid_head:n #1 { \multispan{2}{\textbf{#1}} &&& }
% typeset an equation row, adding equation numbers and references
\cs_new:Npn \__grid_row:n #1 {
  \refstepcounter{equation}
  \refstepcounter{GridEqnRow}
  % split #1 into column entries using the ,
  \seq_set_split:Nnn \l_grid_col_seq { , } {#1}
  \seq_map_inline:Nn \l_grid_col_seq {
      \refstepcounter{GridEqnCol}
      \tl_set:No \l_tmpa_tl {\tl_use:N \l_grid_label_tl \theGridEqnRow}
      % align* disables equation numbers so need \ltx@label instead of \label
      \use:c{ltx@label}{ \tl_use:N \l_tmpa_tl }
      ##1 & \theGridEqnCol &&
   }
   \\
}
\ExplSyntaxOff
\begin{document}

  \begin{equationgrid}[Reference case,   Modified Case]{one}%
    a &= kb,  a' &= 3b\\
    x &= y^k, y' &= y^{0.5} \\
    z &= e^k, z' &= e^{1.1}
  \end{equationgrid}

  \begin{equationgrid}{two}%
    a &= kb,  a' &= 3 b,     a &= k b, a' &= 3 b\\
    x &= y^k, y' &= y^{0.5}, x &= y^k, y' &= y^{0.5} \\
    z &= e^k, z' &= e^{1.1}, z &= e^k, z' &= e^{1.1}
  \end{equationgrid}

  As you see, equations \ref{one-1a} and \ref{two-1a} are similar.

\end{document}

A final caveat: because the rows are separated by \\ and the columns by commas , you cannot use either of these inside the equations. If you want to insert commas then the easiest way would be use to \newcommand\comma{,}. I have followed the syntax of the OP but I would probably put a comma at the end of each equation.

EDIT

Here is an updated version of the code where the equationgrid environment now accepts an additional optional argument as <...> that gives a comma separated list of column indices for which the equation numbers should be omitted. In addition, you can place a \notag command in any cell to suppress the equation number for just that cell (note that the \notag command must be before the comma!). For example,

\begin{equationgrid}<1,3>{three}%
  a &= kb,  a' &= 3 b,     a &= k b, a' &= 3 b\\
  x &= y^k, y' &= y^{0.5}, x &= y^k, y' &= y^{0.5} \\
  z &= e^k, z' &= e^{1.1}\notag, z &= e^k, z' &= e^{1.1}
\end{equationgrid}

suppresses the equation numbers in columns 1 and 3 and in row 3, column 2 to produce:

enter image description here

Here is the updated code:

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}
% two counters for the keeping track of grid rows and columns
\newcounter{GridEqnCol}[equation]
\newcounter{GridEqnRow}
\renewcommand\theGridEqnCol{(\theequation\alph{GridEqnCol})}
\ExplSyntaxOn
\bool_new:N \g_print_eq_bool  % suppress equation numbers in this column
\int_new:N \l_grid_row_int    % grid row number
\seq_new:N \l_grid_col_seq    % the column entries in one row
\seq_new:N \l_grid_head_seq   % the optional column headers
\seq_new:N \l_grid_row_seq    % the rows of the equation
\seq_new:N \l_suppress_eq_seq % suppress equation numbers in these columns
\tl_new:N  \l_grid_hline_tl   % a hack to adjust the columns
\tl_new:N  \l_grid_label_tl   % for construction equation labels
\renewcommand\theGridEqnRow{ \tl_use:N \l_grid_label_tl-\arabic{GridEqnRow}\alph{GridEqnCol} }
% \begin{equationgrid}<suppress column equation numbers>[column headers as csv]{label}...\end{equationgrid}
\NewDocumentEnvironment{equationgrid}{ D<>{} o m b }{
    % split the environment body into rows using the \\
    \tl_clear:N \l_grid_hline_tl
    \int_zero:N \l_grid_row_int
    \let\notag\relax % for completeness but not strictly necessary
    \setcounter{GridEqnRow}{0}
    \seq_set_split:Nnn \l_suppress_eq_seq { , } { #1 }
    \tl_set:Nn \l_grid_label_tl {#3}
    \seq_set_split:Nnn \l_grid_row_seq { \\ } { #4 }
    \IfNoValueTF{#2}{ \seq_clear:N \l_grid_head_seq }
    {
      \seq_set_split:Nnn \l_grid_head_seq {,} {#2}
      \tl_put_right:Nx \l_grid_hline_tl {
          \noexpand\cline{1-\int_eval:n{2+4*\seq_count:N \l_grid_head_seq} }
      }
    }
    \begin{align*}
      \seq_if_empty:NF \l_grid_head_seq {
         \seq_map_function:NN \l_grid_head_seq \__grid_head:n
         \\\tl_use:N \l_grid_hline_tl
      }
      \seq_map_inline:Nn \l_grid_row_seq { \__grid_row:n {##1} }
    \end{align*}
}{}
% typeset an entry of the header row
\cs_new:Npn \__grid_head:n #1 { \multispan{2}{\textbf{#1}} &&& }
% typeset an equation row, adding equation numbers and references
\cs_new:Npn \__grid_row:n #1 {
  \refstepcounter{equation}
  \refstepcounter{GridEqnRow}
  % split #1 into column entries using the ,
  \seq_set_split:Nnn \l_grid_col_seq { , } {#1}
  \seq_map_inline:Nn \l_grid_col_seq {
      \refstepcounter{GridEqnCol}
      \bool_gset_true:N \g_print_eq_bool
      \seq_if_in:NxT \l_suppress_eq_seq {\arabic{GridEqnCol}} { \bool_gset_false:N \g_print_eq_bool }
      \str_if_in:nnT { ##1 } { \notag } { \bool_gset_false:N \g_print_eq_bool }
      \bool_if:NT \g_print_eq_bool
      {
        % align* disables equation numbers so need \ltx@label instead of \label
        \use:c{ltx@label}{ \theGridEqnRow }
      }
      ##1 & \bool_if:NT \g_print_eq_bool {\theGridEqnCol} &&
   }
   \\
}
\cs_generate_variant:Nn \seq_if_in:NnF {NxF}
\ExplSyntaxOff
\begin{document}

  \begin{equationgrid}[Reference case,   Modified Case]{one}%
    a &= kb,  a' &= 3b\\
    x &= y^k, y' &= y^{0.5} \\
    z &= e^k, z' &= e^{1.1}
  \end{equationgrid}

  \begin{equationgrid}{two}%
    a &= kb,  a' &= 3 b,     a &= k b, a' &= 3 b\\
    x &= y^k, y' &= y^{0.5}, x &= y^k, y' &= y^{0.5} \\
    z &= e^k, z' &= e^{1.1}, z &= e^k, z' &= e^{1.1}
  \end{equationgrid}

  As you see, equations \ref{one-1a} and \ref{two-1a} are similar.

  \begin{equationgrid}<1,3>{three}%
    a &= kb,  a' &= 3 b,     a &= k b, a' &= 3 b\\
    x &= y^k, y' &= y^{0.5}, x &= y^k, y' &= y^{0.5} \\
    z &= e^k, z' &= e^{1.1}\notag, z &= e^k, z' &= e^{1.1}
  \end{equationgrid}

\end{document}
  • I am quite happy with this solution, and I am awarding the bounty to you. There is a problem with the cross-referencing two \ref{two-1a} does not work and produces ?. Instead, one has to manually count the past number of equationgrid rows and type \ref{two-4a} to get the correct output, which isn't really scalable. Can you consider updating your answer if you have a fix for this? – Dr Krishnakumar Gopalakrishnan Mar 26 '20 at 23:57
  • @Krishna Thank you! Sorry, the labels were working earlier so I must have broken them during one of edits. I believe that they are working again now. Let me know if there are any other problems. –  Mar 27 '20 at 13:04
  • sorry to bother. Is there a chance your custom definitions can be modified so that the equation number of a particular column can be suppressed entirely? Consider that there is now a need for a third column with just some textual remarks for each row, e.g. \text{Here is a remark for row 1} that must not be numbered. – Dr Krishnakumar Gopalakrishnan Apr 04 '20 at 23:13
  • @Krishna See my edit –  Apr 05 '20 at 03:25