% \iffalse meta-comment % % Copyright (C) 2017 by F. Pantigny % ----------------------------------- % % This file may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3 % of this license or (at your option) any later version. % The latest version of this license is in: % % http://www.latex-project.org/lppl.txt % % and version 1.3 or later is part of all distributions of LaTeX % version 2005/12/01 or later. % % \fi % \iffalse \def\myfileversion{1.4} \def\myfiledate{2018/04/16} % % %<*batchfile> \begingroup \input l3docstrip.tex \keepsilent \usedir{tex/latex/nicematrix} \preamble Copyright (C) 2018 by F. Pantigny ----------------------------------- This file may be distributed and/or modified under the conditions of the LaTeX Project Public License, either version 1.3 of this license or (at your option) any later version. The latest version of this license is in: http://www.latex-project.org/lppl.txt and version 1.3 or later is part of all distributions of LaTeX version 2005/12/01 or later. \endpreamble \askforoverwritefalse \endgroup % % %<@@=nm> %<*driver> \documentclass[dvipsnames]{l3doc}% dvipsnames is for xcolor (loaded by Tikz, loaded by nicematrix) \VerbatimFootnotes \usepackage{xltxtra} \usepackage{geometry} \geometry{left=2.8cm,right=2.8cm,top=2.5cm,bottom=2.5cm,papersize={21cm,29.7cm}} \usepackage{nicematrix} \NewDocumentEnvironment {scope} {} {} {} \def\interitem{\vskip 7mm plus 2 mm minus 3mm} \def\emphase{\bgroup\color{RoyalPurple}\let\next=} \fvset{commandchars=\~\#\@,formatcom={\color{gray}}} \parindent 0pt \DisableCrossrefs \begin{document} \DocInput{nicematrix.dtx} \end{document} % % \fi % \title{The package \pkg{nicematrix}\thanks{This document corresponds to the version~\myfileversion\space of \pkg{nicematrix}, % at the date of~\myfiledate.}} \author{F. Pantigny \\ \texttt{fpantigny@wanadoo.fr}} % % \maketitle % % \begin{abstract} % The LaTeX package \pkg{nicematrix} provides new environments similar to the classical environments |{array}| and % |{matrix}| but with some additional features. Among these features are the possibilities to fix the width of the % columns and to draw continuous ellipsis dots between the cells of the array. % \end{abstract} % % \vspace{1cm} % \section{Presentation} % % % This package can be used with |xelatex|, |lualatex|, |pdflatex| but also by the classical workflow % |latex|-|dvips|-|ps2pdf| (or Adobe Distiller). Two or three compilations may be necessary. This package requires % the packages \pkg{expl3}, \pkg{l3keys2e}, \pkg{xparse}, \pkg{array}, \pkg{mathtools} and \pkg{tikz}. % % \medskip % The package \pkg{nicematrix} aims to draw beautiful matrices in a way almost transparent for the user. % % \medskip % Consider, for example, the matrix\enskip % $A = \begin{pmatrix} % 1 &\cdots &\cdots &1 \\ % 0 &\ddots & &\vdots \\ % \vdots &\ddots &\ddots &\vdots \\ % 0 &\cdots &0 &1 % \end{pmatrix}$ % % \medskip % Usually, when using LaTeX and \pkg{amsmath} (or \pkg{mathtools}), such a matrix is composed with an environment % |{pmatrix}| and the following code: % \begin{Verbatim} % $A = \begin{pmatrix} % 1 & \cdots & \cdots & 1 \\ % 0 & \ddots & & \vdots \\ % \vdots & \ddots & \ddots & \vdots \\ % 0 & \cdots & 0 & 1 % \end{pmatrix}$ % \end{Verbatim} % % \medskip % If we load the package \pkg{nicematrix} with the option |transparent|, the same code will give the % following result: % % \begin{scope} % \NiceMatrixOptions{transparent} % \[A = \begin{pmatrix} % 1 & \cdots & \cdots & 1 \\ % 0 & \ddots & & \vdots \\ % \vdots & \ddots & \ddots & \vdots \\ % 0 & \cdots & 0 & 1 % \end{pmatrix}\] % \end{scope} % % \medskip % The dotted lines are drawn with Tikz. Two compilations may be necessary. % % \medskip % A command |\NiceMatrixOptions| is provided to fix the options (the scope of the options fixed by this command is % the current TeX group). % % % \section{How to use \{NiceMatrix\} for new code} % % \subsection{The environment \{NiceMatrix\} and its variants} % % The package \pkg{nicematrix} provides new environments |{NiceMatrix}|, |{pNiceMatrix}|, |{bNiceMatrix}|, % |{BNiceMatrix}|, |{vNiceMatrix}| and |{VNiceMatrix}|. By default, these environments behave almost exactly as the % corresponding environments of \pkg{amsmath} (and \pkg{mathtools}): |{matrix}|, |{pmatrix}|, |{bmatrix}|, % |{Bmatrix}|, |{vmatrix}| and |{Vmatrix}|. % % \smallskip % Inside these environments, five new commands are defined: |\Ldots|, |\Cdots|, |\Vdots|, |\Ddots| and |\Iddots|. % These commands are intended to be used in place of |\dots|, |\cdots|, |\vdots|, |\ddots| and % |\iddots|.\footnote{The command |\iddots|, defined in \pkg{nicematrix}, is a variant of % |\ddots| with dots going forward: \smash{$\iddots$}. If |mathdots| is loaded, the version of |mathdots| is used.} % % \smallskip % Each of them must be used alone in the cell of the array and it draws a dotted line between the first non-empty % cells\footnote{The precise definition of a ``non-empty cell'' is given below.} on both sides of the current cell. % Of course, for |\Ldots| and |\Cdots|, it's an horizontal line; for |\Vdots|, it's a vertical line and for % |\Ddots| and |\Iddots| diagonals ones.\par\nobreak % \bigskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % \begin{bNiceMatrix} % a_1 & \Cdots & & & a_1 \\ % \Vdots & a_2 & \Cdots & & a_2 \\ % & \Vdots & \Ddots \\ % \\ % a_1 & a_2 & & & a_n \\ % \end{bNiceMatrix} % \end{BVerbatim} % $\begin{bNiceMatrix} % a_1 & \Cdots & & & a_1 \\ % \Vdots & a_2 & \Cdots & & a_2 \\ % & \Vdots & \Ddots \\ % \\ % a_1 & a_2 & & & a_n \\ % \end{bNiceMatrix}$ % % \interitem % In order to represent the null matrix, one can use the following codage:\par\nobreak % \bigskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % \begin{bNiceMatrix} % 0 & \Cdots & 0 \\ % \Vdots & & \Vdots \\ % 0 & \Cdots & 0 % \end{bNiceMatrix} % \end{BVerbatim} % $\begin{bNiceMatrix} % 0 & \Cdots & 0 \\ % \Vdots & & \Vdots \\ % 0 & \Cdots & 0 % \end{bNiceMatrix}$ % % \bigskip % However, one may want a larger matrix. Usually, in such a case, the users of LaTeX add a new row and a new % column. It's possible to use the same method with \pkg{nicematrix}:\par\nobreak % \bigskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % \begin{bNiceMatrix} % 0 & \Cdots & \Cdots & 0 \\ % \Vdots & & & \Vdots \\ % \Vdots & & & \Vdots \\ % 0 & \Cdots & \Cdots & 0 % \end{bNiceMatrix} % \end{BVerbatim} % $\begin{bNiceMatrix} % 0 & \Cdots & \Cdots & 0 \\ % \Vdots & & & \Vdots \\ % \Vdots & & & \Vdots \\ % 0 & \Cdots & \Cdots & 0 % \end{bNiceMatrix}$ % % \bigskip % In the first column of this exemple, there are two instructions |\Vdots| but only one dotted line is drawn (there % is no overlapping graphic objects in the resulting \textsc{pdf}). % % However, useless computations are performed by TeX before detecting that both instructions would eventually yield % the same dotted line. That's why the package \pkg{nicematrix} provides starred versions of |\Ldots|, |\Cdots|, % etc.: |\Ldots*|, |\Cdots*|, etc. These versions are simply equivalent to |\hphantom{\ldots}|, % |\hphantom{\cdots}|, etc. The user should use these starred versions whenever a classical version has already % been used for the same dotted line.\par\nobreak % \bigskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % \begin{bNiceMatrix} % 0 & \Cdots & ~emphase#\Cdots*@ & 0 \\ % \Vdots & & & \Vdots \\ % ~emphase#\Vdots*@ & & & ~emphase#\Vdots*@ \\ % 0 & \Cdots & ~emphase#\Cdots*@ & 0 % \end{bNiceMatrix} % \end{BVerbatim} % $\begin{bNiceMatrix} % 0 & \Cdots & & 0 \\ % \Vdots & & & \\ % & & & \Vdots \\ % 0 & & \Cdots & 0 % \end{bNiceMatrix}$ % % \bigskip % In fact, in this example, it would be possible to draw the same matrix without starred commands with the % following code:\par\nobreak % \bigskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % \begin{bNiceMatrix} % 0 & \Cdots & & 0 \\ % \Vdots & & & \\ % & & & \Vdots \\ % 0 & & \Cdots & 0 % \end{bNiceMatrix} % \end{BVerbatim} % $\begin{bNiceMatrix} % 0 & \Cdots & & 0 \\ % \Vdots & & & \\ % & & & \Vdots \\ % 0 & & \Cdots & 0 % \end{bNiceMatrix}$ % % \bigskip % There are also other means to change the size of the matrix. Someone might want to use the optional argument of % the command~|\\| for the vertical dimension and a command~|\hspace*| in a cell for the horizontal % dimension.\footnote{Nevertheless, the best way to fix the width of a column is to use the environment % |{NiceArray}| with a column of type~|w| (or |W|).} % % However, a command~|\hspace*| might interfer with the construction of the dotted lines. That's why the package % \pkg{nicematrix} provides a command~|\Hspace| which is a variant of |\hspace| transparent for the dotted lines of % \pkg{nicematrix}.\par\nobreak % \bigskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % \begin{bNiceMatrix} % 0 & \Cdots & ~emphase#\Hspace*{1cm}@ & 0 \\ % \Vdots & & & \Vdots \\~emphase#[1cm]@ % 0 & \Cdots & & 0 % \end{bNiceMatrix} % \end{BVerbatim} % $\begin{bNiceMatrix} % 0 & \Cdots & \Hspace*{1cm} & 0 \\ % \Vdots & & & \Vdots \\[1cm] % 0 & \Cdots & & 0 % \end{bNiceMatrix}$ % % \vskip1cm % \subsection{The option nullify-dots} % % Consider the following matrix composed classicaly with the environment |{pmatrix}|.\par\nobreak % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=7cm] % $A = \begin{pmatrix} % a_0 & b \\ % a_1 & \\ % a_2 & \\ % a_3 & \\ % a_4 & \\ % a_5 & b % \end{pmatrix}$ % \end{BVerbatim} % $A = \begin{pmatrix} % a_0 & b \\ % a_1 & \\ % a_2 & \\ % a_3 & \\ % a_4 & \\ % a_5 & b % \end{pmatrix}$ % % % \bigskip % If we add |\vdots| instructions in the second column, the geometry of the matrix is modified.\par\nobreak % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=7cm] % $B = \begin{pmatrix} % a_0 & b \\ % a_1 & \vdots \\ % a_2 & \vdots \\ % a_3 & \vdots \\ % a_4 & \vdots \\ % a_5 & b % \end{pmatrix}$ % \end{BVerbatim} % $B = \begin{pmatrix} % a_0 & b \\ % a_1 & \vdots \\ % a_2 & \vdots \\ % a_3 & \vdots \\ % a_4 & \vdots \\ % a_5 & b % \end{pmatrix}$ % % \bigskip % By default, with \pkg{nicematrix}, if we replace |{pmatrix}| by |{pNiceMatrix}| and |\vdots| by % |\Vdots| (or |\Vdots*| for efficiency), the geometry of the matrix is not changed.\par\nobreak % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=7cm] % $C = \begin{pNiceMatrix} % a_0 & b \\ % a_1 & \Vdots \\ % a_2 & \Vdots* \\ % a_3 & \Vdots* \\ % a_4 & \Vdots* \\ % a_5 & b % \end{pNiceMatrix}$ % \end{BVerbatim} % $C = \begin{pNiceMatrix} % a_0 & b \\ % a_1 & \Vdots \\ % a_2 & \Vdots* \\ % a_3 & \Vdots* \\ % a_4 & \Vdots* \\ % a_5 & b % \end{pNiceMatrix}$ % % \bigskip % However, one may prefer the geometry of the first matrix $A$ and would like to have such a geometry with a dotted % line in the second column. It's possible by using the option |nullify-dots| (and only one instruction |\Vdots| is % necessary).\par\nobreak % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=7cm] % $D = \begin{pNiceMatrix}[~emphase#nullify-dots@] % a_0 & b \\ % a_1 & \Vdots \\ % a_2 & \\ % a_3 & \\ % a_4 & \\ % a_5 & b % \end{pNiceMatrix}$ % \end{BVerbatim} % $D = \begin{pNiceMatrix}[nullify-dots] % a_0 & b \\ % a_1 & \Vdots \\ % a_2 & \\ % a_3 & \\ % a_4 & \\ % a_5 & b % \end{pNiceMatrix}$ % % \medskip % The option |nullify-dots| smashes the instructions |\Ldots| (and the variants) vertically but also horizontally. % % % % \vskip1cm % \section{How to use nicematrix for existing code} % % The package \pkg{nicematrix} provides an option called |transparent| for using existing code transparently in the % environments |{matrix}|. This option can be set as option of |\usepackage| or with the command % |\NiceMatrixOptions|. % % % In fact, this option is an alias for the conjonction of two options: |renew-dots| and |renew-matrix|. % % \smallskip % % \begin{itemize} % \item The option |renew-dots|\par\nobreak % With this option, the commands |\ldots|, |\cdots|, |\vdots|, |\ddots| and |\iddots|\footnote{The command % |\iddots| is not a command of LaTeX but is defined by the package \pkg{nicematrix}. If |mathdots| is loaded, the % version of |mathdots| is used.} are redefined within the environments provided by \pkg{nicematrix} % and behave like |\Ldots|, |\Cdots|, |\Vdots|, |\Ddots| and |\Iddots|; the command |\dots| (``automatic % dots'' of |amsmath| --- and |mathtools|) is also redefined to behave like |\Ldots|. % % \item The option |renew-matrix|\par\nobreak % With this option, the environment |{matrix}| is redefined and behave like |{NiceMatrix}|, and so on for the five % variants. % \end{itemize} % % \bigskip % Therefore, with the option |transparent|, a classical code gives directly the ouput of \pkg{nicematrix}.\par\nobreak % \bigskip % \begin{BVerbatim}[baseline=c] % ~emphase#\NiceMatrixOptions{transparent}@ % \begin{pmatrix} % 1 & \cdots & \cdots & 1 \\ % 0 & \ddots & & \vdots \\ % \vdots & \ddots & \ddots & \vdots \\ % 0 & \cdots & 0 & 1 % \end{pmatrix} % \end{BVerbatim} % \hspace{2cm} % \begin{scope} % \NiceMatrixOptions{transparent} % $\begin{pmatrix} % 1 & \cdots & \cdots & 1 \\ % 0 & \ddots & & \vdots \\ % \vdots & \ddots & \ddots & \vdots \\ % 0 & \cdots & 0 & 1 % \end{pmatrix}$ % \end{scope} % % % \section{The environment \{NiceArray\}} % % In fact, the environment |{NiceMatrix}| relies upon an environment |{NiceArray}| defined in the package % \pkg{nicematrix}. % % \medskip % This environment |{NiceArray}| itself relies upon the environment |{array}| of the package \pkg{array}.\footnote{The % environment |{array}| is defined in standard LaTeX but is redefined in the package \pkg{array} (loaded by % \pkg{nicematrix}).} % % \medskip % The differences between |{NiceArray}| and |{array}| are as follow. % \begin{itemize} % \item The commands |\Cdots| and its variants are available in the environment |{NiceArray}|. % \item The environment |{NiceArray}| accepts (between brackets) the options |t|, |c| and |b| as the classical % |{array}| but also the following options defined by \pkg{nicematrix}: |renew-dots|, |nullify-dots|, % |columns-width| (explained below), |exterior-arraycolsep| and |parallelize-diags| (these last two options are % technical options described further). % \item For technical reasons, in the preamble of the environment |{NiceArray}|, the user % must use the letters |L|, |C| and~|R|\footnote{The column types |L|, |C| and |R| are defined locally inside % |{NiceArray}| with |\newcolumntype| of \pkg{array}. This definition overrides an eventual previous definition.} % instead of |l|, |c| and |r|. It's possible to use the constructions \verb|w{...}{...}|, \verb|W{...}{...}|, % \verb+|+, |>{...}|, |<{...}|, |@{...}|, |!{...}| and |*{n}{...}| but the letters |p|, |m| and |b| should not be used. % \end{itemize} % % % \vspace{1cm} % An example with a linear system (we need |{NiceArray}| for the vertical rule): % % \bigskip % \begin{BVerbatim}[baseline=c] % $\left[\begin{NiceArray}{CCCC|C} % a_1 & ? & \Cdots & ? & ? \\ % 0 & & \Ddots & \Vdots & \Vdots\\ % \Vdots & \Ddots & \Ddots & ? \\ % 0 & \Cdots & 0 & a_n & ? \\ % \end{NiceArray}\right]$ % \end{BVerbatim} % \hspace{2.5cm} % $\left[\begin{NiceArray}{CCCC|C} % a_1 & ? & \Cdots & ? & ? \\ % 0 & & \Ddots & \Vdots & \Vdots\\ % \Vdots & \Ddots & \Ddots & ? \\ % 0 & \Cdots & 0 & a_n & ? \\ % \end{NiceArray}\right]$ % % \vspace{1cm} % An example where we use |{NiceArray}| because we want to use the types |L| and |R| for the columns: % % \bigskip % \begin{BVerbatim}[baseline=c] % $\left(\begin{NiceArray}{LCR} % a_{11} & \Cdots & a_{1n} \\ % a_{21} & & a_{2n} \\ % \Vdots & & \Vdots \\ % a_{n-1,1} & \Cdots & a_{n-1,n} \\ % \end{NiceArray}\right)$ % \end{BVerbatim} % \hspace{4cm} % $\left(\begin{NiceArray}{LCR} % a_{11} & \Cdots & a_{1n} \\ % a_{21} & & a_{2n} \\ % \Vdots & & \Vdots \\ % a_{n-1,1} & \Cdots & a_{n-1,n} \\ % \end{NiceArray}\right)$ % % \vskip1cm % As in the environment |{array}| of the extension \pkg{array}, it's possible to fix the width of a column by using % the letter |w| or the letter |W| in the preamble. In the following example, the width of the third column is % fixed to 1~cm.\par\nobreak % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % $\left(\begin{NiceArray}{CC~emphase#w{c}{1cm}@} % 1 & 2 & 3 \\ % 4 & 5 & 6 \\ % 7 & 8 & 9 % \end{NiceArray}\right)$ % \end{BVerbatim} % $\left(\begin{NiceArray}{CCw{c}{1cm}} % 1 & 2 & 3 \\ % 4 & 5 & 6 \\ % 7 & 8 & 9 % \end{NiceArray}\right)$ % % \bigskip % However, the environment |{NiceArray}| and the other environments defined in this extension have an option called % |columns-width| which fixes the width of all columns of the matrix.\par\nobreak % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % $\begin{pNiceMatrix}[~emphase#columns-width = 1cm@] % 1 & 12 & -123 \\ % 12 & 0 & 0 \\ % 4 & 1 & 2 % \end{pNiceMatrix}$ % \end{BVerbatim} % $\begin{pNiceMatrix}[columns-width = 1cm] % 1 & 12 & -123 \\ % 12 & 0 & 0 \\ % 4 & 1 & 2 % \end{pNiceMatrix}$ % % \medskip % Note that the space inserted between two columns (equal to 2 |\arraycolsep|) is not suppressed. % % \bigskip % It's also possible to give the value |auto| to the option |columns-width|: all the columns of the array will % have a width equal to the widest cell of the array. \emph{Two or three compilations may be necessary}.\par\nobreak % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % $\begin{pNiceMatrix}[~emphase#columns-width = auto@] % 1 & 12 & -123 \\ % 12 & 0 & 0 \\ % 4 & 1 & 2 % \end{pNiceMatrix}$ % \end{BVerbatim} % $\left(\begin{NiceArray}[columns-width = auto]{CCC} % 1 & 12 & -123 \\ % 12 & 0 & 0 \\ % 4 & 1 & 2 % \end{NiceArray}\right)$ % % % \section{The environment \{pNiceArrayC\} and its variants} % % The package \pkg{nicematrix} provides also environments to compose matrices with an exterior column, that is to % say on the right of the closing delimiter. These environments are |{pNiceArrayC}|, |{vNiceArrayC}|, % |{VNiceArrayC}|, |{bNiceArrayC}| and |{BNiceArrayC}| (there is no environment |{NiceArrayC}| since such an % environment would logically be equivalent to |{NiceArray}|). % % All these environments have the same characteristics even if, for sake of simplicity, we will speak only of % |{pNiceArrayC}|. % % \medskip % \begin{itemize} % \item The command |\Cdots| and its variants are available in |{pNiceArrayC}|. % \item The environment |{pNiceArrayC}| takes a mandatory argument which is the preamble of the array. The types % of columns available are the same as for the environment |{NiceArray}|. \emph{However, no specification must be % given for the last column:} it will automatically (and necessarily) be a column~|L|. % \item The options available are |columns-width| (doesn't apply to the exterior column), |renew-dots|, % |nullify-dots|, |parallelize-diags| (this technical option is described further) and an option specific to these % environments, called |code-for-last-col|. This last option specifies tokens that will be inserted before each % cell of the last column, \emph{before} the symbol |$| of the math mode. % \end{itemize} % % % \bigskip % \begin{BVerbatim}[baseline=c] % \begin{pNiceArrayC}{RRRR|R}[~emphase#code-for-last-col={\small\color{blue}}@, % columns-width=auto] % 1& 2& 2& 3& -2 \\ % 0& 0& -1& 5& -5 & L_2 \gets 2L_1-L_2 \\ % 0& -1& -3& 3& -7 & L_3 \gets L_1-L_3 % \end{pNiceArrayC} % \end{BVerbatim} % % \smallskip % \[\begin{pNiceArrayC}{RRRR|R}[code-for-last-col={\small\color{blue}}, % columns-width=auto] % 1& 2& 2& 3& -2 \\ % 0& 0& -1& 5& -5 & L_2 \gets 2L_1-L_2 \\ % 0& -1& -3& 3& -7 & L_3 \gets L_1-L_3 % \end{pNiceArrayC}\] % % \bigskip % % \begin{Verbatim} % $\begin{pNiceArrayC}{*6C|C}[nullify-dots,code-for-last-col={\small}] % 1 & 1 & 1 &\Cdots & & 1 & 0 & \\ % 0 & 1 & 0 &\Cdots & & 0 & & L_2 \gets L_2-L_1 \\ % 0 & 0 & 1 &\Ddots & & \Vdots & & L_3 \gets L_3-L_1 \\ % & & &\Ddots & & & \Vdots & \Vdots \\ % \Vdots & & &\Ddots & & 0 & \\ % 0 & & &\Cdots & 0 & 1 & 0 & L_n \gets L_n-L_1 % \end{pNiceArrayC}$ % \end{Verbatim} % % \[\begin{pNiceArrayC}{*6C|C}[nullify-dots,code-for-last-col={\small}] % 1 & 1 & 1 &\Cdots & & 1 & 0 & \\ % 0 & 1 & 0 &\Cdots & & 0 & & L_2 \gets L_2-L_1 \\ % 0 & 0 & 1 &\Ddots & & \Vdots & & L_3 \gets L_3-L_1 \\ % & & &\Ddots & & & \Vdots & \Vdots \\ % \Vdots & & &\Ddots & & 0 & \\ % 0 & & &\Cdots & 0 & 1 & 0 & L_n \gets L_n-L_1 % \end{pNiceArrayC}\] % % % \section{Technical remarks} % % \subsection{Diagonal lines} % % By default, all the diagonal lines of a same array are ``parallelized''. That means that the first diagonal line % is drawn and, then, the other lines are drawn parallel to the first one (by rotation around the left-most % extremity of the line). That's why the position of the instructions |\Ddots| in the array can have a marked % effect on the final result. % % \medskip % In the following examples, the first |\Ddots| instruction is written in color: % % \medskip % \begin{scope} % \begin{minipage}{9.5cm} % Example with parallelization (default): % \begin{Verbatim} % $A = \begin{pNiceMatrix} % 1 & \Cdots & & 1 \\ % a+b & ~emphase#\Ddots@~ & & \Vdots \\ % \Vdots & \Ddots & & \\ % a+b & \Cdots & a+b & 1 % \end{pNiceMatrix}$ % \end{Verbatim} % \end{minipage} % $A = \begin{pNiceMatrix} % 1 & \Cdots & & 1 \\ % a+b & \Ddots & & \Vdots \\ % \Vdots & \Ddots & & \\ % a+b & \Cdots & a+b & 1 % \end{pNiceMatrix}$ % % \bigskip % \NiceMatrixOptions{parallelize-diags=true}% % \begin{minipage}{9.5cm} % % \begin{Verbatim} % $A = \begin{pNiceMatrix} % 1 & \Cdots & & 1 \\ % a+b & & & \Vdots \\ % \Vdots & ~emphase#\Ddots@~ & \Ddots & \\ % a+b & \Cdots & a+b & 1 % \end{pNiceMatrix}$ % \end{Verbatim} % \end{minipage} % $A = \begin{pNiceMatrix} % 1 & \Cdots & & 1 \\ % a+b & & & \Vdots \\ % \Vdots & \Ddots & \Ddots & \\ % a+b & \Cdots & a+b & 1 % \end{pNiceMatrix}$ % % \bigskip % It's possible to turn off the parallelization with the option |parallelize-diags| set to |false|: \par\nobreak % % \medskip % \NiceMatrixOptions{parallelize-diags=false}% % \begin{minipage}{9.5cm} % The same example without parallelization: % \end{minipage} % $A = \begin{pNiceMatrix} % 1 & \Cdots & & 1 \\ % a+b & \Ddots & & \Vdots \\ % \Vdots & \Ddots & & \\ % a+b & \Cdots & a+b & 1 % \end{pNiceMatrix}$ % % % \end{scope} % % \vskip1cm % \subsection{The ``empty'' cells} % % An instruction like |\Ldots|, |\Cdots|, etc. tries to determine the first non-empty cell on both % sides\footnote{If \pkg{nicematrix} can't find theses cells, an error |Imposible instruction| is raised. Nevertheless, % with the option |silent|, these instructions are discarded silently.}. However, a empty cell is not necessarily a % cell with no TeX content (that is to say a cell with no token between the two ampersands~|&|). Indeed, a cell % with contents |\hspace*{1cm}| may be considered as empty. % % \interitem % For \pkg{nicematrix}, the precise rules are as follow. % % \begin{itemize} % \item An implicit cell is empty. For example, in the following matrix: % % \begin{Verbatim} % \begin{pmatrix} % a & b \\ % c \\ % \end{pmatrix} % \end{Verbatim} % % the last cell (second row and second column) is empty. % % \medskip % \item Each cell whose TeX ouput has a width less than 0.5~pt is empty. % % \medskip % \item A cell which contains a command |\Ldots|, |\Cdots|, |\Vdots|, |\Ddots| or |\Iddots| and their starred % versions is empty. We recall that theses commands should be used alone in a cell. % % \medskip % \item A cell with a command |\Hspace| (or |\Hspace*|) is empty. This command |\Hspace| is a command defined by % the package \pkg{nicematrix} with the same meaning as |\hspace| except that the cell where it is used is % considered as empty. This command can be used to fix the width of some columns of the matrix without interfering % with \pkg{nicematrix}. % % \end{itemize} % % \interitem % A dotted line must be delimited by two non-empty cells. If it's not possible to find one of these cells whitin % the boundaries of the matrix, an error is issued and the instruction is ignored. % % \vspace{1cm} % \subsection{The option exterior-arraycolsep} % % The environment |{array}| inserts un horizontal space equal to |\arraycolsep| before and after each column. In % particular, there is a space equal to |\arraycolsep| before and after the array. This feature of the environment % |{array}| was probably not a good idea.\footnote{In the documentation of |{amsmath}|, we can read: {\itshape The % extra space of |\arraycolsep| that \pkg{array} adds on each side is a waste so we remove it [in |{matrix}|] % (perhaps we should instead remove it from array in general, but that's a harder task).} It's possible to suppress % these spaces for a given environment |{array}| with a construction like |\begin{array}{@{}ccccc@{}}|.} % % The environment |{matrix}| and its variants (|{pmatrix}|, |{vmatrix}|, etc.) of \pkg{amsmath} and \pkg{mathtools} % prefer to delete these spaces with explicit instructions |\hskip -\arraycolsep| and |{NiceArray}| does likewise. % % However, the user can change this behaviour with the boolean option |exterior-arraycolsep|. With this option, % |{NiceArray}| will insert the same horizontal spaces as the environment |{array}|. This % option can be set as an option of an environment |{NiceArray}| (between square brackets) or with the command % |\NiceMatrixOptions|. % % % \section{Examples} % % \bigskip % A tridiagonal matrix: % % \bigskip % \begin{BVerbatim}[baseline=c] % $\begin{pNiceMatrix}[nullify-dots] % a & b & 0 & & \Cdots & 0 \\ % b & a & b & \Ddots & & \Vdots \\ % 0 & b & a & \Ddots & & \\ % & \Ddots & \Ddots & \Ddots & & 0 \\ % \Vdots & & & & & b \\ % 0 & \Cdots & & 0 & b & a % \end{pNiceMatrix}$ % \end{BVerbatim} % \hspace{1.5cm} % $\begin{pNiceMatrix}[nullify-dots] % a & b & 0 & & \Cdots & 0 \\ % b & a & b & \Ddots & & \Vdots \\ % 0 & b & a & \Ddots & & \\ % & \Ddots & \Ddots & \Ddots & & 0 \\ % \Vdots & & & & & b \\ % 0 & \Cdots & & 0 & b & a % \end{pNiceMatrix}$ % % \vspace{2cm} % % A permutation matrix: % % \bigskip % \begin{BVerbatim}[baseline=c] % $\begin{pNiceMatrix} % 0 & 1 & 0 & & \Cdots & 0 \\ % \Vdots & & & \Ddots & & \Vdots \\ % & & & \Ddots & & \\ % & & & \Ddots & & 0 \\ % 0 & 0 & & & & 1 \\ % 1 & 0 & & \Cdots & & 0 % \end{pNiceMatrix}$ % \end{BVerbatim} % \hspace{2.5cm} % $\begin{pNiceMatrix} % 0 & 1 & 0 & & \Cdots & 0 \\ % \Vdots & & & \Ddots & & \Vdots \\ % & & & \Ddots & & \\ % & & & \Ddots & & 0 \\ % 0 & 0 & & & & 1 \\ % 1 & 0 & & \Cdots & & 0 % \end{pNiceMatrix}$ % % \vspace{2cm} % % An example with |\Iddots|: % % \bigskip % \begin{BVerbatim}[baseline=c] % $\begin{pNiceMatrix} % 1 & \Cdots & & 1 \\ % \Vdots & & & 0 \\ % & ~emphase#\Iddots@ & ~emphase#\Iddots@ & \Vdots \\ % 1 & 0 & \Cdots & 0 % \end{pNiceMatrix}$ % \end{BVerbatim} % \hspace{4cm} % $\begin{pNiceMatrix} % 1 & \Cdots & & 1 \\ % \Vdots & & & 0 \\ % & \Iddots & \Iddots & \Vdots \\ % 1 & 0 & \Cdots & 0 % \end{pNiceMatrix}$ % % % % % \vspace{1cm} % % \section{Implementation} % % By default, the package \pkg{nicematrix} doesn't patch any existing code. % % \smallskip % However, when the option |renew-dots| is used, the commands |\cdots|, |\ldots|, |\dots|, |\vdots|, |\ddots| and % |\iddots| are redefined in the environments provided by \pkg{nicematrix} as explained previously. In the same way, % if the option |renew-matrix| is used, the environment |{matrix}| of \pkg{amsmath} (and \pkg{mathtools}) is % redefined. % % \smallskip % On the other hand, the environnement |{array}| is never redefined. % % \smallskip % Of course, the package \pkg{nicematrix} uses the features of the package \pkg{array}. It tries to be independant of its % implementation. Unfortunately, it was not possible to be strictly independant: the package \pkg{nicematrix} relies upon the % fact that the package |{array}| uses |\ialign| to begin the |\halign|. % % \subsection{Declaration of the package and extensions loaded} % % \bigskip % We give the traditionnal declaration of a package written with |expl3|: % \begin{macrocode} \RequirePackage{l3keys2e} \ProvidesExplPackage {nicematrix} {\myfiledate} {\myfileversion} {Draws nice dotted lines in matrix environments} % \end{macrocode} % % The command for the treatment of the options of |\usepackage| is at the end of this package for technical reasons. % % \bigskip % We load \pkg{array}, \pkg{mathtools} (\pkg{mathtools} may be considered as the successor of \pkg{amsmath}) and \pkg{tikz}. % \begin{macrocode} \RequirePackage{array} \RequirePackage{mathtools} \RequirePackage{tikz} % \end{macrocode} % % \bigskip % The package \pkg{xparse} will be used to define the environment |{NiceMatrix}|, its variants and the % document-level commands (|\NiceMatrixOptions|, etc.). % \begin{macrocode} \RequirePackage{xparse} % \end{macrocode} % % \bigskip % \subsection{Technical definitions} % % % First, we define a command |\iddots| similar to |\ddots| ($\ddots$) but with dots going forward ($\iddots$). We % use |\ProvideDocumentCommand| of \pkg{xparse}, and so, if the command |\iddots| has already been defined (for % example by the package \pkg{mathdots}), we don't define it again. % % \begin{macrocode} \ProvideDocumentCommand \iddots {} {\mathinner{\mkern 1mu \raise \p@ \hbox{.} \mkern 2mu \raise 4\p@ \hbox{.} \mkern 2mu \raise 7\p@ \vbox{\kern 7pt \hbox{.}} \mkern 1mu}} % \end{macrocode} % % This definition is a variant of the standard definition of |\ddots|. % % \bigskip % In the environment |{NiceMatrix}|, the command |\multicolumn| will be linked to the following command % |\@@_multicolumn:| but only if the option |renew-matrix| is not set. Indeed, if the option |renew-matrix| is used, % we want to let the possibility to the user to use |\multicolumn| (or |\hdotsfor| of \pkg{amsmath}) in some % matrices without dotted lines and to have the automatic dotted lines of \pkg{nicematrix} in other matrices. % \begin{macrocode} \cs_new_protected:Nn \@@_multicolumn:nn {\msg_error:nn {nicematrix} {Multicolumn~forbidden}} % \end{macrocode} % This command |\@@_multicolumn:nn| takes two arguments, and therefore, the first two arguments of |\column| will % be gobbled. % % \bigskip % The following counter will count the environments |{NiceArray}|. The value of this counter will be used to % prefix the names of the Tikz nodes created in the array. % \begin{macrocode} \int_new:N \g_@@_env_int % \end{macrocode} % % \bigskip % The dimension |\l_@@_columns_width_dim| will be used when the options specify that all the columns must have the % same width. % \begin{macrocode} \dim_new:N \l_@@_columns_width_dim % \end{macrocode} % \bigskip % \subsection{The options} % % The token list |\l_@@_pos_env_tl| will contains one of the three values |t|, |c| or |b| and will indicate to % position of the environment as in the option of the environment |{array}|. For the environment |{NiceMatrix}| % (and its variants) and |{pNiceArrayC}| (and its variants), the value will programmatically be fixed to |c|. For the % environment |{NiceArray}|, however, the three values |t|, |c| and |b| are possible. % \begin{macrocode} \tl_new:N \l_@@_pos_env_tl \tl_set:Nn \l_@@_pos_env_tl c % \end{macrocode} % % The boolean |\l_@@_exterior_arraycolsep_bool| corresponds to the option |exterior-arraycolsep|. If this option is % set, a space equal to |\arraycolsep| will be put on both sides of an environment |{NiceArray}| (but neither for % |{NiceMatrix}| and its variants nor |{pNiceArrayC}| and its variants even if these environments relies upon |{NiceArray}|). % \begin{macrocode} \bool_new:N \l_@@_exterior_arraycolsep_bool % \end{macrocode} % % \bigskip % The flag |\l_@@_parallelize_diags_bool| controls wether the diagonals are parallelized. The default % is~|true|. % \begin{macrocode} \bool_new:N \l_@@_parallelize_diags_bool \bool_set_true:N \l_@@_parallelize_diags_bool % \end{macrocode} % % \bigskip % The flag |\l_@@_nullify_dots_bool| corresponds to the option |nullify-dots|. When the flag is down, the % instructions like |\vdots| are inserted within a |\hphantom| (and so the constructed matrix has exactly the same % size as a matrix constructed with the classical |{matrix}| and |\ldots|, |\vdots|, etc.) % \begin{macrocode} \bool_new:N \l_@@_nullify_dots_bool % \end{macrocode} % % \bigskip % The flag |\l_@@_renew_matrix_bool| will be raised if the option |renew-matrix| is used. % \begin{macrocode} \bool_new:N \l_@@_renew_matrix_bool % \end{macrocode} % % \bigskip % The following flag will be used when the current options specify that all the columns of the array must have the % same width equal to the largest width of a cell of the array (except the cell of the ``exterior column'' of an % environment of the kind of |{pNiceArrayC}|). % \begin{macrocode} \bool_new:N \l_@@_auto_columns_width_bool % \end{macrocode} % % \bigskip % The token list |\l_@@_code_for_last_col_tl| will contains code inserted at the beginning of each cell\footnote{At % the beginning of each cell but before the character |$| of the mathematical mode.} of the last % column in the environment |{pNiceArrayC}| (and its variants). It corresponds to the option |code-for-last-col|. % \begin{macrocode} \tl_new:N \l_@@_code_for_last_col_tl % \end{macrocode} % % \bigskip % We define a set of options which will be used with the command |NiceMatrixOptions|.\footnote{Before the version % 1.3, the names of the options were in ``caml style'' (like |ParallelizeDiagonals|) which was not a good idea. In % version 1.4, the names are converted in lowercase with hyphens (like |parallelize-diags|). For compatibility, the % old names are conversed.} % \begin{macrocode} \keys_define:nn {NiceMatrix/NiceMatrixOptions} {parallelize-diags .bool_set:N = \l_@@_parallelize_diags_bool, parallelize-diags .default:n = true, ParallelizeDiagonals .meta:n = parallelize-diags, % \end{macrocode} % % \bigskip % With the option |renew-dots|, the command |\cdots|, |\ldots|, |\vdots| and |\ddots| are redefined and behave like the % commands |\Cdots|, |\Ldots|, |\Vdots| and |\Ddots|. % \begin{macrocode} renew-dots .bool_set:N = \l_@@_renew_dots_bool, renew-dots .default:n = true, RenewDots .meta:n = renew-dots, % \end{macrocode} % % \bigskip % With the option |renew-matrix|, the environment |{matrix}| of \pkg{amsmath} and its variants are redefined to % behave like the environment |{NiceMatrix}| and its variants. % \begin{macrocode} renew-matrix .code:n = {\cs_set_eq:NN \env@matrix \NiceMatrix \bool_set_true:N \l_@@_renew_matrix_bool}, renew-matrix .value_forbidden:n = true, RenewMatrix .meta:n = renew-matrix, transparent .meta:n = {renew-dots,renew-matrix}, transparent .value_forbidden:n = true, Transparent .meta:n = transparent, % \end{macrocode} % % \bigskip % Without the option |nullify-dots|, the instructions like |\vdots| are inserted within a % |\hphantom| (and so the constructed matrix has exactly the same size as a matrix constructed with the % classical |{matrix}| and |\ldots|, |\vdots|, etc.). This option is set by default. % \begin{macrocode} nullify-dots .bool_set:N = \l_@@_nullify_dots_bool , nullify-dots .default:n = true, NullifyDots .meta:n = nullify-dots, % \end{macrocode} % % % \bigskip % With the option |silent|, no error is generated for the impossible instructions. This option can be useful when % adapting an existing code. % \begin{macrocode} silent .code:n = {\msg_redirect_name:nnn {nicematrix} {Impossible~instruction} {none}} , silent .value_forbidden:n = true, Silent .meta:n = silent, % \end{macrocode} % % \bigskip % The following option is only for the environment |{pNiceArrayC}| and its variants. It will contains code inserted % at the beginning of each cell of the last column.\footnote{In an environment |{pNiceArrayC}|, the last column is % composed outside the parentheses of the array.} % \begin{macrocode} code-for-last-col .tl_set:N = \l_@@_code_for_last_col_tl, code-for-last-col .value_required:n = true, % \end{macrocode} % % \bigskip % The option |exterior-arraycolsep| will have effect only in |{NiceArray}| for those who want to have for % |{NiceArray}| the same behaviour as |{array}|. % \begin{macrocode} exterior-arraycolsep .bool_set:N = \l_@@_exterior_arraycolsep_bool , exterior-arraycolsep .default:n = true, unknown .code:n = \msg_error:nn {nicematrix} {Unknown~key~for~NiceMatrixOptions}} % \end{macrocode} % % \begin{macrocode} \msg_new:nnnn {nicematrix} {Unknown~key~for~NiceMatrixOptions} {The~key~"\tl_use:N\l_keys_key_tl"~is~unknown~for~the~command \token_to_str:N \NiceMatrixOptions.\\ If~you~go~on,~it~will~be~ignored.\\ For~a~list~of~the~available~keys,~type~H~.} {The~available~keys~are~(in~alphabetic~order):~ code-for-last-col,~ exterior-arraycolsep,~ nullify-dots,~ parallelize-diags,~ renew-dots,~ renew-matrix~ and~transparent} % \end{macrocode} % % \bigskip % |\NiceMatrixOptions| is the command of the \pkg{nicematrix} package to fix options at the document level. The % scope of these specifications is the current TeX group. % \begin{macrocode} \NewDocumentCommand \NiceMatrixOptions {m} {\keys_set:nn {NiceMatrix/NiceMatrixOptions} {#1}} % \end{macrocode} % % % \bigskip % \begin{macrocode} \keys_define:nn {NiceMatrix/NiceMatrix} {parallelize-diags .bool_set:N = \l_@@_parallelize_diags_bool, parallelize-diags .default:n = true, renew-dots .bool_set:N = \l_@@_renew_dots_bool, renew-dots .default:n = true, nullify-dots .bool_set:N = \l_@@_nullify_dots_bool , nullify-dots .default:n = true, % \end{macrocode} % The option |columns-width| is the width of the columns it we want the same width for all the columns of the % array. A value of 0~pt means that the width of the column will be the natural width of the column. % \begin{macrocode} columns-width .code:n = \str_if_eq:nnTF {#1} {auto} {\bool_set_true:N \l_@@_auto_columns_width_bool} {\dim_set:Nn \l_@@_columns_width_dim {#1}}, unknown .code:n = \msg_error:nn {nicematrix} {Unknown~option~for~NiceMatrix}} % \end{macrocode} % % \begin{macrocode} \msg_new:nnnn {nicematrix} {Unknown~option~for~NiceMatrix} {The~option~"\tl_use:N\l_keys_key_tl"~is~unknown~for~the~environment~ \{NiceMatrix\}~and~its~variants.\\ If~you~go~on,~it~will~be~ignored.\\ For~a~list~of~the~available~options,~type~H~.} {The~available~options~are~(in~alphabetic~order):~ columns-width,~ nullify-dots,~ parallelize-diags~ and~renew-dots.} % \end{macrocode} % % \bigskip % \begin{macrocode} \keys_define:nn {NiceMatrix/NiceArray} {parallelize-diags .bool_set:N = \l_@@_parallelize_diags_bool, parallelize-diags .default:n = true, renew-dots .bool_set:N = \l_@@_renew_dots_bool, renew-dots .default:n = true, nullify-dots .bool_set:N = \l_@@_nullify_dots_bool , nullify-dots .default:n = true, exterior-arraycolsep .bool_set:N = \l_@@_exterior_arraycolsep_bool , exterior-arraycolsep .default:n = true, columns-width .code:n = \str_if_eq:nnTF {#1} {auto} {\bool_set_true:N \l_@@_auto_columns_width_bool} {\dim_set:Nn \l_@@_columns_width_dim {#1}}, columns-width .value_required:n = true, % \end{macrocode} % % \bigskip % The options |c|, |t| and |b| of the environment |{NiceArray}| have the same meaning as the option of the classical % environment |{array}|. % \begin{macrocode} c .code:n = \tl_set:Nn \l_@@_pos_env_tl c, t .code:n = \tl_set:Nn \l_@@_pos_env_tl t, b .code:n = \tl_set:Nn \l_@@_pos_env_tl b, unknown .code:n = \msg_error:nn {nicematrix} {Unknown~option~for~NiceArray}} % \end{macrocode} % % \begin{macrocode} \msg_new:nnnn {nicematrix} {Unknown~option~for~NiceArray} {The~option~"\tl_use:N\l_keys_key_tl"~is~unknown~for~the~environment~ \{NiceArray\}.\\ If~you~go~on,~it~will~be~ignored.\\ For~a~list~of~the~available~options,~type~H~.} {The~available~options~are~(in~alphabetic~order):~ b,~ c,~ columns-width,~ exterior-arraycolsep,~ nullify-dots,~ parallelize-diags,~ renew-dots~ and~t.} % \end{macrocode} % % \bigskip % \subsection{The environments \{NiceArray\} and \{NiceMatrix\}} % % The pseudo-environment |\@@_Cell:n|--|\@@_end_Cell:| will be used to format the cells of the array. In the code, % the affectations are global because this pseudo-environment will be used in the cells of a |\halign| (via an % environment |{array}|). % % The argument of |\@@_Cell:n| is a letter |l|, |c| or |r| that describes the type of column: we store this letter % at the end of |\g_@@_preamble_aux_tl| (see the redefinition of |\ialign| in the environment |{NiceArray}| for % explanations). % \begin{macrocode} \cs_new_protected:Nn \@@_Cell:n {\tl_gput_right:Nn \g_@@_preamble_aux_tl {#1} % \end{macrocode} % We increment |\g_@@_column_int|, which is the counter of the columns. % \begin{macrocode} \int_gincr:N \g_@@_column_int \hbox_set:Nw \l_tmpa_box $} % $ % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Nn \@@_end_Cell: {$ % $ \hbox_set_end: % \end{macrocode} % We want to compute in |\l_@@_max_cell_width_dim| the width of the widest cell of the array (except the cells of % the last column of an environment of the kind of |{pNiceArrayC}|). % \begin{macrocode} \dim_gset:Nn \g_@@_max_cell_width_dim {\dim_max:nn \g_@@_max_cell_width_dim {\box_wd:N \l_tmpa_box}} \tikz[remember~picture, inner~sep = 0pt, minimum~width = 0pt, baseline] \node [anchor=base] (nm-\int_use:N \g_@@_env_int- \int_use:N \g_@@_row_int- \int_use:N \g_@@_column_int) \bgroup \box_use:N \l_tmpa_box \egroup ;} % \end{macrocode} % % % \interitem % The environment |{NiceArray}| is the main environment of the extension \pkg{nicematrix}. % % In order to clarify the explanations, we will first give the definition of the environment |{NiceMatrix}|. % % Our environment |{NiceMatrix}| must have the same second part as the environment |{matrix}| of \pkg{amsmath} % (because of the programmation of the option |renew-matrix|). Hence, this second part is the following: % % \begin{Verbatim} % \endarray % \skip_horizontal:n {-\arraycolsep} % \end{Verbatim} % % That's why, in the definition of |{NiceMatrix}|, we must use |\NiceArray| and not |\begin{NiceArray}| % (and, in the definition of |{NiceArray}|, we will have to use |\array|, and not |\begin{array}|: see below). % % \medskip % Here's the definition of |{NiceMatrix}|: % \begin{macrocode} \NewDocumentEnvironment {NiceMatrix} {O{}} {\keys_set:nn {NiceMatrix/NiceMatrix} {#1} \tl_set:Nn \l_@@_pos_env_tl c \bool_set_false:N \l_@@_exterior_arraycolsep_bool \NiceArray{*\c@MaxMatrixCols{C}} } {\endarray \skip_horizontal:n {-\arraycolsep}} % \end{macrocode} % % \interitem % For the definition of |{NiceArray}| (just below), we have the following constraints: % \begin{itemize} % \item we must use |\array| in the first part of |{NiceArray}| and, therefore, |\endarray| in the second part ; % \item we have to put a |\aftergroup \@@_draw_lines:| in the first part of |{NiceArray}| so that |\@@_draw_lines| % will be executed at the end of the current environment (either |{NiceArray}| or |{NiceMatrix}|). % \end{itemize} % % \begin{macrocode} \cs_generate_variant:Nn \dim_set:Nn {Nx} \NewDocumentEnvironment {NiceArray} {O{} m O{}} {\aftergroup \@@_write_max_cell_width: \aftergroup \@@_draw_lines: % \end{macrocode} % % We increment the counter |\g_@@_env_int| which counts the environments |{NiceArray}|. % \begin{macrocode} \int_gincr:N \g_@@_env_int \dim_gzero_new:N \g_@@_max_cell_width_dim \keys_set:nn {NiceMatrix/NiceArray} {#1,#3} % \end{macrocode} % % If the user requires all the columns to have a width equal to the widest cell of the array, we read this length in % the file |.aux| (of, course, this is possible only on the second run of LaTeX : on the first run, the dimension % |\l_@@_columns_width_dim| will be set to zero --- and the columns will have their natural width). % \begin{macrocode} \bool_if:NT \l_@@_auto_columns_width_bool {\cs_if_free:cTF {_@@_max_cell_width_\int_use:N \g_@@_env_int} {\dim_set:Nn \l_@@_columns_width_dim \c_zero_dim} {\dim_set:Nx \l_@@_columns_width_dim {\use:c {_@@_max_cell_width_\int_use:N \g_@@_env_int}}}} % \end{macrocode} % The environment |{array}| uses internally the command |\ialign| and, in particular, this command |\ialign| sets % |\everycr| to |{}|. However, we want to use |\everycr| in our array (in particular to increment |\g_@@_row_int|). % The solution is to give to |\ialign| a new definition (giving to |\everycr| the value we want) % that will revert automatically to its default definition after the first utilisation.\footnote{With this programmation, we will % have, in the cells of the array, a clean version of |\ialign|. That's necessary: the user will probably not employ directly % |\ialign| in the array... but more likely environments that utilize |\ialign| internally (e.g.: |{substack}|)} % \begin{macrocode} \cs_set:Npn \ialign {\everycr{\noalign{\int_gincr:N \g_@@_row_int \int_gzero:N \g_@@_column_int % \end{macrocode} % We want to have the preamble of the array in |\g_@@_preamble_tl| at the end of the array. However, some rows of the array % may be shorter (that is to say without all the ampersands) and it's not possible to know which row will be the % longest. That's why, during the construction of a row, we retrieve the corresponding preamble in % |\g_@@_preamble_aux_tl|. At the end of the array, we are sure that the longest value will be the real preamble of % the array (stored in |\g_@@_preamble_tl|). % \begin{macrocode} \int_compare:nNnT {\tl_count:N \g_@@_preamble_aux_tl} > {\tl_count:N \g_@@_preamble_tl} {\tl_gset_eq:NN \g_@@_preamble_tl \g_@@_preamble_aux_tl} \tl_gclear:N \g_@@_preamble_aux_tl}} \skip_zero:N \tabskip \cs_set:Npn \ialign {\everycr{} \skip_zero:N \tabskip \halign} \halign} % \end{macrocode} % % We define the new column types |L|, |C| and |R| that must be used instead of |l|, |c| and |r| in the preamble of % |{NiceArray}|. % \begin{macrocode} \dim_compare:nNnTF \l_@@_columns_width_dim = \c_zero_dim {\newcolumntype{L}{>{\@@_Cell:n l}l<{\@@_end_Cell:}} \newcolumntype{C}{>{\@@_Cell:n c}c<{\@@_end_Cell:}} \newcolumntype{R}{>{\@@_Cell:n r}r<{\@@_end_Cell:}}} % \end{macrocode} % If there is an option that specify that all the columns must have the same width, the column types~|L|, |C| % and~|R| are in fact defined upon the column type~|w| of array which is, in fact, redefined below. % \begin{macrocode} {\newcolumntype{L}{wl{\dim_use:N \l_@@_columns_width_dim}} \newcolumntype{C}{wc{\dim_use:N \l_@@_columns_width_dim}} \newcolumntype{R}{wr{\dim_use:N \l_@@_columns_width_dim}}} % \end{macrocode} % % We nullify the definitions of the column types |w| and |W| because we want to avoid a warning in the log file % for a redefinition of a column type. % \begin{macrocode} \cs_set_eq:NN \NC@find@w \relax \cs_set_eq:NN \NC@find@W \relax % \end{macrocode} % % We redefine the column types |w| and |W| of the package \pkg{array}. % \begin{macrocode} \newcolumntype{w}[2] {>{\hbox_set:Nw \l_tmpa_box \@@_Cell:n ##1} c <{\@@_end_Cell: \hbox_set_end: \makebox[##2][##1]{\box_use:N \l_tmpa_box}}} \newcolumntype{W}[2] {>{\hbox_set:Nw \l_tmpa_box \@@_Cell:n ##1} c <{\@@_end_Cell: \hbox_set_end: \cs_set_eq:NN \hss \hfil \makebox[##2][##1]{\box_use:N \l_tmpa_box}}} % \end{macrocode} % % The commands |\Ldots|, |\Cdots|, etc. will be defined only in the environment |{NiceArray}|. % \begin{macrocode} \cs_set_eq:NN \Ldots \@@_Ldots \cs_set_eq:NN \Cdots \@@_Cdots \cs_set_eq:NN \Vdots \@@_Vdots \cs_set_eq:NN \Ddots \@@_Ddots \cs_set_eq:NN \Iddots \@@_Iddots \cs_set_eq:NN \Hspace \@@_Hspace: \cs_set_eq:NN \NiceMatrixEndPoint \@@_NiceMatrixEndPoint: \bool_if:NT \l_@@_renew_dots_bool {\cs_set_eq:NN \ldots \@@_Ldots \cs_set_eq:NN \cdots \@@_Cdots \cs_set_eq:NN \vdots \@@_Vdots \cs_set_eq:NN \ddots \@@_Ddots \cs_set_eq:NN \iddots \@@_Iddots} \bool_if:NF \l_@@_renew_matrix_bool {\cs_set_eq:NN \multicolumn \@@_multicolumn:nn} % \end{macrocode} % % % We have to remind the types of the columns (|l|, |c| or |r|) because we will use this information when we will % draw the vertical dotted lines. That's why we store the types of the columns in |\g_@@_preamble_tl| (for example, % if the preamble of |{NiceArray}| is |L*4{C}R|, the final value of |\g_@@_preamble_tl| will be |lccccr| if the % user really uses the six columns). % \begin{macrocode} \tl_clear_new:N \g_@@_preamble_tl \tl_clear_new:N \g_@@_preamble_aux_tl % \end{macrocode} % % The sequence |\g_@@_empty_cells_seq| will contains a list of ``empty'' cells (not all the empty cells of the % matrix). If we want to indicate that the cell in row~$i$ and column~$j$ must be considered as empty, the token % list ``|i-j|'' will be put in this sequence. % \begin{macrocode} \seq_gclear_new:N \g_@@_empty_cells_seq % \end{macrocode} % % The counter |\g_@@_instruction_int| will count the instructions (|\Cdots|, |\Vdots|, |\Ddots|, etc.) in the matrix. % \begin{macrocode} \int_gzero_new:N \g_@@_instruction_int % \end{macrocode} % % The counter |\g_@@_row_int| will be used to count the rows of the array (its incrementation will be in % |\everycr|). At the end of the environment |{array}|, this counter will give the total number of rows of the matrix. % \begin{macrocode} \int_gzero_new:N \g_@@_row_int % \end{macrocode} % % The counter |\g_@@_column_int| will be used to count the columns of the array (it will be set to zero in % |\everycr|). This counter is updated in the command |\@@_Cell:n| executed at the beginning of each cell. At the % end of the array (in the beginning of |\@@_draw_lines:|), it will be set to the total number of columns of the array. % \begin{macrocode} \int_gzero_new:N \g_@@_column_int \cs_set_eq:NN \@ifnextchar \new@ifnextchar % \end{macrocode} % % The extra horizontal spaces on both sides of an environment |{array}| should be considered as a bad idea of % standard LaTeX. In the environment |{matrix}| the package \pkg{amsmath} prefers to suppress these spaces with % instructions ``|\hskip -\arraycolsep|''. In the same way, we decide to suppress them in |{NiceArray}|. However, for better % compatibility, we give an option |exterior-arraycolsep| to control this feature. % \begin{macrocode} \bool_if:NF \l_@@_exterior_arraycolsep_bool {\skip_horizontal:n {-\arraycolsep}} % \end{macrocode} % % Eventually, the environment |{NiceArray}| is defined upon the environment |{array}|. The token list |l_@@_pos_tl| % will contain one of the values |t|, |c| or |b|. % \begin{macrocode} \array[\l_@@_pos_env_tl]{#2}} % \end{macrocode} % % \bigskip % \begin{macrocode} {\endarray \bool_if:NF \l_@@_exterior_arraycolsep_bool {\skip_horizontal:n {-\arraycolsep}}} % \end{macrocode} % % % \interitem % We create the variants of the environment |{NiceMatrix}|. % \begin{macrocode} \NewDocumentEnvironment {pNiceMatrix} {} {\left(\begin{NiceMatrix}} {\end{NiceMatrix}\right)} % \end{macrocode} % % \begin{macrocode} \NewDocumentEnvironment {bNiceMatrix} {} {\left[\begin{NiceMatrix}} {\end{NiceMatrix}\right]} % \end{macrocode} % % \begin{macrocode} \NewDocumentEnvironment {BNiceMatrix} {} {\left\{\begin{NiceMatrix}} {\end{NiceMatrix}\right\}} % \end{macrocode} % % \begin{macrocode} \NewDocumentEnvironment {vNiceMatrix} {} {\left\lvert\begin{NiceMatrix}} {\end{NiceMatrix}\right\rvert} % \end{macrocode} % % \begin{macrocode} \NewDocumentEnvironment {VNiceMatrix} {} {\left\lVert\begin{NiceMatrix}} {\end{NiceMatrix}\right\rVert} % \end{macrocode} % % \interitem % For the option \verb|columns-width=auto|, we want to known the maximal width of the cells of the array (except % the cells of the ``exterior'' column of an environment of the kind of |{pNiceAccayC}|). This length can be known % only after the end of the construction of the array: that's why we store this value in the main |.aux| file and % it will be available in the next run. % \begin{macrocode} \cs_new:Nn \@@_write_max_cell_width: {\iow_now:Nx \@mainaux {\ExplSyntaxOn \cs_gset:cpn {_@@_max_cell_width_\int_use:N \g_@@_env_int} {\dim_use:N \g_@@_max_cell_width_dim} \ExplSyntaxOff}} % \end{macrocode} % % \interitem % The conditionnal |\@@_if_not_empty_cell:nnT| test wether a cell is empty. The first two arguments must be LaTeX3 % counters for the row and the column of the considered cell. % \begin{macrocode} \prg_set_conditional:Npnn \@@_if_not_empty_cell:nn #1#2 {T} % \end{macrocode} % If the cell is a implicit cell (that is after the symbol |\\| of end of row), the cell must, of course, be % considered as empty. It's easy to check wether we are in this situation considering the correspondant Tikz node. % \begin{macrocode} {\cs_if_exist:cTF {pgf@sh@ns@nm-\int_use:N \g_@@_env_int- \int_use:N #1- \int_use:N #2} % \end{macrocode} % We manage a list of ``empty cells'' called |\g_@@_empty_cells_seq|. In fact, this list is not a list of all the % empty cells of the array but only those explicitely declared empty for some reason. It's easy to check if the % current cell is in this list. % \begin{macrocode} {\seq_if_in:NxTF \g_@@_empty_cells_seq {\int_use:N #1-\int_use:N #2} {\prg_return_false:} % \end{macrocode} % In the general case, we consider the width of the Tikz node corresponding to the cell. In order to compute this % width, we have to extract the coordinate of the west and east anchors of the node. This extraction needs a % command environment |{pgfpicture}| but, in fact, nothing is drawn. % \begin{macrocode} {\begin{pgfpicture} % \end{macrocode} % We store the name of the node corresponding to the cell in |\l_tmpa_tl|. % \begin{macrocode} \tl_set:Nx \l_tmpa_tl {nm-\int_use:N \g_@@_env_int- \int_use:N #1- \int_use:N #2} \pgfpointanchor \l_tmpa_tl {east} \dim_gset:Nn \g_tmpa_dim \pgf@x \pgfpointanchor \l_tmpa_tl {west} \dim_gset:Nn \g_tmpb_dim \pgf@x \end{pgfpicture} \dim_compare:nNnTF {\dim_abs:n {\g_tmpb_dim-\g_tmpa_dim}} < {0.5 pt} {\prg_return_false:} {\prg_return_true:} }} {\prg_return_false:} } % \end{macrocode} % % \interitem % For each drawing instruction in the matrix (like |\Cdots|, etc.), we create a global property list to store the % informations corresponding to the instruction. Such an property list will have three fields: % \begin{itemize} % \item a field ``type'' with the type of the instruction (|cdots|, |vdots|, |ddots|, etc.); % \item a field ``row'' with the number of the row of the matrix where the instruction appeared; % \item a field ``column'' with the number of the column of the matrix where the instruction appeared. % \end{itemize} % % \interitem % The argument of the following command |\@@_instruction_of_type:n| is the type of the instruction (|cdots|, % |vdots|, |ddots|, etc.). This command creates the corresponding property list. % \begin{macrocode} \cs_new_protected:Nn \@@_instruction_of_type:n % \end{macrocode} % First, we increment the counter of the instructions (this counter is initialized in the beginning of the % environment |{NiceMatrix}|). This incrementation is global because the command will be used in the cell of a |\halign|). % \begin{macrocode} {\int_gincr:N \g_@@_instruction_int \prop_put:Nnn \l_tmpa_prop {type} {#1} \prop_put:NnV \l_tmpa_prop {row} \g_@@_row_int \prop_put:NnV \l_tmpa_prop {column} \g_@@_column_int % \end{macrocode} % The property list has been created in a local variable for convenience. Now, it will be stored in a % global variable indicating the number of the instruction. % \begin{macrocode} \prop_gclear_new:c {g_@@_instruction_\int_use:N\g_@@_instruction_int _prop} \prop_gset_eq:cN {g_@@_instruction_\int_use:N\g_@@_instruction_int _prop} \l_tmpa_prop } % \end{macrocode} % % % \bigskip % \subsection{We draw the lines in the matrix} % \begin{macrocode} \cs_new_protected:Nn \@@_draw_lines: { % \end{macrocode} % The last |\cr| in the array has incremented the counter |\g_@@_row_int|. That's why we decrement it to have the % real number of rows. % \begin{macrocode} \int_decr:N \g_@@_row_int % \end{macrocode} % The counter |\g_@@_column_int| will now be the total number of columns in the array. % \begin{macrocode} \int_set:Nn \g_@@_column_int {\tl_count:N \g_@@_preamble_tl} % \end{macrocode} % % The sequence |\l_@@_yet_drawn_seq| contains a list of lines which have been drawn previously in the matrix. We % maintain this sequence because we don't want to draw two overlapping lines. % \begin{macrocode} \seq_clear_new:N \l_@@_yet_drawn_seq % \end{macrocode} % % % The following variables will be used further. % \begin{macrocode} \int_zero_new:N \l_@@_type_int \int_zero_new:N \l_@@_row_int \int_zero_new:N \l_@@_column_int \int_zero_new:N \l_@@_di_int \int_zero_new:N \l_@@_dj_int % \end{macrocode} % % By befault, the diagonal lines will be parallelized\footnote{It's possible to use the option % |parallelize-diags| to disable this parallelization.}. There are two types of diagonals lines: the $|\Ddots|$ % diagonals and the |\Iddots| diagonals. We have to count both types in order to known wether a diagonal is the % first of its type in the current |{NiceArray}| environment. % \begin{macrocode} \bool_if:NT \l_@@_parallelize_diags_bool {\int_zero_new:N \l_@@_ddots_int \int_zero_new:N \l_@@_iddots_int % \end{macrocode} % % The dimensions |\l_@@_delta_x_one_dim| and |\l_@@_delta_y_one_dim| will contains the $\Delta_x$ and $\Delta_y$ of the % first |\Ddots| diagonal. We have to store these values in order to draw the others |\Ddots| diagonals parallel to % the first one. Similarly |\l_@@_delta_x_two_dim| and |\l_@@_delta_y_two_dim| are the $\Delta_x$ and $\Delta_y$ of % the first |\Iddots| diagonal. % \begin{macrocode} \dim_zero_new:N \l_@@_delta_x_one_dim \dim_zero_new:N \l_@@_delta_y_one_dim \dim_zero_new:N \l_@@_delta_x_two_dim \dim_zero_new:N \l_@@_delta_y_two_dim} % \end{macrocode} % % \interitem % The counter |\l_@@_instruction_int| will be the index of the loop over the instructions. The first value is~$1$. % \begin{macrocode} \int_zero_new:N \l_@@_instruction_int \int_incr:N \l_@@_instruction_int % \end{macrocode} % % \interitem % We begin the loop over the instructions (the incrementation is at the end of the loop). % \begin{macrocode} \int_until_do:nNnn \l_@@_instruction_int > \g_@@_instruction_int { % \end{macrocode} % % \interitem % We extract from the property list of the current instruction the fields ``type'', ``row'' and ``column'' and we % store these values. We have to do a conversion because the components of a property list are token lists (and not % integers). % \begin{macrocode} \prop_get:cnN {g_@@_instruction_\int_use:N \l_@@_instruction_int _prop} {type} \l_tmpa_tl \int_set:Nn \l_@@_type_int {\l_tmpa_tl} \prop_get:cnN {g_@@_instruction_\int_use:N \l_@@_instruction_int _prop} {row} \l_tmpa_tl \int_set:Nn \l_@@_row_int {\l_tmpa_tl} \prop_get:cnN {g_@@_instruction_\int_use:N \l_@@_instruction_int _prop} {column} \l_tmpa_tl \int_set:Nn \l_@@_column_int {\l_tmpa_tl} % \end{macrocode} % % \interitem % We fix the values of |\l_@@_di_int| and |\l_@@_dj_int| which indicate the direction of the dotted line to draw in % the matrix. % \begin{macrocode} \int_case:nn \l_@@_type_int { 0 {\int_set:Nn \l_@@_di_int 0 \int_set:Nn \l_@@_dj_int 1} 1 {\int_set:Nn \l_@@_di_int 0 \int_set:Nn \l_@@_dj_int 1} 2 {\int_set:Nn \l_@@_di_int 1 \int_set:Nn \l_@@_dj_int 0} 3 {\int_set:Nn \l_@@_di_int 1 \int_set:Nn \l_@@_dj_int 1} 4 {\int_set:Nn \l_@@_di_int 1 \int_set:Nn \l_@@_dj_int {-1}}} % \end{macrocode} % % \interitem % An instruction for a dotted line must have a initial cell and a final cell which are both not empty. If it's not % the case, the instruction is said \emph{impossible}. An error will be raised if an impossible instruction is % encountered. % \begin{macrocode} \bool_if_exist:NTF \l_@@_impossible_instruction_bool {\bool_set_false:N \l_@@_impossible_instruction_bool} {\bool_new:N \l_@@_impossible_instruction_bool} % \end{macrocode} % % \interitem % We will determine |\l_@@_final_i_int| and |\l_@@_final_j_int| which will be the ``coordinates'' of the end of the % dotted line we have to draw. % \begin{macrocode} \int_zero_new:N \l_@@_final_i_int \int_zero_new:N \l_@@_final_j_int \int_set:Nn \l_@@_final_i_int \l_@@_row_int \int_set:Nn \l_@@_final_j_int \l_@@_column_int \bool_if_exist:NTF \l_@@_stop_loop_bool {\bool_set_false:N \l_@@_stop_loop_bool} {\bool_new:N \l_@@_stop_loop_bool} \bool_do_until:Nn \l_@@_stop_loop_bool {\int_add:Nn \l_@@_final_i_int \l_@@_di_int \int_add:Nn \l_@@_final_j_int \l_@@_dj_int % \end{macrocode} % We test if we are still in the matrix. % \begin{macrocode} \bool_if:nTF { \int_compare_p:nNn \l_@@_final_i_int < 1 || \int_compare_p:nNn \l_@@_final_i_int > \g_@@_row_int || \int_compare_p:nNn \l_@@_final_j_int < 1 || \int_compare_p:nNn \l_@@_final_j_int > \g_@@_column_int} % \end{macrocode} % If we are outside the matrix, the instruction is impossible and, of course, we stop the loop. % \begin{macrocode} {\bool_set_true:N \l_@@_impossible_instruction_bool \bool_set_true:N \l_@@_stop_loop_bool} % \end{macrocode} % If we are in the matrix, we test if the cell is empty. If it's not the case, we stop the loop because we have % found the correct values for |\l_@@_final_i_int| and |\l_@@_final_j_int|. % \begin{macrocode} {\@@_if_not_empty_cell:nnT \l_@@_final_i_int \l_@@_final_j_int {\bool_set_true:N \l_@@_stop_loop_bool}} } % \end{macrocode} % % \interitem % We will determine |\l_@@_initial_i_int| and |\l_@@_initial_j_int| which will be the ``coordinates'' of the % beginning of the dotted line we have to draw. The programmation is similar to the previous one. % \begin{macrocode} \int_zero_new:N \l_@@_initial_i_int \int_zero_new:N \l_@@_initial_j_int \int_set:Nn \l_@@_initial_i_int \l_@@_row_int \int_set:Nn \l_@@_initial_j_int \l_@@_column_int % \end{macrocode} % If we know that the instruction is impossible (because it was not possible to found the correct value for % |\l_@@_final_i_int| and |\l_@@_final_j_int|), we don't do this loop. % \begin{macrocode} \bool_set_eq:NN \l_@@_stop_loop_bool \l_@@_impossible_instruction_bool \bool_do_until:Nn \l_@@_stop_loop_bool {\int_sub:Nn \l_@@_initial_i_int \l_@@_di_int \int_sub:Nn \l_@@_initial_j_int \l_@@_dj_int \bool_if:nTF { \int_compare_p:nNn \l_@@_initial_i_int < 1 || \int_compare_p:nNn \l_@@_initial_i_int > \g_@@_row_int || \int_compare_p:nNn \l_@@_initial_j_int < 1 || \int_compare_p:nNn \l_@@_initial_j_int > \g_@@_column_int} {\bool_set_true:N \l_@@_impossible_instruction_bool \bool_set_true:N \l_@@_stop_loop_bool} {\@@_if_not_empty_cell:nnT \l_@@_initial_i_int \l_@@_initial_j_int {\bool_set_true:N \l_@@_stop_loop_bool}} } % \end{macrocode} % % \interitem % Now, we can determine wether we have to draw a line. % If the line is impossible, of course, we won't draw any line. % \begin{macrocode} \bool_if:NTF \l_@@_impossible_instruction_bool {\msg_error:nn {nicematrix} {Impossible~instruction}} % \end{macrocode} % % If the dotted line to draw is in the list of the previously drawn lines (|\l_@@_yet_drawn_seq|), we don't draw % (so, we won't have overlapping lines in the \textsc{pdf}). The token list |\l_tmpa_tl| is the $4$-uplet % characteristic of the line. % \begin{macrocode} {\tl_set:Nx \l_tmpa_tl {\int_use:N \l_@@_initial_i_int- \int_use:N \l_@@_initial_j_int- \int_use:N \l_@@_final_i_int- \int_use:N \l_@@_final_j_int} \seq_if_in:NVF \l_@@_yet_drawn_seq \l_tmpa_tl % \end{macrocode} % % If the dotted line to draw is not in the list, we add it the list |\l_@@_yet_drawn_seq|. % \begin{macrocode} {\seq_put_left:NV \l_@@_yet_drawn_seq \l_tmpa_tl % \end{macrocode} % % \medskip % The four following variables are global because we will have to do affectations in a Tikz instruction (in order % to extract the coordinates of two extremities of the line to draw). % \begin{macrocode} \dim_zero_new:N \g_@@_x_initial_dim \dim_zero_new:N \g_@@_y_initial_dim \dim_zero_new:N \g_@@_x_final_dim \dim_zero_new:N \g_@@_y_final_dim % \end{macrocode} % % % We draw the line. % \begin{macrocode} \int_case:nn \l_@@_type_int {0 \@@_draw_ldots_line: 1 \@@_draw_cdots_line: 2 \@@_draw_vdots_line: 3 \@@_draw_ddots_line: 4 \@@_draw_iddots_line:}}} % \end{macrocode} % % \bigskip % Incrementation of the index of the loop (and end of the loop). % \begin{macrocode} \int_incr:N \l_@@_instruction_int } } % \end{macrocode} % % % \interitem % The command |\@@_retrieve_coords:nn| retrieves the Tikz coordinates of the two extremities of the dotted line we % will have to draw \footnote{In fact, with diagonals lines, or vertical lines in columns of type |L| or |R|, a % adjustment of one of the coordinates may be done.}. This command has four implicit arguments which are % |\l_@@_initial_i_int|, |\l_@@_initial_j_int|, |\l_@@_final_i_int| and |\l_@@_final_j_int|. % % The two arguments of the command |\@@_retrieve_coords:nn| are the anchors that must be used for the two nodes. % % The coordinates are stored in |\g_@@_x_initial_dim|, |\g_@@_y_initial_dim|, |\g_@@_x_final_dim|, % |\g_@@_y_final_dim|. These variables are global for technical reasons: we have to do an affectation in an % environment |{pgfpicture}|. % \begin{macrocode} \cs_new_protected:Nn \@@_retrieve_coords:nn {\begin{tikzpicture}[remember~picture] \tikz@parse@node\pgfutil@firstofone (nm-\int_use:N \g_@@_env_int- \int_use:N \l_@@_initial_i_int- \int_use:N \l_@@_initial_j_int.#1) \dim_gset:Nn \g_@@_x_initial_dim \pgf@x \dim_gset:Nn \g_@@_y_initial_dim \pgf@y \tikz@parse@node\pgfutil@firstofone (nm-\int_use:N \g_@@_env_int- \int_use:N \l_@@_final_i_int- \int_use:N \l_@@_final_j_int.#2) \dim_gset:Nn \g_@@_x_final_dim \pgf@x \dim_gset:Nn \g_@@_y_final_dim \pgf@y \end{tikzpicture} } % \end{macrocode} % % \interitem % \begin{macrocode} \cs_new_protected:Nn \@@_draw_ldots_line: {\@@_retrieve_coords:nn {south~east} {south~west} \@@_draw_tikz_line:} % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Nn \@@_draw_cdots_line: {\@@_retrieve_coords:nn {mid~east} {mid~west} \@@_draw_tikz_line:} % \end{macrocode} % % \bigskip % For the vertical dotted lines, there is a problem because we want really vertical lines. If the type of the % column is |c| (from a type |C| in |{NiceArray}|), all the Tikz nodes of the column have the same $x$-value for the % anchors |south| and |north|. However, if the type of the column is |l| or |r| (from a type |L| or |R| in % |{NiceArray}|), the geometric line from the anchors |south| and |north| would probably not be really vertical. % That's why we need to known the type of the column and that's why we have constructed a token list % |\g_@@_preamble_tl| to store the types (|l|, |c| or |r|) of all the columns. % \begin{macrocode} \cs_new_protected:Nn \@@_draw_vdots_line: {\@@_retrieve_coords:nn {south} {north} % \end{macrocode} % We store in |\t_tmpa_tl| the type of the column (|l|, |c| or |r|). % \begin{macrocode} \tl_set:Nx \l_tmpa_tl {\tl_item:Nn \g_@@_preamble_tl \l_@@_initial_j_int} % \end{macrocode} % If the column is of type |l|, we will draw the dotted on the left-most abscissa. % \begin{macrocode} \tl_set:Nn \l_tmpb_tl {l} \tl_if_eq:NNT \l_tmpa_tl \l_tmpb_tl {\dim_set:Nn \l_tmpa_dim {\dim_min:nn \g_@@_x_initial_dim \g_@@_x_final_dim} \dim_set_eq:NN \g_@@_x_initial_dim \l_tmpa_dim \dim_set_eq:NN \g_@@_x_final_dim \l_tmpa_dim} % \end{macrocode} % If the column is of type |r|, we will draw the dotted on the right-most abscissa. % \begin{macrocode} \tl_set:Nn \l_tmpb_tl {r} \tl_if_eq:NNT \l_tmpa_tl \l_tmpb_tl {\dim_set:Nn \l_tmpa_dim {\dim_max:nn \g_@@_x_initial_dim \g_@@_x_final_dim} \dim_set_eq:NN \g_@@_x_initial_dim \l_tmpa_dim \dim_set_eq:NN \g_@@_x_final_dim \l_tmpa_dim} % \end{macrocode} % Now, the coordinates of the line to draw are computed in |\g_@@_x_initial_dim|, |\g_@@_y_initial_dim|, % |\g_@@_x_final_dim| and |\g_@@_y_final_dim|. We can draw the line with |\l_@@_draw_tikz_line:| as usual. % \begin{macrocode} \@@_draw_tikz_line:} % \end{macrocode} % % \interitem % For the diagonal lines, the situation is a bit more complicated because, by default, we parallelize the diagonals % lines. The first diagonal line is drawn and then, all the other diagonal lines are drawn parallel to the first % one. % \begin{macrocode} \cs_new_protected:Nn \@@_draw_ddots_line: {\@@_retrieve_coords:nn {south~east} {north~west} % \end{macrocode} % We have retrieved the coordinates in the usual way (they are stored in |\g_@@_x_initial_dim|, etc.). % If the parallelization of the diagonals is set, we will have (maybe) to adjust the fourth coordinate. % \begin{macrocode} \bool_if:NT \l_@@_parallelize_diags_bool {\int_incr:N \l_@@_ddots_int % \end{macrocode} % We test if the diagonal line is the first one (the counter |\l_@@_ddots_int| is created for this usage). % \begin{macrocode} \int_compare:nNnTF \l_@@_ddots_int = 1 % \end{macrocode} % If the diagonal line is the first one, we have no adjustment of the line to do but we store the $\Delta_x$ and the % $\Delta_y$ of the line because these values will be used to draw the others diagonal lines parallels to the first one. % \begin{macrocode} {\dim_set:Nn \l_@@_delta_x_one_dim {\g_@@_x_final_dim - \g_@@_x_initial_dim } \dim_set:Nn \l_@@_delta_y_one_dim {\g_@@_y_final_dim - \g_@@_y_initial_dim }} % \end{macrocode} % If the diagonal line is not the first one, we have to adjust the second extremity of the line by modifying % the coordinate |\g_@@_y_initial_dim|. % \begin{macrocode} {\dim_gset:Nn \g_@@_y_final_dim {\g_@@_y_initial_dim + (\g_@@_x_final_dim - \g_@@_x_initial_dim) * \dim_ratio:nn \l_@@_delta_y_one_dim \l_@@_delta_x_one_dim }}} % \end{macrocode} % Now, we can draw the dotted line (after a possible change of |\g_@@_y_initial_dim|). % \begin{macrocode} \@@_draw_tikz_line:} % \end{macrocode} % % \bigskip % We draw the |\Iddots| diagonals in the same way. % \begin{macrocode} \cs_new_protected:Nn \@@_draw_iddots_line: {\@@_retrieve_coords:nn {south~west} {north~east} \bool_if:NT \l_@@_parallelize_diags_bool {\int_incr:N \l_@@_iddots_int \int_compare:nNnTF \l_@@_iddots_int = 1 {\dim_set:Nn \l_@@_delta_x_two_dim {\g_@@_x_final_dim - \g_@@_x_initial_dim } \dim_set:Nn \l_@@_delta_y_two_dim {\g_@@_y_final_dim - \g_@@_y_initial_dim }} {\dim_gset:Nn \g_@@_y_final_dim {\g_@@_y_initial_dim + (\g_@@_x_final_dim - \g_@@_x_initial_dim) * \dim_ratio:nn \l_@@_delta_y_two_dim \l_@@_delta_x_two_dim }}} \@@_draw_tikz_line:} % \end{macrocode} % % \bigskip % \subsection{The actual instructions for drawing the dotted line with Tikz} % % The command |\@@_draw_tikz_line:| draws the line using four implicit arguments: % % \quad |\g_@@_x_initial_dim|, |\g_@@_y_initial_dim|, |\g_@@_x_final_dim| and |\g_@@_y_final_dim|. % These variables are global for technical reasons: their first affectation was in an instruction |\tikz|. % % \begin{macrocode} \cs_new_protected:Nn \@@_draw_tikz_line: { % \end{macrocode} % The dimension |\l_@@_l_dim| is the length $\ell$ of the line to draw. We use the floating point reals of % \pkg{expl3} to compute this length. % \begin{macrocode} \dim_zero_new:N \l_@@_l_dim \dim_set:Nn \l_@@_l_dim { \fp_to_dim:n { sqrt( ( \dim_use:N \g_@@_x_final_dim -\dim_use:N \g_@@_x_initial_dim) ^2 +( \dim_use:N \g_@@_y_final_dim -\dim_use:N \g_@@_y_initial_dim) ^2 )} } % \end{macrocode} % The integer |\l_tmpa_int| is the number of dots of the dotted line. % \begin{macrocode} \int_set:Nn \l_tmpa_int {\dim_ratio:nn {\l_@@_l_dim - 0.54em} {0.45em}} % \end{macrocode} % The dimensions |\l_tmpa_dim| and |\l_tmpb_dim| are the coordinates of the vector between two dots in the % dotted line. % \begin{macrocode} \dim_set:Nn \l_tmpa_dim { (\g_@@_x_final_dim - \g_@@_x_initial_dim) * \dim_ratio:nn {0.45em} \l_@@_l_dim} \dim_set:Nn \l_tmpb_dim { (\g_@@_y_final_dim - \g_@@_y_initial_dim) * \dim_ratio:nn {0.45em} \l_@@_l_dim} % \end{macrocode} % In the loop over the dots (|\int_step_inline:nnnn|), the dimensions |\g_@@_x_initial_dim| and % |\g_@@_y_initial_dim| will be used for the coordinates of the dots. % \begin{macrocode} \dim_gadd:Nn \g_@@_x_initial_dim { (\g_@@_x_final_dim - \g_@@_x_initial_dim) * \dim_ratio:nn {\l_@@_l_dim - 0.45 em * \l_tmpa_int} {\l_@@_l_dim * 2}} \dim_gadd:Nn \g_@@_y_initial_dim { (\g_@@_y_final_dim - \g_@@_y_initial_dim) * \dim_ratio:nn {\l_@@_l_dim - 0.45 em * \l_tmpa_int} {\l_@@_l_dim * 2}} \begin{tikzpicture}[overlay] \int_step_inline:nnnn 0 1 \l_tmpa_int { \pgfpathcircle{\pgfpoint{\g_@@_x_initial_dim} {\g_@@_y_initial_dim}} {0.53pt} \pgfusepath{fill} \dim_gadd:Nn \g_@@_x_initial_dim \l_tmpa_dim \dim_gadd:Nn \g_@@_y_initial_dim \l_tmpb_dim } \end{tikzpicture} } % \end{macrocode} % % \bigskip % \subsection{User commands available in the new environments} % % We give new names for the commands |\ldots|, |\cdots|, |\vdots| and |\ddots| because these commands will be % redefined (if the option |renew-dots| is used). % \begin{macrocode} \cs_set_eq:NN \@@_ldots \ldots \cs_set_eq:NN \@@_cdots \cdots \cs_set_eq:NN \@@_vdots \vdots \cs_set_eq:NN \@@_ddots \ddots \cs_set_eq:NN \@@_iddots \iddots % \end{macrocode} % % \interitem % The command |\@@_add_to_empty_cells:| adds the current cell to |\g_@@_empty_cells_seq| which is the list of the % empty cells (the cells explicitly declared ``empty'': there may be, of course, other empty cells in the matrix). % \begin{macrocode} \cs_new_protected:Nn \@@_add_to_empty_cells: {\seq_gput_right:Nx \g_@@_empty_cells_seq {\int_use:N \g_@@_row_int- \int_use:N \g_@@_column_int}} % \end{macrocode} % % \interitem % The commands |\@@_Ldots|, |\@@_Cdots|, |\@@_Vdots|, |\@@_Ddots| and |\@@_Iddots| will be linked to |\Ldots|, % |\Cdots|, |\Vdots|, |\Ddots| and |\Iddots| in the environments |{NiceArray}| (the other environments of % \pkg{nicematrix} rely upon |{NiceArray}|). % \begin{macrocode} \NewDocumentCommand \@@_Ldots {s} {\IfBooleanF {#1} {\@@_instruction_of_type:n 0} \bool_if:NF \l_@@_nullify_dots_bool {\phantom \@@_ldots} \@@_add_to_empty_cells:} % \end{macrocode} % % \bigskip % \begin{macrocode} \NewDocumentCommand \@@_Cdots {s} {\IfBooleanF {#1} {\@@_instruction_of_type:n 1} \bool_if:NF \l_@@_nullify_dots_bool {\phantom \@@_cdots} \@@_add_to_empty_cells:} % \end{macrocode} % % \bigskip % \begin{macrocode} \NewDocumentCommand \@@_Vdots {s} {\IfBooleanF {#1} {\@@_instruction_of_type:n 2} \bool_if:NF \l_@@_nullify_dots_bool {\phantom \@@_vdots} \@@_add_to_empty_cells:} % \end{macrocode} % % \bigskip % \begin{macrocode} \NewDocumentCommand \@@_Ddots {s} {\IfBooleanF {#1} {\@@_instruction_of_type:n 3} \bool_if:NF \l_@@_nullify_dots_bool {\phantom \@@_ddots} \@@_add_to_empty_cells:} % \end{macrocode} % % \bigskip % \begin{macrocode} \NewDocumentCommand \@@_Iddots {s} {\IfBooleanF {#1} {\@@_instruction_of_type:n 4} \bool_if:NF \l_@@_nullify_dots_bool {\phantom \@@_iddots} \@@_add_to_empty_cells:} % \end{macrocode} % % % \bigskip % The command |\@@_Hspace:| will be linked to |\hspace| in |{NiceArray}|. % \begin{macrocode} \cs_new_protected:Nn \@@_Hspace: {\@@_add_to_empty_cells: \hspace} % \end{macrocode} % % \bigskip % The command |\@@_NiceMatrixEndPoint:| will be linked to |\NiceMatrixEndPoint| in |{NiceArray}|. % \begin{macrocode} \cs_new_protected:Nn \@@_NiceMatrixEndPoint: {\kern 0.5pt} % \end{macrocode} % % \bigskip % \subsection{We process the options} % % We process the options when the package is loaded (with |\usepackage|) but we recommend to use % |\NiceMatrixOptions| instead. % % We must process these options after the definition of the environment |{NiceMatrix}| because the option % |renew-matrix| execute the code |\cs_set_eq:NN \env@matrix \NiceMatrix|. % % Of course, the command |\NiceMatrix| must be defined before such an instruction is executed. % \begin{macrocode} \ProcessKeysOptions {NiceMatrix} % \end{macrocode} % % % \bigskip % \subsection{The error messages} % \begin{macrocode} \msg_new:nnnn {nicematrix} {Impossible~instruction} {It's~not~possible~to~execute~the~instruction~ \int_case:nn \l_@@_type_int {0 {\token_to_str:N \Ldots} 1 {\token_to_str:N \Cdots} 2 {\token_to_str:N \Vdots} 3 {\token_to_str:N \Ddots}}~in~the~row~\int_use:N\l_@@_row_int\ ~and~the~column~\int_use:N\l_@@_column_int\space of~the~matrix~ because~it's~impossible~to~find~one~of~its~extremities~ (both~extremities~must~be~non~empty~cells~of~the~matrix).~ If~you~go~on,~the~instruction~will~be~ignored.} {You~can~specify~an~end~of~line~on~a~empty~cell~ with~\token_to_str:N \NiceMatrixEndPoint.} % \end{macrocode} % % \begin{macrocode} \msg_new:nnn {nicematrix} {Multicolumn~forbidden} {The~command~\token_to_str:N \multicolumn\ is~forbidden~in~the~environment~\{NiceMatrix\}~ and~its~variants.~The~command~\token_to_str:N \hdotsfor\ of~amsmath~is~also~forbidden~since~it~uses~ \token_to_str:N \multicolumn.~You~can~go~on~but~your~line~will~ probably~be~wrong.} % \end{macrocode} % % \bigskip % \subsection{The environment \{pNiceArrayC\} and its variants} % % The code in this section can be removed without affecting the previous code. % % \medskip % First, we define a set of options for the environment |{pNiceArrayC}| and its variants. This set of keys is named % |NiceMatrix/NiceArrayC| even though there is no environment called |{NiceArrayC}|. % % \begin{macrocode} \keys_define:nn {NiceMatrix/NiceArrayC} {parallelize-diags .bool_set:N = \l_@@_parallelize_diags_bool, parallelize-diags .default:n = true, renew-dots .bool_set:N = \l_@@_renew_dots_bool, renew-dots .default:n = true, nullify-dots .bool_set:N = \l_@@_nullify_dots_bool , nullify-dots .default:n = true, code-for-last-col .tl_set:N = \l_@@_code_for_last_col_tl, code-for-last-col .value_required:n = true, columns-width .code:n = \str_if_eq:nnTF {#1} {auto} {\bool_set_true:N \l_@@_auto_columns_width_bool} {\dim_set:Nn \l_@@_columns_width_dim {#1}}, columns-width .value_required:n = true, unknown .code:n = \msg_error:nn {nicematrix} {Unknown~option~for~pNiceArrayC}} % \end{macrocode} % % \begin{macrocode} \msg_new:nnnn {nicematrix} {Unknown~option~for~pNiceArrayC} {The~option~"\tl_use:N\l_keys_key_tl"~is~unknown~for~the~environment~ \{\@currenvir\}.\\ If~you~go~on,~it~will~be~ignored.\\ For~a~list~of~the~available~options,~type~H~.} {The~available~options~are~(in~alphabetic~order):~ code-for-last-col,~ columns-width,~ nullify-dots,~ parallelize-diags~ and~renew-dots.} % \end{macrocode} % % \bigskip % In the environment |{pNiceArrayC}| (and its variants), the last column is composed with instructions % |\hbox_overlap_right:n| (this instruction may be seen as the \pkg{expl3} equivalent of the classical command % |\rlap|). After the composition of the array, an horizontal skip is inserted to compensate for these % overlapping boxes. % % \medskip % The command |\@@_NiceArrayC:nn| will be used in the environment |{pNiceArrayC}| and its variants. % \begin{macrocode} \cs_new_protected:Nn \@@_NiceArrayC:nn {\dim_gzero_new:N \g_@@_width_last_col_dim \keys_set:nn {NiceMatrix/NiceArrayC} {#1} \bool_set_false:N \l_@@_exterior_arraycolsep_bool \tl_set:Nn \l_@@_pos_env_tl c \begin{NiceArray} % \end{macrocode} % The beginning of the preamble is the argument of the environment |{pNiceArrayC}|. % \begin{macrocode} {#2 % \end{macrocode} % % However, we add a last column with its own specification. For a cell in this last column, the first operation is % to store the content of the cell in the box |\l_tmpa_box|. This is allowed in \pkg{expl3} with the construction % |\hbox_set:Nw \l_tmpa_box| ... |\hbox_set_end:|. % \begin{macrocode} >{\int_gincr:N \g__nm_column_int \hbox_set:Nw \l_tmpa_box \l_@@_code_for_last_col_tl \tikz[remember~picture, inner~sep = 0pt, minimum~width = 0pt, baseline] \node [anchor=base] (nm-\int_use:N \g__nm_env_int- \int_use:N \g__nm_row_int- \int_use:N \g__nm_column_int) \bgroup $ % $ } l % \end{macrocode} % % We actualize the value of |\g_@@with_last_col_dim| which, at the end of the array, will contains the maximal width % of the cells of the last column (thus, it will be equal to the width of the last column). % \begin{macrocode} <{ $ % $ \egroup ; \hbox_set_end: \dim_gset:Nn \g_@@_width_last_col_dim {\dim_max:nn \g_@@_width_last_col_dim {\box_wd:N \l_tmpa_box}} \tl_gput_right:Nn \g__nm_preamble_aux_tl {#1} \skip_horizontal:n {-2\arraycolsep} % \end{macrocode} % The content of the cell is inserted in a overlapping position. % \begin{macrocode} \hbox_overlap_right:n {\skip_horizontal:n {2\arraycolsep} \box_use:N \l_tmpa_box}}}} % \end{macrocode} % This ends the preamble of the array that will be constructed (a rather long preamble, indeed). % % \bigskip % The command |\@@_after_last_col:| will be used to insert, after the construction of the array (and after the % insertion of the right parenthesis, brace, bracket, etc.), an horizontal space in order to compensate for the % overlapping boxes. % \begin{macrocode} \cs_new:Nn \@@_after_last_col: {\dim_compare:nNnF \g_@@_width_last_col_dim = \c_zero_dim {\skip_horizontal:n {\g_@@_width_last_col_dim}{}}} % \end{macrocode} % % \bigskip % \begin{macrocode} \NewDocumentEnvironment {pNiceArrayC} {O{} m O{}} {\left( \@@_NiceArrayC:nn {#1,#3} {#2}} {\end{NiceArray} \right) \@@_after_last_col:} \NewDocumentEnvironment {vNiceArrayC} {O{} m O{}} {\left| \@@_NiceArrayC:nn {#1,#3} {#2}} {\end{NiceArray} \right| \@@_after_last_col:} \NewDocumentEnvironment {VNiceArrayC} {O{} m O{}} {\left\| \@@_NiceArrayC:nn {#1,#3} {#2}} {\end{NiceArray} \right\| \@@_after_last_col:} \NewDocumentEnvironment {bNiceArrayC} {O{} m O{}} {\left[ \@@_NiceArrayC:nn {#1,#3} {#2}} {\end{NiceArray} \right] \@@_after_last_col:} \NewDocumentEnvironment {BNiceArrayC} {O{} m O{}} {\left\{ \@@_NiceArrayC:nn {#1,#3} {#2}} {\end{NiceArray} \right\} \@@_after_last_col:} % \end{macrocode} % % % % \section{History} % % \subsection{Changes between versions 1.0 and 1.1} % % Option |silent| (with this option, the impossible instructions are discarded silently). % % The dotted lines are no longer drawn with Tikz nodes but with Tikz circles (for efficiency). % % Modification of the code which is now twice faster. % % \subsection{Changes between versions 1.1 and 1.2} % % New environment |{NiceArray}| with column types |L|, |C| and |R|. % % \subsection{Changes between version 1.2 and 1.3} % % New environment |{pNiceArrayC}| and its variants. % % We decrement |\g_@@_row_int| in |\@@_draw_arrows:| to have the exact number of rows. % % Correction of a bug in the definition of |{BNiceMatrix}|, |{vNiceMatrix}| and |{VNiceMatrix}| (in fact, it was a % typo). % % Options are now available locally in |{pNiceMatrix}| and its variants. % % The names of the options are changed. The old names were names in ``camel style''. New names are in lowercase and % hyphens (but backward compatibility is kept). % % % \subsection{Changes between version 1.3 and 1.4} % % The column types |w| and |W| can now be used in the environments |{NiceArray}|, |{pNiceArrayC}| and its variants % with the same meaning as in the package \pkg{array}. % % New option |columns-width| to fix the same width for all the columns of the array. % % \endinput % Local Variables: % TeX-fold-mode: nil % End: