2

I want a way to set matrix entries aligned by their sign automatically. For example, output of

\begin{bmatrix}
    1&1&-1\\
    -1&1& 1\\
    1&-1& 1
\end{bmatrix}

be same as output of

\begin{bmatrix}
    \phantom{-}1&\phantom{-}1&-1\\
    -1&\phantom{-}1& \phantom{-}1\\
    \phantom{-}1&-1& \phantom{-}1
\end{bmatrix}

Is it possible at all?

  • 3
    Wouldn't it be simpler to use \begin{bmatrix*}[r] ... \end{bmatrix*}, defined by mathtools? – Bernard Jan 02 '20 at 22:02
  • yes. that's it. Now is it possible to redefine \begin{bmatrix}... \end{bmatrix} as \begin{bmatrix*}[r] ... \end{bmatrix*}? –  Jan 02 '20 at 22:27
  • I never tried it, but it might work. Other than that a ‘search and replace’ from within your editor would be fine too. – Bernard Jan 02 '20 at 23:57

3 Answers3

4

The amsmath environments [pbBvV]?matrix use a common \env@matrix macro to start the alignment. In this macro there is \array{*\c@MaxMatrixCols c}, which centers the contents of the cells by default. One quick way to change that default globally is to redefine that macro with r instead of c, or load etoolbox and do \patchcmd\env@matrix{c}{r}{}{}.

Alternatively, you can redefine \env@matrix to take an argument for the alignment, and patch the environments which use it to check for such optional argument. This is essentially what mathtools's starred environments do.

In the code below I used a loop to patch all the environments in one go (with a single default), but you can change them selectively if you want different behaviours.

Also, if you use a right aligned cell, then the numbers will be right aligned (thanks, Sherlock), and if two numbers have different widths (say, -1 and -12), then their rightmost end will be aligned, not the minus signs. To align the minus sign you can use the J column type defined (and not defined) in Schrödinger's cat's answer.

enter image description here

\documentclass{article}
\usepackage{amsmath}
\usepackage{array}
\usepackage{etoolbox}
\makeatletter
\def\env@matrix[#1]{\hskip -\arraycolsep
  \let\@ifnextchar\new@ifnextchar
  \array{*\c@MaxMatrixCols #1}}
\@tfor\@temp:=\matrix\pmatrix\bmatrix\Bmatrix\vmatrix\Vmatrix\do
  {\expandafter\patchcmd\@temp
     {\env@matrix}
     {\@ifnextchar[%]   default V
        \env@matrix{\env@matrix[J]}}
     {}{\FAILED}}
% From Mr. Cat's answer: https://tex.stackexchange.com/a/522747/134574
\newcolumntype{J}{>{\CheckSign}l}
\def\CheckSign\ignorespaces{%
  \@ifnextchar-{}{\@ifnextchar+{}{\phantom{-}}}}
\makeatother
\begin{document}
\[
\begin{bmatrix}
    1&1&-1\\
    -1&1& 1\\
    1&-1&-12\\
    1&-1&+12
\end{bmatrix}
\]
\end{document}
  • Nice. But if I change $m_{33}$ to $-12$ same problem appear again. –  Jan 03 '20 at 06:36
  • @C.F.G Initially I based my answer off of this comment of yours. I added the sign check in Schrödinger's cat's answer to use left aligned cells with a slot for unary signs. – Phelype Oleinik Jan 03 '20 at 13:35
  • Sorry, I did not want to annoy you. ;-) I thought about the +, too, but then I thought that there could be \pm, a \mp, all of which would arguably make more sense than just a +, and I let it be in the end because it may easily become a never-ending story. That is, - signs are rather frequent, and for them it makes IMHO more sense to write an automatic solution than for all the other cases, which seem to be much rarer. –  Jan 03 '20 at 17:26
  • @Schrödinger'scat When did you annoy me? Indeed, a - is by far mode common than the other cases you mentioned (which I haven't thought about :-). I'll leave the code for + in case someone needs to extend the code for their needs. – Phelype Oleinik Jan 03 '20 at 18:12
4

Here are two more proposals. The first one is conceptually very similar to Sebastiano's nice answer (and can be seen as an addendum to his). One can set the column type to r also with the mathtools package. The second proposal is based on this very nice answer, which solves a very related problem. It really does what you ask for, i.e. inserts a \phantom{-} if there is no minus, and comes in two variations, one with c and one with l columns (which I think makes more sense).

\documentclass{article}
\usepackage{mathtools}
\usepackage{array}% for second solution 
\makeatletter
\def\CheckMinus\ignorespaces{\@ifnextchar-{}{\phantom{-}}}
\makeatother
\newcolumntype{I}{>{\CheckMinus}c}
\newcolumntype{J}{>{\CheckMinus}l}

\begin{document}
\begin{enumerate}
 \item Just mathtools and change column type to \texttt{r}.
\[
\begin{bmatrix*}[r]
    1&1&-1\\
    -1&1& 1\\
    1&-1& 1
\end{bmatrix*}\quad\text{and}\quad\begin{bmatrix*}[r]
    12&1&-12\\
    -1&1& 12\\
    1&-12& 1
\end{bmatrix*}
\]
 \item Insert \verb|\phantom{-}| if there is no minus and use \texttt{c} column.
\[
\begin{bmatrix*}[I]
    1&1&-1\\
    -1&1& 1\\
    1&-1& 1
\end{bmatrix*}\quad\text{and}\quad\begin{bmatrix*}[I]
    12&1&-12\\
    -1&1& 12\\
    1&-12& 1
\end{bmatrix*}
\]
 \item Insert \verb|\phantom{-}| if there is no minus and use \texttt{l} column.
\[
\begin{bmatrix*}[J]
    1&1&-1\\
    -1&1& 1\\
    1&-1& 1
\end{bmatrix*}\quad\text{and}\quad\begin{bmatrix*}[J]
    12&1&-12\\
    -1&1& 12\\
    1&-12& 1
\end{bmatrix*}
\]
\end{enumerate}
\end{document}

enter image description here

3

You can use the spalign package. Here there is an example for your request.

enter image description here

%% Compile and read me!
\documentclass[a4paper,12pt]{article}
\usepackage{spalign}
\begin{document}
\[ \spalignmat[r]{-1 1 -1; -1 1 1; 1 -1 1} \]
\end{document}
Sebastiano
  • 54,118