5

I am using the spalign package to typeset matrices and systems of equations.

Basically it just lets you use spaces (or commas) and semicolons instead of & and \\ when typing in matrices and similar things based on arrays.

I would like to vertically align some matrices or systems of equations as though their baseline is the baseline of the first row (or equation) rather than being vertically centered, as can be done in the array environment by using the [t] option.

MWE is:

\documentclass[12pt]{report}
\usepackage{spalign}
\usepackage{amsmath}

\begin{document}
Normal matrix vertically aligned so that it is vertically centered:

\[
  A=\spalignmat{1 2 3;4 5 6;7 8 9}
\]

The same matrix using amsmath environments:
\[
  A=\begin{pmatrix}
      1&2&3\\
      4&5&6\\
      7&8&9
  \end{pmatrix}
\]

I would like it to vertically align with baseline at the baseline of the first row, like you can do with an array:

\[
  A=\begin{array}[t]{ccc}
      1&2&3\\
      4&5&6\\
      7&8&9
  \end{array}
\]

A system using spalign:
$\spalignsys{2x + 3y = 1;x - y = 10}$
\end{document}

enter image description here

I would like to be able to align the matrix (and system) the way the array is aligned. The spalign package has tools to create your own shortcut commands (so I know how to make a top-aligned array environment that uses the spalign shortcuts), but I don't know how to make it automatically handle the delimiters and column alignments. Similarly, I can use array environment to typeset the system, but it's nice to have the number of variables and such handled automatically as in spalign.

If it can't be done in spalign, a solution using the pmatrix environment would be the next best thing (however, as you can see in the example, the spacing between the array and delimiters is a little different there, so it's not ideal for me, since it would look different than my other matrices).

Thanks for any help!

5 Answers 5

3

This is not supported by spalign.

Here's a different implementation.

\documentclass[12pt]{report}
\usepackage{xparse}
\usepackage{amsmath}
\usepackage{delarray}

\ExplSyntaxOn
\NewDocumentCommand{\extraalign}{O{}m}
 {
  \group_begin:
  \keys_set:nn { extraalign } { #1 }
  \extraalign_make:n { #2 }
  \group_end:
 }

\NewDocumentCommand{\extraalignset}{m}
 {
  \keys_set:nn { extraalign } { #1 }
 }

\tl_new:N \l__extraalign_cols_tl
\tl_new:N \l__extraalign_row_tl
\seq_new:N \l__extraalign_rows_in_seq
\seq_new:N \l__extraalign_rows_out_seq
\seq_new:N \l__extraalign_row_seq
\int_new:N \l__extraalign_cols_int

\keys_define:nn { extraalign }
 {
  h .code:n = \tl_set:Nn \l__extraalign_cols_tl { *{\l__extraalign_cols_int}{#1} },
  h .initial:n = c,
  v .tl_set:N = \l__extraalign_vertical_tl,
  v .initial:n = c,
  p .code:n = \tl_set:Nn \l__extraalign_cols_tl { #1 },
  l .tl_set:N = \l__extraalign_left_tl,
  l .initial:n = (,
  r .tl_set:N = \l__extraalign_right_tl,
  r .initial:n = ),
 }

\cs_new_protected:Nn \extraalign_make:n
 {
  \__extraalign_body:n { #1 }
  \__extraalign_preamble:VVVV
   \l__extraalign_vertical_tl % vertical alignment
   \l__extraalign_left_tl     % left delimiter
   \l__extraalign_right_tl    % right delimiter
   \l__extraalign_cols_tl     % column spec
  % deliver the matrix
  \seq_use:Nn \l__extraalign_rows_out_seq { \\ }
  \end{array}
 }

\cs_new_protected:Nn \__extraalign_preamble:nnnn
 {
  \begin{array}[#1]#2{@{}#4@{}}#3
 }
\cs_generate_variant:Nn \__extraalign_preamble:nnnn { VVVV }

\cs_new_protected:Nn \__extraalign_body:n
 {
  \seq_set_split:Nnn \l__extraalign_rows_in_seq { ; } { #1 }
  \seq_clear:N \l__extraalign_rows_out_seq
  \seq_map_variable:NNn \l__extraalign_rows_in_seq \l__extraalign_row_tl
   {
    \__extraalign_makerow:V \l__extraalign_row_tl
   }
 }

\cs_new_protected:Nn \__extraalign_makerow:n
 {
  \seq_set_split:Nnn \__extraalign_row_seq { ~ } { #1 }
  \int_compare:nT { \l__extraalign_cols_int = 0 }
   {
    \int_set:Nn \l__extraalign_cols_int { \seq_count:N \__extraalign_row_seq }
   }
  \seq_put_right:Nx \l__extraalign_rows_out_seq
   { \seq_use:Nn \__extraalign_row_seq { & } }
 }
\cs_generate_variant:Nn \__extraalign_makerow:n { V }

\ExplSyntaxOff


\begin{document}

\begin{gather*}
  A=\begin{pmatrix}1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9\end{pmatrix}
\quad
  A=\extraalign{1 2 3;4 5 6;7 8 9}
\\
  A=\extraalign[v=t]{1 2 3;4 5 6;7 8 9}
\quad
  A=\extraalign[p=rcl,v=t]{-1 2 3;4 5 66;700 8 9000}
\\
  A=\extraalign[l=\{,r=.,h=l]{aaaa ; bbb ; c}
\end{gather*}

\end{document}

The optional argument to \extraalign contains a key-value list of options

  • h for the general format of columns (default c), with as many columns as required
  • p for a special preamble, specifying all columns
  • v for the vertical alignment, t, c or b (default c)
  • l for the left delimiter (default (); use . for no delimiter
  • r for the right delimiter (default )); use . for no delimiter

Should you want to change the default values, use \extraalignset with the values you want. For instance, if you do

\extraalignset{ l = [, r = ] }

all matrices (in the current scope or globally if done in the preamble) will use brackets unless locally countermanded.

enter image description here

Just for completeness, here's how you can do augmented matrices.

\extraalignset{l=[,r=]}

\begin{gather*}
  A=\extraalign[p=cccc|cc]{1 2 3 4 5 6;4 5 6 7 8 9;7 8 9 1 2 3}
  \quad
  A=\extraalign[p=cccc|cc,v=t]{1 2 3 4 5 6;4 5 6 7 8 9;7 8 9 1 2 3}
\\
  A=\extraalign[p=ccc|ccc]{1 2 3 4 5 6;4 5 6 7 8 9;7 8 9 1 2 3}
  \quad
  A=\extraalign[p=ccc|ccc,v=t]{1 2 3 4 5 6;4 5 6 7 8 9;7 8 9 1 2 3}
\end{gather*}

enter image description here

2
  • This is really great. I haven't used ExplSyntax before so it's hard for me to follow, but it works as advertised. Thank you for taking the time to answer. If I wasn't so stubbornly attached to spalign I would probably use this due to how versatile it is.
    – JasonV
    Mar 18, 2019 at 17:47
  • @JasonV I added how to get augmented matrices (no change to the code).
    – egreg
    Mar 19, 2019 at 18:16
2
\documentclass{article}
\usepackage{tabstackengine,scalerel}
\TABstackMath
\setstacktabbedgap{1ex}
\strutlongstacks{T}
\begin{document}
\[
A = \tabbedLongunderstack{1&2&3\\4&5&6\\7&8&9}
\]
\[
A = \scaleleftright[1.5ex]{\Biggl(}
   {\tabbedLongunderstack{1&2&3\\4&5&6\\7&8&9}}{\Biggr)}
\]
\[
\savestack\mysystem{\setstacktabbedgap{0pt}%
  \tabbedCenterstack[r]{2x +& 3y =& 1\\x -& y =& 10}}
\renewcommand\stackalignment{r}
\stackunder[10pt]
{$A = \tabbedLongunderstack{1&2&3\\4&5&6\\7&8&9}$}
{A system using tabstackengine: $\biggl\{\mysystem$}
\]
\end{document}

enter image description here

1
  • Works as advertised. I will stick with spalign for now, but I'll look into how yours works also.
    – JasonV
    Mar 18, 2019 at 17:50
2

I appreciate the other answers. This was bothering me for a while, and as it sat unanswered for so long (I think it is too specific, no one but me apparently needed to be able to do this) I had found a way to do it by patching the spalign commands. Just in case anyone else ever wonders how to do this, I'll post my answer here.

I had to dig into the existing spalign code a bit. The matrices are built using arrays as expected, so I initially thought to just replace \begin{align} by \begin{align}[t]. However, this creates a problem where the delimiters are also centered on the top line:

align top

To solve that problem, I used delarray as suggested in this answer (and as suggested again by egreg's answer this question).

However, this required a much more complicated find-and-replace in the existing code of spalign, since the macros in that package put the delimiters outside of the array environment (as is usual when not using delarray. At any rate, I became a little obsessed with solving this problem and managed it with xpatch and some trial-and-error. I think it's a bit of a mess (partly because of the way *s are handled in spalign), but the following code creates duplicates of several of the spalign environments, aligned with their top rows, with all optional arguments and starred versions intact:

\documentclass[12pt]{report}
\usepackage{amsmath}
\usepackage[delims={[}{]},sysdelims={.}{.}]{spalign} %set to square brackets on matrices and no delimiters on systems
\usepackage{letltxmacro}
\usepackage{delarray}
\usepackage{xpatch}

\makeatletter

\let\tmat=\spalignmat
\let\tmatx=\spalignmat@x
\LetLtxMacro\tmatstar\spalignmat@star
\xpatchcmd{\tmat}{\spalignmat@x}{\tmatx}{}{}
\xpatchcmd{\tmatx}{\spalignmat@star}{\tmatstar}{}{}
\xpatchcmd{\tmatstar}{\spalign@maybedelim}{\spalignenv}{}{}
\xpatchcmd{\tmatstar}{\begin{array}{\spalign@repeated}}%
    {\begin{array}[t]\ifspalign@star\else\spalign@leftdelim\fi%
    {@{\spalignmatdelimskip}\spalign@repeated @{\spalignmatdelimskip}}%
    \ifspalign@star\else\spalign@rightdelim\fi}{}{}
\xpatchcmd{\tmatstar}{{\hskip-\arraycolsep\spalignmatdelimskip}}{}{}{}
\providecommand{\dtmat}[2][r]{{\detm \tmat[#1]{#2}}}

\let\tamatn=\spalignaugmatn
\let\tamatnx=\spalignaugmatn@x
\LetLtxMacro\tamatnstar\spalignaugmatn@star
\xpatchcmd{\tamatn}{\spalignaugmatn@x}{\tamatnx}{}{}
\xpatchcmd{\tamatnx}{\spalignaugmatn@star}{\tamatnstar}{}{}
\xpatchcmd{\tamatnstar}{\spalign@maybedelim}{\spalignenv}{}{}
\xpatchcmd{\tamatnstar}{\begin{array}{\spalign@repeated@one|\spalign@repeated@two}}%
    {\begin{array}[t]\ifspalign@star\else\spalign@leftdelim\fi%
    {@{\spalignmatdelimskip}\spalign@repeated@one|\spalign@repeated@two @{\spalignmatdelimskip}}\ifspalign@star\else\spalign@rightdelim\fi}{}{}
\xpatchcmd{\tamatnstar}{{\hskip-\arraycolsep\spalignmatdelimskip}}{}{}{}

\providecommand{\tamat}[1][r]{%
    \tamatn[#1]{1}%
    }%

\let\tamath=\spalignaugmathalf
\let\tamathx=\spalignaugmathalf@x
\LetLtxMacro\tamathstar\spalignaugmathalf@star
\xpatchcmd{\tamath}{\spalignaugmathalf@x}{\tamathx}{}{}
\xpatchcmd{\tamathx}{\spalignaugmathalf@star}{\tamathstar}{}{}
\xpatchcmd{\tamathstar}{\spalign@maybedelim}{\spalignenv}{}{}
\xpatchcmd{\tamathstar}{\begin{array}{\spalign@repeated@one|\spalign@repeated@two}}%
    {\begin{array}[t]\ifspalign@star\else\spalign@leftdelim\fi%
    {@{\spalignmatdelimskip}\spalign@repeated@one|\spalign@repeated@two @{\spalignmatdelimskip}}\ifspalign@star\else\spalign@rightdelim\fi}{}{}
\xpatchcmd{\tamathstar}{{\hskip-\arraycolsep\spalignmatdelimskip}}{}{}{}

\let\tsys=\spalignsys
\let\tsysx=\spalignsys@x
\let\tsysstar=\spalignsys@star
\xpatchcmd{\tsys}{\spalignsys@x}{\tsysx}{}{}
\xpatchcmd{\tsysx}{\spalignsys@star}{\tsysstar}{}{}
\xpatchcmd{\tsysstar}{\vcenter}{\vtop}{}{}

\makeatother

\begin{document}

\[
    A=\spalignmat{1 2 3;4 5 6;7 8 9}. \quad A=\tmat{1 2 3;4 5 6;7 8 9}.
\]

\[
    A=\spalignaugmat{1 2 3;4 5 6;7 8 9}. \quad A=\tamat{1 2 3;4 5 6;7 8 9}.
\]

\[
    A=\spalignaugmatn{2}{1 2 3 4 5 6;4 5 6 7 8 9;7 8 9 1 2 3}. \quad A=\tamatn{2}{1 2 3 4 5 6;4 5 6 7 8 9;7 8 9 1 2 3}.
\]

\[
    A=\spalignaugmathalf{1 2 3 4 5 6;4 5 6 7 8 9;7 8 9 1 2 3}. \quad A=\tamath{1 2 3 4 5 6;4 5 6 7 8 9;7 8 9 1 2 3}.
\]

System of equations:
$\spalignsys{2x + 3y = 1;x - y = 10}$.\quad
Top aligned:
$\tsys{2x + 3y = 1;x - y = 10}$.

\end{document}

Which produces: top aligned spalign

Those were all I needed, so they're all I patched. Others could be done similarly.

The *ed versions omit the delimiters, and the matrices take optional arguments to specify column alignments. Both of these features still work as in the original spalign.

It would perhaps be easier to just define anew the macros I want instead of using \xpatchcmd, but I found it instructive to do it this way. I had never used xpatch before and learned a lot in this first attempt.

I was not able to get the delimiters top-aligned for a system of equations because spalign uses halign for that instead of the array environment. For me, this was not a problem, since the book I am teaching from doesn't use delimiters on systems anyway, and I wanted to use consistent notation.

1

I recommend using tikzmark library of TikZ.

enter image description here

\documentclass[12pt]{report}
\usepackage{tikz}
\usetikzlibrary{tikzmark}
\usepackage{amsmath}
\begin{document}
Normal matrix vertically aligned so that it is vertically centered:
\[
A=\begin{pmatrix}
1&2&3\\
4&5&6\\
7&8&9
\end{pmatrix}
\]

To vertically align with baseline at the baseline of the first row, you can use \verb|tikzmark| library of TikZ as follows.
\[
%\phantom{A=}
\begin{pmatrix}
\tikzmarknode{1}{1}&2&3\\
4&5&6\\
7&8&9
\end{pmatrix}
\]
\begin{tikzpicture}[overlay,remember picture]
\path (1)--+(180:.4) node[left]{$A=$};
\end{tikzpicture}
Based on TikZ, \verb|tikzmark| is very flexible, well-adapted with \LaTeX\ documents.   
\end{document}

You can you \phantom{A=} if the formular is needed to be exactly centered.

1

The environment {bNiceMatrix} of nicematrix provides a key light-syntax for a syntax inspired by spalign and a key t for a top-line alignment as in {array}.

So, it's direct to program a command \MyMatrix doing what you wish.

\documentclass[12pt]{article}
\usepackage{nicematrix}

\NewDocumentCommand { \MyMatrix } { m }
  { 
    \begin{bNiceMatrix}[t,light-syntax]
    #1
    \end{bNiceMatrix}
  }

\begin{document}
\[ A=\MyMatrix{1 2 3;4 5 6;7 8 9} \]
\end{document}

You need several compilations (because nicematrix uses PGF/Tikz nodes under the hood).

Output of the above code

You must log in to answer this question.

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