3

I have been looking for a solution for typesetting a series of equations into two columns of equal width, with both columns vertically aligned on top, with no extra space. To be specific, I am looking for a solution in which I do:

\begin{envthatiwant}{2}
a &= a \\
b &= b \\
c &= c \\
d &= d
\end{envthatiwant}

And it automatically splits into two columns (bonus points if there are an odd number of lines and it's smart enough to figure out to break at say c (out of a b c d e)).

I have some attempts from reading other solutions but I have not found a satisfactory one. Below is a MWE code and five cases.

The first case is a naive one, just using multicols + noindent. The spacing is quite random and unpredictable to a layman so a solution such as this is far from what I want.

The second case is putting aligns in multicols and putting noindents (I also wonder if there is a way to automatically put them) in the beginning of specific environments. The problem here however is that these

The third case is using code similar to the solution that I want, but obviously it does not work so well.

The fourth case is using aligned, which I saw from the previous solutions. This is a bit close since everything is vertically aligned thanks to the [t] parameter. However, it does not split it into two columns of equal length, like in the case of multicols (see case 1, 2). Of course I can add \qquads or whatever but that will need some manual intervention every time.

The fifth case abuses align. This is closest to what I want BUT code-wise, it is a nightmare since I have to plan ahead and think how many equations I want to put. If I wanted to, say, add an equation between c and d, then I would have to manually move everything one step down.

\documentclass{article}
\usepackage{amsmath}
\usepackage{multicol}

\begin{document}

\noindent Hello! This is Case 1.
\begin{multicols}{2} \noindent
$$a = a$$
$$b = b$$
\\ \noindent
$$c = c$$
$$d = d$$
\end{multicols}

\noindent Hello! This is Case 2.
\begin{multicols}{2} \noindent
\begin{align*}
a &= a \\ 
b &= b
\end{align*} \noindent
\begin{align*}
c &= c \\
d &= d
\end{align*}
\end{multicols}

\noindent Hello! This is Case 3.
\begin{multicols}{2}
\begin{align*}
a &= a \\ 
b &= b \\
c &= c \\
d &= d
\end{align*}
\end{multicols}

\noindent Hello! This is Case 4.
$$
\begin{aligned}[t]
a &= a \\ 
b &= b
\end{aligned} \qquad %if you want
\begin{aligned}[t]
c &= c \\ 
d &= d
\end{aligned}
$$

\noindent Hello! This is Case 5.
\begin{align*}
a &= a & c &= c \\
b &= b & d &= d
\end{align*}

enter image description here

1 Answer 1

2

This code will store the rows and round the number up to a multiple of #1 (the desired number of columns). Next, with a nested cycle, it picks up the entries number

1+0*n, 1+1*n, ..., 1+(#1-1)*n
2+0*n, 1+1*n, ..., 2+(#1-1)*n
...
n+0*n, n+1*n, ..., n+(#1-1)*n

where n is the final number of rows, storing each new row with items separated by &.

Finally it delivers the result, with rows separated by \\.

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentEnvironment{columnalign}{m b}
 {% #1 = number of columns, #2 = body
  \guissmo_columnalign:nn { #1 } { #2 }
 }
 {\ignorespacesafterend}

\seq_new:N \l__guissmo_columnalign_in_seq
\seq_new:N \l__guissmo_columnalign_out_seq
\seq_new:N \l__guissmo_columnalign_temp_seq
\int_new:N \l__guissmo_columnalign_rows_int

\cs_new_protected:Nn \guissmo_columnalign:nn
 {
  % store the rows in the sequence
  \seq_set_split:Nnn \l__guissmo_columnalign_in_seq { \\ } { #2 }
  \int_compare:nF { \int_mod:nn { \seq_count:N \l__guissmo_columnalign_in_seq } { #1 } = 0 }
   {% number of rows not a multiple of #1, add empty entries
    \prg_replicate:nn { #1 - \int_mod:nn { \seq_count:N \l__guissmo_columnalign_in_seq } { #1 } }
     {
      \seq_put_right:Nn \l__guissmo_columnalign_in_seq {}
     }
   }
  \seq_clear:N \l__guissmo_columnalign_out_seq
  \int_set:Nn \l__guissmo_columnalign_rows_int 
   { \int_div_truncate:nn { \seq_count:N \l__guissmo_columnalign_in_seq } { #1 } }
  \int_step_inline:nn { \l__guissmo_columnalign_rows_int }
   {% clear the temporary sequence
    \seq_clear:N \l__guissmo_columnalign_temp_seq
    \int_step_inline:nnn { 0 } { #1 - 1 }
     {
      \seq_put_right:Nx \l__guissmo_columnalign_temp_seq
       {
        \seq_item:Nn \l__guissmo_columnalign_in_seq
         { ##1 + \l__guissmo_columnalign_rows_int * ####1 }
       }
     }
    \seq_put_right:Nx \l__guissmo_columnalign_out_seq
     {
      \seq_use:Nn \l__guissmo_columnalign_temp_seq { & }
     }
   }
   % now \l__guissmo_columnalign_out_seq contains the new rows
   \begin{align*}
   \seq_use:Nn \l__guissmo_columnalign_out_seq { \\ }
   \end{align*}
 }

\ExplSyntaxOff

\begin{document}

\begin{columnalign}{2}
a&=a \\
b&=b \\
c&=c \\
d&=d \\
e&=e
\end{columnalign}

\begin{columnalign}{3}
a&=a \\
b&=b \\
c&=c \\
d&=d \\
e&=e
\end{columnalign}

\begin{columnalign}{3}
a&=a \\
b&=b \\
c&=c \\
d&=d \\
e&=e \\
f&=f
\end{columnalign}

\end{document}

enter image description here

Here's a version where you can also add a single equation number for the block. The new optional argument sets the intercolumn spacing.

\documentclass{article}
\usepackage{amsmath,array}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentEnvironment{columnalign}{O{3em} m b}
 {% #1 = column spacing, #2 = number of columns, #3 = body
  \guissmo_columnalign:nnnn { #1 } { #2 } { #3 } { }
 }
 {}
\NewDocumentEnvironment{columnalign*}{O{3em} m b}
 {% #1 = column spacing, #2 = number of columns, #3 = body
  \guissmo_columnalign:nnnn { #1 } { #2 } { #3 } { * }
 }
 {}

\seq_new:N \l__guissmo_columnalign_in_seq
\seq_new:N \l__guissmo_columnalign_out_seq
\seq_new:N \l__guissmo_columnalign_temp_seq
\int_new:N \l__guissmo_columnalign_rows_int

\cs_new_protected:Nn \guissmo_columnalign:nnnn
 {
  \__guissmo_split:nnn { #1 } { #2 } { #3 }
  % now \l__guissmo_columnalign_out_seq contains the new rows
  \begin{equation#4}
  \begin{alignedat}{3}
  \seq_use:Nn \l__guissmo_columnalign_out_seq { \\ }
  \end{alignedat}
  \end{equation#4}
 }

\cs_new_protected:Nn \__guissmo_split:nnn
 {
  % store the rows in the sequence
  \seq_set_split:Nnn \l__guissmo_columnalign_in_seq { \\ } { #3 }
  \int_compare:nF { \int_mod:nn { \seq_count:N \l__guissmo_columnalign_in_seq } { #2 } = 0 }
   {% number of rows not a multiple of #2, add empty entries
    \prg_replicate:nn { #2 - \int_mod:nn { \seq_count:N \l__guissmo_columnalign_in_seq } { #2 } }
     {
      \seq_put_right:Nn \l__guissmo_columnalign_in_seq {}
     }
   }
  \seq_clear:N \l__guissmo_columnalign_out_seq
  \int_set:Nn \l__guissmo_columnalign_rows_int 
   { \int_div_truncate:nn { \seq_count:N \l__guissmo_columnalign_in_seq } { #2 } }
  \int_step_inline:nn { \l__guissmo_columnalign_rows_int }
   {% clear the temporary sequence
    \seq_clear:N \l__guissmo_columnalign_temp_seq
    \int_step_inline:nnn { 0 } { #2 - 1 }
     {
      \seq_put_right:Nx \l__guissmo_columnalign_temp_seq
       {
        \seq_item:Nn \l__guissmo_columnalign_in_seq
         { ##1 + \l__guissmo_columnalign_rows_int * ####1 }
       }
     }
    \seq_put_right:Nx \l__guissmo_columnalign_out_seq
     {
      \seq_use:Nn \l__guissmo_columnalign_temp_seq { &\hspace{#1} }
     }
   }
 }

\ExplSyntaxOff

\begin{document}

\begin{columnalign}{2}
a&=a \\
b&=b \\
c&=c \\
d&=d \\
e&=e
\end{columnalign}

\begin{columnalign}[2em]{3}
a&=a \\
b&=b \\
c&=c \\
d&=d \\
e&=e
\end{columnalign}

\begin{columnalign*}{3}
a&=a \\
b&=bbbb \\
c&=ccc \\
d&=d \\
e&=e \\
f&=f
\end{columnalign*}

\end{document}

enter image description here

4
  • Thank you. However, I am getting an error: "! LaTeX3 Error: Unknown argument type 'b' for the command '\environment(LaTeX3) columnalign'.For immediate help type H <return>.... {}". Do you know how that works?
    – Guissmo
    Oct 11, 2019 at 6:21
  • 1
    @Guissmo You eed to update your TeX system.
    – egreg
    Oct 11, 2019 at 6:53
  • Now, it works. Thanks! Can I make a follow-up question? What if I want each set of equations be numbered as one equation? I tried changing align to align/split but that did not seem to work as split only wants one ampersand, if I understand correctly?
    – Guissmo
    Oct 11, 2019 at 9:25
  • 1
    @Guissmo Added as requested
    – egreg
    Oct 11, 2019 at 13:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .