1

When I need to write a loooooong equation, or put several closely related multiline equations together under a single number, alignment gets tricky because I need multiple alignment points, and the layout is not necessarily table-like, because "cells" placed above each other may have different widths.

My question: how can automatic multiple alignment be achieved in LaTeX equations? I would like to have different alignment symbols like &1, &2 etc., so that &1 would be aligned only with &1, &2 only with &2, and so on.

Usually I deal with multiple alignment by setting \minalignsep to 0pt and using aligned nested into equation (I define a custom environment to automate this). Alignment issues when the number of alignment points differs from line to line are addressed with \mathrlap from mathtools package (at this point the solution is already not automatic, because \mathrlaps have to be put manually where needed). Sometimes even this is not enough, and I need to use nested aligned environments or something.

An example (red lines indicate alignment points):

enter image description here

You can see the layout does not have a table-like structure with well-defined columns, it is a "broken" table, that is why it required nested aligneds. Yes, I could have just aligned everything at the leftmost red line, but it would look less structured.

This was generated by

\documentclass{article}
\usepackage{amsmath}
\usepackage{mathtools}
\usepackage{environ}

\renewcommand\minalignsep{0pt}
\NewEnviron{eq}[1]
  {\begin{equation}
    \label{eq:#1}
     \begin{aligned}
       \BODY
     \end{aligned}
    \end{equation}}

\begin{document}

\begin{eq}{random_label}
        \Xi &= 666\sum_{i \in \{ \text{description of a set} \} } && (\text{a long prefactor})\\
        &&&\times (\text{a long expression})\\
        & \mathrlap{
            \begin{aligned}
                {}+ 666\sum_{i=0}^{\infty} &(\text{another long prefactor})\\
                &\times (\text{another long expression})
            \end{aligned}
           }
\end{eq}

\end{document}

Instead, I would rather write something like

\begin{eq}{random_label}
        \Xi &1 = 666\sum_{i \in \{ \text{description of a set} \} } &2 (\text{a long prefactor})\\
        &2 \times (\text{a long expression})\\
        &1 + 666\sum_{i=0}^{\infty} &3(\text{another long prefactor})\\
        &3 \times (\text{another long expression})
\end{eq}

Is there a simple way to implement this syntax, or cumbersome custom macros are necessary?

3 Answers 3

1

Welcome! I do not understand your environment, but with just align and aligned one would get

\documentclass{article}
\usepackage{amsmath}
\begin{document}
\begin{align}
        \Xi &= 666\sum_{i \in \{ \text{description of a set} \} }
        \begin{aligned}[t]
         & (\text{a long prefactor})\\
        &\times (\text{a long expression})\\
        \end{aligned}\notag\\
        &{}+ 666\sum_{i=0}^{\infty}
            \begin{aligned}[t]
                 &(\text{another long prefactor})\\
                &\times (\text{another long expression})
            \end{aligned}
\end{align}

\end{document}

enter image description here

1
  • This is basically a cleaner version of my code, with two inner aligneds instead of an aligned wrapped into \mathrlap. But you still need to write those aligneds manually. I'm looking for a syntax that would allow me to just write an equation, insert line breaks, indicate what should be aligned with what, and that's it. No aligneds or other commands. They make the code cumbersome, ampersands should be enough. Commented May 3, 2020 at 22:39
0

You can, but you have to use something else than \\ to separate the various blocks, I chose \newblock.

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

\ExplSyntaxOn

\NewDocumentEnvironment{eq}{mb}
 {
  \seq_set_split:Nnn \l__undefnick_eq_seq { \newblock } { #2 }
  \seq_map_function:NN \l__undefnick_eq_seq \__undefnick_eq_block:n
  \begin{equation}\label{eq:#1}\begin{aligned}
  \tl_use:N \l__undefnick_eq_tl
  \end{aligned}\end{equation}
 }{}

\seq_new:N \l__undefnick_eq_seq
\seq_new:N \l__undefnick_block_seq
\seq_new:N \l__undefnick_partial_seq
\tl_new:N \l__undefnick_eq_tl
\tl_new:N \l__undefnick_partial_tl
\tl_new:N \l__undefnick_last_tl

\cs_set_protected:Nn \__undefnick_eq_block:n
 {
  \seq_set_split:Nnn \l__undefnick_block_seq { \\ } { #1 }
  \int_compare:nTF { \seq_count:N \l__undefnick_block_seq = 1 }
   {% no inner block
    \tl_put_right:Nn \l__undefnick_eq_tl { #1 }
   }
   {% inner block, we need to detach the last item
    \seq_pop_left:NN \l__undefnick_block_seq \l__undefnick_partial_tl
    \seq_set_split:NnV \l__undefnick_partial_seq { & } \l__undefnick_partial_tl
    \seq_pop_right:NN \l__undefnick_partial_seq \l__undefnick_last_tl
    % add the first to items to the body
    \tl_put_right:Nx \l__undefnick_eq_tl { \seq_use:Nn \l__undefnick_partial_seq { & } }
    % start making the inner aligned
    \tl_put_right:Nn \l__undefnick_eq_tl { \begin{aligned}[t] }
    % reinstate the last item in the partial sequence
    \seq_put_left:Nx \l__undefnick_block_seq { & \exp_not:V \l__undefnick_last_tl }
    % add the inner block
    \tl_put_right:Nx \l__undefnick_eq_tl { \seq_use:Nn \l__undefnick_block_seq { \\ } }
    % finish the inner block
    \tl_put_right:Nn \l__undefnick_eq_tl { \end{aligned} \\ }
   }
 }

\ExplSyntaxOff

\begin{document}

\begin{eq}{random_label}
\Xi
&= 666\sum_{i \in \{ \text{some set} \} }
     & (\text{a long prefactor})\\
     & \times (\text{a long expression})
\newblock
&+ 666\sum_{i=0}^{\infty}
     &(\text{another long prefactor})\\
     &\times (\text{another long expression})
\end{eq}

\end{document}

enter image description here

2
  • This is more automatic than the Schrödinger's cat's answer, but it works only in the case of two-level aligned nesting, if I understand correctly. Commented May 5, 2020 at 17:05
  • @undefined_nickname Yes, I can't think to anything more complex than this. By the way it is completely automatic under the specifications.
    – egreg
    Commented May 5, 2020 at 17:07
0

This is actually a comment to @egreg, but it's too long to be a comment.

I expected something like this algorithm:

  1. Check if the equation has the form [something] &[one or more digits] [something] &[one or more digits] ... [something]. If not, issue an error.
  2. Find line breaks and separate the equation into lines.
  3. Find all alignment symbols and order them from left to right. If there are contradicting constraints, issue an error. Example: if there are three lines with alignment symbols '&4 &1 &13', '&1 &2 &3', and '&2 &4 &6', then this is an error, because &4 is to the left of &1 (first line), which is to the left of &2 (second line), which is to the left of &4 (third line), which is impossible.
  4. Find the width of each 'cell' between two consecutive alignment symbols.
  5. Each alignment symbol corresponds to an imaginary vertical line in the final layout of the equation. Calculate the distance between each pair of consecutive lines from the 'cell' widths. For example, if we have three lines of the form '&4 [smth 16mm wide] &1 [smth 5mm wide] &13', '&1 [smth 7mm wide] &2 [smth 14mm wide] &3', '&5 [smth 11mm wide] &4 [smth 24mm wide] &6', the resulting distances between alignment points would be '&5 11mm &4 16mm &1 5mm &13 24-16-5=3mm &6'. If the graph of alignment point has cycles, there will be contradicting constraints, and an error should be issued. Example: three lines '&1 ... &2 ... &3', '&4 ... &2 ... &5', '&6 ... &5 ... &3'. There is a cycle '&2, line 1' - '&3, line 1' - '&3, line 3' - '&5, line 3' - '&5, line 2' - '&2, line 2' - '&2, line 1'. This should be an error.
  6. If a line has something before the leftmost alignment symbol, it should be right-aligned, everything else should be left-aligned. Typeset the equation so that its left boundary is where appropriate and the distances between alignment points are those found in the previous step.

But it seems this is not easy to be implemented in LaTeX. For example, when I tried to implement step 1, I found that \regex_match:nnTF cannot be used to check if a regex matches the whole expression.

1
  • Sorry, I won't follow you. I can remove my answer. Best regards.
    – egreg
    Commented May 5, 2020 at 17:26

You must log in to answer this question.

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