% \iffalse meta-comment % % Copyright (C) 2018-2019 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{3.15} \def\myfiledate{2020/04/06} % % %<*batchfile> \begingroup \input l3docstrip.tex \keepsilent \usedir{tex/latex/nicematrix} \preamble Copyright (C) 2018-2020 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 % % %<*driver> \documentclass[dvipsnames]{l3doc}% dvipsnames is for xcolor (loaded by Tikz) \VerbatimFootnotes \usepackage{xltxtra} \usepackage[xetex]{geometry} \geometry{left=2.8cm,right=2.8cm,top=2.5cm,bottom=2.5cm,papersize={21cm,29.7cm}} \usepackage{colortbl} \usepackage{tikz} \usetikzlibrary{fit} \usepackage{nicematrix} \usepackage{siunitx} \NewDocumentEnvironment {scope} {} {} {} \def\interitem{\vspace{7mm plus 2 mm minus 3mm}} \def\emphase{\bgroup\color{RoyalPurple}\let\next=} \fvset{commandchars=\~\#\@,formatcom=\color{gray}} \usepackage{titlesec} \titlespacing*{\section}{0pt}{6.5ex plus 1ex minus .2ex}{4.3ex plus .2ex} \titlespacing*{\subsection}{0pt}{4.5ex plus 1ex minus .2ex}{2ex plus .2ex} \usepackage{multicol} \usepackage{arydshln} \setlength{\columnseprule}{0.4pt} \usepackage{footnotehyper} \usepackage{varwidth} \parindent 0pt \EnableCrossrefs \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}} % % \hypersetup % { % pdfinfo = % { % Title = The package 'nicematrix' , % Subject = A LaTeX package , % Author = F. Pantigny % } % } % % % \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 and \textbf{loads} % the packages \pkg{l3keys2e}, \pkg{xparse}, \pkg{array}, \pkg{amsmath}, % \pkg{pgfcore} and the module \pkg{shapes} of \textsc{pgf} (\pkg{tikz} is % \emph{not} loaded). The final user only has to load the package with % |\usepackage{nicematrix}|. % % % \medskip % \begin{savenotes} % \begin{minipage}{0.6\linewidth} % This package provides some new tools to draw mathematical matrices. The main % features are the following: % \begin{itemize}\setlength{\itemsep}{0pt} % \item continuous dotted lines\footnote{If the class option |draft| is % used, these dotted lines will not be drawn for a faster compilation.}; % \item exterior rows and columns for labels; % \item a control of the width of the columns. % \end{itemize} % \end{minipage} % \end{savenotes} % \hspace{1.4cm} % $\begin{bNiceArray}{CCCC}[first-row,first-col, % code-for-first-col=\color{blue}\scriptstyle, % code-for-first-row=\color{blue}\scriptstyle, % columns-width = auto] % & C_1 & C_2 & \Cdots & C_n \\ % L_1 & a_{11} & a_{12} & \Cdots & a_{1n} \\ % L_2 & a_{21} & a_{22} & \Cdots & a_{2n} \\ % \Vdots & \Vdots & \Vdots & \Ddots & \Vdots\\ % L_n & a_{n1} & a_{n2} & \Cdots & a_{nn} % \end{bNiceArray}$ % % \medskip % A command |\NiceMatrixOptions| is provided to fix the options (the % scope of the options fixed by this command is the current TeX group). % % % \bigskip % \textbf{An example for the continuous dotted lines} % % \medskip % \begin{minipage}{10cm} % For example, consider the following code which uses an environment |{pmatrix}| % of \pkg{amsmath}. % % \smallskip % \begin{BVerbatim} % $A = \begin{pmatrix} % 1 & \cdots & \cdots & 1 \\ % 0 & \ddots & & \vdots \\ % \vdots & \ddots & \ddots & \vdots \\ % 0 & \cdots & 0 & 1 % \end{pmatrix}$ % \end{BVerbatim} % % \smallskip % This code composes the matrix $A$ on the right. % \end{minipage}\hspace{1cm} % $A = \begin{pmatrix} % 1 &\cdots &\cdots &1 \\ % 0 &\ddots & &\vdots \\ % \vdots &\ddots &\ddots &\vdots \\ % 0 &\cdots &0 &1 % \end{pmatrix}$ % % % \bigskip % \begin{scope} % \NiceMatrixOptions{transparent} % \begin{minipage}{10cm} % Now, if we use the package \pkg{nicematrix} with the option \\ % |transparent|, the same code will give the result on the right. % \end{minipage}\hspace{1cm} % $A = \begin{pmatrix} % 1 & \cdots & \cdots & 1 \\ % 0 & \ddots & & \vdots \\ % \vdots & \ddots & \ddots & \vdots \\ % 0 & \cdots & 0 & 1 % \end{pmatrix}$ % \end{scope} % % % \section{The environments of this package} % % The package \pkg{nicematrix} defines the following new environments. % % \medskip % \begin{ttfamily} % \setlength{\tabcolsep}{3mm} % \begin{tabular}{llll} % \{NiceMatrix\} & \{NiceArray\} & \{pNiceArray\} \\ % \{pNiceMatrix\} & & \{bNiceArray\} \\ % \{bNiceMatrix\} & & \{BNiceArray\} \\ % \{BNiceMatrix\} & & \{vNiceArray\} \\ % \{vNiceMatrix\} & & \{VNiceArray\} \\ % \{VNiceMatrix\} & & \{NiceArrayWithDelims\} \\ % \end{tabular} % \end{ttfamily} % % % \medskip % By default, the environments |{NiceMatrix}|, |{pNiceMatrix}|, |{bNiceMatrix}|, % |{BNiceMatrix}|, |{vNiceMatrix}| and |{VNiceMatrix}| behave almost exactly as % the corresponding environments of \pkg{amsmath}: |{matrix}|, |{pmatrix}|, % |{bmatrix}|, |{Bmatrix}|, |{vmatrix}| and |{Vmatrix}|. % % % \medskip % The environment |{NiceArray}| is similar to the environment |{array}| of the % package |{array}|. However, for technical reasons, in the preamble of the % environment |{NiceArray}|, the user must use the letters |L|, |C| and~|R| % instead of |l|, |c| and |r|. It's possible to use the constructions % |w{...}{...}|, |W{...}{...}|\footnote{However, for the columns of type |w| and % |W|, the cells are composed in math mode (in the environments of % \pkg{nicematrix}) whereas in |{array}| of \pkg{array}, they are composed in % text mode.}, "|", |>{...}|, |<{...}|, |@{...}|, |!{...}| and |*{n}{...}| but % the letters |p|, |m| and |b| should not be used. See p.~\pageref{NiceArray} % the section relating to |{NiceArray}|. % % % \section{The continuous dotted lines} % % Inside the environments of the package \pkg{nicematrix}, 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. If |mathdots| is loaded, the % version of |mathdots| is used. It corresponds to the command |\adots| of % \pkg{unicode-math}.} % \newcounter{fniddots} % \setcounter{fniddots}{\thefootnote} % % \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 (cf. p.~\pageref{empty-cells}).} 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| diagonal ones. It's possible to change the color of these lines % with the option |color|.\footnote{It's also possible to change the color of % all theses dotted lines with the option |xdots/color| (\textsl{xdots} to % remind that it works for |\Cdots|, |\Ldots|, |\Vdots|, etc.): cf. p. \pageref{customization}.}\par\nobreak % % \bigskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % \begin{bNiceMatrix} % a_1 & \Cdots & & & a_1 \\ % \Vdots & a_2 & \Cdots & & a_2 \\ % & \Vdots & \Ddots[color=red] \\ % \\ % 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[color=red] \\ % \\ % 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}\footnote{And it's not possible to draw a |\Ldots| and a % |\Cdots| line between the same cells.}). % % \bigskip % In fact, in this example, it would be possible to draw the same matrix more % easily 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{In \pkg{nicematrix}, one should use |\hspace*| and not % |\hspace| for such an usage because \pkg{nicematrix} loads \pkg{array}. One % may also remark that it's possible to fix the width of a column by using the % environment |{NiceArray}| (or one of its variants) with a column of type~|w| % or~|W|: see p.~\pageref{width}} % % 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}$ % % \subsection{The option nullify-dots} % % % Consider the following matrix composed classicaly with the environment % \verb|{pmatrix}| of \pkg{amsmath}.\par\nobreak % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % $A = \begin{pmatrix} % h & i & j & k & l & m \\ % x & & & & & x \\ % \end{pmatrix}$ % \end{BVerbatim} % $A = \begin{pmatrix} % h & i & j & k & l & m \\ % x & & & & & x \\ % \end{pmatrix}$ % % % \bigskip % If we add \verb|\ldots| instructions in the second row, the geometry of the % matrix is modified.\par\nobreak % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % $B = \begin{pmatrix} % h & i & j & k & l & m \\ % x & \ldots & \ldots & \ldots & \ldots & x \\ % \end{pmatrix}$ % \end{BVerbatim} % $B = \begin{pmatrix} % h & i & j & k & l & m \\ % x & \ldots & \ldots & \ldots & \ldots & x \\ % \end{pmatrix}$ % % \bigskip % By default, with \pkg{nicematrix}, if we replace \verb|{pmatrix}| by % \verb|{pNiceMatrix}| and \verb|\ldots| by \verb|\Ldots|, the geometry of the matrix is not % changed.\par\nobreak % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % $C = \begin{pNiceMatrix} % h & i & j & k & l & m \\ % x & \Ldots & \Ldots & \Ldots & \Ldots & x \\ % \end{pNiceMatrix}$ % \end{BVerbatim} % $C = \begin{pNiceMatrix} % h & i & j & k & l & m \\ % x & \Ldots & \Ldots & \Ldots & \Ldots & x \\ % \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 row. It's possible by % using the option \verb|nullify-dots| (and only one instruction \verb|\Ldots| is % necessary).\par\nobreak % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % $D = \begin{pNiceMatrix}[~emphase#nullify-dots@] % h & i & j & k & l & m \\ % x & \Ldots & & & & x \\ % \end{pNiceMatrix}$ % \end{BVerbatim} % $D = \begin{pNiceMatrix}[nullify-dots] % h & i & j & k & l & m \\ % x & \Ldots & & & & x \\ % \end{pNiceMatrix}$ % % \medskip % The option |nullify-dots| smashes the instructions |\Ldots| (and the variants) % horizontally but also vertically. % % \medskip % \textbf{There must be no space before the opening bracket (|[|) of the options % of the environment.} % % % \subsection{The command \textbackslash Hdotsfor} % % Some people commonly use the command |\hdotsfor| of \pkg{amsmath} in order to % draw horizontal dotted lines in a matrix. In the environments of % \pkg{nicematrix}, one should use instead |\Hdotsfor| in order to draw dotted % lines similar to the other dotted lines drawn by the package \pkg{nicematrix}. % % As with the other commands of \pkg{nicematrix} (like |\Cdots|, |\Ldots|, % |\Vdots|, etc.), the dotted line drawn with |\Hdotsfor| extends until the % contents of the cells on both sides. % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=7cm] % $\begin{pNiceMatrix} % 1 & 2 & 3 & 4 & 5 \\ % 1 & ~emphase#\Hdotsfor{3}@ & 5 \\ % 1 & 2 & 3 & 4 & 5 \\ % 1 & 2 & 3 & 4 & 5 % \end{pNiceMatrix}$ % \end{BVerbatim} % $\begin{pNiceMatrix} % 1 & 2 & 3 & 4 & 5 \\ % 1 & \Hdotsfor{3} & 5 \\ % 1 & 2 & 3 & 4 & 5 \\ % 1 & 2 & 3 & 4 & 5 % \end{pNiceMatrix}$ % % \bigskip % However, if these cells are empty, the dotted line extends only in the cells % specified by the argument of |\Hdotsfor| (by design). % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=7cm] % $\begin{pNiceMatrix} % 1 & 2 & 3 & 4 & 5 \\ % & ~emphase#\Hdotsfor{3}@ \\ % 1 & 2 & 3 & 4 & 5 \\ % 1 & 2 & 3 & 4 & 5 % \end{pNiceMatrix}$ % \end{BVerbatim} % $\begin{pNiceMatrix} % 1 & 2 & 3 & 4 & 5 \\ % & \Hdotsfor{3} \\ % 1 & 2 & 3 & 4 & 5 \\ % 1 & 2 & 3 & 4 & 5 % \end{pNiceMatrix}$ % % % Remark: Unlike the command |\hdotsfor| of \pkg{amsmath}, the command % |\Hdotsfor| may be used when the package \pkg{colortbl} is loaded (but you % might have problem if you use |\rowcolor| on the same row as |\Hdotsfor|). % % \subsection{How to generate the continuous dotted lines transparently} % % The package \pkg{nicematrix} provides an option called |transparent| for using % existing code transparently in the environments of the \pkg{amsmath} : % |{matrix}|, |{pmatrix}|, |{bmatrix}|, etc. In fact, this % option is an alias for the conjonction of two options: % |renew-dots| and |renew-matrix|.\footnote{The options |renew-dots|, % |renew-matrix| and |transparent| can be fixed with the command % |\NiceMatrixOptions| like the other options. However, they can also be fixed % as options of the command |\usepackage| (it's an exception for these three % specific options.)} % % \smallskip % % \begin{itemize} % \item The option |renew-dots|\par\nobreak % % With this option, the commands |\ldots|, |\cdots|, |\vdots|, |\ddots|, % |\iddots|\footnotemark[\thefniddots] and |\hdotsfor| are redefined within the % environments provided by \pkg{nicematrix} and behave like |\Ldots|, |\Cdots|, % |\Vdots|, |\Ddots|, |\Iddots| and |\Hdotsfor|; the command |\dots| % (``automatic dots'' of |amsmath|) 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{scope} % \NiceMatrixOptions{transparent} % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % ~emphase#\NiceMatrixOptions{transparent}@ % \begin{pmatrix} % 1 & \cdots & \cdots & 1 \\ % 0 & \ddots & & \vdots \\ % \vdots & \ddots & \ddots & \vdots \\ % 0 & \cdots & 0 & 1 % \end{pmatrix} % \end{BVerbatim} % $\begin{pmatrix} % 1 & \cdots & \cdots & 1 \\ % 0 & \ddots & & \vdots \\ % \vdots & \ddots & \ddots & \vdots \\ % 0 & \cdots & 0 & 1 % \end{pmatrix}$ % \end{scope} % % \subsection{The labels of the dotted lines} % % The commands |\Ldots|, |\Cdots|, |\Vdots|, |\Ddots|, |\Iddots| and |\Hdotsfor| % (and the command |\line| in the |code-after| which is described % p.~\pageref{line-in-code-after}) accept two optional arguments specified % by the tokens |_| and |^| for labels positionned below and above the line. The % arguments are composed in math mode with |\scriptstyle|. % % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % $\begin{bNiceMatrix} % 1 & \hspace*{1cm} & 0 \\[8mm] % & ~emphase#\Ddots^{n \text{ times}}@ & \\ % 0 & & 1 \\ % \end{bNiceMatrix}$ % \end{BVerbatim} % $\begin{bNiceMatrix} % 1 & \hspace*{1cm} & 0 \\[8mm] % & \Ddots^{n \text{ times}} & \\ % 0 & & 1 \\ % \end{bNiceMatrix}$ % % \subsection{Customization of the dotted lines} % % \label{customization} % The dotted lines drawn by |\Ldots|, |\Cdots|, |\Vdots|, |\Ddots|, |\Iddots| % and |\Hdotsfor| (and by the command |\line| in the |code-after| which is described % p.~\pageref{line-in-code-after}) may be customized by three options (specified % between square brackets after the command): % \begin{itemize} % \item |color|; % \item |shorten|; % \item |line-style|. % \end{itemize} % % These options may also be fixed with |\NiceMatrixOptions| or at the level of a % given environment but, in those cases, they must be prefixed by |xdots|, and, % thus have for names: % \begin{itemize} % \item |xdots/color|; % \item |xdots/shorten|; % \item |xdots/line-style|. % \end{itemize} % % For the clarity of the explanations, we will use those names. % % \bigskip % \textbf{The option xdots/color}\par\nobreak % % \smallskip % The option |xdots/color| fixes the color or the dotted line. However, one should % remark that the dotted lines drawn in the exterior rows and columns have a % special treatment: cf. p.~\pageref{exterior}. % % \bigskip % \textbf{The option xdots/shorten}\par\nobreak % % \smallskip % The option |xdots/shorten| fixes the margin of both extremities of the line. % The name is derived from the options ``|shorten >|'' and ``|shorten <|'' of % Tikz but one should notice that \pkg{nicematrix} only provides % |xdots/shorten|. The initial value of this parameter is 0.3~em (it is % recommanded to use a unit of length dependent of the current font). % % \bigskip % \textbf{The option xdots/line-style}\par\nobreak % % \smallskip % It should be pointed that, by default, the lines drawn by Tikz with the % parameter |dotted| are composed of square dots (and not rounded % ones).\footnote{The first reason of this behaviour is that the \textsc{pdf} % format includes a description for dashed lines. The lines specified with this % descriptor are displayed very efficiently by the \textsc{pdf} readers. It's % easy, starting from these dashed lines, % to create a line composed by square dots whereas a line of rounded dots needs % a specification of each dot in the \textsc{pdf} file.} % % \begin{BVerbatim}[baseline=c,boxwidth=9cm] % \tikz \draw [dotted] (0,0) -- (5,0) ; % \end{BVerbatim} % \tikz \draw [dotted] (0,0) -- (5,0) ; % % \medskip % In order to provide lines with rounded dots in the style of those provided by % |\ldots| (at least with the \emph{Computer Modern} fonts), the package % \pkg{nicematrix} embeds its own system to draw a dotted line (and this system % uses \textsc{pgf} and not Tikz). This style is called |standard| and that's % the initial value of the parameter |xdots/line-style|. % % However (when Tikz is loaded) it's possible to use for |xdots/line-style| any style % provided by Tikz, that is to say any sequence of options provided by Tikz for % the Tizk pathes (with the exception of ``|color|'', ``|shorten >|'' and % ``|shorten <|''). % % \medskip % Here is for example a tridiagonal matrix with the style |loosely dotted|:\par\nobreak % % \medskip % \begin{BVerbatim}[baseline=c] % $\begin{pNiceMatrix}[nullify-dots,~emphase#xdots/line-style=loosely dotted@] % 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} % % % \[\begin{pNiceMatrix}[nullify-dots,xdots/line-style=loosely dotted] % 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}\] % % % % \section{The PGF/Tikz nodes created by nicematrix} % % \label{name} % % The package \pkg{nicematrix} creates a PGF/Tikz node for each (non-empty) cell % of the considered array. These nodes are used to draw the dotted lines between % the cells of the matrix. However, the user may wish to use directly these % nodes. It's possible (if Tikz has been loaded\footnote{We remind that, since % the version 3.13, \pkg{nicematrix} doesn't load Tikz by default by only % \textsc{pgf} (Tikz is a layer over \textsc{pfg}).}). First, the user have to % give a name to the array (with the key called |name|). Then, the nodes are % accessible through the names ``\textsl{name}-$i$-$j$'' where \textsl{name} is % the name given to the array and $i$ and $j$ the numbers of the row and the % column of the considered cell. % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=11cm] % $\begin{pNiceMatrix}[name=~emphase#mymatrix@] % 1 & 2 & 3 \\ % 4 & 5 & 6 \\ % 7 & 8 & 9 % \end{pNiceMatrix}$ % \tikz[remember picture,overlay] % \draw ~emphase#(mymatrix-2-2)@ circle (2mm) ; % \end{BVerbatim} % $\begin{pNiceMatrix}[name=mymatrix] % 1 & 2 & 3 \\ % 4 & 5 & 6 \\ % 7 & 8 & 9 % \end{pNiceMatrix}$ % \tikz[remember picture,overlay] % \draw (mymatrix-2-2) circle (2mm) ; % % \medskip % Don't forget the options |remember picture| and |overlay|. % % \bigskip % In the following example, we have underlined all the nodes of the matrix. % \[\begin{pNiceMatrix}[ % code-after = {\begin{tikzpicture} % [every node/.style = {blend mode = multiply, % fill = red!15, % inner sep = 0 pt }] % \node [fit = (1-1)] {} ; % \node [fit = (1-3)] {} ; % \node [fit = (2-2)] {} ; % \node [fit = (3-1)] {} ; % \node [fit = (3-3)] {} ; % \node [fit = (1-2)] {} ; % \node [fit = (2-1)] {} ; % \node [fit = (2-3)] {} ; % \node [fit = (3-2)] {} ; % \end{tikzpicture}}] % a & a + b & a + b + c \\ % a & a & a + b \\ % a & a & a % \end{pNiceMatrix}\] % % % \bigskip % In fact, the package \pkg{nicematrix} can create ``extra nodes'': the ``medium % nodes'' and the ``large nodes''. The first ones % are created with the option |create-medium-nodes| and the second ones with the % option |create-large-nodes|.\footnote{There is also an option % |create-extra-nodes| which is an alias for the conjonction of % |create-medium-nodes| and |create-large-nodes|.} % % \medskip % The names of the ``medium nodes'' are constructed by adding the suffix % ``|-medium|'' to the names of the ``normal nodes''. In the following example, % we have underlined the ``medium nodes''. We consider that this example is % self-explanatory. % \[\begin{pNiceMatrix}[ % create-medium-nodes, % code-after = {\begin{tikzpicture} % [every node/.style = {fill = red!15, % blend mode = multiply, % inner sep = 0pt}, % name suffix = -medium] % \node [fit = (1-1)] {} ; % \node [fit = (1-2)] {} ; % \node [fit = (1-3)] {} ; % \node [fit = (2-1)] {} ; % \node [fit = (2-2)] {} ; % \node [fit = (2-3)] {} ; % \node [fit = (3-1)] {} ; % \node [fit = (3-2)] {} ; % \node [fit = (3-3)] {} ; % \end{tikzpicture}}] % a & a + b & a + b + c \\ % a & a & a + b \\ % a & a & a % \end{pNiceMatrix}\] % % % \medskip % The names of the ``large nodes'' are constructed by adding the suffix % ``|-large|'' to the names of the ``normal nodes''. In the following example, % we have underlined the ``large nodes''. We consider that this example is % self-explanatory.\footnote{There is no ``large nodes'' created in the exterior % rows and columns (for these rows and columns, cf. p.~\pageref{exterior}).} % % \[\begin{pNiceMatrix}[ % create-large-nodes, % code-after = {\begin{tikzpicture} % [every node/.style = {blend mode = multiply, % inner sep = 0pt}, % name suffix = -large] % \node [fit = (1-1),fill = red!15] {} ; % \node [fit = (1-3),fill = red!15] {} ; % \node [fit = (2-2),fill = red!15] {} ; % \node [fit = (3-1),fill = red!15] {} ; % \node [fit = (3-3),fill = red!15] {} ; % \node [fit = (1-2),fill = blue!15] {} ; % \node [fit = (2-1),fill = blue!15] {} ; % \node [fit = (2-3),fill = blue!15] {} ; % \node [fit = (3-2),fill = blue!15] {} ; % \end{tikzpicture}}] % a & a + b & a + b + c \\ % a & a & a + b \\ % a & a & a % \end{pNiceMatrix}\] % % % \medskip % The ``large nodes'' of the first column and last column may appear too small % for some usage. That's why it's possible to use the options |left-margin| and % |right-margin| to add space on both sides of the array and also space in the % ``large nodes'' of the first column and last column. In the following example, % we have used the options |left-margin| and |right-margin|.\footnote{The % options |left-margin| and |right-margin| take dimensions as values but, if no % value is given, the default value is used, which is |\arraycolsep| (by % default: 5~pt). There is also an option |margin| to fix both |left-margin| and % |right-margin| to the same value.} % \[\begin{pNiceMatrix}[ % create-large-nodes,left-margin,right-margin, % code-after = {\begin{tikzpicture} % [every node/.style = {blend mode = multiply, % inner sep = 0pt}, % name suffix = -large] % \node [fit = (1-1),fill = red!15] {} ; % \node [fit = (1-3),fill = red!15] {} ; % \node [fit = (2-2),fill = red!15] {} ; % \node [fit = (3-1),fill = red!15] {} ; % \node [fit = (3-3),fill = red!15] {} ; % \node [fit = (1-2),fill = blue!15] {} ; % \node [fit = (2-1),fill = blue!15] {} ; % \node [fit = (2-3),fill = blue!15] {} ; % \node [fit = (3-2),fill = blue!15] {} ; % \end{tikzpicture}}] % a & a + b & a + b + c \\ % a & a & a + b \\ % a & a & a % \end{pNiceMatrix}\] % % \medskip % It's also possible to add more space on both side of the array with the % options |extra-left-margin| and |extra-right-margin|. These margins are not % incorporated in the ``large nodes''. It's possible to fix both values with the % option |extra-margin| and, in the following example, we use |extra-margin| % with the value $3$~pt. % \[\begin{pNiceMatrix}[ % create-large-nodes,margin,extra-margin=3pt, % code-after = {\begin{tikzpicture} % [every node/.style = {blend mode = multiply, % inner sep = 0 pt}, % name suffix = -large] % \node [fit = (1-1),fill = red!15] {} ; % \node [fit = (1-3),fill = red!15] {} ; % \node [fit = (2-2),fill = red!15] {} ; % \node [fit = (3-1),fill = red!15] {} ; % \node [fit = (3-3),fill = red!15] {} ; % \node [fit = (1-2),fill = blue!15] {} ; % \node [fit = (2-1),fill = blue!15] {} ; % \node [fit = (2-3),fill = blue!15] {} ; % \node [fit = (3-2),fill = blue!15] {} ; % \end{tikzpicture}}] % a & a + b & a + b + c \\ % a & a & a + b \\ % a & a & a % \end{pNiceMatrix}\] % % \medskip % In this case, if we want a control over the height of the rows, we can add a % |\strut| in each row of the array. % \[\begin{pNiceMatrix}[ % create-large-nodes,left-margin,right-margin,extra-right-margin=3pt, % extra-left-margin=3pt, % code-after = {\begin{tikzpicture} % [every node/.style = {blend mode = multiply, % inner sep = 0 pt}, % name suffix = -large] % \node [fit = (1-1),fill = red!15] {} ; % \node [fit = (1-3),fill = red!15] {} ; % \node [fit = (2-2),fill = red!15] {} ; % \node [fit = (3-1),fill = red!15] {} ; % \node [fit = (3-3),fill = red!15] {} ; % \node [fit = (1-2),fill = blue!15] {} ; % \node [fit = (2-1),fill = blue!15] {} ; % \node [fit = (2-3),fill = blue!15] {} ; % \node [fit = (3-2),fill = blue!15] {} ; % \end{tikzpicture}}] % \strut a & a + b & a + b + c \\ % \strut a & a & a + b \\ % \strut a & a & a % \end{pNiceMatrix}\] % % \bigskip % We explain below how to fill the nodes created by \pkg{nicematrix} (cf. p. % \pageref{highlight}). % % \section{The code-after} % % \label{code-after} % The option |code-after| may be used to give some code that will be excuted % after the construction of the matrix (and thus after the construction of % all the nodes). % % \smallskip % \textbf{If Tikz is loaded}\footnote{We remind that, since the version 3.13, % \pkg{nicematrix} doesn't load Tikz by default but only \textsc{pgf} (Tikz is a % layer over \textsc{pfg}).}, one may access to that nodes with classical Tikz % instructions. The nodes should be designed as $i$-$j$ (without the prefix % corresponding to the name of the environment). % % Moreover, a special command, called |\line|, is available to draw directly % dotted lines between nodes. It may be used, for example, to draw a dotted line % between two adjacents cells. \label{line-in-code-after} % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=11cm] % \NiceMatrixOptions{xdots/shorten = 0.6 em} % \begin{pNiceMatrix}[~emphase#code-after=\line{2-2}{3-3}@] % I & 0 & \Cdots &0 \\ % 0 & I & \Ddots &\Vdots\\ % \Vdots &\Ddots & I &0 \\ % 0 &\Cdots & 0 &I % \end{pNiceMatrix} % \end{BVerbatim} % \begin{scope} % \NiceMatrixOptions{xdots/shorten = 0.6 em} % $\begin{pNiceMatrix}[code-after=\line{2-2}{3-3}] % I & 0 & \Cdots &0 \\ % 0 & I & \Ddots &\Vdots\\ % \Vdots &\Ddots & I &0 \\ % 0 &\Cdots & 0 &I % \end{pNiceMatrix}$ % \end{scope} % % \medskip % For the readability of the code, an alternative syntax is provided: it's % possible to give the instructions of the |\code-after| at the end of the % environment, after the keyword |\CodeAfter|. % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=11cm] % \NiceMatrixOptions{xdots/shorten = 0.6 em} % \begin{pNiceMatrix} % I & 0 & \Cdots &0 \\ % 0 & I & \Ddots &\Vdots\\ % \Vdots &\Ddots & I &0 \\ % 0 &\Cdots & 0 &I % ~emphase#\CodeAfter@ % ~emphase#\line{2-2}{3-3}@ % \end{pNiceMatrix} % \end{BVerbatim} % \begin{scope} % \NiceMatrixOptions{xdots/shorten = 0.6 em} % $\begin{pNiceMatrix} % I & 0 & \Cdots &0 \\ % 0 & I & \Ddots &\Vdots\\ % \Vdots &\Ddots & I &0 \\ % 0 &\Cdots & 0 &I % \CodeAfter % \line{2-2}{3-3} % \end{pNiceMatrix}$ % \end{scope} % % \section{The environment \{NiceArray\} and its variants} % \label{NiceArray} % % The environment |{NiceArray}| is similar to the environment |{array}|. As for % |{array}|, the mandatory argument is the preamble of the array. However, for % technical reasons, in this preamble, 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. In fact, the column types |w| and |W| are % also redefined.} instead of |l|, |c| and |r|. It's possible % to use the constructions |w{...}{...}|, |W{...}{...}|, "|", |>{...}|, % |<{...}|, |@{...}|, |!{...}| and |*{n}{...}| but the letters |p|, |m| and |b| % should not be used.\footnote{In a command |\multicolumn|, one should also use % the letters |L|, |C|, |R|.} % % \bigskip % The package \pkg{nicematrix} provides also the variants |{pNiceArray}|, %|{vNiceArray}|, |{VNiceArray}|, |{bNiceArray}| and |{BNiceArray}|. % % \bigskip % Of course, one of the benefits of |{pNiceArray}| over |{pNiceMatrix}| is the % possibility of drawing vertical rules: % %\bigskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % $\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} % $\left[\begin{NiceArray}{CCCC|C} % a_1 & ? & \Cdots & ? & ? \\ % 0 & & \Ddots & \Vdots & \Vdots\\ % \Vdots & \Ddots & \Ddots & ? \\ % 0 & \Cdots & 0 & a_n & ? % \end{NiceArray}\right]$ % % \bigskip % Another benefit is the possibility of using different alignments of columns. % % \bigskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % $\begin{pNiceArray}{LCR} % a_{11} & \Cdots & a_{1n} \\ % a_{21} & & a_{2n} \\ % \Vdots & & \Vdots \\ % a_{n-1,1} & \Cdots & a_{n-1,n} % \end{pNiceArray}$ % \end{BVerbatim} % $\begin{pNiceArray}{LCR} % a_{11} & \Cdots & a_{1n} \\ % a_{21} & & a_{2n} \\ % \Vdots & & \Vdots \\ % a_{n-1,1} & \Cdots & a_{n-1,n} % \end{pNiceArray}$ % % % \bigskip % In fact, the environment |{pNiceArray}| and its variants are based upon a % more general environment, called |{NiceArrayWithDelims}|. The first two % mandatory arguments of this environment are the left and right delimiters used % in the construction of the matrix. It's possible to use % |{NiceArrayWithDelims}| if we want to use atypical or asymetrical delimiters. % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=11cm] % $\begin{~emphase#NiceArrayWithDelims@} % {\downarrow}{\uparrow}{CCC}[margin] % 1 & 2 & 3 \\ % 4 & 5 & 6 \\ % 7 & 8 & 9 \\ % \end{~emphase#NiceArrayWithDelims@}$ % \end{BVerbatim} % $\begin{NiceArrayWithDelims} % {\downarrow}{\uparrow}{CCC}[margin] % 1 & 2 & 3 \\ % 4 & 5 & 6 \\ % 7 & 8 & 9 \\ % \end{NiceArrayWithDelims}$ % % % \bigskip % \section{The vertical position of the arrays} % % The package \pkg{nicematrix} provides a option |baseline| for the vertical % position of the arrays. This option takes as value an integer which is the % number of the row on which the array will be aligned. % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=9cm] % $A = \begin{pNiceMatrix}[baseline=2] % \frac{1}{\sqrt{1+p^2}} & p & 1-p \\ % 1 & 1 & 1 \\ % 1 & p & 1+p % \end{pNiceMatrix}$ % \end{BVerbatim} % $A = \begin{pNiceMatrix}[baseline=2] % \frac{1}{\sqrt{1+p^2}} & p & 1-p \\ % 1 & 1 & 1 \\ % 1 & p & 1+p % \end{pNiceMatrix}$ % % % \medskip % It's also possible to use the option |baseline| with one of the special values % |t|, |c| or |b|. These letters may also be used absolutely like the option of % the environment |{array}| of \pkg{array}. The initial value of |baseline| is~|c|. % % % \medskip % In the following example, we use the option |t| (equivalent to |baseline=t|) % immediately after an |\item| of list. One should remark that the presence of % a |\hline| at the beginning of the array doesn't prevent the alignment of the % baseline with the baseline of the first row (with |{array}| of \pkg{array}, % one must use |\firsthline|\footnote{It's also possible to use |\firsthline| % with |{NiceArray}|.}). % % \smallskip % \begin{BVerbatim}[baseline=c,boxwidth=9cm] % \begin{enumerate} % \item an item % \smallskip % \item \renewcommand{\arraystretch}{1.2} % $\begin{NiceArray}~emphase#[t]@{LCCCCCC} % \hline % n & 0 & 1 & 2 & 3 & 4 & 5 \\ % u_n & 1 & 2 & 4 & 8 & 16 & 32 % \hline % \end{NiceArray}$ % \end{enumerate} % \end{BVerbatim} % \begin{minipage}{5cm} % \begin{enumerate} % \item an item % \smallskip % \item \renewcommand{\arraystretch}{1.2} % $\begin{NiceArray}[t]{LCCCCCC} % \hline % n & 0 & 1 & 2 & 3 & 4 & 5 \\ % u_n & 1 & 2 & 4 & 8 & 16 & 32 \\ % \hline % \end{NiceArray}$ % \end{enumerate} % \end{minipage} % % \medskip % However, it's also possible to use the tools of \pkg{booktabs}: |\toprule|, % |\bottomrule| and |\midrule|.\par\nobreak % % \smallskip % \begin{BVerbatim}[baseline=c,boxwidth=9cm] % \begin{enumerate} % \item an item % \smallskip % \item % $\begin{NiceArray}[t]{LCCCCCC} % ~emphase#\toprule@ % n & 0 & 1 & 2 & 3 & 4 & 5 \\ % ~emphase#\midrule@ % u_n & 1 & 2 & 4 & 8 & 16 & 32 % ~emphase#\bottomrule@ % \end{NiceArray}$ % \end{enumerate} % \end{BVerbatim} % \begin{minipage}{5cm} % \begin{enumerate} % \item an item % \smallskip % \item % $\begin{NiceArray}[t]{LCCCCCC} % \toprule % n & 0 & 1 & 2 & 3 & 4 & 5 \\ % \midrule % u_n & 1 & 2 & 4 & 8 & 16 & 32 \\ % \bottomrule % \end{NiceArray}$ % \end{enumerate} % \end{minipage} % % % \bigskip % \section{The exterior rows and columns} % The options |first-row|, |last-row|, |first-col| and |last-col| allow the % composition of exterior rows and columns in the environments of % \pkg{nicematrix}. % \label{exterior} % % A potential ``first row'' (exterior) has the number $0$ (and not $1$). Idem % for the potential ``first column''. % % \begin{Verbatim} % $\begin{pNiceMatrix}[~emphase#first-row,last-row,first-col,last-col@] % $\begin{pNiceMatrix}[~emphase#first-row,last-row,first-col,last-col@,nullify-dots] % & C_1 & \Cdots & & C_4 & \\ % L_1 & a_{11} & a_{12} & a_{13} & a_{14} & L_1 \\ % \Vdots & a_{21} & a_{22} & a_{23} & a_{24} & \Vdots \\ % & a_{31} & a_{32} & a_{33} & a_{34} & \\ % L_4 & a_{41} & a_{42} & a_{43} & a_{44} & L_4 \\ % & C_1 & \Cdots & & C_4 & % \end{pNiceMatrix}$ % \end{pNiceMatrix}$ % \end{Verbatim} % % \[\begin{pNiceMatrix}[first-row,last-row,first-col,last-col,nullify-dots] % & C_1 & \Cdots & & C_4 & \\ % L_1 & a_{11} & a_{12} & a_{13} & a_{14} & L_1 \\ % \Vdots & a_{21} & a_{22} & a_{23} & a_{24} & \Vdots \\ % & a_{31} & a_{32} & a_{33} & a_{34} & \\ % L_4 & a_{41} & a_{42} & a_{43} & a_{44} & L_4 \\ % & C_1 & \Cdots & & C_4 & % \end{pNiceMatrix}\] % % % \bigskip % We have several remarks to do. % \begin{itemize} % \item For the environments with an explicit preamble (i.e. |{NiceArray}| and % its variants), no letter must be given in that preamble for the potential % first column and the potential last column: they will automatically (and % necessarily) be of type |R| for the first column and |L| for the last one. % \item One may wonder how \pkg{nicematrix} determines the number of rows and % columns which are needed for the composition of the ``last row'' and ``last % column''. % \begin{itemize} % \item For the environments with explicit preamble, like |{NiceArray}| and % |{pNiceArray}|, the number of columns can obviously be computed from the % preamble. % % \item When the option |light-syntax| (cf. p. \pageref{light-syntax}) is used, % \pkg{nicematrix} has, in any case, to load the whole body of the environment % (and that's why it's not possible to put verbatim material in the array with % the option |light-syntax|). The analysis of this whole body gives the number % of rows (but not the number of columns). % % \item In the other cases, \pkg{nicematrix} compute the number of rows and % columns during the first compilation and write the result in the |aux| file % for the next run. % % \textsl{However, it's possible to provide the number of the last row and the number of % the last column as values of the options |last-row| and |last-col|, tending to % an acceleration of the whole compilation of the document.} That's what we will % do throughout the rest of the document. % \end{itemize} % \end{itemize} % % \bigskip % It's possible to control the appearance of these rows and columns with options % |code-for-first-row|, |code-for-last-row|, |code-for-first-col| and % |code-for-last-col|. These options % specify tokens that will be inserted before each cell of the corresponding row % or column. % % % \begin{Verbatim} % \NiceMatrixOptions{~emphase#code-for-first-row@ = \color{red}, % ~emphase#code-for-first-col@ = \color{blue}, % ~emphase#code-for-last-row@ = \color{green}, % ~emphase#code-for-last-col@ = \color{magenta}} % $\begin{pNiceArray}{CC|CC}[first-row,last-row=5,first-col,last-col,nullify-dots] % & C_1 & \Cdots & & C_4 & \\ % L_1 & a_{11} & a_{12} & a_{13} & a_{14} & L_1 \\ % \Vdots & a_{21} & a_{22} & a_{23} & a_{24} & \Vdots \\ % \hline % & a_{31} & a_{32} & a_{33} & a_{34} & \\ % L_4 & a_{41} & a_{42} & a_{43} & a_{44} & L_4 \\ % & C_1 & \Cdots & & C_4 & % \end{pNiceArray}$ % \end{Verbatim} % % \begin{scope} % \NiceMatrixOptions{code-for-first-row = \color{red}, % code-for-first-col = \color{blue}, % code-for-last-row = \color{green}, % code-for-last-col = \color{magenta}} % \begin{displaymath} % \begin{pNiceArray}{CC|CC}[first-row,last-row=5,first-col,last-col,nullify-dots] % & C_1 & \multicolumn1C{\Cdots} & & C_4 & \\ % L_1 & a_{11} & a_{12} & a_{13} & a_{14} & L_1 \\ % \Vdots & a_{21} & a_{22} & a_{23} & a_{24} & \Vdots \\ % \hline % & a_{31} & a_{32} & a_{33} & a_{34} & \\ % L_4 & a_{41} & a_{42} & a_{43} & a_{44} & L_4 \\ % & C_1 & \multicolumn1C{\Cdots} & & C_4 & % \end{pNiceArray} % \end{displaymath} % \end{scope} % % % \emph{Remarks} % \begin{itemize}[beginpenalty=10000] % \item As shown in the previous example, an horizontal rule (drawn by |\hline|) % doesn't extend in the exterior columns and a vertical rule (specified by a % ``\verb+|+'' in the preamble of the array) doesn't extend in the exterior % rows.\footnote{The latter is not true when the package \pkg{arydshln} is % loaded besides \pkg{nicematrix}. In fact, \pkg{nicematrix} and \pkg{arydhsln} % are not totally compatible because \pkg{arydshln} redefines many internals of % \pkg{array}. On another hand, if one really wants a vertical rule running in % the first and in the last row, he should use |!{\vline}| instead of \verb+|+ % in the preamble of the array.} % % If one wishes to define new specifiers for columns in order to draw vertical % rules (for example thicker than the standard rules), he should consider the % command |\OnlyMainNiceMatrix| described on page~\pageref{OnlyMainNiceMatrix}. % % \item A specification of color present in |code-for-first-row| also applies to % a dotted line draw in this exterior ``first row'' (excepted if a value has % been given to |xdots/color|). Idem for the other exterior rows and columns. % % \item Logically, the potential option |columns-width| (described % p.~\pageref{width}) doesn't apply to the ``first column'' and ``last column''. % \item For technical reasons, it's not possible to use the option of the % command |\\| after the ``first row'' or before the ``last row'' (the placement % of the delimiters would be wrong). % \end{itemize} % % % % % % \section{The dotted lines to separate rows or columns} % % % In the environments of the package \pkg{nicematrix}, it's possible to use % the command |\hdottedline| (provided by \pkg{nicematrix}) which is a % counterpart of the classical commands |\hline| and |\hdashline| (the latter is % a command of \pkg{arydshln}). % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=9.5cm] % \begin{pNiceMatrix} % 1 & 2 & 3 & 4 & 5 \\ % ~emphase#\hdottedline@ % 6 & 7 & 8 & 9 & 10 \\ % 11 & 12 & 13 & 14 & 15 % \end{pNiceMatrix} % \end{BVerbatim} % $\begin{pNiceMatrix} % 1 & 2 & 3 & 4 & 5 \\ % \hdottedline % 6 & 7 & 8 & 9 & 10 \\ % 11 & 12 & 13 & 14 & 15 % \end{pNiceMatrix}$ % % % \bigskip % In the environments with an explicit preamble (like |{NiceArray}|, etc.), it's % possible to draw a vertical dotted line with the specifier ``|:|''. % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=9.5cm] % \left(\begin{NiceArray}{CCCC~emphase#:@C} % 1 & 2 & 3 & 4 & 5 \\ % 6 & 7 & 8 & 9 & 10 \\ % 11 & 12 & 13 & 14 & 15 % \end{NiceArray}\right) % \end{BVerbatim} % $\left(\begin{NiceArray}{CCCC:C} % 1 & 2 & 3 & 4 & 5 \\ % 6 & 7 & 8 & 9 & 10 \\ % 11 & 12 & 13 & 14 & 15 % \end{NiceArray}\right)$ % % % \bigskip % These dotted lines do \emph{not} extend in the potential exterior rows and % columns. % % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=9.5cm] % $\begin{pNiceArray}{CCC:C}[ % first-row,last-col, % code-for-first-row = \color{blue}\scriptstyle, % code-for-last-col = \color{blue}\scriptstyle ] % C_1 & C_2 & C_3 & C_4 \\ % 1 & 2 & 3 & 4 & L_1 \\ % 5 & 6 & 7 & 8 & L_2 \\ % 9 & 10 & 11 & 12 & L_3 \\ % \hdottedline % 13 & 14 & 15 & 16 & L_4 % \end{pNiceArray}$ % \end{BVerbatim} % $\begin{pNiceArray}{CCC:C}[ % first-row,last-col, % code-for-first-row = \color{blue}\scriptstyle, % code-for-last-col = \color{blue}\scriptstyle ] % C_1 & C_2 & C_3 & C_4 \\ % 1 & 2 & 3 & 4 & L_1 \\ % 5 & 6 & 7 & 8 & L_2 \\ % 9 & 10 & 11 & 12 & L_3 \\ % \hdottedline % 13 & 14 & 15 & 16 & L_4 % \end{pNiceArray}$ % % \bigskip % It's possible to change in \pkg{nicematrix} the letter used to specify a % vertical dotted line with the option |letter-for-dotted-lines| available in % |\NiceMatrixOptions|. For example, in this document, we have loaded the % package \pkg{arydshln} which uses the letter ``|:|'' to specify a vertical % dashed line. Thus, by using |letter-for-dotted-lines|, we can use the % vertical lines of both \pkg{arydshln} and \pkg{nicematrix}. % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=9.5cm] % \NiceMatrixOptions{letter-for-dotted-lines = I} % \arrayrulecolor{blue} % \left(\begin{NiceArray}{~emphase#C|C:CIC@} % 1 & 2 & 3 & 4 \\ % 5 & 6 & 7 & 8 \\ % 9 & 10 & 11 & 12 % \end{NiceArray}\right) % \arrayrulecolor{black} % \end{BVerbatim} % \begin{scope} % \NiceMatrixOptions{letter-for-dotted-lines = I} % \arrayrulecolor{blue} % $\left(\begin{NiceArray}{C|C:CIC} % 1 & 2 & 3 & 4 \\ % 5 & 6 & 7 & 8 \\ % 9 & 10 & 11 & 12 % \end{NiceArray}\right)$ % \arrayrulecolor{black} % \end{scope} % % \smallskip % We have used the command |\arrayrulecolor| (de \pkg{colortbl}) to draw in blue % the three rules. % % \bigskip % \emph{Remark} : In the package \pkg{array} (on which the package % \pkg{nicematrix} relies), horizontal and vertical rules make the array larger % or wider by a quantity equal to the width of the rule\footnote{In fact, this % is true only for |\hline| and ``"|"'' but not for |\cline|.}. In % \pkg{nicematrix}, the dotted lines drawn by |\hdottedline| and ``|:|'' do % likewise. % % % % \section{The width of the columns} % \label{width} % % In the environments with an explicit preamble (like |{NiceArray}|, % |{pNiceArray}|, etc.), it's possible to fix the width of a given column with % the standard letters |w| and |W| of the package \pkg{array}. In the % environments of \pkg{nicematrix}, the cells of such columns are composed in % mathematical mode, whereas, in |{array}| of \pkg{array}, they are composed in % text mode. % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % $\left(\begin{NiceArray}{~emphase#wc{1cm}@CC} % 1 & 12 & -123 \\ % 12 & 0 & 0 \\ % 4 & 1 & 2 % \end{NiceArray}\right)$ % \end{BVerbatim} % $\left(\begin{NiceArray}{wc{1cm}CC} % 1 & 12 & -123 \\ % 12 & 0 & 0 \\ % 4 & 1 & 2 % \end{NiceArray}\right)$ % % % \bigskip % In the environments of \pkg{nicematrix}, it's also possible to fix the \emph{minimal} % width of all the columns of a matrix directly with the option |columns-width|. % % \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 (of course, it's possible to suppress this space by setting % |\arraycolsep| equal to $0$~pt). % % \bigskip % It's possible to give the special 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.\footnote{The result is achieved with only one compilation (but Tikz % will have written informations in the |.aux| file and a message requiring a % second compilation will appear).}\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} % $\begin{pNiceMatrix}[columns-width = auto] % 1 & 12 & -123 \\ % 12 & 0 & 0 \\ % 4 & 1 & 2 % \end{pNiceMatrix}$ % % \bigskip % Without surprise, it's possible to fix the minimal width of the columns of all % the matrices of a current scope with the command % |\NiceMatrixOptions|.\par\nobreak % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=8.5cm] % ~emphase#\NiceMatrixOptions{columns-width=10mm}@ % $\begin{pNiceMatrix} % a & b \\ c & d \\ % \end{pNiceMatrix} % = % \begin{pNiceMatrix} % 1 & 1245 \\ 345 & 2 \\ % \end{pNiceMatrix}$ % \end{BVerbatim} % \begin{scope} % \NiceMatrixOptions{columns-width=10mm} % $\begin{pNiceMatrix} % a & b \\ % c & d \\ % \end{pNiceMatrix} % = % \begin{pNiceMatrix} % 1 & 1245 \\ % 345 & 2 \\ % \end{pNiceMatrix}$ % \end{scope} % % % \bigskip % But it's also possible to fix a zone where all the matrices will have their % columns of the same width, equal to the widest cell of all the matrices. This % construction uses the environment |{NiceMatrixBlock}| with the option % |auto-columns-width|\footnote{At this time, this is the only usage of the % environment |{NiceMatrixBlock}| but it may have other usages in the future.}. % The environment |{NiceMatrixBlock}| has no direct link with the command % |\Block| presented just below (cf.~p.~\pageref{Block}). % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=8.5cm] % ~emphase#\begin{NiceMatrixBlock}[auto-columns-width]@ % $\begin{pNiceMatrix} % a & b \\ c & d \\ % \end{pNiceMatrix} % = % \begin{pNiceMatrix} % 1 & 1245 \\ 345 & 2 \\ % \end{pNiceMatrix}$ % ~emphase#\end{NiceMatrixBlock}@ % \end{BVerbatim} % \begin{NiceMatrixBlock}[auto-columns-width] % $\begin{pNiceMatrix} % a & b \\ c & d \\ % \end{pNiceMatrix} % = % \begin{pNiceMatrix} % 1 & 1245 \\ 345 & 2 \\ % \end{pNiceMatrix}$ % \end{NiceMatrixBlock} % % \medskip % \textbf{Several compilations may be necessary to achieve the job.} % % % \section{Block matrices} % \label{Block} % % This section has no direct link with the previous one where an environment % |{NiceMatrixBlock}| was introduced. % % In the environments of \pkg{nicematrix}, it's possible to use the command % |\Block| in order to place an element in the center of a rectangle of merged % cells of the array. % % The command |\Block| must be used in the upper leftmost cell of the array with % two arguments. The first argument is the size of the block with the syntax % $i$\verb|-|$j$ where $i$ is the number of rows of the block and $j$ its number % of columns. The second argument is the content of the block (composed in math % mode). A Tikz node corresponding to the merged cells is created with the name % ``$i$-$j$-block''. If the user has required the creation of the ``medium % nodes'', a node of this type is also created with a name suffixed by % |-medium|. % % \medskip % In the following examples, we use the command |\arrayrulecolor| of % \pkg{colortbl}. % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=10.6cm] % \arrayrulecolor{blue} % $\begin{bNiceArray}{CCC|C}[margin] % ~emphase#\Block{3-3}{A}@ & & & 0 \\ % & \hspace*{1cm} & & \Vdots \\ % & & & 0 \\ % \hline % 0 & \Cdots& 0 & 0 % \end{bNiceArray}$ % \arrayrulecolor{black} % \end{BVerbatim} % \begin{scope} % \arrayrulecolor{blue} % $\begin{bNiceArray}{CCC|C}[margin] % \Block{3-3}{A} & & & 0 \\ % & \hspace*{1cm} & & \Vdots \\ % & & & 0 \\ % \hline % 0 & \Cdots& 0 & 0 % \end{bNiceArray}$ % \arrayrulecolor{black} % \end{scope} % % \bigskip % One may wish to raise the size of the ``$A$'' placed in the block of the % previous example. Since this element is composed in math mode, it's not % possible to use directly a command like |\large|, |\Large| and |\LARGE|. % That's why the command |\Block| provides an option between angle brackets to % specify some TeX code which will be inserted before the beginning of the % math mode. % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=10.6cm] % \arrayrulecolor{blue} % $\begin{bNiceArray}{CCC|C}[margin] % \Block{3-3}~emphase#<\Large>@{A} & & & 0 \\ % & \hspace*{1cm} & & \Vdots \\ % & & & 0 \\ % \hline % 0 & \Cdots& 0 & 0 % \end{bNiceArray}$ % \arrayrulecolor{black} % \end{BVerbatim} % \begin{scope} % \arrayrulecolor{blue} % $\begin{bNiceArray}{CCC|C}[margin] % \Block{3-3}<\Large>{A} & & & 0 \\ % & \hspace*{1cm} & & \Vdots \\ % & & & 0 \\ % \hline % 0 & \Cdots& 0 & 0 % \end{bNiceArray}$ % \arrayrulecolor{black} % \end{scope} % % \medskip % For technical reasons, you can't write |\Block{|$i$|-|$j$|}{<}|. But you can % write |\Block{|$i$|-|$j$|}<>{<}| with the expected result. % % % \section{Advanced features} % % % \subsection{Alignement option in NiceMatrix} % % The environments without preamble (|{NiceMatrix}|, |{pNiceMatrix}|, % |{bNiceMatrix}|, etc.) provide two options |l| and |r| (equivalent at |L| and % |R|) which generate all the columns aligned leftwards (or % rightwards).\footnote{This is a part of the functionality provided by the % environments |{pmatrix*}|, |{bmatrix*}|, etc. of \pkg{mathtools}.} % % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % $\begin{bNiceMatrix}[R] % \cos x & - \sin x \\ % \sin x & \cos x % \end{bNiceMatrix}$ % \end{BVerbatim} % $\begin{bNiceMatrix}[R] % \cos x & - \sin x \\ % \sin x & \cos x % \end{bNiceMatrix}$ % % % \subsection{The command \textbackslash rotate} % % The package \pkg{nicematrix} provides a command |\rotate|. When used in the % beginning of a cell, this command composes the contents of the cell after a % rotation of 90° in the direct sens. % % In the following command, we use that command in the |code-for-first-row|. % %\bigskip % %\begin{BVerbatim}[baseline=c,boxwidth=12cm] % \NiceMatrixOptions% % {code-for-first-row = \scriptstyle ~emphase#\rotate@ \text{image of }, % code-for-last-col = \scriptstyle } % $A = \begin{pNiceMatrix}[first-row,last-col=4] % e_1 & e_2 & e_3 \\ % 1 & 2 & 3 & e_1 \\ % 4 & 5 & 6 & e_2 \\ % 7 & 8 & 9 & e_3 \\ % \end{pNiceMatrix}$ % \end{BVerbatim} % \begin{varwidth}{10cm} % \NiceMatrixOptions% % {code-for-first-row = \scriptstyle\rotate \text{image of }, % code-for-last-col = \scriptstyle } % $ A = \begin{pNiceMatrix}[first-row,last-col=4] % e_1 & e_2 & e_3 \\ % 1 & 2 & 3 & e_1 \\ % 4 & 5 & 6 & e_2 \\ % 7 & 8 & 9 & e_3 \\ % \end{pNiceMatrix}$ % \end{varwidth} % % \bigskip % If the command |\rotate| is used in the ``last row'' (exterior to the matrix), % the corresponding elements are aligned upwards as shown below. % % \bigskip % \begin{BVerbatim}[baseline=c,boxwidth=12cm] % \NiceMatrixOptions% % {code-for-last-row = \scriptstyle ~emphase#\rotate@ , % code-for-last-col = \scriptstyle } % $A = \begin{pNiceMatrix}[last-row=4,last-col=4] % 1 & 2 & 3 & e_1 \\ % 4 & 5 & 6 & e_2 \\ % 7 & 8 & 9 & e_3 \\ % \text{image of } e_1 & e_2 & e_3 \\ % \end{pNiceMatrix}$ % \end{BVerbatim} % \begin{varwidth}{10cm} % \NiceMatrixOptions% % {code-for-last-row = \scriptstyle\rotate , % code-for-last-col = \scriptstyle }% % $A = \begin{pNiceMatrix}[last-row=4,last-col=4] % 1 & 2 & 3 & e_1 \\ % 4 & 5 & 6 & e_2 \\ % 7 & 8 & 9 & e_3 \\ % \text{image of } e_1 & e_2 & e_3 \\ % \end{pNiceMatrix}$ % \end{varwidth} % % % % \subsection{The option small} % % \label{small} % % With the option |small|, the environments of the package \pkg{nicematrix} % are composed in a way similar to the environment |{smallmatrix}| of the % package \pkg{amsmath} (and the environments |{psmallmatrix}|, % |{bsmallmatrix}|, etc. of the package \pkg{mathtools}). % % \bigskip % \begin{Verbatim} % $\begin{bNiceArray}{CCCC|C}[~emphase#small@, % last-col, % code-for-last-col = \scriptscriptstyle, % columns-width = 3mm ] % 1 & -2 & 3 & 4 & 5 \\ % 0 & 3 & 2 & 1 & 2 & L_2 \gets 2 L_1 - L_2 \\ % 0 & 1 & 1 & 2 & 3 & L_3 \gets L_1 + L_3 \\ % \end{bNiceArray}$ % \end{Verbatim} % % % \[\begin{bNiceArray}{CCCC|C}[small, last-col, % code-for-last-col = \scriptscriptstyle, % columns-width=3mm] % 1 & -2 & 3 & 4 & 5 \\ % 0 & 3 & 2 & 1 & 2 & L_2 \gets 2 L_1 - L_2 \\ % 0 & 1 & 1 & 2 & 3 & L_3 \gets L_1 + L_3 \\ % \end{bNiceArray}\] % % % % \bigskip % One should note that the environment |{NiceMatrix}| with the option |small| is % not composed \emph{exactly} as the environment |{smallmatrix}|. Indeed, all % the environments of \pkg{nicematrix} are constructed upon |{array}| (of the % package \pkg{array}) whereas the environment |{smallmatrix}| is constructed % directly with an |\halign| of TeX. % % \medskip % In fact, the option |small| corresponds to the following tuning: % \begin{itemize} % \item the cells of the array are composed with \verb|\scriptstyle|; % \item \verb|\arraystretch| is set to $0.47$; % \item \verb|\arraycolsep| is set to $1.45$~pt; % \item the characteristics of the dotted lines are also modified. % \end{itemize} % % \subsection{The counters iRow and jCol} % % In the cells of the array, it's possible to use the LaTeX counters |iRow| and % |jCol| which represent the number of the current row and the number of the % current column\footnote{We recall that the exterior ``first row'' (if it % exists) has the number~$0$ and that the exterior ``first column'' (if it % exists) has also the number~$0$.}. Of course, the user must not change the % value of these counters which are used internally by \pkg{nicematrix}. % % In the |code-after| (cf. p. \pageref{code-after}), |iRow| represents the total % number of rows (excepted the potential exterior rows) and |jCol| represents % the total number of columns (excepted the potential exterior columns). % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=10.6cm] % $\begin{pNiceMatrix}% don't forget the % % [first-row, % first-col, % code-for-first-row = \mathbf{~emphase#\alph{jCol}@} , % code-for-first-col = \mathbf{~emphase#\arabic{iRow}@} ] % & & & & \\ % & 1 & 2 & 3 & 4 \\ % & 5 & 6 & 7 & 8 \\ % & 9 & 10 & 11 & 12 % \end{pNiceMatrix}$ % \end{BVerbatim} % $\begin{pNiceMatrix}[first-row, % first-col, % code-for-first-row = \mathbf{\alph{jCol}} , % code-for-first-col = \mathbf{\arabic{iRow}} ] % & & & & \\ % & 1 & 2 & 3 & 4 \\ % & 5 & 6 & 7 & 8 \\ % & 9 & 10 & 11 & 12 % \end{pNiceMatrix}$ % % \medskip % If LaTeX counters called |iRow| and |jCol| are defined in the document by % packages other than \pkg{nicematrix} (or by the user), they are shadowed in % the environments of \pkg{nicematrix}. % % \bigskip % The package \pkg{nicematrix} also provides commands in order to compose % automatically matrices from a general pattern. These commands are % |\pAutoNiceMatrix|, |\bAutoNiceMatrix|, |\vAutoNiceMatrix|, % |\VAutoNiceMatrix| and |\BAutoNiceMatrix|. % % These commands take two mandatory arguments. The first is the format of the % matrix, with the syntax $n$-$p$ where $n$ is the number of rows and $p$ the % number of columns. The second argument is the pattern (it's a list of tokens % which are inserted in each cell of the constructed matrix, excepted in the % cells of the eventual exterior rows and columns). % % \medskip % \begin{Verbatim} % $C = ~emphase#\pAutoNiceMatrix@{3-3}{C_{\arabic{iRow},\arabic{jCol}}}$ % \end{Verbatim} % % % $C = \pAutoNiceMatrix{3-3}{C_{\arabic{iRow},\arabic{jCol}}}$ % % \subsection{The options hlines, vlines and hvlines} % % \label{hvlines} % You can add horizontal rules between rows in the environments of % \pkg{nicematrix} with the usual command |\hline| and you can use the specifier % ``"|"'' to add vertical rules. However, by convenience, the package % \pkg{nicematrix} also provides the option |hlines| (resp. |vlines|) which will % draw all the horizontal (resp. vertical) rules (excepted, of course, the % exterior rules corresponding to the exterior rows and columns). The key % |hvlines| is an alias for the conjonction for the keys |hlines| et |vlines|. % % % \medskip % In the following example, we use the command |\arrayrulecolor| of % \pkg{colortbl}. % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=11cm] % \arrayrulecolor{blue} % $\begin{NiceArray}{CCCC}% % [~emphase#hvlines@,first-row,first-col] % % & e & a & b & c \\ % e & e & a & b & c \\ % a & a & e & c & b \\ % b & b & c & e & a \\ % c & c & b & a & e % \end{NiceArray}$ % \arrayrulecolor{black} % \end{BVerbatim} % \arrayrulecolor{blue} % $\begin{NiceArray}{CCCC}[hvlines,first-row,first-col] % & e & a & b & c \\ % e & e & a & b & c \\ % a & a & e & c & b \\ % b & b & c & e & a \\ % c & c & b & a & e % \end{NiceArray}$ % \arrayrulecolor{black} % % \bigskip % However, there is a difference between the key |vlines| and the use of % the specifier ``"|"'' in the preamble of the environment: the rules drawn by % |vlines| completely cross the double-rules drawn by |\hline\hline|. % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=11.5cm] % $\begin{NiceArray}{CCCC}[vlines] \hline % a & b & c & d \\ \hline \hline % 1 & 2 & 3 & 4 \\ % 1 & 2 & 3 & 4 \\ \hline % \end{NiceArray}$ % \end{BVerbatim} % $\begin{NiceArray}{CCCC}[vlines] % \hline % a & b & c & d \\ % \hline \hline % 1 & 2 & 3 & 4 \\ % 1 & 2 & 3 & 4 \\ % \hline % \end{NiceArray}$ % % \bigskip % For the environments with delimiters (for example |{pNiceArray}| or % |{pNiceMatrix}|), the option |vlines| don't draw vertical rules on both sides, % where are the delimiters (fortunately). % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=10.6cm] % \setlength{\arrayrulewidth}{0.2pt} % $\begin{pNiceMatrix}[vlines] % 1 & 2 & 3 & 4 & 5 & 6 \\ % 1 & 2 & 3 & 4 & 5 & 6 \\ % 1 & 2 & 3 & 4 & 5 & 6 \\ % \end{pNiceMatrix}$ % \end{BVerbatim} % \begin{scope} % \setlength{\arrayrulewidth}{0.2pt} % $\begin{pNiceMatrix}[vlines] % 1 & 2 & 3 & 4 & 5 & 6 \\ % 1 & 2 & 3 & 4 & 5 & 6 \\ % 1 & 2 & 3 & 4 & 5 & 6 \\ % \end{pNiceMatrix}$ % \end{scope} % % % \subsection{The option light-syntax} % % \label{light-syntax} % The option |light-syntax|\footnote{This option is inspired by the package % \pkg{spalign} of Joseph Rabinoff.} allows the user to compose the arrays with a % lighter syntax, which gives a more readable TeX source. % % When this option is used, one should use the semicolon for the end of a row % and spaces or tabulations to separate the columns. However, as usual in the % TeX world, the spaces after a control sequence are discarded and the elements % between curly braces are considered as a whole. % % \bigskip % The following example has been composed with XeLaTeX with \pkg{unicode-math}, % which allows the use of greek letters directly in the TeX source. % % \medskip % \begin{scope} % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % $\begin{bNiceMatrix}[~emphase#light-syntax@,first-row,first-col] % {} a b ; % a 2\cos a {\cos a + \cos b} ; % b \cos a+\cos b { 2 \cos b } % \end{bNiceMatrix}$ % \end{BVerbatim} % \end{scope} % $\begin{bNiceMatrix}[light-syntax,first-row,first-col] % {} a b ; % a 2\cos a {\cos a + \cos b} ; % b \cos a+\cos b { 2 \cos b } % \end{bNiceMatrix}$ % % \medskip % It's possible to change the character used to mark the end of rows with the % option |end-of-row|. As said before, the initial value is a semicolon. % % \medskip % When the option |light-syntax| is used, it is not possible to put verbatim % material (for example with the command |\verb|) in the cells of the % array.\footnote{The reason is that, when the option |light-syntax| is used, % the whole content of the environment is loaded as a TeX argument to be % analyzed. The environment doesn't behave in that case as a standard % environment of LaTeX which only put TeX commands before and after the content.} % % \subsection{Use of the column type S of siunitx} % % If the package \pkg{siunitx} is loaded (before or after \pkg{nicematrix}), % it's possible to use the |S| column type of \pkg{siunitx} in the environments % of \pkg{nicematrix}. The implementation doesn't use explicitly any private % macro of \pkg{siunitx}. % % % \medskip % \begin{BVerbatim}[baseline = c, boxwidth = 10.5cm] % $\begin{pNiceArray}{~emphase#S@CWc{1cm}C}[nullify-dots,first-row] % {C_1} & \Cdots & & C_n \\ % 2.3 & 0 & \Cdots & 0 \\ % 12.4 & \Vdots & & \Vdots \\ % 1.45 \\ % 7.2 & 0 & \Cdots & 0 % \end{pNiceArray}$ % \end{BVerbatim} % $\begin{pNiceArray}{SCWc{1cm}C}[nullify-dots,first-row] % {C_1} & \Cdots & & C_n \\ % 2.3 & 0 & \Cdots & 0 \\ % 12.4 & \Vdots & & \Vdots \\ % 1.45 \\ % 7.2 & 0 & \Cdots & 0 % \end{pNiceArray}$ % % \medskip % On the other hand, the |d| columns of the package \pkg{dcolumn} are not % supported by \pkg{nicematrix}. % % % % \section{Technical remarks} % % \subsection{Definition of new column types} % % \label{OnlyMainNiceMatrix} % % The package \pkg{nicematrix} provides the command |\OnlyMainNiceMatrix| % which is meant to be used in definitions of new column types. Its argument is % evaluated if and only if we are in the main part of the array, that is to say % not in an eventual exterior row. % % For example, one may wish to define a new column type |?| in order to draw a % (black) heavy rule of width 1~pt. The following definition will do the % job\footnote{The command |\vrule| is a TeX (and not LaTeX) command.}: % % \begin{Verbatim} % \newcolumntype{?}{!{\OnlyMainNiceMatrix{\vrule width 1 pt}}} % \end{Verbatim} % % The heavy vertical rule won't extend in the exterior rows: % \medskip % \begin{scope} % \newcolumntype{?}{!{\OnlyMainNiceMatrix{\vrule width 1 pt}}} % % \begin{BVerbatim}[baseline = c, boxwidth = 10.5cm] % $\begin{pNiceArray}{CC?CC}[first-row,last-row=3] % C_1 & C_2 & C_3 & C_4 \\ % a & b & c & d \\ % e & f & g & h \\ % C_1 & C_2 & C_3 & C_4 % \end{pNiceArray}$ % \end{BVerbatim} % $\begin{pNiceArray}{CC?CC}[first-row,last-row=3] % C_1 & C_2 & C_3 & C_4 \\ % a & b & c & d \\ % e & f & g & h \\ % C_1 & C_2 & C_3 & C_4 % \end{pNiceArray}$ % \end{scope} % % \medskip % The specifier |?| may be used in a standard environment |{array}| (of the % package \pkg{array}) and, in this case, the command |\OnlyMainNiceMatrix| is % no-op. % % % \subsection{The names of the PGF nodes created by nicematrix} % % We have said that, when a name is given to an environment of \pkg{nicematrix}, % it's possible to access the PGF/Tikz nodes through this name (cf. % p.~\pageref{name}). % % That's the recommended way to access these nodes. However, we describe now the % internal names of these nodes. % % The environments created by \pkg{nicematrix} are numbered by an internal % global counter. The command |\NiceMatrixLastEnv| provides the number of the % last environment of \pkg{nicematrix} (for LaTeX, it's a ``fully expandable'' % command and not a counter). % % For the environment of number~$n$, the node in row~$i$ and column~$j$ has the % name |nm-|$n$|-|$i$|-|$j$. The |medium| and |large| nodes have the same name, % suffixed by |-medium| and |-large|. % % % \subsection{Diagonal lines} % % By default, all the diagonal lines\footnote{We speak of the lines created by % |\Ddots| and not the lines created by a command |\line| in |code-after|.} 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} % % \subsection{The ``empty'' cells} % % \label{empty-cells} % An instruction like |\Ldots|, |\Cdots|, etc. tries to determine the first % non-empty cells on both sides. However, an 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 which only contains |\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 equal to zero is empty. % % % \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} % % % \subsection{The option exterior-arraycolsep} % % The environment |{array}| inserts an 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).}}. The environment |{matrix}| of % \pkg{amsmath} and its variants (|{pmatrix}|, |{vmatrix}|, etc.) of % \pkg{amsmath} prefer to delete these spaces with explicit instructions % |\hskip -\arraycolsep|\footnote{And not by inserting |@{}| on both sides of the % preamble of the array. As a consequence, the length of the |\hline| is not % modified and may appear too long, in particular when using square brackets}. % The package \pkg{nicematrix} does the same in all its environments, % |{NiceArray}| included. However, if the user wants the environment % |{NiceArray}| behaving by default like the environment |{array}| of % \pkg{array} (for example, when adapting an existing document) it's possible to % control this behaviour with the option |exterior-arraycolsep|, set by the % command |\NiceMatrixOptions|. With this option, exterior spaces of length % |\arraycolsep| will be inserted in the environments |{NiceArray}| (the other % environments of \pkg{nicematrix} are not affected). % % % \subsection{The class option draft} % % When the class option |draft| is used, the dotted lines are not drawn, for a % faster compilation. % % \subsection{A technical problem with the argument of % \textbackslash\textbackslash} % % % For technical, reasons, if you use the optional argument of the command |\\|, % the vertical space added will also be added to the ``normal'' node % corresponding at the previous node. % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=11cm] % \begin{pNiceMatrix} % a & \frac AB \\~emphase#[2mm]@ % b & c % \end{pNiceMatrix} % \end{BVerbatim} % $\begin{pNiceMatrix}[ % code-after = {\tikz \node [inner sep = 0pt, % fill = red!15, % blend mode = multiply, % fit = (1-2) ] {} ; } ] % a & \frac AB \\[2mm] % b & c % \end{pNiceMatrix}$ % % \bigskip % There are two solutions to solve this problem. The first solution is to use a % TeX command to insert space between the rows. % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=11cm] % \begin{pNiceMatrix} % a & \frac AB \\ % ~emphase#\noalign{\kern2mm}@ % b & c % \end{pNiceMatrix} % \end{BVerbatim} % $\begin{pNiceMatrix}[ % code-after = {\tikz \node [inner sep = 0pt, % fill = red!15, % blend mode = multiply, % fit = (1-2) ] {} ; } ] % a & \frac AB \\ % \noalign{\kern2mm} % b & c % \end{pNiceMatrix}$ % % % \bigskip % The other solution is to use the command |\multicolumn| in the previous cell. % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=11cm] % \begin{pNiceMatrix} % a & ~emphase#\multicolumn1C{\frac AB}@ \\[2mm] % b & c % \end{pNiceMatrix} % \end{BVerbatim} % $\begin{pNiceMatrix}[ % code-after = {\tikz \node [inner sep = 0pt, % fill = red!15, % blend mode = multiply, % fit = (1-2) ] {} ; } ] % a & \multicolumn1C{\frac AB} \\[2mm] % b & c % \end{pNiceMatrix}$ % % % \subsection{Obsolete environments} % % The version 3.0 of \pkg{nicematrix} has introduced the environment % |{pNiceArray}| (and its variants) with the options |first-row|, |last-row|, % |first-col| and |last-col|. % % Consequently the following environments present in previous versions of % \pkg{nicematrix} are deprecated: % % % \begin{itemize} % \item |{NiceArrayCwithDelims}| ; % \item |{pNiceArrayC}|, |{bNiceArrayC}|, |{BNiceArrayC}|, |{vNiceArrayC}|, % |{VNiceArrayC}| ; % \item |{NiceArrayRCwithDelims}| ; % \item |{pNiceArrayRC}|, |{bNiceArrayRC}|, |{BNiceArrayRC}|, |{vNiceArrayRC}|, % |{VNiceArrayRC}|. % \end{itemize} % % Since the version 3.12, the only way to use these environments is loading % \pkg{nicematrix} with the option |obsolete-environments|. % % However, these environments will certainly be completely deleted in a future % version of \pkg{nicematrix}. % % \section{Examples} % % \subsection{Dotted lines} % % % A permutation matrix (as an example, we have raised the value of % |xdots/shorten|). % % \label{permutation} % \bigskip % \begin{BVerbatim}[baseline=c] % $\begin{pNiceMatrix}[~emphase#xdots/shorten=0.6em@] % 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}[xdots/shorten=0.6em] % 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| (we have raised again the value of % |xdots/shorten|).\par\nobreak % % \bigskip % \begin{BVerbatim}[baseline=c] % $\begin{pNiceMatrix}[xdots/shorten=0.9em] % 1 & \Cdots & & 1 \\ % \Vdots & & & 0 \\ % & ~emphase#\Iddots@ & ~emphase#\Iddots@ & \Vdots \\ % 1 & 0 & \Cdots & 0 % \end{pNiceMatrix}$ % \end{BVerbatim} % \hspace{4cm} % $\begin{pNiceMatrix}[xdots/shorten=0.9em] % 1 & \Cdots & & 1 \\ % \Vdots & & & 0 \\ % & \Iddots & \Iddots & \Vdots \\ % 1 & 0 & \Cdots & 0 % \end{pNiceMatrix}$ % % % \vspace{2cm} % An example with |\multicolumn|:\par\nobreak % % \bigskip % \begin{BVerbatim} % \begin{BNiceMatrix}[nullify-dots] % 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10\\ % 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10\\ % \Cdots & & ~emphase#\multicolumn{6}{C}{10 \text{ other rows}}@ & \Cdots \\ % 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 % \end{BNiceMatrix} % \end{BVerbatim} % % \bigskip % \[\begin{BNiceMatrix}[nullify-dots] % 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10\\ % 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10\\ % \Cdots & & \multicolumn{6}{C}{10 \text{ other rows}} & \Cdots \\ % 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 % \end{BNiceMatrix}\] % % \vspace{2cm} % An example with |\Hdotsfor|:\par\nobreak % % \bigskip % \begin{BVerbatim}[baseline=c,boxwidth=11cm] % \begin{pNiceMatrix}[nullify-dots] % 0 & 1 & 1 & 1 & 1 & 0 \\ % 0 & 1 & 1 & 1 & 1 & 0 \\ % \Vdots & ~emphase#\Hdotsfor{4}@ & \Vdots \\ % & ~emphase#\Hdotsfor{4}@ & \\ % & ~emphase#\Hdotsfor{4}@ & \\ % & ~emphase#\Hdotsfor{4}@ & \\ % 0 & 1 & 1 & 1 & 1 & 0 % \end{pNiceMatrix} % \end{BVerbatim} % $\begin{pNiceMatrix}[nullify-dots] % 0 & 1 & 1 & 1 & 1 & 0 \\ % 0 & 1 & 1 & 1 & 1 & 0 \\ % \Vdots & \Hdotsfor{4} & \Vdots \\ % & \Hdotsfor{4} & \\ % & \Hdotsfor{4} & \\ % & \Hdotsfor{4} & \\ % 0 & 1 & 1 & 1 & 1 & 0 % \end{pNiceMatrix}$ % % \vspace{2cm} % An example for the resultant of two polynoms:\par\nobreak % % \bigskip % \begin{BVerbatim} % \setlength{\extrarowheight}{1mm} % \[\begin{vNiceArray}{CCCC:CCC}[columns-width=6mm] % a_0 & && &b_0 & & \\ % a_1 &\Ddots&& &b_1 &\Ddots& \\ % \Vdots&\Ddots&& &\Vdots &\Ddots&b_0 \\ % a_p & &&a_0 & & &b_1 \\ % &\Ddots&&a_1 &b_q & &\Vdots\\ % & &&\Vdots & &\Ddots& \\ % & &&a_p & & &b_q % \end{vNiceArray}\] % \end{BVerbatim} % % \bigskip % % \begin{scope} % \setlength{\extrarowheight}{1mm} % \[\begin{vNiceArray}{CCCC:CCC}[columns-width=6mm] % a_0 & && &b_0 & & \\ % a_1 &\Ddots&& &b_1 &\Ddots& \\ % \Vdots&\Ddots&& &\Vdots &\Ddots&b_0 \\ % a_p & &&a_0 & & &b_1 \\ % &\Ddots&&a_1 &b_q & &\Vdots\\ % & &&\Vdots & &\Ddots& \\ % & &&a_p & & &b_q % \end{vNiceArray}\] % \end{scope} % % \vspace{2cm} % An example for a linear system (the vertical rule has been drawn in blue with % the tools of \pkg{colortbl}):\par\nobreak % % \begin{Verbatim} % \arrayrulecolor{blue} % $\begin{pNiceArray}{*6C|C}[nullify-dots,last-col,code-for-last-col=\scriptstyle] % 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{pNiceArray}$ % \arrayrulecolor{black} % \end{Verbatim} % % \arrayrulecolor{blue} % \[\begin{pNiceArray}{*6C|C}[nullify-dots,last-col,code-for-last-col=\scriptstyle] % 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{pNiceArray}\] % \arrayrulecolor{black} % % % % \subsection{Dotted lines which are no longer dotted} % % The option |line-style| controls the style of the lines drawn by |\Ldots|, % |\Cdots|, etc. Thus, it's possible with these commands to draw lines which are % not longer dotted. % % \begin{Verbatim} % \NiceMatrixOptions % {nullify-dots,code-for-first-col = \color{blue},code-for-first-col=\color{blue}} % $\begin{pNiceMatrix}[first-row,first-col] % & & \Ldots[line-style={solid,<->},shorten=0pt]^{n \text{ columns}} \\ % & 1 & 1 & 1 & \Ldots & 1 \\ % & 1 & 1 & 1 & & 1 \\ % \Vdots[line-style={solid,<->}]_{n \text{ rows}} & 1 & 1 & 1 & & 1 \\ % & 1 & 1 & 1 & & 1 \\ % & 1 & 1 & 1 & \Ldots & 1 \\ % \end{pNiceMatrix}$ % \end{Verbatim} % % % \begin{scope} % \NiceMatrixOptions % {nullify-dots,code-for-first-col = \color{blue},code-for-first-row=\color{blue}} % \[\begin{pNiceMatrix}[first-row,first-col] % & & \Ldots[line-style={solid,<->},shorten=0pt]^{n \text{ columns}} \\ % & 1 & 1 & 1 & \Ldots & 1 \\ % & 1 & 1 & 1 & & 1 \\ % \Vdots[line-style={solid,<->}]_{n \text{ rows}} & 1 & 1 & 1 & & 1 \\ % & 1 & 1 & 1 & & 1 \\ % & 1 & 1 & 1 & \Ldots & 1 \\ % \end{pNiceMatrix}\] % \end{scope} % % \subsection{Width of the columns} % % % \medskip % In the following example, we use |{NiceMatrixBlock}| with the option % |auto-columns-width| because we want the same automatic width for all the % columns of the matrices. % % \bigskip % \begin{BVerbatim} % ~emphase#\begin{NiceMatrixBlock}[auto-columns-width]@ % \NiceMatrixOptions{code-for-last-col = \color{blue}\scriptstyle,light-syntax} % \setlength{\extrarowheight}{1mm} % $\begin{pNiceArray}{CCCC:C}[last-col] % 1 1 1 1 1 ; % 2 4 8 16 9 ; % 3 9 27 81 36 ; % 4 16 64 256 100 % \end{pNiceArray}$ % \medskip % $\begin{pNiceArray}{CCCC:C}[last-col] % 1 1 1 1 1 ; % 0 2 6 14 7 { L_2 \gets -2 L_1 + L_2 } ; % 0 6 24 78 33 { L_3 \gets -3 L_1 + L_3 } ; % 0 12 60 252 96 { L_4 \gets -4 L_1 + L_4 } % \end{pNiceArray}$ % ... % ~emphase#\end{NiceMatrixBlock}@ % \end{BVerbatim} % % \bigskip % % % \begin{multicols}{2} % \begin{NiceMatrixBlock}[auto-columns-width] % \NiceMatrixOptions{code-for-last-col = \color{blue}\scriptstyle,light-syntax} % \setlength{\extrarowheight}{1mm} % % \enskip $\begin{pNiceArray}{CCCC:C}[last-col] % 1 1 1 1 1 ; % 2 4 8 16 9 ; % 3 9 27 81 36 ; % 4 16 64 256 100 % \end{pNiceArray}$ % % \medskip % % \enskip $\begin{pNiceArray}{CCCC:C}[last-col] % 1 1 1 1 1 ; % 0 2 6 14 7 { L_2 \gets -2 L_1 + L_2 } ; % 0 6 24 78 33 { L_3 \gets -3 L_1 + L_3 } ; % 0 12 60 252 96 { L_4 \gets -4 L_1 + L_4 } % \end{pNiceArray}$ % % \medskip % % \enskip $\begin{pNiceArray}{CCCC:C}[last-col] % 1 1 1 1 1 ; % 0 1 3 7 \frac72 { L_2 \gets \frac12 L_2 } ; % 0 3 12 39 \frac{33}2 { L_3 \gets \frac12 L_3 } ; % 0 1 5 21 8 { L_4 \gets \frac1{12} L_4 } % \end{pNiceArray}$ % % \medskip % % \enskip $\begin{pNiceArray}{CCCC:C}[last-col] % 1 1 1 1 1 ; % 0 1 3 7 \frac72 ; % 0 0 3 18 6 { L_3 \gets -3 L_2 + L_3 } ; % 0 0 -2 -14 -\frac92 { L_4 \gets L_2 - L_4 } % \end{pNiceArray}$ % % \medskip % % \enskip $\begin{pNiceArray}{CCCC:C}[last-col] % 1 1 1 1 1 ; % 0 1 3 7 \frac72 ; % 0 0 1 6 2 { L_3 \gets \frac13 L_3 } ; % 0 0 -2 -14 -\frac92 % \end{pNiceArray}$ % % \medskip % % \enskip $\begin{pNiceArray}{CCCC:C}[last-col] % 1 1 1 1 1 ; % 0 1 3 7 \frac72 ; % 0 0 1 6 2 ; % 0 0 0 -2 -\frac12 { L_4 \gets L_3 + L_4 } % \end{pNiceArray}$ % \end{NiceMatrixBlock} % \end{multicols} % % % \subsection{How to highlight cells of the matrix} % % % \label{highlight} % The following examples require Tikz (by default, \pkg{nicematrix} only loads % \textsc{pgf}) and the Tikz library |fit|. The following lines in the preamble % of your document may do the job: % \begin{verbatim} % \usepackage{tikz} % \usetikzlibrary{fit} % \end{verbatim} % % \medskip % In order to highlight a cell of a matrix, it's possible to ``draw'' one of the % correspondant nodes (the ``normal node'', the ``medium node'' or the ``large % node''). In the following example, we use the ``large nodes'' of the diagonal % of the matrix (with the Tikz key ``|name suffix|'', it's easy to use the % ``large nodes''). % % We redraw the nodes with other nodes by using the Tikz library |fit|. Since we % want to redraw the nodes exactly, we have to set |inner sep = 0 pt| (if we % don't do that, the new nodes will be larger that the nodes created by % \pkg{nicematrix}). % % \begin{Verbatim} % $\begin{pNiceArray}{>{\strut}CCCC}[create-large-nodes,margin,extra-margin = 2pt] % a_{11} & a_{12} & a_{13} & a_{14} \\ % a_{21} & a_{22} & a_{23} & a_{24} \\ % a_{31} & a_{32} & a_{33} & a_{34} \\ % a_{41} & a_{42} & a_{43} & a_{44} % \CodeAfter % \begin{tikzpicture}[~emphase#name suffix = -large@, % every node/.style = {draw,~emphase#inner sep = 0 pt@}] % \node [fit = (1-1)] {} ; % \node [fit = (2-2)] {} ; % \node [fit = (3-3)] {} ; % \node [fit = (4-4)] {} ; % \end{tikzpicture} % \end{pNiceArray}$ % \end{Verbatim} % % \[\begin{pNiceArray}{>{\strut}CCCC}[create-large-nodes,margin,extra-margin = 2pt] % a_{11} & a_{12} & a_{13} & a_{14} \\ % a_{21} & a_{22} & a_{23} & a_{24} \\ % a_{31} & a_{32} & a_{33} & a_{34} \\ % a_{41} & a_{42} & a_{43} & a_{44} % \CodeAfter % \begin{tikzpicture}[name suffix = -large, % every node/.style = {draw,inner sep = 0 pt}] % \node [fit = (1-1)] {} ; % \node [fit = (2-2)] {} ; % \node [fit = (3-3)] {} ; % \node [fit = (4-4)] {} ; % \end{tikzpicture} % \end{pNiceArray}\] % % % We should remark that the rules we have drawn are drawn \emph{after} the % construction of the array and thus, they don't spread the cells of the % array. We recall that, on the other side, the command |\hline|, the specifier % ``"|"'' and the options |hlines| and |vlines| spread the cells (when the % package \pkg{array} is loaded but, when the package \pkg{nicematrix} is % loaded, \pkg{array} is always loaded).\footnote{On the other side, the command % |\cline| doesn't spread the rows of the array.} % % % \vspace{1cm} % The package \pkg{nicematrix} is constructed upon the environment |{array}| % and, therefore, it's possible to use the package \pkg{colortbl} in the % environments of \pkg{nicematrix}. However, it's not always easy to do a fine % tuning of \pkg{colortbl}. That's why we propose another method to highlight a % row of the matrix. We create a rectangular Tikz node which encompasses the % nodes of the second row with the Tikz library \pkg{fit}. This Tikz node is % filled after the construction of the matrix. In order to see the text % \emph{under} this node, we have to use transparency with the |blend mode| % equal to |multiply|. % % \tikzset{highlight/.style={rectangle, % fill=red!15, % blend mode = multiply, % rounded corners = 0.5 mm, % inner sep=1pt, % fit = #1}} % % \medskip % \begin{Verbatim} % \tikzset{highlight/.style={rectangle, % fill=red!15, % ~emphase#blend mode = multiply@, % rounded corners = 0.5 mm, % inner sep=1pt, % fit = ~#1}} % % $\begin{bNiceMatrix}[~emphase#code-after = {\tikz \node [highlight = (2-1) (2-3)] {} ;}@] % 0 & \Cdots & 0 \\ % 1 & \Cdots & 1 \\ % 0 & \Cdots & 0 % \end{bNiceMatrix}$ % \end{Verbatim} % % \[\begin{bNiceMatrix}[code-after = {\tikz \node [highlight = (2-1) (2-3)] {} ;}] % 0 & \Cdots & 0 \\ % 1 & \Cdots & 1 \\ % 0 & \Cdots & 0 % \end{bNiceMatrix}\] % % % \bigskip % This code fails with |latex|-|dvips|-|ps2pdf| because Tikz for |dvips|, as for % now, doesn't support blend modes. However, the following code, in the % preamble, should activate blend modes in this way of compilation. % % % \begin{scope} \small % |\ExplSyntaxOn| % % |\makeatletter| % % |\tl_set:Nn \l_tmpa_tl {pgfsys-dvips.def}| % % |\tl_if_eq:NNT \l_tmpa_tl \pgfsysdriver| % % | {\cs_set:Npn\pgfsys@blend@mode#1{\special{ps:~/\tl_upper_case:n #1~.setblendmode}}}| % % |\makeatother| % % |\ExplSyntaxOff| % \end{scope} % % \vspace{1cm} % We recall that, for a rectangle of merged cells (with the command |\Block|), a % Tikz node is created for the set of merged cells with the name % $i$|-|$j$-|block| where $i$ and $j$ are the number of the row and the number % of the column of the upper left cell (where the command |\Block| has been % issued). If the user has required the creation of the |medium| nodes, a node % of this type is also created with a name suffixed by |-medium|. % % \medskip % \begin{BVerbatim}[baseline=c,boxwidth=11.6cm] % $\begin{pNiceMatrix}[margin,create-medium-nodes] % \Block{3-3}<\Large>{A} & & & 0 \\ % & \hspace*{1cm} & & \Vdots \\ % & & & 0 \\ % 0 & \Cdots& 0 & 0 % \CodeAfter % \tikz \node [~emphase#highlight = (1-1-block-medium)@] {} ; % \end{pNiceMatrix}$ % \end{BVerbatim} % $\begin{pNiceMatrix}[margin,create-medium-nodes] % \Block{3-3}<\Large>{A} & & & 0 \\ % & \hspace*{1cm} & & \Vdots \\ % & & & 0 \\ % 0 & \Cdots& 0 & 0 % \CodeAfter % \tikz \node [highlight = (1-1-block-medium)] {} ; % \end{pNiceMatrix}$ % % % \vspace{1cm} % Consider now the following matrix which we have named |example|. % % \medskip % \begin{Verbatim} % $\begin{pNiceArray}{CCC}[~emphase#name=example@,last-col,create-medium-nodes] % a & a + b & a + b + c & L_1 \\ % a & a & a + b & L_2 \\ % a & a & a & L_3 % \end{pNiceArray}$ % \end{Verbatim} % % \[\begin{pNiceArray}{CCC}[last-col] % a & a + b & a + b + c & L_1 \\ % a & a & a + b & L_2 \\ % a & a & a & L_3 % \end{pNiceArray}\] % % \bigskip % If we want to highlight each row of this matrix, we can use the previous % technique three times. % % \begin{Verbatim} % \tikzset{mes-options/.style={remember picture, % overlay, % name prefix = exemple-, % highlight/.style = {fill = red!15, % blend mode = multiply, % inner sep = 0pt, % fit = ~#1}}} % \end{Verbatim} % % % \tikzset{mes-options/.style={remember picture, % overlay, % name prefix = exemple-, % highlight/.style = {fill = red!15, % blend mode = multiply, % inner sep = 0pt, % fit = #1}}} % % \begin{Verbatim} % \begin{tikzpicture}[mes-options] % \node [highlight = (1-1) (1-3)] {} ; % \node [highlight = (2-1) (2-3)] {} ; % \node [highlight = (3-1) (3-3)] {} ; % \end{tikzpicture} % \end{Verbatim} % % % \medskip % We obtain the following matrix. % % \[\begin{pNiceArray}{CCC}[ % last-col, % code-after = {\begin{tikzpicture}[every node/.style = {fill = red!15, % blend mode = multiply, % inner sep = 0pt}] % \node [fit = (1-1) (1-3)] {} ; % \node [fit = (2-1) (2-3)] {} ; % \node [fit = (3-1) (3-3)] {} ; % \end{tikzpicture}}] % a & a + b & a + b + c & L_1\\ % a & a & a + b & L_2 \\ % a & a & a & L_3 % \end{pNiceArray}\] % % \medskip % The result may seem disappointing. We can improve it by using the ``medium % nodes'' instead of the ``normal nodes''. % % \begin{Verbatim} % \begin{tikzpicture}[mes-options, ~emphase#name suffix = -medium@] % \node [highlight = (1-1) (1-3)] {} ; % \node [highlight = (2-1) (2-3)] {} ; % \node [highlight = (3-1) (3-3)] {} ; % \end{tikzpicture} % \end{Verbatim} % % \medskip % We obtain the following matrix. % % \[\begin{pNiceArray}{CCC}[ % last-col, % create-medium-nodes, % code-after = {\begin{tikzpicture}[highlight/.style = {fill = red!15, % blend mode = multiply, % inner sep = 0pt, % fit = #1}, % name suffix = -medium] % \node [highlight = (1-1) (1-3)] {} ; % \node [highlight = (2-1) (2-3)] {} ; % \node [highlight = (3-1) (3-3)] {} ; % \end{tikzpicture}}] % a & a + b & a + b + c & L_1 \\ % a & a & a + b & L_2 \\ % a & a & a & L_3 % \end{pNiceArray}\] % % % % \vspace{1cm} % % In the following example, we use the ``large nodes'' to highlight a zone of % the matrix.\par\nobreak % \begin{Verbatim} % \begin{pNiceArray}{>{\strut}CCCC}[create-large-nodes,margin,extra-margin=2pt] % A_{11} & A_{12} & A_{13} & A_{14} \\ % A_{21} & A_{22} & A_{23} & A_{24} \\ % A_{31} & A_{32} & A_{33} & A_{34} \\ % A_{41} & A_{42} & A_{43} & A_{44} % \CodeAfter % \tikz \path [~emphase#name suffix = -large@,fill = red!15, blend mode = multiply] % (1-1.north west) % |- (2-2.north west) % |- (3-3.north west) % |- (4-4.north west) % |- (4-4.south east) % |- (1-1.north west) ; % \end{pNiceArray} % \end{Verbatim} % % % \[\begin{pNiceArray}{>{\strut}CCCC}[create-large-nodes,margin,extra-margin=2pt] % A_{11} & A_{12} & A_{13} & A_{14} \\ % A_{21} & A_{22} & A_{23} & A_{24} \\ % A_{31} & A_{32} & A_{33} & A_{34} \\ % A_{41} & A_{42} & A_{43} & A_{44} % \CodeAfter % \tikz \path [name suffix = -large,fill = red!15, blend mode = multiply] % (1-1.north west) % |- (2-2.north west) % |- (3-3.north west) % |- (4-4.north west) % |- (4-4.south east) % |- (1-1.north west) ; % \end{pNiceArray}\] % % \subsection{Direct use of the Tikz nodes} % % In the following example, we illustrate the mathematical product of two % matrices. % % \medskip % The use of |{NiceMatrixBlock}| with the option |auto-columns-width| % gives the same width for all the columns and, therefore, a perfect alignment % of the two superposed matrices. % \begin{Verbatim} % \begin{NiceMatrixBlock}[auto-columns-width] % \end{Verbatim} % % \begin{Verbatim} % \NiceMatrixOptions{nullify-dots} % \end{Verbatim} % % The three matrices will be displayed using an environment |{array}| (an % environment |{tabular}| may also be possible). % \begin{Verbatim} % $\begin{array}{cc} % & % \end{Verbatim} % % The matrix $B$ has a ``first row'' (for $C_j$) and that's why we use the key % |first-row|. % \begin{Verbatim} % \begin{bNiceArray}{C>{\strut}CCCC}[name=B,first-row] % & & C_j \\ % b_{11} & \Cdots & b_{1j} & \Cdots & b_{1n} \\ % \Vdots & & \Vdots & & \Vdots \\ % & & b_{kj} \\ % & & \Vdots \\ % b_{n1} & \Cdots & b_{nj} & \Cdots & b_{nn} % \end{bNiceArray} \\ \\ % \end{Verbatim} % % The matrix $A$ has a ``first column'' (for $L_i$) and that's why we use the % key |first-col|. % \begin{Verbatim} % \begin{bNiceArray}{CC>{\strut}CCC}[name=A,first-col] % & a_{11} & \Cdots & & & a_{1n} \\ % & \Vdots & & & & \Vdots \\ % L_i & a_{i1} & \Cdots & a_{ik} & \Cdots & a_{in} \\ % & \Vdots & & & & \Vdots \\ % & a_{n1} & \Cdots & & & a_{nn} \\ % \end{bNiceArray} % & % \end{Verbatim} % % In the matrix product, the two dotted lines have an open extremity. % \begin{Verbatim} % \begin{bNiceArray}{CC>{\strut}CCC} % & & & & \\ % & & \Vdots \\ % \Cdots & & c_{ij} \\ % \\ % \\ % \end{bNiceArray} % \end{array}$ % % \end{NiceMatrixBlock} % \end{Verbatim} % % \begin{Verbatim} % \begin{tikzpicture}[remember picture, overlay] % \node [highlight = (A-3-1) (A-3-5) ] {} ; % \node [highlight = (B-1-3) (B-5-3) ] {} ; % \draw [color = gray] (A-3-3) to [bend left] (B-3-3) ; % \end{tikzpicture} % \end{Verbatim} % % % \begin{NiceMatrixBlock}[auto-columns-width] % \NiceMatrixOptions{nullify-dots} % $\begin{array}{cc} % & % \begin{bNiceArray}{C>{\strut}CCCC}[name=B,first-row] % & & C_j \\ % b_{11} & \Cdots & b_{1j} & \Cdots & b_{1n} \\ % \Vdots & & \Vdots & & \Vdots \\ % & & b_{kj} \\ % & & \Vdots \\ % b_{n1} & \Cdots & b_{nj} & \Cdots & b_{nn} % \end{bNiceArray} \\ \\ % \begin{bNiceArray}{CC>{\strut}CCC}[name=A,first-col] % & a_{11} & \Cdots & & & a_{1n} \\ % & \Vdots & & & & \Vdots \\ % L_i & a_{i1} & \Cdots & a_{ik} & \Cdots & a_{in} \\ % & \Vdots & & & & \Vdots \\ % & a_{n1} & \Cdots & & & a_{nn} \\ % \end{bNiceArray} % & % \begin{bNiceArray}{CC>{\strut}CCC} % & & & & \\ % & & \Vdots \\ % \Cdots & & c_{ij} \\ % \\ % \\ % \end{bNiceArray} % \end{array}$ % % \end{NiceMatrixBlock} % % \begin{tikzpicture}[remember picture, overlay] % \node [highlight = (A-3-1) (A-3-5) ] {} ; % \node [highlight = (B-1-3) (B-5-3) ] {} ; % \draw [color = gray] (A-3-3) to [bend left] (B-3-3) ; % \end{tikzpicture} % % % % \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} is redefined. % % \smallskip % On the other hand, the environment |{array}| is never redefined. % % \smallskip % Of course, the package \pkg{nicematrix} uses the features of the package % \pkg{array}. It tries to be independent of its implementation. Unfortunately, % it was not possible to be strictly independent: the package \pkg{nicematrix} % relies upon the fact that the package |{array}| uses |\ialign| to begin the % |\halign|. % % % \bigskip % \subsection*{Declaration of the package and packages loaded} % % % The prefix |nicematrix| has been registred for this package. % % See: |http://mirrors.ctan.org/macros/latex/contrib/l3kernel/l3prefixes.pdf| % %<@@=nicematrix> % % \bigskip % First, we load \pkg{pgfcore} and the module \pkg{shapes}. We do so because % it's not possible to use |\usepgfmodule| in |\ExplSyntaxOn|. % \begin{macrocode} \RequirePackage{pgfcore} \usepgfmodule{shapes} % \end{macrocode} % % % We give the traditional declaration of a package written with |expl3|: % \begin{macrocode} \RequirePackage{l3keys2e} \ProvidesExplPackage {nicematrix} {\myfiledate} {\myfileversion} {Mathematical matrices with PGF/TikZ} % \end{macrocode} % % % \medskip % The version of 2020/02/08 of \pkg{expl3} has replaced |\l_keys_key_tl| by % |\l_keys_key_str|. We have immediately changed in this file. Now, you test the % existence of |\l_keys_key_str| in order to detect whether the version of LaTeX % used by the final user is up to date. % \begin{macrocode} \msg_new:nnn { nicematrix } { expl3~too~old } { Your~version~of~LaTeX~(especially~expl3)~is~too~old.~ You~can~go~on~but~you~will~probably~have~other~errors~ if~you~use~the~functionalities~of~nicematrix. } \cs_if_exist:NF \l_keys_key_str { \msg_error:nn { nicematrix } { expl3~too~old } } % \end{macrocode} % % % \bigskip % We test the class option |draft|. In this case, we raise the flag % |\c_@@_draft_bool| because we won't draw the dotted lines if the option % |draft| is used. % \begin{macrocode} \bool_new:N \c_@@_draft_bool \DeclareOption { draft } { \bool_set_true:N \c_@@_draft_bool } \DeclareOption* { } \ProcessOptions \relax % \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 some packages. % \begin{macrocode} \RequirePackage { array } \RequirePackage { amsmath } \RequirePackage { xparse } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_error:n { \msg_error:nn { nicematrix } } \cs_new_protected:Npn \@@_error:nn { \msg_error:nnn { nicematrix } } \cs_new_protected:Npn \@@_error:nnn { \msg_error:nnnn { nicematrix } } \cs_new_protected:Npn \@@_fatal:n { \msg_fatal:nn { nicematrix } } \cs_new_protected:Npn \@@_fatal:nn { \msg_fatal:nnn { nicematrix } } \cs_new_protected:Npn \@@_msg_new:nn { \msg_new:nnn { nicematrix } } \cs_new_protected:Npn \@@_msg_new:nnn { \msg_new:nnnn { nicematrix } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_msg_redirect_name:nn { \msg_redirect_name:nnn { nicematrix } } % \end{macrocode} % % % \bigskip % \subsection*{Technical definitions} % % \begin{macrocode} \bool_new:N \c_@@_tikz_loaded_bool \AtBeginDocument { \@ifpackageloaded { tikz } { % \end{macrocode} % In some constructions, we will have to use a |{pgfpicture}| which \emph{must} % be replaced by a |{tikzpicture}| if Tikz is loaded. However, this switch % between |{pgfpicture}| and |{tikzpicture}| can't be done dynamically with a % conditional because, when the Tikz library |external| is loaded by the user, % the pair |\tikzpicture|-|\endtikpicture| (or % |\begin{tikzpicture}-\end{tikzpicture}| must be statically ``visible'' (even % when extenalization is not activated). % % That's why we create |\c_@@_pgfortikzpicture_tl| and % |\c_@@_endpgfortikzpicture_tl| which will be used to construct in a % |\AtBeginDocument| the correct version of some commands. % \begin{macrocode} \bool_set_true:N \c_@@_tikz_loaded_bool \tl_const:Nn \c_@@_pgfortikzpicture_tl { \exp_not:N \tikzpicture } \tl_const:Nn \c_@@_endpgfortikzpicture_tl { \exp_not:N \endtikzpicture } } { \tl_const:Nn \c_@@_pgfortikzpicture_tl { \exp_not:N \pgfpicture } \tl_const:Nn \c_@@_endpgfortikzpicture_tl { \exp_not:N \endpgfpicture } } } % \end{macrocode} % % We test whether the current class is \cls{revtex4-1} or \cls{revtex4-2} % because these classes redefines |\array| (of \pkg{array}) in a way % incompatible with our programmation. % \begin{macrocode} \bool_new:N \c_@@_revtex_bool \@ifclassloaded { revtex4-1 } { \bool_set_true:N \c_@@_revtex_bool } { } \@ifclassloaded { revtex4-2 } { \bool_set_true:N \c_@@_revtex_bool } { } % \end{macrocode} % % % The following message must be defined right now because it may be used during % the loading of the package. % \begin{macrocode} \@@_msg_new:nn { Draft~mode } { The~compilation~is~in~draft~mode:~the~dotted~lines~won't~be~drawn. } % \end{macrocode} % % \begin{macrocode} \bool_if:NT \c_@@_draft_bool { \msg_warning:nn { nicematrix } { Draft~mode } } % \end{macrocode} % % % \bigskip % 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 { \tex_mkern:D 1 mu \box_move_up:nn { 1 pt } { \hbox:n { . } } \tex_mkern:D 2 mu \box_move_up:nn { 4 pt } { \hbox:n { . } } \tex_mkern:D 2 mu \box_move_up:nn { 7 pt } { \vbox:n { \kern 7 pt \hbox:n { . } } } \tex_mkern:D 1 mu } } % \end{macrocode} % % This definition is a variant of the standard definition of |\ddots|. % % % \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} % % \begin{macrocode} \cs_new:Npn \@@_env: { nm - \int_use:N \g_@@_env_int } \cs_new_protected:Npn \@@_qpoint: #1 { \pgfpointanchor { \@@_env: - #1 } { center } } % \end{macrocode} % % \bigskip % We also define a counter to count the environments |{NiceMatrixBlock}|. % \begin{macrocode} \int_new:N \g_@@_NiceMatrixBlock_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 (but, if the key |columns-width| % is used with the special value |auto|, the boolean % |l_@@_auto_columns_width_bool| also will be raised). % \begin{macrocode} \dim_new:N \l_@@_columns_width_dim % \end{macrocode} % % \bigskip % The sequence |\g_@@_names_seq| will be the list of all the names of % environments used (via the option |name|) in the document: two environments % must not have the same name. However, it's possible to use the option % |allow-duplicate-names|. % \begin{macrocode} \seq_new:N \g_@@_names_seq % \end{macrocode} % % \bigskip % We want to know if we are in an environment of \pkg{nicematrix} because we % will raise an error if the user tries to use nested environments. % \begin{macrocode} \bool_new:N \l_@@_in_env_bool % \end{macrocode} % % % \bigskip % If the user uses |{NiceArray}| (and not another environment relying upon % |{NiceArrayWithDelims}| like |{pNiceArray}|), we will raise the flag % |\l_@@_NiceArray_bool|. We have to know that, because, in |{NiceArray}|, we % won't use a structure with |\left| and |\right| and we will use the option of % position (|t|, |b| or |c|). % \begin{macrocode} \bool_new:N \l_@@_NiceArray_bool % \end{macrocode} % % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_test_if_math_mode: { \if_mode_math: \else: \@@_fatal:n { Outside~math~mode } \fi: } % \end{macrocode} % % % % \bigskip % We have to know whether \pkg{colortbl} is loaded for the redefinition of % |\everycr| and |\vline| and for the options |hlines| and |vlines|. % \begin{macrocode} \bool_new:N \c_@@_colortbl_loaded_bool \AtBeginDocument { \@ifpackageloaded { colortbl } { \bool_set_true:N \c_@@_colortbl_loaded_bool \cs_set_protected:Npn \@@_vline_i: { { \CT@arc@ \vline } } } { } } % \end{macrocode} % % \begin{macrocode} \colorlet { nicematrix-last-col } { . } \colorlet { nicematrix-last-row } { . } % \end{macrocode} % % \bigskip % The length |\l_@@_inter_dots_dim| is the distance between two dots for the % dotted lines. The default value is 0.45~em but it will be changed if the % option |small| is used. % \begin{macrocode} \dim_new:N \l_@@_inter_dots_dim \dim_set:Nn \l_@@_inter_dots_dim { 0.45 em } % \end{macrocode} % % \bigskip % The length |\l_@@_xdots_shorten_dim| is the minimal distance between a % node (in fact an anchor of that node) and a dotted line (we say ``minimal'' % because, by definition, a dotted line is not a continuous line and, therefore, % this distance may vary a little). % \begin{macrocode} \dim_new:N \l_@@_xdots_shorten_dim \dim_set:Nn \l_@@_xdots_shorten_dim { 0.3 em } % \end{macrocode} % % \bigskip % The length |\l_@@_radius_dim| is the radius of the dots for the dotted lines % (for |\hdottedline| and |\dottedline| and for all the other dotted lines when % |line-style| is equal to |standard|, which is the initial value). The initial % value is 0.53~pt but it will be changed if the option |small| is used (to % 0.37~pt). % \begin{macrocode} \dim_new:N \l_@@_radius_dim \dim_set:Nn \l_@@_radius_dim { 0.53 pt } % \end{macrocode} % % \bigskip % The name of the current environment or the current command (despite the name % which contains \textsl{env}). % \begin{macrocode} \str_new:N \g_@@_name_env_str % \end{macrocode} % % The string |\g_@@_com_or_env_str| will contain the word \emph{command} or % \emph{environment} whether we are in a command of \pkg{nicematrix} or a an % environment of \pkg{nicematrix}. The default value is \emph{environment}. % \begin{macrocode} \str_new:N \g_@@_com_or_env_str \str_set:Nn \g_@@_com_or_env_str { environment } % \end{macrocode} % % The following control sequence will be able to reconstruct the full name of % the current command or environment (despite the name which contains % \textsl{env}). This command must \emph{not} be protected since it's used in % error messages. % \begin{macrocode} \cs_new:Npn \@@_full_name_env: { \str_if_eq:VnTF \g_@@_com_or_env_str { command } { command \space \c_backslash_str \g_@@_name_env_str } { environment \space \{ \g_@@_name_env_str \} } } % \end{macrocode} % % \bigskip % \begin{macrocode} \tl_new:N \g_@@_internal_code_after_tl \tl_new:N \g_@@_code_after_tl % \end{macrocode} % % % \bigskip % The counters |\l_@@_save_iRow_int| and |\l_@@_save_jCol_int| will be used to % save the values of the eventual LaTeX counters |iRow| and |jCol|. These LaTeX % counters will be restored at the end of the environment. % \begin{macrocode} \int_new:N \l_@@_save_iRow_int \int_new:N \l_@@_save_jCol_int % \end{macrocode} % % The TeX counters |\c@iRow| and |\c@jCol| will be created in the beginning of % |{NiceArrayWithDelims}| (if they don't exist previously). % % \begin{macrocode} \bool_new:N \g_@@_row_of_col_done_bool % \end{macrocode} % % \begin{macrocode} \tl_new:N \l_@@_initial_suffix_tl \tl_new:N \l_@@_initial_anchor_tl \tl_new:N \l_@@_final_suffix_tl \tl_new:N \l_@@_final_anchor_tl % \end{macrocode} % % \begin{macrocode} \dim_new:N \l_@@_x_initial_dim \dim_new:N \l_@@_y_initial_dim \dim_new:N \l_@@_x_final_dim \dim_new:N \l_@@_y_final_dim % \end{macrocode} % % \begin{macrocode} \dim_new:N \l_tmpc_dim \dim_new:N \l_tmpd_dim % \end{macrocode} % % \begin{macrocode} \bool_new:N \g_@@_empty_cell_bool % \end{macrocode} % % \medskip % The token list |\l_@@_xdots_line_style_tl| corresponds to the option |tikz| of the % commands |\Cdots|, |\Ldots|, etc. and of the options |line-style| for the % environments and |\NiceMatrixOptions|. The constant |\c_@@_standard_tl| will % be used in some tests. % \begin{macrocode} \tl_new:N \l_@@_xdots_line_style_tl \tl_const:Nn \c_@@_standard_tl { standard } \tl_set_eq:NN \l_@@_xdots_line_style_tl \c_@@_standard_tl % \end{macrocode} % % \bigskip % \textbf{Variables for the exterior rows and columns}\par\nobreak % % \medskip % The keys for the exterior rows and columns are |first-row|, |first-col|, % |last-row| and |last-col|. However, internally, these keys are not coded in a % similar way. % % \bigskip % \begin{itemize} % \item \textbf{First row}\par\nobreak % The integer |\l_@@_first_row_int| is the number of the first row of the % array. The default value is $1$, but, if the option |first-row| is used, % the value will be~$0$. As usual, the global version is for the passage in the % |\group_insert_after:N|. % \begin{macrocode} \int_new:N \l_@@_first_row_int \int_set:Nn \l_@@_first_row_int 1 % \end{macrocode} % % \medskip % \item \textbf{First column}\par\nobreak % The integer |\l_@@_first_col_int| is the number of the first column of the % array. The default value is $1$, but, if the option |first-col| is used, % the value will be~$0$. % \begin{macrocode} \int_new:N \l_@@_first_col_int \int_set:Nn \l_@@_first_col_int 1 % \end{macrocode} % % \medskip % \item \textbf{Last row}\par\nobreak % The counter |\l_@@_last_row_int| is the number of the eventual ``last row'', % as specified by the key |last-row|. A value of $-2$ means that there is no % ``last row''. A value of $-1$ means that there is a ``last row'' but we don't % know the number of that row (the key |last-row| has been used without value % and the actual value has not still been read in the |aux| file). % \begin{macrocode} \int_new:N \l_@@_last_row_int \int_set:Nn \l_@@_last_row_int { -2 } % \end{macrocode} % % \smallskip % If, in an environment like |{pNiceArray}|, the option |last-row| is used % without value, we will globally raise the following flag. It will be used to % know if we have, after the construction of the array, to write in the |aux| % file the number of the ``last row''.\footnote{We can't use % |\l_@@_last_row_int| for this usage because, if \pkg{nicematrix} has read its % value from the |aux| file, the value of the counter won't be $-1$ any longer.} % \begin{macrocode} \bool_new:N \l_@@_last_row_without_value_bool % \end{macrocode} % % \smallskip % Idem for |\l_@@_last_col_without_value_bool| % \begin{macrocode} \bool_new:N \l_@@_last_col_without_value_bool % \end{macrocode} % % \medskip % \item \textbf{Last column}\par\nobreak % % For the eventual ``last column'', we use an integer. A value of $-2$ means % that there is no last column. A value of $-1$ means that there is a last % column but we don't know its value because the user has used the option % |last-col| without value (it's possible in an environment without preamble % like |{pNiceMatrix}|). A value of $0$ means that the option |last-col| has % been used in an environment with preamble (like |{pNiceArray}|). % \begin{macrocode} \int_new:N \l_@@_last_col_int \int_set:Nn \l_@@_last_col_int { -2 } % \end{macrocode} % % However, we have also a boolean. Consider the following code: % \begin{center} % \begin{BVerbatim} % \begin{pNiceArray}{CC}[last-col] % 1 & 2 \\ % 3 & 4 % \end{pNiceArray} % \end{BVerbatim} % \end{center} % In such a code, the ``last column'' specified by the key |last-col| is not % used. We want to be able to detect such a situation and we create a boolean % for that job. % \begin{macrocode} \bool_new:N \g_@@_last_col_found_bool % \end{macrocode} % This boolean is set to |false| at the end of |\@@_pre_array:|. % \end{itemize} % % \bigskip % \textbf{The column S of siunitx}\par\nobreak % % \medskip % We want to know whether the package \pkg{siunitx} is loaded and, if it is % loaded, we redefine the |S| columns of \pkg{siunitx}. % \begin{macrocode} \bool_new:N \c_@@_siunitx_loaded_bool \AtBeginDocument { \@ifpackageloaded { siunitx } { \bool_set_true:N \c_@@_siunitx_loaded_bool } { } } % \end{macrocode} % % \medskip % The command |\NC@rewrite@S| is a LaTeX command created by \pkg{siunitx} in % connection with the |S| column. In the code of \pkg{siunitx}, this command is % defined by: % \begin{Verbatim}[commandchars=\~\!\+, formatcom = \small] % \renewcommand*{\NC@rewrite@S}[1][] % { % \@temptokena \exp_after:wN % { % \tex_the:D \@temptokena % > { \__siunitx_table_collect_begin: S {#1} } % c % < { \__siunitx_table_print: } % } % \NC@find % } % \end{Verbatim} % We want to patch this command (in the environments of \pkg{nicematrix}) in % order to have: % \begin{Verbatim}[commandchars=\~\!\+, formatcom = \small] % \renewcommand*{\NC@rewrite@S}[1][] % { % \@temptokena \exp_after:wN % { % \tex_the:D \@temptokena % > { ~emphase!\@@_Cell:+ \__siunitx_table_collect_begin: S {#1} } % c % < { \__siunitx_table_print: ~emphase!\@@_end_Cell:+ } % } % \NC@find % } % \end{Verbatim} % However, we don't want do use explicitly any private command of \pkg{siunitx}. % That's why we will extract the name of the two |\__siunitx...| commands by % their position in the code of |\NC@rewrite@S|. % % Since the command |\NC@rewrite@S| appends some tokens to the \emph{toks} list % |\@temptokena|, we use the LaTeX command |\NC@rewrite@S| in a group % (|\group_begin:|--|\group_end:|) and we extract the two command names which % are in the toks |\@temptokena|. However, this extraction can be done only % when \pkg{siunitx} is loaded (and it may be loaded after \pkg{nicematrix}) % and, in fact, after the beginning of the document --- because some % instructions of \pkg{siunitx} are executed in a |\AtBeginDocument|). That's % why this extraction will be done only at the first use of an % environment of \pkg{nicematrix} with the command |\@@_adapt_S_column:|. % \begin{macrocode} \cs_set_protected:Npn \@@_adapt_S_column: { \bool_if:NT \c_@@_siunitx_loaded_bool { \group_begin: \@temptokena = { } % \end{macrocode} % We protect |\NC@find| which is at the end of |\NC@rewrite@S|. % \begin{macrocode} \cs_set_eq:NN \NC@find \prg_do_nothing: \NC@rewrite@S { } % \end{macrocode} % Conversion of the \emph{toks} |\@temptokena| in a token list of \pkg{expl3} % (the toks are not supported by \pkg{expl3} but we can, nevertheless, use the % option |V| for |\tl_gset:NV|). % \begin{macrocode} \tl_gset:NV \g_tmpa_tl \@temptokena \group_end: \tl_new:N \c_@@_table_collect_begin_tl \tl_set:Nx \l_tmpa_tl { \tl_item:Nn \g_tmpa_tl 2 } \tl_gset:Nx \c_@@_table_collect_begin_tl { \tl_item:Nn \l_tmpa_tl 1 } \tl_new:N \c_@@_table_print_tl \tl_gset:Nx \c_@@_table_print_tl { \tl_item:Nn \g_tmpa_tl { -1 } } % \end{macrocode} % The token lists |\c_@@_table_collect_begin_tl| and |\c_@@_table_print_tl| % contain now the two commands of \pkg{siunitx}. % % \smallskip % If the adaptation has been done, the command |\@@_adapt_S_column:| becomes % no-op (globally). % \begin{macrocode} \cs_gset_eq:NN \@@_adapt_S_column: \prg_do_nothing: } } % \end{macrocode} % % \bigskip % The command |\@@_renew_NC@rewrite@S:| will be used in each environment of % \pkg{nicematrix} in order to ``rewrite'' the |S| column in each environment % (only if the boolean |\c_@@_siunitx_loaded_bool| is raised, of course). % \begin{macrocode} \cs_new_protected:Npn \@@_renew_NC@rewrite@S: { \renewcommand*{\NC@rewrite@S}[1][] { \@temptokena \exp_after:wN { \tex_the:D \@temptokena > { \@@_Cell: \c_@@_table_collect_begin_tl S {##1} } c < { \c_@@_table_print_tl \@@_end_Cell: } } \NC@find } } % \end{macrocode} % % \bigskip % The following command is only for efficiency. It must \emph{not} be protected % because it will be used (for instance) in names of \textsc{pgf} nodes. % \begin{macrocode} \cs_new:Npn \@@_succ:n #1 { \the \numexpr #1 + 1 \relax } \cs_new:Npn \@@_pred:n #1 { \the \numexpr #1 - 1 \relax } % \end{macrocode} % % \subsection*{Command for creation of rectangle nodes} % % % The following command should be used in a |{pgfpicture}|. It creates an % rectangular (empty but with a name) when the four corners are given. % % |#1| is the name of the node which will be created; % |#2| and |#3| are the coordinates of one of the corner of the rectangle; % |#4| and |#5| are the coordinates of the opposite corner. % \begin{macrocode} \cs_new_protected:Npn \@@_pgf_rect_node:nnnnn #1 #2 #3 #4 #5 { \begin { pgfscope } \pgfset { outer~sep = \c_zero_dim , inner~sep = \c_zero_dim , minimum~size = \c_zero_dim } \pgftransformshift { \pgfpoint { 0.5 * ( #2 + #4 ) } { 0.5 * ( #3 + #5 ) } } \pgfnode { rectangle } { center } { \vbox_to_ht:nn { \dim_abs:n { #5 - #3 } } { \vfill \hbox_to_wd:nn { \dim_abs:n { #4 - #2 } } { } } } { #1 } { } \end { pgfscope } } % \end{macrocode} % % \medskip % The command |\@@_pgf_rect_node:nnn| is a variant of |\@@_pgr_rect_node:nnnn|: % it takes two \textsc{pgf} points as arguments instead of the four dimensions % which are the coordinates. % \begin{macrocode} \cs_new_protected:Npn \@@_pgf_rect_node:nnn #1 #2 #3 { \begin { pgfscope } \pgfset { outer~sep = \c_zero_dim , inner~sep = \c_zero_dim , minimum~size = \c_zero_dim } \pgftransformshift { \pgfpointscale { 0.5 } { \pgfpointadd { #2 } { #3 } } } \pgfpointdiff { #3 } { #2 } \pgfgetlastxy \l_tmpa_dim \l_tmpb_dim \pgfnode { rectangle } { center } { \vbox_to_ht:nn { \dim_abs:n \l_tmpb_dim } { \vfill \hbox_to_wd:nn { \dim_abs:n \l_tmpa_dim } { } } } { #1 } { } \end { pgfscope } } % \end{macrocode} % % % \bigskip % \subsection*{The options} % % The boolean |\l_@@_light_syntax_bool| corresponds to the option |light-syntax|. % \begin{macrocode} \bool_new:N \l_@@_light_syntax_bool % \end{macrocode} % % \bigskip % The token list |\l_@@_baseline_str| may contain one of the three values |t|, % |c| or |b| as in the option of the environment |{array}|. However, it may also % contain an integer (which represents the number of the row to which align the % array). % \begin{macrocode} \str_new:N \l_@@_baseline_str \str_set:Nn \l_@@_baseline_str c % \end{macrocode} % % \bigskip % The flag |\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}| (as it is done in % |{array}| of \pkg{array}). % \begin{macrocode} \bool_new:N \l_@@_exterior_arraycolsep_bool % \end{macrocode} % % \bigskip % The flag |\l_@@_parallelize_diags_bool| controls whether the diagonals are % parallelized. The initial value 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_@@_hlines_bool| corresponds to the option |\hlines| and the flag % |\l_@@_vlines_bool| to the option |\vlines|. % \begin{macrocode} \bool_new:N \l_@@_hlines_bool \bool_new:N \l_@@_vlines_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 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 cells of the potential exterior columns). % \begin{macrocode} \bool_new:N \l_@@_auto_columns_width_bool % \end{macrocode} % % % \bigskip % The token list |\l_@@_name_str| will contain the optional name of the % environment: this name can be used to access to the Tikz nodes created in the % array from outside the environment. % \begin{macrocode} \str_new:N \l_@@_name_str % \end{macrocode} % % \bigskip % The boolean |\l_@@_medium_nodes_bool| will be used to indicate whether the % ``medium nodes'' are created in the array. Idem for the ``large nodes''. % \begin{macrocode} \bool_new:N \l_@@_medium_nodes_bool \bool_new:N \l_@@_large_nodes_bool % \end{macrocode} % % \bigskip % The dimension |\l_@@_left_margin_dim| correspond to the option |left-margin|. % Idem for the right margin. These parameters are involved in the creation of % the ``medium nodes'' but also in the placement of the delimiters and the % drawing of the horizontal dotted lines (|\hdottedline|). % \begin{macrocode} \dim_new:N \l_@@_left_margin_dim \dim_new:N \l_@@_right_margin_dim % \end{macrocode} % % \bigskip % The following dimensions will be used internally to compute the width of the % potential ``first column'' and ``last column''. % \begin{macrocode} \dim_new:N \g_@@_width_last_col_dim \dim_new:N \g_@@_width_first_col_dim % \end{macrocode} % % \bigskip % The dimensions |\l_@@_extra_left_margin_dim| and % |\l_@@_extra_right_margin_dim| correspond to the options |extra-left-margin| % and |extra-right-margin|. % \begin{macrocode} \dim_new:N \l_@@_extra_left_margin_dim \dim_new:N \l_@@_extra_right_margin_dim % \end{macrocode} % % \medskip % The token list |\l_@@_end_of_row_tl| corresponds to the option |end-of-row|. % It specifies the symbol used to mark the ends of rows when the light syntax is % used. % \begin{macrocode} \tl_new:N \l_@@_end_of_row_tl \tl_set:Nn \l_@@_end_of_row_tl { ; } % \end{macrocode} % % \medskip % The following parameter is for the color the dotted lines drawn by |\Cdots|, % |\Ldots|, |\Vdots|, |\Ddots|, |\Iddots| and |\Hdotsfor| but \emph{not} the % dotted lines drawn by |\hdottedline| and ``|:|''. % \begin{macrocode} \tl_new:N \l_@@_xdots_color_tl % \end{macrocode} % % \medskip % Sometimes, we want to have several arrays vertically juxtaposed in order to % have an alignment of the columns of these arrays. To acheive this goal, one % may wish to use the same width for all the columns (for example with the % option |columns-width| or the option |auto-columns-width| of the environment % |{NiceMatrixBlock}|). However, even if we use the same type of delimiters, the % width of the delimiters may be different from an array to another because the % width of the delimiter is fonction of its size. That's why we create an option % called |max-delimiter-width| which will give to the delimiters the width of % a delimiter (of the same type) of big size. The following boolean corresponds % to this option. % \begin{macrocode} \bool_new:N \l_@@_max_delimiter_width_bool % \end{macrocode} % % \bigskip % First, we define a set of keys ``|NiceMatrix / Global|'' which will be used % (with the mechanism of |.inherit:n|) by other sets of keys. % \begin{macrocode} \keys_define:nn { NiceMatrix / xdots } { line-style .code:n = { \bool_lazy_or:nnTF % \end{macrocode} % We can't use |\c_@@_tikz_loaded_bool| to test whether \pkg{tikz} is loaded % because |\NiceMatrixOptions| may be used in the preamble of the document. % \begin{macrocode} { \cs_if_exist_p:N \tikzpicture } { \str_if_eq_p:nn { #1 } { standard } } { \tl_set:Nn \l_@@_xdots_line_style_tl { #1 } } { \@@_error:n { bad~option~for~line-style } } } , line-style .value_required:n = true , color .tl_set:N = \l_@@_xdots_color_tl , color .value_required:n = true , shorten .dim_set:N = \l_@@_xdots_shorten_dim , shorten .value_required:n = true , % \end{macrocode} % The options |down| and |up| are not documented for the final user because he % should use the syntax with |^| and |_|. % \begin{macrocode} down .tl_set:N = \l_@@_xdots_down_tl , up .tl_set:N = \l_@@_xdots_up_tl , unknown .code:n = \@@_error:n { Unknown~option~for~xdots } } % \end{macrocode} % % % \begin{macrocode} \keys_define:nn { NiceMatrix / Global } { xdots .code:n = \keys_set:nn { NiceMatrix / xdots } { #1 } , max-delimiter-width .bool_set:N = \l_@@_max_delimiter_width_bool , light-syntax .bool_set:N = \l_@@_light_syntax_bool , light-syntax .default:n = true , end-of-row .tl_set:N = \l_@@_end_of_row_tl , end-of-row .value_required:n = true , code-for-first-col .tl_set:N = \l_@@_code_for_first_col_tl , code-for-first-col .value_required:n = true , code-for-last-col .tl_set:N = \l_@@_code_for_last_col_tl , code-for-last-col .value_required:n = true , code-for-first-row .tl_set:N = \l_@@_code_for_first_row_tl , code-for-first-row .value_required:n = true , code-for-last-row .tl_set:N = \l_@@_code_for_last_row_tl , code-for-last-row .value_required:n = true , small .bool_set:N = \l_@@_small_bool , hlines .bool_set:N = \l_@@_hlines_bool , vlines .bool_set:N = \l_@@_vlines_bool , hvlines .meta:n = { hlines , vlines } , parallelize-diags .bool_set:N = \l_@@_parallelize_diags_bool , % \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 .value_forbidden:n = true , nullify-dots .bool_set:N = \l_@@_nullify_dots_bool , % \end{macrocode} % % \bigskip % In some circonstancies, the ``medium nodes'' are created automatically, for % example when a dotted line has an ``open'' extremity (idem for the ``large nodes''). % \begin{macrocode} create-medium-nodes .bool_set:N = \l_@@_medium_nodes_bool , create-large-nodes .bool_set:N = \l_@@_large_nodes_bool , create-extra-nodes .meta:n = { create-medium-nodes , create-large-nodes } , left-margin .dim_set:N = \l_@@_left_margin_dim , left-margin .default:n = \arraycolsep , right-margin .dim_set:N = \l_@@_right_margin_dim , right-margin .default:n = \arraycolsep , margin .meta:n = { left-margin = #1 , right-margin = #1 } , margin .default:n = \arraycolsep , extra-left-margin .dim_set:N = \l_@@_extra_left_margin_dim , extra-right-margin .dim_set:N = \l_@@_extra_right_margin_dim , extra-margin .meta:n = { extra-left-margin = #1 , extra-right-margin = #1 } , extra-margin .value_required:n = true } % \end{macrocode} % % \bigskip % We define a set of keys used by the environments of \pkg{nicematrix} (but not % by the command |\NiceMatrixOptions|). % \begin{macrocode} \keys_define:nn { NiceMatrix / Env } { % \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 = \str_set:Nn \l_@@_baseline_str c , t .code:n = \str_set:Nn \l_@@_baseline_str t , b .code:n = \str_set:Nn \l_@@_baseline_str b , baseline .tl_set:N = \l_@@_baseline_str , baseline .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 , name .code:n = % \end{macrocode} % We test whether we are in the measuring phase of an environment of % \pkg{amsmath} (always loaded by \pkg{nicematrix}) because we want to avoid a % fallacious message of duplicate name in this case. % \begin{macrocode} \legacy_if:nF { measuring@ } { \str_set:Nn \l_tmpa_str { #1 } \seq_if_in:NVTF \g_@@_names_seq \l_tmpa_str { \@@_error:nn { Duplicate~name } { #1 } } { \seq_gput_left:NV \g_@@_names_seq \l_tmpa_str } \str_set_eq:NN \l_@@_name_str \l_tmpa_str } , name .value_required:n = true , code-after .tl_gset:N = \g_@@_code_after_tl , code-after .value_required:n = true , first-col .code:n = \int_zero:N \l_@@_first_col_int , first-row .code:n = \int_zero:N \l_@@_first_row_int , last-row .int_set:N = \l_@@_last_row_int , last-row .default:n = -1 , } % \end{macrocode} % % % \bigskip % We begin the construction of the major sets of keys (used by the different % user commands and environments). % \begin{macrocode} \keys_define:nn { NiceMatrix } { NiceMatrixOptions .inherit:n = { NiceMatrix / Global , } , NiceMatrixOptions / xdots .inherit:n = NiceMatrix / xdots , NiceMatrix .inherit:n = { NiceMatrix / Global , NiceMatrix / Env , } , NiceMatrix / xdots .inherit:n = NiceMatrix / xdots , NiceArray .inherit:n = { NiceMatrix / Global , NiceMatrix / Env , } , NiceArray / xdots .inherit:n = NiceMatrix / xdots , pNiceArray .inherit:n = { NiceMatrix / Global , NiceMatrix / Env , } , pNiceArray / xdots .inherit:n = NiceMatrix / xdots } % \end{macrocode} % % % \bigskip % We finalise the definition of the set of keys % ``|NiceMatrix / NiceMatrixOptions|'' with the options specific to % |\NiceMatrixOptions|. % \begin{macrocode} \keys_define:nn { NiceMatrix / NiceMatrixOptions } { % \end{macrocode} % % 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 = \@@_renew_matrix: , renew-matrix .value_forbidden:n = true , transparent .meta:n = { renew-dots , renew-matrix } , transparent .value_forbidden: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 , % \end{macrocode} % % \bigskip % If the option |columns-width| is used, all the columns will have the same % width. % % In |\NiceMatrixOptions|, the special value |auto| is not available. % \begin{macrocode} columns-width .code:n = \str_if_eq:nnTF { #1 } { auto } { \@@_error:n { Option~auto~for~columns-width } } { \dim_set:Nn \l_@@_columns_width_dim { #1 } } , % \end{macrocode} % % \bigskip % Usually, an error is raised when the user tries to give the same to name two % distincts environments of \pkg{nicematrix} (theses names are global and not % local to the current TeX scope). However, the option |allow-duplicate-names| % disables this feature. % \begin{macrocode} allow-duplicate-names .code:n = \@@_msg_redirect_name:nn { Duplicate~name } { none } , allow-duplicate-names .value_forbidden:n = true , % \end{macrocode} % % \bigskip % By default, the specifier used in the preamble of the array (for example in % |{pNiceArray}|) to draw a vertical dotted line between two columns is the % colon ``|:|''. However, it's possible to change this letter with % |letter-for-dotted-lines| and, by the way, the letter ``|:|'' will remain free % for other packages (for example \pkg{arydshln}). % \begin{macrocode} letter-for-dotted-lines .code:n = { \int_compare:nTF { \tl_count:n { #1 } = 1 } { \str_set:Nx \l_@@_letter_for_dotted_lines_str { #1 } } { \@@_error:n { Bad~value~for~letter~for~dotted~lines } } } , letter-for-dotted-lines .value_required:n = true , unknown .code:n = \@@_error:n { Unknown~key~for~NiceMatrixOptions } } % \end{macrocode} % % \begin{macrocode} \str_new:N \l_@@_letter_for_dotted_lines_str \str_set_eq:NN \l_@@_letter_for_dotted_lines_str \c_colon_str % \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 % We finalise the definition of the set of keys % ``|NiceMatrix / NiceMatrix|'' with the options specific to |{NiceMatrix}|. % % \begin{macrocode} \keys_define:nn { NiceMatrix / NiceMatrix } { last-col .code:n = \tl_if_empty:nTF {#1} { \bool_set_true:N \l_@@_last_col_without_value_bool \int_set:Nn \l_@@_last_col_int { -1 } } { \int_set:Nn \l_@@_last_col_int { #1 } } , l .code:n = \tl_set:Nn \l_@@_type_of_col_tl L , r .code:n = \tl_set:Nn \l_@@_type_of_col_tl R , L .code:n = \tl_set:Nn \l_@@_type_of_col_tl L , R .code:n = \tl_set:Nn \l_@@_type_of_col_tl R , unknown .code:n = \@@_error:n { Unknown~option~for~NiceMatrix } } % \end{macrocode} % % % % \bigskip % We finalise the definition of the set of keys ``|NiceMatrix / NiceArray|'' % with the options specific to |{NiceArray}|. % % \begin{macrocode} \keys_define:nn { NiceMatrix / NiceArray } { % \end{macrocode} % % In the environments |{NiceArray}| and its variants, the option |last-col| must % be used without value because the number of columns of the array is read % from the preamble of the array. % \begin{macrocode} last-col .code:n = \tl_if_empty:nF { #1 } { \@@_error:n { last-col~non~empty~for~NiceArray } } \int_zero:N \l_@@_last_col_int , unknown .code:n = \@@_error:n { Unknown~option~for~NiceArray } } % \end{macrocode} % % % % \begin{macrocode} \keys_define:nn { NiceMatrix / pNiceArray } { first-col .code:n = \int_zero:N \l_@@_first_col_int , last-col .code:n = \tl_if_empty:nF {#1} { \@@_error:n { last-col~non~empty~for~NiceArray } } \int_zero:N \l_@@_last_col_int , first-row .code:n = \int_zero:N \l_@@_first_row_int , last-row .int_set:N = \l_@@_last_row_int , last-row .default:n = -1 , unknown .code:n = \@@_error:n { Unknown~option~for~NiceMatrix } } % \end{macrocode} % % % \bigskip % \subsection*{Important code used by \{NiceArrayWithDelims\} } % % The pseudo-environment |\@@_Cell:|--|\@@_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}|). % % \begin{macrocode} \cs_new_protected:Npn \@@_Cell: { % \end{macrocode} % We increment |\c@jCol|, which is the counter of the columns. % \begin{macrocode} \int_gincr:N \c@jCol % \end{macrocode} % Now, we increment the counter of the rows. We don't do this incrementation in % the |\everycr| because some packages, like \pkg{arydshln}, create special rows % in the |\halign| that we don't want to take into account. % \begin{macrocode} \int_compare:nNnT \c@jCol = 1 { \int_compare:nNnT \l_@@_first_col_int = 1 \@@_begin_of_row: } \int_gset:Nn \g_@@_col_total_int { \int_max:nn \g_@@_col_total_int \c@jCol } % \end{macrocode} % The content of the cell is composed in the box |\l_@@_cell_box| because we want % to compute some dimensions of the box. The |\hbox_set_end:| corresponding to % this |\hbox_set:Nw| will be in the |\@@_end_Cell:| (and the % |\c_math_toggle_token| also). % \begin{macrocode} \hbox_set:Nw \l_@@_cell_box \c_math_toggle_token \bool_if:NT \l_@@_small_bool \scriptstyle % \end{macrocode} % % We will call \emph{corners} of the matrix the cases which are at the % intersection of the exterior rows and exterior columns (of course, the four % corners doesn't always exist simultaneously). % % The codes |\l_@@_code_for_first_row_tl| and \emph{al} don't apply in the % corners of the matrix. % \begin{macrocode} \int_compare:nNnTF \c@iRow = 0 { \int_compare:nNnT \c@jCol > 0 { \l_@@_code_for_first_row_tl \xglobal \colorlet { nicematrix-first-row } { . } } } { \int_compare:nNnT \c@iRow = \l_@@_last_row_int { \l_@@_code_for_last_row_tl \xglobal \colorlet { nicematrix-last-row } { . } } } } % \end{macrocode} % % \interitem % The following macro |\@@_begin_of_row| is usually used in the cell % number~$1$ of the row. However, when the key |first-col| is used, % |\@@_begin_of_row| is executed in the cell number~$0$ of the row. % \begin{macrocode} \cs_new_protected:Npn \@@_begin_of_row: { \int_gincr:N \c@iRow \dim_gset_eq:NN \g_@@_dp_ante_last_row_dim \g_@@_dp_last_row_dim \dim_gset:Nn \g_@@_dp_last_row_dim { \box_dp:N \@arstrutbox } \dim_gset:Nn \g_@@_ht_last_row_dim { \box_ht:N \@arstrutbox } \pgfpicture \pgfrememberpicturepositiononpagetrue \pgfcoordinate { \@@_env: - row - \int_use:N \c@iRow - base } \pgfpointorigin \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \@@_env: - row - \int_use:N \c@iRow - base } { \l_@@_name_str - row - \int_use:N \c@iRow - base } } \endpgfpicture } % \end{macrocode} % % % \interitem % The following code is used in each cell of the array. It actualises quantities % that, at the end of the array, will give informations about the vertical % dimension of the two first rows and the two last rows. If the user uses the % |last-row|, some lines will be dynamically added to this command. % \begin{macrocode} \cs_new_protected:Npn \@@_update_for_first_and_last_row: { \int_compare:nNnTF \c@iRow = 0 { \dim_gset:Nn \g_@@_dp_row_zero_dim { \dim_max:nn \g_@@_dp_row_zero_dim { \box_dp:N \l_@@_cell_box } } \dim_gset:Nn \g_@@_ht_row_zero_dim { \dim_max:nn \g_@@_ht_row_zero_dim { \box_ht:N \l_@@_cell_box } } } { \int_compare:nNnT \c@iRow = 1 { \dim_gset:Nn \g_@@_ht_row_one_dim { \dim_max:nn \g_@@_ht_row_one_dim { \box_ht:N \l_@@_cell_box } } } } } % \end{macrocode} % % % \begin{macrocode} \cs_new_protected:Npn \@@_end_Cell: { \c_math_toggle_token \hbox_set_end: % \end{macrocode} % % We want to compute in |\g_@@_max_cell_width_dim| the width of the widest cell % of the array (except the cells of the ``first column'' and the ``last % column''). % % \begin{macrocode} \dim_gset:Nn \g_@@_max_cell_width_dim { \dim_max:nn \g_@@_max_cell_width_dim { \box_wd:N \l_@@_cell_box } } % \end{macrocode} % % The following computations are for the ``first row'' and the ``last row''. % \begin{macrocode} \@@_update_for_first_and_last_row: % \end{macrocode} % % \medskip % If the cell is empty, or may be considered as if, we must not create the % \textsc{pgf} node, for two reasons: % \begin{itemize} % \item it's a waste of time since such a node would be rather pointless; % \item we test the existence of these nodes in order to determine whether a % cell is empty when we search the extremities of a dotted line. % \end{itemize} % However, it's very difficult to determine whether a cell is empty. As of now, % we use the following technic: % \begin{itemize} % \item if the width of the box |\l_@@_cell_box| (created with the content of % the cell) is equal to zero, we consider the cell as empty (however, % this is not perfect since the user may have use a |\rlap|, a |\llap| or a % |\mathclap| of \pkg{mathtools}. % \item the cells with a command |\Ldots| or |\Cdots|, |\Vdots|, etc., % should also be considered as empty; if |nullify-dots| is in force, there would % be nothing to do (in this case the previous commands only write an instruction % in a kind of |code-after|); however, if |nullify-dots| is not in force, a % phantom of |\ldots|, |\cdots|, |\vdots| is inserted and its width is not equal % to zero; that's why these commands raise a boolean |\g_@@_empty_cell_bool| and % we begin by testing this boolean. % \end{itemize} % \begin{macrocode} \bool_if:NTF \g_@@_empty_cell_bool { \box_use_drop:N \l_@@_cell_box \bool_gset_false:N \g_@@_empty_cell_bool } { \dim_compare:nNnTF { \box_wd:N \l_@@_cell_box } > \c_zero_dim \@@_node_for_the_cell: { \box_use_drop:N \l_@@_cell_box } } \bool_gset_false:N \g_@@_empty_cell_bool } % \end{macrocode} % % \medskip % The following command creates the \textsc{pgf} name of the node with, of % course, |\l_@@_cell_box| as the content. % \begin{macrocode} \cs_new_protected:Npn \@@_node_for_the_cell: { \pgfpicture \pgfsetbaseline \c_zero_dim \pgfrememberpicturepositiononpagetrue \pgfset { inner~sep = \c_zero_dim , minimum~width = \c_zero_dim } \pgfnode { rectangle } { base } { \box_use_drop:N \l_@@_cell_box } { \@@_env: - \int_use:N \c@iRow - \int_use:N \c@jCol } { } \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \l_@@_name_str - \int_use:N \c@iRow - \int_use:N \c@jCol } { \@@_env: - \int_use:N \c@iRow - \int_use:N \c@jCol } } \endpgfpicture } % \end{macrocode} % % \interitem % The first argument of the following command |\@@_instruction_of_type:nn| % defined below is the type of the instruction (|Cdots|, |Vdots|, |Ddots|, % etc.). The second argument is the list of options. This command writes in the % corresponding |\g_@@_|\textsl{type}|_lines_tl| the instruction which will % actually draw the line after the construction of the matrix. % % \medskip % For example, for the following matrix, % % \smallskip % \begin{BVerbatim}[baseline=c,boxwidth=11cm] % \begin{pNiceMatrix} % 1 & 2 & 3 & 4 \\ % 5 & \Cdots & & 6 \\ % 7 & \Cdots[color=red] \\ % \end{pNiceMatrix} % \end{BVerbatim} % $\begin{pNiceMatrix} % 1 & 2 & 3 & 4 \\ % 5 & \Cdots & & 6 \\ % 7 & \Cdots[color=red] \\ % \end{pNiceMatrix}$ % % \smallskip % the content of |\g_@@_Cdots_lines_tl| will be: % % \smallskip % \begin{scope} % \color{gray} % \verb|\@@_draw_Cdots:nnn {2}{2}{}| % % \verb|\@@_draw_Cdots:nnn {3}{2}{color=red}| % \end{scope} % % % \bigskip % We begin with a test of the flag |\c_@@_draft_bool| because, if the key % |draft| is used, the dotted lines are not drawn. % \begin{macrocode} \bool_if:NTF \c_@@_draft_bool { \cs_set_protected:Npn \@@_instruction_of_type:nn #1 #2 { } } { \cs_new_protected:Npn \@@_instruction_of_type:nn #1 #2 { % \end{macrocode} % It's important to use a |\tl_gput_right:cx| and not a |\tl_gput_left:cx| % because we want the |\Ddots| lines to be drawn in the order of appearance % in the array (for parallelisation). % \begin{macrocode} \tl_gput_right:cx { g_@@_ #1 _ lines _ tl } { \use:c { @@ _ draw _ #1 : nnn } { \int_use:N \c@iRow } { \int_use:N \c@jCol } { \exp_not:n { #2 } } } } } % \end{macrocode} % % % \bigskip % We want to use |\array| of \pkg{array}. However, if the class used is % \cls{revtex4-1} or \cls{revtex4-2}, we have to do some tuning and use the % command |\@array@array| instead of |\array| because these classes do a % redefinition of |\array| incompatible with our use of |\array|. % % \begin{macrocode} \cs_new_protected:Npn \@@_array: { \bool_if:NTF \c_@@_revtex_bool { \cs_set_eq:NN \@acoll \@arrayacol \cs_set_eq:NN \@acolr \@arrayacol \cs_set_eq:NN \@acol \@arrayacol \cs_set:Npn \@halignto { } \@array@array } \array % \end{macrocode} % |\l_@@_baseline_str| may have the value |t|, |c| or |b|. However, if the value % is |b|, we compose the |\array| (of \pkg{array}) with the option |t| and the % right translation will be done further. % \begin{macrocode} [ \str_if_eq:VnTF \l_@@_baseline_str c c t ] } % \end{macrocode} % % \medskip % We keep in memory the standard version of |\ialign| because we will redefine % |\ialign| in the environment |{NiceArrayWithDelims}| but restore the standard % version for use in the cells of the array. % \begin{macrocode} \cs_set_eq:NN \@@_standard_ialign: \ialign % \end{macrocode} % % \bigskip % The following must \emph{not} be protected because it begins with |\noalign|. % \begin{macrocode} \cs_new:Npn \@@_everycr: { \noalign { \@@_everycr_i: } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_everycr_i: { \int_gzero:N \c@jCol % \end{macrocode} % The |\hbox:n| (or |\hbox|) is mandatory. % \begin{macrocode} \hbox { \pgfpicture \pgfrememberpicturepositiononpagetrue \pgfcoordinate { \@@_env: - row - \@@_succ:n \c@iRow } \pgfpointorigin \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \@@_env: - row - \int_use:N \c@iRow - row } { \l_@@_name_str - row - \int_use:N \c@iRow - row } } \endpgfpicture } % \end{macrocode} % We add the potential horizontal lines specified by the option |hlines|. % \begin{macrocode} \bool_if:NT \l_@@_hlines_bool { % \end{macrocode} % The counter |\c@iRow| has the value $-1$ only if there is a ``first % row'' and that we are before that ``first row'', i.e. just before the % beginning of the array. % \begin{macrocode} \int_compare:nNnT \c@iRow > { -1 } { \bool_if:NF \g_@@_row_of_col_done_bool { \int_compare:nNnF \c@iRow = \l_@@_last_row_int { \bool_if:NTF \c_@@_colortbl_loaded_bool { { \CT@arc@ \hrule height \arrayrulewidth } } { \hrule height \arrayrulewidth } } } } } } % \end{macrocode} % % \bigskip % The following code |\@@_pre_array:| is used in |{NiceArrayWithDelims}|. It % exists as a standalone macro only for lisibility. % \label{prearray} % % \begin{macrocode} \cs_new_protected:Npn \@@_pre_array: { \box_clear_new:N \l_@@_cell_box \cs_if_exist:NT \theiRow { \int_set_eq:NN \l_@@_save_iRow_int \c@iRow } \int_gzero_new:N \c@iRow \cs_if_exist:NT \thejCol { \int_set_eq:NN \l_@@_save_jCol_int \c@jCol } \int_gzero_new:N \c@jCol \normalbaselines % \end{macrocode} % If the option |small| is used, we have to do some tuning. In particular, we % change the value of |\arraystretch| (this parameter is used in the % construction of |\@arstrutbox| in the beginning of |{array}|). % \begin{macrocode} \bool_if:NT \l_@@_small_bool { % \end{macrocode} % \begin{macrocode} \cs_set:Npn \arraystretch { 0.47 } \dim_set:Nn \arraycolsep { 1.45 pt } } % \end{macrocode} % % % \bigskip % The environment |{array}| uses internally the command |\ialign|. We change the % definition of |\ialign| for several reasons. In particular, |\ialign| sets % |\everycr| to |{ }| and we \emph{need} to have to change the value of % |\everycr|. % \begin{macrocode} \cs_set:Npn \ialign { \bool_if:NTF \c_@@_colortbl_loaded_bool { \CT@everycr { \noalign { \cs_gset_eq:NN \CT@row@color \prg_do_nothing: } \@@_everycr: } } { \everycr { \@@_everycr: } } \tabskip = \c_zero_skip % \end{macrocode} % % The box |\@arstrutbox| is a box constructed in the beginning of the % environment |{array}|. The construction of that box takes into account the % current values of |\arraystretch|\footnote{The option |small| of % \pkg{nicematrix} changes (among other) the value of |\arraystretch|. This is % done, of course, before the call of |{array}|.} and |\extrarowheight| (of % \pkg{array}). That box is inserted (via |\@arstrut|) in the beginning of each % row of the array. That's why we use the dimensions of that box to initialize % the variables which will be the dimensions of the potential first and last row % of the environment. This initialization must be done after the creation of % |\@arstrutbox| and that's why we do it in the |\ialign|. % \begin{macrocode} \dim_gzero_new:N \g_@@_dp_row_zero_dim \dim_gset:Nn \g_@@_dp_row_zero_dim { \box_dp:N \@arstrutbox } \dim_gzero_new:N \g_@@_ht_row_zero_dim \dim_gset:Nn \g_@@_ht_row_zero_dim { \box_ht:N \@arstrutbox } \dim_gzero_new:N \g_@@_ht_row_one_dim \dim_gset:Nn \g_@@_ht_row_one_dim { \box_ht:N \@arstrutbox } \dim_gzero_new:N \g_@@_dp_ante_last_row_dim \dim_gzero_new:N \g_@@_ht_last_row_dim \dim_gset:Nn \g_@@_ht_last_row_dim { \box_ht:N \@arstrutbox } \dim_gzero_new:N \g_@@_dp_last_row_dim \dim_gset:Nn \g_@@_dp_last_row_dim { \box_dp:N \@arstrutbox } % \end{macrocode} % After its first use, the definition of |\ialign| will revert % automatically to its default definition. With this programmation, we will % have, in the cells of the array, a clean version of |\ialign|.\footnote{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_eq:NN \ialign \@@_standard_ialign: \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} \newcolumntype L { > \@@_Cell: l < \@@_end_Cell: } \newcolumntype C { > \@@_Cell: c < \@@_end_Cell: } \newcolumntype R { > \@@_Cell: r < \@@_end_Cell: } % \end{macrocode} % We keep in memory the old versions or |\ldots|, |\cdots|, etc. only because we % use them inside |\phantom| commands in order that the new commands |\Ldots|, % |\Cdots|, etc. give the same spacing (except when the option |nullify-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 \cs_set_eq:NN \firsthline \hline \cs_set_eq:NN \lasthline \hline \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 \hdottedline \@@_hdottedline: \cs_set_eq:NN \Hspace \@@_Hspace: \cs_set_eq:NN \Hdotsfor \@@_Hdotsfor: \cs_set_eq:NN \multicolumn \@@_multicolumn:nnn \cs_set_eq:NN \Block \@@_Block: \cs_set_eq:NN \rotate \@@_rotate: \cs_set_eq:NN \OnlyMainNiceMatrix \@@_OnlyMainNiceMatrix:n \cs_set_eq:NN \CodeAfter \@@_CodeAfter:n \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 \cs_set_eq:NN \dots \@@_Ldots \cs_set_eq:NN \hdotsfor \@@_Hdotsfor: } % \end{macrocode} % % % The sequence |\g_@@_multicolumn_cells_seq| will contain the list of the cells % of the array where a command |\multicolumn{|$n$|}{...}{...}| with $n>1$ is % issued. In |\g_@@_multicolumn_sizes_seq|, the ``sizes'' (that is to say the % values of $n$) correspondant will be stored. These lists will be used for the % creation of the ``medium nodes'' (if they are created). % \begin{macrocode} \seq_gclear_new:N \g_@@_multicolumn_cells_seq \seq_gclear_new:N \g_@@_multicolumn_sizes_seq % \end{macrocode} % % % The counter |\c@iRow| will be used to count the rows of the array (its % incrementation will be in the first cell of the row). % \begin{macrocode} \int_gset:Nn \c@iRow { \l_@@_first_row_int - 1 } % \end{macrocode} % % At the end of the environment |{array}|, |\c@iRow| will be the total % number de rows. % % |\g_@@_row_total_int| will be the number or rows excepted the last row (if % |\l_@@_last_row_bool| has been raised with the option |last-row|). % \begin{macrocode} \int_gzero_new:N \g_@@_row_total_int % \end{macrocode} % % The counter |\c@jCol| will be used to count the columns of the array. % Since we want to know the total number of columns of the matrix, we also % create a counter |\g_@@_col_total_int|. These counters are updated in the % command |\@@_Cell:| executed at the beginning of each cell. % \begin{macrocode} \int_gzero_new:N \g_@@_col_total_int % \end{macrocode} % % \begin{macrocode} \cs_set_eq:NN \@ifnextchar \new@ifnextchar % \end{macrocode} % % We nullify the definitions of the column types |w| and |W| before their % redefinition because we want to avoid a warning in the log file for a % redefinition of a column type. We must put |\relax| and not % |\prg_do_nothing:|. % \begin{macrocode} \cs_set_eq:NN \NC@find@w \relax \cs_set_eq:NN \NC@find@W \relax \newcolumntype w [ 2 ] { > { \hbox_set:Nw \l_@@_cell_box \@@_Cell: } c < { \@@_end_Cell: \hbox_set_end: % \end{macrocode} % The |\str_lowercase:n| is only for giving the user the ability to write % |wC{1cm}| instead of |wc{1cm}| for homogeneity with the letters |L|, |C| and % |R| used elsewhere in the preamble instead of |l|, |c| and |r|. % \begin{macrocode} \makebox [ ##2 ] [ \str_lowercase:n { ##1 } ] { \box_use_drop:N \l_@@_cell_box } } } \newcolumntype W [ 2 ] { > { \hbox_set:Nw \l_@@_cell_box \@@_Cell: } c < { \@@_end_Cell: \hbox_set_end: \cs_set_eq:NN \hss \hfil \makebox [ ##2 ] [ \str_lowercase:n { ##1 } ] { \box_use_drop:N \l_@@_cell_box } } } % \end{macrocode} % % \bigskip % By default, the letter used to specify a dotted line in the preamble of an % environment of \pkg{nicematrix} (for example in |{pNiceArray}|) is the letter % |:|. However, this letter is used by some packages, for example % \pkg{arydshln}. That's why it's possible to change the letter used by % \pkg{nicematrix} with the option |letter-for-dotted-lines| which changes the % value of |\l_@@_letter_for_dotted_lines_str|. We rescan this string (which is % always of length~1) in particular for the case where |pdflatex| is used with % \pkg{french-babel} (the colon is activated by \pkg{french-babel} at the % beginning of the document). % \begin{macrocode} \tl_set_rescan:Nno \l_@@_letter_for_dotted_lines_str { } \l_@@_letter_for_dotted_lines_str \exp_args:NV \newcolumntype \l_@@_letter_for_dotted_lines_str { ! { % \end{macrocode} % % \medskip % The following code because we want the dotted line to have exactly the same % position as a vertical rule drawn by ``"|"'' (considering the rule having a % width equal to the diameter of the dots). % \begin{macrocode} \int_compare:nNnF \c@iRow = 0 { \int_compare:nNnF \c@iRow = \l_@@_last_row_int { \skip_horizontal:N 2\l_@@_radius_dim } } % \end{macrocode} % % \medskip % Consider the following code: % \begin{center} % \begin{BVerbatim} % \begin{NiceArray}{C:CC:C} % a & b % c & d \\ % e & f & g & h \\ % i & j & k & l % \end{NiceArray} % \end{BVerbatim} % \end{center} % The first ``|:|'' in the preamble will be encountered during the first row of % the environment |{NiceArray}| but the second one will be encountered only in % the third row. We have to issue a command |\vdottedline:n| in the |code-after| % only one time for each ``|:|'' in the preamble. That's why we keep a counter % |\g_@@_last_vdotted_col_int| and with this counter, we know whether a letter % ``|:|'' encountered during the parsing has already been taken into account in % the |code-after|. % \begin{macrocode} \int_compare:nNnT \c@jCol > \g_@@_last_vdotted_col_int { \int_gset_eq:NN \g_@@_last_vdotted_col_int \c@jCol \tl_gput_right:Nx \g_@@_internal_code_after_tl % \end{macrocode} % The command |\@@_vdottedline:n| is protected, and, therefore, won't be % expanded before writing on |\g_@@_internal_code_after_tl|. % \begin{macrocode} { \@@_vdottedline:n { \int_use:N \c@jCol } } } } } \int_gzero_new:N \g_@@_last_vdotted_col_int \bool_if:NT \c_@@_siunitx_loaded_bool \@@_renew_NC@rewrite@S: \int_gset:Nn \g_@@_last_vdotted_col_int { -1 } \bool_gset_false:N \g_@@_last_col_found_bool % \end{macrocode} % % \medskip % During the construction of the array, the instructions |\Cdots|, |\Ldots|, % etc. will be written in token lists |\g_@@_Cdots_lines_tl|, etc. which will be % executed after the construction of the array. % \begin{macrocode} \tl_gclear_new:N \g_@@_Cdots_lines_tl \tl_gclear_new:N \g_@@_Ldots_lines_tl \tl_gclear_new:N \g_@@_Vdots_lines_tl \tl_gclear_new:N \g_@@_Ddots_lines_tl \tl_gclear_new:N \g_@@_Iddots_lines_tl \tl_gclear_new:N \g_@@_Hdotsfor_lines_tl } % \end{macrocode} % % \bigskip % \subsection*{The environment \{NiceArrayWithDelims\}} % % \begin{macrocode} \NewDocumentEnvironment { NiceArrayWithDelims } { m m O { } m ! O { } } { \tl_set:Nn \l_@@_left_delim_tl { #1 } \tl_set:Nn \l_@@_right_delim_tl { #2 } \bool_gset_false:N \g_@@_row_of_col_done_bool \str_if_empty:NT \g_@@_name_env_str { \str_gset:Nn \g_@@_name_env_str { NiceArrayWithDelims } } \@@_adapt_S_column: \@@_test_if_math_mode: \bool_if:NT \l_@@_in_env_bool { \@@_fatal:n { Yet~in~env } } \bool_set_true:N \l_@@_in_env_bool % \end{macrocode} % % We deactivate Tikz externalization because we will use \textsc{pgf} pictures with the % options |overlay| and |remember picture| (or equivalent forms). % \begin{macrocode} \cs_if_exist:NT \tikz@library@external@loaded { \tikzset { external / export = false } \cs_if_exist:NT \ifstandalone { \tikzset { external / optimize = false } } } % \end{macrocode} % % We increment the counter |\g_@@_env_int| which counts the environments % of the package. % \begin{macrocode} \int_gincr:N \g_@@_env_int \bool_if:NF \l_@@_block_auto_columns_width_bool { \dim_gzero_new:N \g_@@_max_cell_width_dim } % \end{macrocode} % % % We do a redefinition of |\@arrayrule| because we want that the vertical rules % drawn by "|" in the preamble of the array don't extend in the potential % exterior rows. % \begin{macrocode} \cs_set_protected:Npn \@arrayrule { \@addtopreamble \@@_vline: } % \end{macrocode} % % % The set of keys is not exactly the same for |{NiceArray}| and for the variants % of |{NiceArray}| (|{pNiceArray}|, |{bNiceArray}|, etc.) because, for % |{NiceArray}|, we have the options |t|, |c|, |b| and |baseline|. % \begin{macrocode} \bool_if:NTF \l_@@_NiceArray_bool { \keys_set:nn { NiceMatrix / NiceArray } } { \keys_set:nn { NiceMatrix / pNiceArray } } { #3 , #5 } % \end{macrocode} % % % A value of $-1$ for the counter |\l_@@_last_row_int| means that the user has % used the option |last-row| without value, that is to say without specifying % the number of that last row. In this case, we try to read that value from the % |aux| file (if it has been written on a previous run). % % \begin{macrocode} \int_compare:nNnT \l_@@_last_row_int > { -2 } { \tl_put_right:Nn \@@_update_for_first_and_last_row: { \dim_gset:Nn \g_@@_ht_last_row_dim { \dim_max:nn \g_@@_ht_last_row_dim { \box_ht:N \l_@@_cell_box } } \dim_gset:Nn \g_@@_dp_last_row_dim { \dim_max:nn \g_@@_dp_last_row_dim { \box_dp:N \l_@@_cell_box } } } } \int_compare:nNnT \l_@@_last_row_int = { -1 } { \bool_set_true:N \l_@@_last_row_without_value_bool % \end{macrocode} % A value based on the name is more reliable than a value based on the number of % the environment. % \begin{macrocode} \str_if_empty:NTF \l_@@_name_str { \cs_if_exist:cT { @@_last_row_ \int_use:N \g_@@_env_int } { \int_set:Nn \l_@@_last_row_int { \use:c { @@_last_row_ \int_use:N \g_@@_env_int } } } } { \cs_if_exist:cT { @@_last_row_ \l_@@_name_str } { \int_set:Nn \l_@@_last_row_int { \use:c { @@_last_row_ \l_@@_name_str } } } } } % \end{macrocode} % % % A value of $-1$ for the counter |\l_@@_last_col_int| means that the user has % used the option |last-col| without value, that is to say without specifying % the number of that last column. In this case, we try to read that value from % the |aux| file (if it has been written on a previous run). % \begin{macrocode} \int_compare:nNnT \l_@@_last_col_int = { -1 } { \str_if_empty:NTF \l_@@_name_str { \cs_if_exist:cT { @@_last_col_ \int_use:N \g_@@_env_int } { \int_set:Nn \l_@@_last_col_int { \use:c { @@_last_col_ \int_use:N \g_@@_env_int } } } } { \cs_if_exist:cT { @@_last_col_ \l_@@_name_str } { \int_set:Nn \l_@@_last_col_int { \use:c { @@_last_col_ \l_@@_name_str } } } } } % \end{macrocode} % % \interitem % The code in |\@@_pre_array:| is used only by |{NiceArrayWithDelims}|. % \begin{macrocode} \@@_pre_array: % \end{macrocode} % % \medskip % We compute the width of the two delimiters. % \begin{macrocode} \dim_zero_new:N \l_@@_left_delim_dim \dim_zero_new:N \l_@@_right_delim_dim \bool_if:NTF \l_@@_NiceArray_bool { \dim_gset:Nn \l_@@_left_delim_dim { 2 \arraycolsep } \dim_gset:Nn \l_@@_right_delim_dim { 2 \arraycolsep } } { % \end{macrocode} % The command |\bBigg@| is a command of \pkg{amsmath}. % \begin{macrocode} \hbox_set:Nn \l_tmpa_box { $ \bBigg@ 5 #1 $ } \dim_set:Nn \l_@@_left_delim_dim { \box_wd:N \l_tmpa_box } \hbox_set:Nn \l_tmpa_box { $\bBigg@ 5 #2 $ } \dim_set:Nn \l_@@_right_delim_dim { \box_wd:N \l_tmpa_box } } % \end{macrocode} % % \medskip % The array will be composed in a box (named |\l_@@_the_array_box|) because we % have to do manipulations concerning the potential exterior rows. % \begin{macrocode} \box_clear_new:N \l_@@_the_array_box % \end{macrocode} % % \medskip % We construct the preamble of the array in |\l_tmpa_tl|. % \begin{macrocode} \tl_set:Nn \l_tmpa_tl { #4 } \int_compare:nNnTF \l_@@_first_col_int = 0 { \tl_put_left:NV \l_tmpa_tl \c_@@_preamble_first_col_tl } { \bool_lazy_all:nT { \l_@@_NiceArray_bool { \bool_not_p:n \l_@@_vlines_bool } { \bool_not_p:n \l_@@_exterior_arraycolsep_bool } } { \tl_put_left:Nn \l_tmpa_tl { @ { } } } } \int_compare:nNnTF \l_@@_last_col_int > { -1 } { \tl_put_right:NV \l_tmpa_tl \c_@@_preamble_last_col_tl } { \bool_lazy_all:nT { \l_@@_NiceArray_bool { \bool_not_p:n \l_@@_vlines_bool } { \bool_not_p:n \l_@@_exterior_arraycolsep_bool } } { \tl_put_right:Nn \l_tmpa_tl { @ { } } } } \tl_put_right:Nn \l_tmpa_tl { > { \@@_error_too_much_cols: } L } % \end{macrocode} % Here is the beginning of the box which will contain the array. The % |\hbox_set_end:| corresponding to this |\hbox_set:Nw| will be in the second % part of the environment (and the closing |\c_math_toggle_token| also). % \begin{macrocode} \hbox_set:Nw \l_@@_the_array_box % \end{macrocode} % If the key |\vlines| is used, we increase |\arraycolsep| by % |0.5\arrayrulewidth| in order to reserve space for the width of the vertical % rules drawn with Tikz after the end of the array. However, the first % |\arraycolsep| is used once (between columns, |\arraycolsep| is used twice). % That's why we add a |0.5\arrayrulewidth| more. % \begin{macrocode} \bool_if:NT \l_@@_vlines_bool { \dim_add:Nn \arraycolsep { 0.5 \arrayrulewidth } \skip_horizontal:N 0.5\arrayrulewidth } \skip_horizontal:N \l_@@_left_margin_dim \skip_horizontal:N \l_@@_extra_left_margin_dim \c_math_toggle_token \bool_if:NTF \l_@@_light_syntax_bool { \begin { @@-light-syntax } } { \begin { @@-normal-syntax } } } % \end{macrocode} % % % \begin{macrocode} { \bool_if:NTF \l_@@_light_syntax_bool { \end { @@-light-syntax } } { \end { @@-normal-syntax } } \c_math_toggle_token \skip_horizontal:N \l_@@_right_margin_dim \skip_horizontal:N \l_@@_extra_right_margin_dim % \end{macrocode} % If the key |\vlines| is used, we have increased |\arraycolsep| by % |0.5\arrayrulewidth| in order to reserve space for the width of the vertical % rules drawn with Tikz after the end of the array. However, the last % |\arraycolsep| is used once (between columns, |\arraycolsep| is used twice). % That's we add a |0.5 \arrayrulewidth| more. % \begin{macrocode} \bool_if:NT \l_@@_vlines_bool { \skip_horizontal:N 0.5\arrayrulewidth } \hbox_set_end: % \end{macrocode} % End of the construction of the array (in the box |\l_@@_the_array_box|). % % \bigskip % It the user has used the key |last-row| with a value, we control that the % given value is correct (since we have just contructed the array, we know the % real number of rows of the array). % \begin{macrocode} \int_compare:nNnT \l_@@_last_row_int > { -2 } { \bool_if:NF \l_@@_last_row_without_value_bool { \int_compare:nNnF \l_@@_last_row_int = \c@iRow { \@@_error:n { Wrong~last~row } \int_gset_eq:NN \l_@@_last_row_int \c@iRow } } } % \end{macrocode} % % Now, the definition of |\c@jCol| and % |\g_@@_col_total_int| change: |\c@jCol| will be the number of % columns without the ``last column''; |\g_@@_col_total_int| will be the % number of columns with this ``last column''.\footnote{We remind that the % potential ``first column'' (exterior) has the number~$0$.} % \begin{macrocode} \int_gset_eq:NN \c@jCol \g_@@_col_total_int \bool_if:nT \g_@@_last_col_found_bool { \int_gdecr:N \c@jCol } % \end{macrocode} % % We fix also the value of |\c@iRow| and |\g_@@_row_total_int| with the % same principle. % \begin{macrocode} \int_gset_eq:NN \g_@@_row_total_int \c@iRow \int_compare:nNnT \l_@@_last_row_int > { -1 } { \int_gdecr:N \c@iRow } % \end{macrocode} % % % % \bigskip % \textbf{Now, we begin the real construction in the output flow of TeX}. First, we take % into account a potential ``first column'' (we remind that this ``first % column'' has been constructed in an overlapping position and that we have % computed its width in |\g_@@_width_first_col_dim|: see % p.~\pageref{overlap-left}). % \begin{macrocode} \int_compare:nNnT \l_@@_first_col_int = 0 { \skip_horizontal:N \arraycolsep \skip_horizontal:N \g_@@_width_first_col_dim } % \end{macrocode} % % The construction of the real box is different in |{NiceArray}| and in the % other environments because, in |{NiceArray}|, we have to take into account the % value of |baseline| and we have no delimiter to put. We begin with |{NiceArray}|. % \begin{macrocode} \bool_if:NTF \l_@@_NiceArray_bool { % \end{macrocode} % Remember that, when the key |b| is used, the |\array| (of \pkg{array}) is % constructed with the option |t| (and not |b|). Now, we do the translation to % take into account the option |b|. % \begin{macrocode} \str_if_eq:VnTF \l_@@_baseline_str { b } { \pgfpicture \@@_qpoint: { row - 1 } \dim_gset_eq:NN \g_tmpa_dim \pgf@y \@@_qpoint: { row - \int_use:N \c@iRow - base } \dim_gsub:Nn \g_tmpa_dim \pgf@y \endpgfpicture \int_compare:nNnT \l_@@_first_row_int = 0 { \dim_gadd:Nn \g_tmpa_dim { \g_@@_ht_row_zero_dim + \g_@@_dp_row_zero_dim } } \box_move_up:nn \g_tmpa_dim { \box_use_drop:N \l_@@_the_array_box } } { \str_if_eq:VnTF \l_@@_baseline_str { c } { \box_use_drop:N \l_@@_the_array_box } { % \end{macrocode} % We convert a value of |t| to a value of |1|. % \begin{macrocode} \str_if_eq:VnT \l_@@_baseline_str { t } { \str_set:Nn \l_@@_baseline_str { 1 } } % \end{macrocode} % Now, we convert the value of |\l_@@_baseline_str| (which should represent an % integer) to an integer stored in |\l_tmpa_int|. % \begin{macrocode} \int_set:Nn \l_tmpa_int \l_@@_baseline_str \bool_if:nT { \int_compare_p:nNn \l_tmpa_int < \l_@@_first_row_int || \int_compare_p:nNn \l_tmpa_int > \g_@@_row_total_int } { \@@_error:n { bad~value~for~baseline } \int_set:Nn \l_tmpa_int 1 } \pgfpicture \@@_qpoint: { row - 1 } \dim_gset_eq:NN \g_tmpa_dim \pgf@y \@@_qpoint: { row - \int_use:N \l_tmpa_int - base } \dim_gsub:Nn \g_tmpa_dim \pgf@y \endpgfpicture \int_compare:nNnT \l_@@_first_row_int = 0 { \dim_gadd:Nn \g_tmpa_dim { \g_@@_ht_row_zero_dim + \g_@@_dp_row_zero_dim } } \box_move_up:nn \g_tmpa_dim { \box_use_drop:N \l_@@_the_array_box } } } } % \end{macrocode} % % Now, in the case of an environment |{pNiceArray}|, |{bNiceArray}|, etc. We % compute |\l_tmpa_dim| which is the total height of the ``first row'' above the % array (when the key |first-row| is used). % \begin{macrocode} { \int_compare:nNnTF \l_@@_first_row_int = 0 { \dim_set_eq:NN \l_tmpa_dim \g_@@_dp_row_zero_dim \dim_add:Nn \l_tmpa_dim \g_@@_ht_row_zero_dim } { \dim_zero:N \l_tmpa_dim } % \end{macrocode} % % We compute |\l_tmpb_dim| which is the total height of the ``last row'' % below the array (when the key |last-row| is used). A value of $-2$ for % |\l_@@_last_row_int| means that there is no ``last row''.\footnote{A value of % $-1$ for |\l_@@_last_row_int| means that there is a ``last row'' but the % the user have not set the value with the option |last row| (and we are in the % first compilation).} % \begin{macrocode} \int_compare:nNnTF \l_@@_last_row_int > { -2 } { \dim_set_eq:NN \l_tmpb_dim \g_@@_ht_last_row_dim \dim_add:Nn \l_tmpb_dim \g_@@_dp_last_row_dim } { \dim_zero:N \l_tmpb_dim } % \end{macrocode} % % \begin{macrocode} \hbox_set:Nn \l_tmpa_box { \c_math_toggle_token \left #1 \vcenter { % \end{macrocode} % We take into account the ``first row'' (we have previously computed its total % height in |\l_tmpa_dim|). The |\hbox:n| (or |\hbox|) is necessary here. % \begin{macrocode} \skip_vertical:N -\l_tmpa_dim \hbox { \skip_horizontal:N -\arraycolsep \box_use_drop:N \l_@@_the_array_box \skip_horizontal:N -\arraycolsep } % \end{macrocode} % We take into account the ``last row'' (we have previously computed its total % height in |\l_tmpb_dim|). % \begin{macrocode} \skip_vertical:N -\l_tmpb_dim } \right #2 \c_math_toggle_token } % \end{macrocode} % Now, the box |\l_tmpa_box| is created with the correct delimiters. % % \smallskip % We will put the box in the TeX flow. However, we have a small work to do % when the option |max-delimiter-width| is used. % \begin{macrocode} \bool_if:NTF \l_@@_max_delimiter_width_bool { \@@_put_box_in_flow_bis:nn { #1 } { #2 } } \@@_put_box_in_flow: } % \end{macrocode} % % We take into account a potential ``last column'' (this ``last column'' has % been constructed in an overlapping position and we have computed its width in % |\g_@@_width_last_col_dim|: see p.~\pageref{overlap-right}). % \begin{macrocode} \bool_if:NT \g_@@_last_col_found_bool { \skip_horizontal:N \g_@@_width_last_col_dim \skip_horizontal:N \arraycolsep } \@@_after_array: } % \end{macrocode} % This is the end of the environment |{NiceArrayWithDelims}|. % % \bigskip % The command |\@@_put_box_in_flow:| puts the box |\l_tmpa_box| (which contains % the array) in the flow. It is used for the environments with delimiters. % First, we have to modify the height and the depth to take back into account % the potential exterior rows (the total height of the first row has been % computed in |\l_tmpa_dim| and the total height of the potential last row in % |\l_tmpb_dim|). % \begin{macrocode} \cs_new_protected:Npn \@@_put_box_in_flow: { \box_set_ht:Nn \l_tmpa_box { \box_ht:N \l_tmpa_box + \l_tmpa_dim } \box_set_dp:Nn \l_tmpa_box { \box_dp:N \l_tmpa_box + \l_tmpb_dim } \str_if_eq:VnTF \l_@@_baseline_str { c } { \box_use_drop:N \l_tmpa_box } \@@_put_box_in_flow_i: } % \end{macrocode} % % \medskip % The command |\@@_put_box_in_flow_i:| is used when the value of % |\l_@@_baseline_str| is different of |c| (which is the initial value and the % most used). % \begin{macrocode} \cs_new_protected:Npn \@@_put_box_in_flow_i: { \str_case:VnF \l_@@_baseline_str { { t } { \int_set:Nn \l_tmpa_int 1 } { b } { \int_set_eq:NN \l_tmpa_int \c@iRow } } { \int_set:Nn \l_tmpa_int \l_@@_baseline_str } \bool_if:nT { \int_compare_p:nNn \l_tmpa_int < \l_@@_first_row_int || \int_compare_p:nNn \l_tmpa_int > \g_@@_row_total_int } { \@@_error:n { bad~value~for~baseline } \int_set:Nn \l_tmpa_int 1 } \pgfpicture \@@_qpoint: { row - 1 } \dim_gset_eq:NN \g_tmpa_dim \pgf@y \@@_qpoint: { row - \@@_succ:n \c@iRow } \dim_gadd:Nn \g_tmpa_dim \pgf@y \dim_gset:Nn \g_tmpa_dim { 0.5 \g_tmpa_dim } % \end{macrocode} % Now, |\g_tmpa_dim| contains the $y$-value of the center of the array (the % delimiters are centered in relation with this value). % \begin{macrocode} \@@_qpoint: { row - \int_use:N \l_tmpa_int - base } \dim_gsub:Nn \g_tmpa_dim \pgf@y % \end{macrocode} % We take into account the position of the mathematical axis. % \begin{macrocode} \dim_gsub:Nn \g_tmpa_dim { \fontdimen22 \textfont2 } % \end{macrocode} % Now, |\g_tmpa_dim| contains the value of the $y$ translation we have to to. % \begin{macrocode} \endpgfpicture \box_move_up:nn \g_tmpa_dim { \box_use_drop:N \l_tmpa_box } \box_use_drop:N \l_tmpa_box } % \end{macrocode} % % \bigskip % The command |\@@_put_box_in_flow_bis:| is used when the option % |max-delimiter-width| is used because, in this case, we have to adjust the % widths of the delimiters. The arguments |#1| and |#2| are the delimiters % specified by the user. % \begin{macrocode} \cs_new_protected:Npn \@@_put_box_in_flow_bis:nn #1 #2 { % \end{macrocode} % We will compute the real width of both delimiters used. % \begin{macrocode} \dim_zero_new:N \l_@@_real_left_delim_dim \dim_zero_new:N \l_@@_real_right_delim_dim \hbox_set:Nn \l_tmpb_box { \c_math_toggle_token \left #1 \vcenter { \vbox_to_ht:nn { \box_ht:N \l_tmpa_box + \box_dp:N \l_tmpa_box } { } } \right . \c_math_toggle_token } \dim_set:Nn \l_@@_real_left_delim_dim { \box_wd:N \l_tmpb_box - \nulldelimiterspace } \hbox_set:Nn \l_tmpb_box { \c_math_toggle_token \left . \vbox_to_ht:nn { \box_ht:N \l_tmpa_box + \box_dp:N \l_tmpa_box } { } \right #2 \c_math_toggle_token } \dim_set:Nn \l_@@_real_right_delim_dim { \box_wd:N \l_tmpb_box - \nulldelimiterspace } % \end{macrocode} % % Now, we can put the box in the TeX flow with the horizontal adjustments on % both sides. % \begin{macrocode} \skip_horizontal:N \l_@@_left_delim_dim \skip_horizontal:N -\l_@@_real_left_delim_dim \@@_put_box_in_flow: \skip_horizontal:N \l_@@_right_delim_dim \skip_horizontal:N -\l_@@_real_right_delim_dim } % \end{macrocode} % % \interitem % The construction of the array in the environment |{NiceArrayWithDelims}| is, % in fact, done by the environment |{@@-light-syntax}| or by the environment % |{@@-normal-syntax}| (whether the option |light-syntax| is used or not). When % the key |light-syntax| is not used, the construction is a standard % environment (and, thus, it's possible to use verbatim in the arrray). % \begin{macrocode} \NewDocumentEnvironment { @@-normal-syntax } { } % \end{macrocode} % First, we test whether the environment is empty. If it is empty, we raise a % fatal error (it's only a security). In order to detect whether it is empty, we % test whether the next token is |\end| and, if it's the case, we test if this % is the end of the environment (if it is not, an standard error will be raised % by LaTeX for incorrect nested environments). % \begin{macrocode} { \peek_meaning_ignore_spaces:NTF \end { \@@_analyze_end:Nn } % \end{macrocode} % Here is the call to |\array| (we have a dedicated macro |\@@_array:| because % of compatibility with the classes \cls{revtex4-1} and \cls{revtex4-2}). % \begin{macrocode} { \exp_args:NV \@@_array: \l_tmpa_tl } } { \@@_create_col_nodes: \endarray } % \end{macrocode} % % % \bigskip % When the key |light-syntax| is used, we use an environment which takes its whole % body as an argument (with the specifier |b| of \pkg{xparse}). % \begin{macrocode} \NewDocumentEnvironment { @@-light-syntax } { b } { % \end{macrocode} % First, we test whether the environment is empty. It's only a security. Of % course, this test is more easy than the similar test for the ``normal syntax'' % because we have the whole body of the environment in |#1|. % \begin{macrocode} \tl_if_empty:nT { #1 } { \@@_fatal:n { empty~environment } } \tl_map_inline:nn { #1 } { \tl_if_eq:nnT { ##1 } { & } { \@@_fatal:n { ampersand~in~light-syntax } } \tl_if_eq:nnT { ##1 } { \\ } { \@@_fatal:n { double-backslash~in~light-syntax } } } % \end{macrocode} % The body of the environment, which is stored in the argument |#1|, is now % splitted into items (and \emph{not} tokens) % \begin{macrocode} \seq_gclear_new:N \g_@@_rows_seq \tl_set_rescan:Nno \l_@@_end_of_row_tl { } \l_@@_end_of_row_tl \exp_args:NNV \seq_gset_split:Nnn \g_@@_rows_seq \l_@@_end_of_row_tl { #1 } % \end{macrocode} % If the environment uses the option |last-row| without value (i.e. without % saying the number of the rows), we have now the opportunity to know that % value. We do it, and so, if the token list |\l_@@_code_for_last_row_tl| is not % empty, we will use directly where it should be. % \begin{macrocode} \int_compare:nNnT \l_@@_last_row_int = { -1 } { \int_set:Nn \l_@@_last_row_int { \seq_count:N \g_@@_rows_seq } } % \end{macrocode} % Here is the call to |\array| (we have a dedicated macro |\@@_array:| because % of compatibility with the classes \cls{revtex4-1} and \cls{revtex4-2}). % \begin{macrocode} \exp_args:NV \@@_array: \l_tmpa_tl % \end{macrocode} % We need a global affectation because, when executing |\l_tmpa_tl|, we will % exit the first cell of the array. % \begin{macrocode} \seq_gpop_left:NN \g_@@_rows_seq \l_tmpa_tl \exp_args:NV \@@_line_with_light_syntax_i:n \l_tmpa_tl \seq_map_function:NN \g_@@_rows_seq \@@_line_with_light_syntax:n \@@_create_col_nodes: \endarray } % \end{macrocode} % Now, the second part of the environment. It is empty. That's not surprising % because we have caught the whole body of the environment with the specifier % |b| provided by \pkg{xparse}. % \begin{macrocode} { } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_line_with_light_syntax_i:n #1 { \seq_gclear_new:N \g_@@_cells_seq \seq_gset_split:Nnn \g_@@_cells_seq { ~ } { #1 } \seq_gpop_left:NN \g_@@_cells_seq \l_tmpa_tl \l_tmpa_tl \seq_map_function:NN \g_@@_cells_seq \@@_cell_with_light_syntax:n } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_line_with_light_syntax:n #1 { \tl_if_empty:nF { #1 } { \\ \@@_line_with_light_syntax_i:n { #1 } } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_cell_with_light_syntax:n #1 { & #1 } % \end{macrocode} % % \bigskip % The following command is used by the code which detects whether the % environment is empty (we raise a fatal error in this case: it's only a % security). % \begin{macrocode} \cs_new_protected:Npn \@@_analyze_end:Nn #1 #2 { \str_if_eq:VnT \g_@@_name_env_str { #2 } { \@@_fatal:n { empty~environment } } % \end{macrocode} % We reput in the stream the |\end{...}| we have extracted and the user will % have an error for incorrect nested environments. % \begin{macrocode} \end { #2 } } % \end{macrocode} % % \bigskip % The command |\@@_create_col_nodes:| will construct a special last row. % That last row is a false row used to create the |col|-nodes and to fix the % width of the columns (when the array is constructed with an option which % specify the width of the columns). % \begin{macrocode} \cs_new:Npn \@@_create_col_nodes: { \crcr \int_compare:nNnT \c@iRow = 0 { \@@_fatal:n { Zero~row } } \int_compare:nNnT \l_@@_first_col_int = 0 { \omit \skip_horizontal:N -2\arraycolsep \pgfpicture \pgfrememberpicturepositiononpagetrue \pgfcoordinate { \@@_env: - col - 0 } \pgfpointorigin \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \@@_env: - col - 0 } { \l_@@_name_str - col - 0 } } \endpgfpicture & } \omit % \end{macrocode} % The following instruction must be put after the instruction |\omit|. % \begin{macrocode} \bool_gset_true:N \g_@@_row_of_col_done_bool % \end{macrocode} % First, we put a ``|col|'' node on the left of the first column (of course, we % have to do that \emph{after} the |\omit|). % \begin{macrocode} \pgfpicture \pgfrememberpicturepositiononpagetrue \pgfcoordinate { \@@_env: - col - 1 } \pgfpointorigin \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \@@_env: - col - 1 } { \l_@@_name_str - col - 1 } } \endpgfpicture % \end{macrocode} % We compute in |\g_tmpa_skip| the common width of the columns (it's a skip and % not a dimension). We use a global variable because we are in a cell of an % |\halign| and because we have to use this variable in other cells (of the same % row). The affectation of |\g_tmpa_skip|, like all the affectations, must be % done after the |\omit| of the cell. % % \smallskip % We give a default value for |\g_tmpa_skip| (|0 pt plus 1 fill|) but it will % just after erased by a fixed value in the concerned cases. % \begin{macrocode} \skip_gset:Nn \g_tmpa_skip { 0 pt~plus 1 fill } \bool_if:NF \l_@@_auto_columns_width_bool { \dim_compare:nNnT \l_@@_columns_width_dim > \c_zero_dim } { \bool_lazy_and:nnTF \l_@@_auto_columns_width_bool { \bool_not_p:n \l_@@_block_auto_columns_width_bool } { \skip_gset_eq:NN \g_tmpa_skip \g_@@_max_cell_width_dim } { \skip_gset_eq:NN \g_tmpa_skip \l_@@_columns_width_dim } \skip_gadd:Nn \g_tmpa_skip { 2 \arraycolsep } } \skip_horizontal:N \g_tmpa_skip \hbox { \pgfpicture \pgfrememberpicturepositiononpagetrue \pgfcoordinate { \@@_env: - col - 2 } \pgfpointorigin \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \@@_env: - col - 2 } { \l_@@_name_str - col - 2 } } \endpgfpicture } % \end{macrocode} % We begin a loop over the columns. The integer |\g_tmpa_int| will be the % number of the current column. This integer is used for the Tikz nodes. % \begin{macrocode} \int_gset:Nn \g_tmpa_int 1 \bool_if:NTF \g_@@_last_col_found_bool { \prg_replicate:nn { \g_@@_col_total_int - 2 } } { \prg_replicate:nn { \g_@@_col_total_int - 1 } } { & \omit % \end{macrocode} % The incrementation of the counter |\g_tmpa_int| must be done after the |\omit| % of the cell. % \begin{macrocode} \int_gincr:N \g_tmpa_int \skip_horizontal:N \g_tmpa_skip % \end{macrocode} % We create the ``|col|'' node on the right of the current column. % \begin{macrocode} \pgfpicture \pgfrememberpicturepositiononpagetrue \pgfcoordinate { \@@_env: - col - \@@_succ:n \g_tmpa_int } \pgfpointorigin \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \@@_env: - col - \@@_succ:n \g_tmpa_int } { \l_@@_name_str - col - \@@_succ:n \g_tmpa_int } } \endpgfpicture } \bool_if:NT \g_@@_last_col_found_bool { \skip_horizontal:N 2\arraycolsep \pgfpicture \pgfrememberpicturepositiononpagetrue \pgfcoordinate { \@@_env: - col - \@@_succ:n \g_@@_col_total_int } \pgfpointorigin \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \@@_env: - col - \@@_succ:n \g_@@_col_total_int } { \l_@@_name_str - col - \@@_succ:n \g_@@_col_total_int } } \endpgfpicture \skip_horizontal:N -2\arraycolsep } \cr } % \end{macrocode} % % % \interitem % Here is the preamble for the ``first column'' (if the user uses the key % |first-col|) % \begin{macrocode} \tl_const:Nn \c_@@_preamble_first_col_tl { > { \@@_begin_of_row: % \end{macrocode} % The contents of the cell is constructed in the box |\l_@@_cell_box| because we % have to compute some dimensions of this box. % \begin{macrocode} \hbox_set:Nw \l_@@_cell_box \c_math_toggle_token \bool_if:NT \l_@@_small_bool \scriptstyle % \end{macrocode} % We insert |\l_@@_code_for_first_col_tl|... but we don't insert it in the % potential ``first row'' and in the potential ``last row''. % \begin{macrocode} \bool_lazy_and:nnT { \int_compare_p:nNn \c@iRow > 0 } { \bool_lazy_or_p:nn { \int_compare_p:nNn \l_@@_last_row_int < 0 } { \int_compare_p:nNn \c@iRow < \l_@@_last_row_int } } { \l_@@_code_for_first_col_tl \xglobal \colorlet { nicematrix-first-col } { . } } } % \end{macrocode} % Be careful: despite this letter |l| the cells of the ``first column'' are % composed in a |R| manner since they are composed in a |\hbox_overlap_left:n|. % \begin{macrocode} l < { \c_math_toggle_token \hbox_set_end: \@@_update_for_first_and_last_row: % \end{macrocode} % We actualise the width of the ``first column'' because we will use this width % after the construction of the array. % \begin{macrocode} \dim_gset:Nn \g_@@_width_first_col_dim { \dim_max:nn \g_@@_width_first_col_dim { \box_wd:N \l_@@_cell_box } } % \end{macrocode} % The content of the cell is inserted in an overlapping position. % \label{overlap-left} % \begin{macrocode} \hbox_overlap_left:n { \dim_compare:nNnTF { \box_wd:N \l_@@_cell_box } > \c_zero_dim \@@_node_for_the_cell: { \box_use_drop:N \l_@@_cell_box } \skip_horizontal:N \l_@@_left_delim_dim \skip_horizontal:N \l_@@_left_margin_dim \skip_horizontal:N \l_@@_extra_left_margin_dim } \skip_horizontal:N -2\arraycolsep } } % \end{macrocode} % % % Here is the preamble for the ``last column'' (if the user uses the key % |last-col|). % \begin{macrocode} \tl_const:Nn \c_@@_preamble_last_col_tl { > { % \end{macrocode} % With the flag |\g_@@_last_col_found_bool|, we will know that the ``last % column'' is really used. % \begin{macrocode} \bool_gset_true:N \g_@@_last_col_found_bool \int_gincr:N \c@jCol \int_gset_eq:NN \g_@@_col_total_int \c@jCol % \end{macrocode} % The contents of the cell is constructed in the box |\l_tmpa_box| because we % have to compute some dimensions of this box. % \begin{macrocode} \hbox_set:Nw \l_@@_cell_box \c_math_toggle_token \bool_if:NT \l_@@_small_bool \scriptstyle % \end{macrocode} % We insert |\l_@@_code_for_last_col_tl|... but we don't insert it in the % potential ``first row'' and in the potential ``last row''. % \begin{macrocode} \int_compare:nNnT \c@iRow > 0 { \bool_lazy_or:nnT { \int_compare_p:nNn \l_@@_last_row_int < 0 } { \int_compare_p:nNn \c@iRow < \l_@@_last_row_int } { \l_@@_code_for_last_col_tl \xglobal \colorlet { nicematrix-last-col } { . } } } } l < { \c_math_toggle_token \hbox_set_end: \@@_update_for_first_and_last_row: % \end{macrocode} % We actualise the width of the ``last column'' because we will use this width % after the construction of the array. % \begin{macrocode} \dim_gset:Nn \g_@@_width_last_col_dim { \dim_max:nn \g_@@_width_last_col_dim { \box_wd:N \l_@@_cell_box } } \skip_horizontal:N -2\arraycolsep % \end{macrocode} % The content of the cell is inserted in an overlapping position. % \label{overlap-right} % \begin{macrocode} \hbox_overlap_right:n { \dim_compare:nNnT { \box_wd:N \l_@@_cell_box } > \c_zero_dim { \skip_horizontal:N \l_@@_right_delim_dim \skip_horizontal:N \l_@@_right_margin_dim \skip_horizontal:N \l_@@_extra_right_margin_dim \@@_node_for_the_cell: } } } } % \end{macrocode} % % % \interitem % The environment |{NiceArray}| is constructed upon the environment % |{NiceArrayWithDelims}| but, in fact, there is a flag |\l_@@_NiceArray_bool|. % In |{NiceArrayWithDelims}|, some special code will be executed if this flag is % raised. % \begin{macrocode} \NewDocumentEnvironment { NiceArray } { } { \bool_set_true:N \l_@@_NiceArray_bool \str_if_empty:NT \g_@@_name_env_str { \str_gset:Nn \g_@@_name_env_str { NiceArray } } % \end{macrocode} % We put . and . for the delimiters but, in fact, that doesn't matter because % these arguments won't be used in |{NiceArrayWithDelims}| (because the flag % |\l_@@_NiceArray_bool| is raised). % \begin{macrocode} \NiceArrayWithDelims . . } { \endNiceArrayWithDelims } % \end{macrocode} % % % \interitem % We create the variants of the environment |{NiceArrayWithDelims}|. % % \begin{macrocode} \NewDocumentEnvironment { pNiceArray } { } { \str_if_empty:NT \g_@@_name_env_str { \str_gset:Nn \g_@@_name_env_str { pNiceArray } } \@@_test_if_math_mode: \NiceArrayWithDelims ( ) } { \endNiceArrayWithDelims } % \end{macrocode} % % \begin{macrocode} \NewDocumentEnvironment { bNiceArray } { } { \str_if_empty:NT \g_@@_name_env_str { \str_gset:Nn \g_@@_name_env_str { bNiceArray } } \@@_test_if_math_mode: \NiceArrayWithDelims [ ] } { \endNiceArrayWithDelims } % \end{macrocode} % % \begin{macrocode} \NewDocumentEnvironment { BNiceArray } { } { \str_if_empty:NT \g_@@_name_env_str { \str_gset:Nn \g_@@_name_env_str { BNiceArray } } \@@_test_if_math_mode: \NiceArrayWithDelims \{ \} } { \endNiceArrayWithDelims } % \end{macrocode} % % \begin{macrocode} \NewDocumentEnvironment { vNiceArray } { } { \str_if_empty:NT \g_@@_name_env_str { \str_gset:Nn \g_@@_name_env_str { vNiceArray } } \@@_test_if_math_mode: \NiceArrayWithDelims | | } { \endNiceArrayWithDelims } % \end{macrocode} % % \begin{macrocode} \NewDocumentEnvironment { VNiceArray } { } { \str_if_empty:NT \g_@@_name_env_str { \str_gset:Nn \g_@@_name_env_str { VNiceArray } } \@@_test_if_math_mode: \NiceArrayWithDelims \| \| } { \endNiceArrayWithDelims } % \end{macrocode} % % \bigskip % \subsection*{The environment \{NiceMatrix\} and its variants} % % \begin{macrocode} \cs_new_protected:Npn \@@_define_env:n #1 { \NewDocumentEnvironment { #1 NiceMatrix } { ! O { } } { \str_gset:Nn \g_@@_name_env_str { #1 NiceMatrix } \tl_set:Nn \l_@@_type_of_col_tl C \keys_set:nn { NiceMatrix / NiceMatrix } { ##1 } \exp_args:Nnx \@@_begin_of_NiceMatrix:nn { #1 } \l_@@_type_of_col_tl } { \end { #1 NiceArray } } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_begin_of_NiceMatrix:nn #1 #2 { \begin { #1 NiceArray } { * { \int_compare:nNnTF \l_@@_last_col_int < 0 \c@MaxMatrixCols { \@@_pred:n \l_@@_last_col_int } } #2 } } % \end{macrocode} % % \begin{macrocode} \@@_define_env:n { } \@@_define_env:n p \@@_define_env:n b \@@_define_env:n B \@@_define_env:n v \@@_define_env:n V % \end{macrocode} % % % % % \bigskip % \subsection*{After the construction of the array} % % \medskip % \begin{macrocode} \cs_new_protected:Npn \@@_after_array: { \group_begin: % \end{macrocode} % When the option |last-col| is used in the environments with explicit preambles % (like |{NiceArray}|, |{pNiceArray}|, etc.) a special type of column is used at % the end of the preamble in order to compose the cells in an overlapping % position (with |\hbox_overlap_right:n|) but (if |last-col| has been used), we % don't have the number of that last column. However, we have to know that % number for the color of the potential |\Vdots| drawn in that last column. % That's why we fix the correct value of |\l_@@_last_col_int| in that case. % \begin{macrocode} \bool_if:NT \g_@@_last_col_found_bool { \int_set_eq:NN \l_@@_last_col_int \g_@@_col_total_int } % \end{macrocode} % % If we are in an environment without preamble (like |{NiceMatrix}| or % |{pNiceMatrix}|) and if the option |last-col| has been used without value % we fix the real value of |\l_@@_last_col_int|. % \begin{macrocode} \bool_if:NT \l_@@_last_col_without_value_bool { \dim_set_eq:NN \l_@@_last_col_int \g_@@_col_total_int \iow_shipout:Nn \@mainaux \ExplSyntaxOn \iow_shipout:Nx \@mainaux { \cs_gset:cpn { @@_last_col_ \int_use:N \g_@@_env_int } { \int_use:N \g_@@_col_total_int } } \str_if_empty:NF \l_@@_name_str { \iow_shipout:Nx \@mainaux { \cs_gset:cpn { @@_last_col_ \l_@@_name_str } { \int_use:N \g_@@_col_total_int } } } \iow_shipout:Nn \@mainaux \ExplSyntaxOff } % \end{macrocode} % % It's also time to give to |\l_@@_last_row_int| its real value. But, if the % user had used the option |last-row| without value, we write in the |aux| file % the number of that last row for the next run. % \begin{macrocode} \bool_if:NT \l_@@_last_row_without_value_bool { \dim_set_eq:NN \l_@@_last_row_int \g_@@_row_total_int % \end{macrocode} % If the option |light-syntax| is used, we have nothing to write since, in this % case, the number of rows is directly determined. % \begin{macrocode} \bool_if:NF \l_@@_light_syntax_bool { \iow_shipout:Nn \@mainaux \ExplSyntaxOn \iow_shipout:Nx \@mainaux { \cs_gset:cpn { @@_last_row_ \int_use:N \g_@@_env_int } { \int_use:N \g_@@_row_total_int } } % \end{macrocode} % If the environment has a name, we also write a value based on the name % because it's more reliable than a value based on the number of the % environment. % \begin{macrocode} \str_if_empty:NF \l_@@_name_str { \iow_shipout:Nx \@mainaux { \cs_gset:cpn { @@_last_row_ \l_@@_name_str } { \int_use:N \g_@@_row_total_int } } } \iow_shipout:Nn \@mainaux \ExplSyntaxOff } } % \end{macrocode} % % % By default, 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 know whether a diagonal is % the first of its type in the current |{NiceArray}| environment. % \begin{macrocode} \bool_if:NT \l_@@_parallelize_diags_bool { \int_gzero_new:N \g_@@_ddots_int \int_gzero_new:N \g_@@_iddots_int % \end{macrocode} % % The dimensions |\g_@@_delta_x_one_dim| and |\g_@@_delta_y_one_dim| will % contain 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 |\g_@@_delta_x_two_dim| and % |\g_@@_delta_y_two_dim| are the $\Delta_x$ and $\Delta_y$ of the first % |\Iddots| diagonal. % \begin{macrocode} \dim_gzero_new:N \g_@@_delta_x_one_dim \dim_gzero_new:N \g_@@_delta_y_one_dim \dim_gzero_new:N \g_@@_delta_x_two_dim \dim_gzero_new:N \g_@@_delta_y_two_dim } % \end{macrocode} % % \begin{macrocode} \bool_if:nTF \l_@@_medium_nodes_bool { \bool_if:NTF \l_@@_large_nodes_bool \@@_create_medium_and_large_nodes: \@@_create_medium_nodes: } { \bool_if:NT \l_@@_large_nodes_bool \@@_create_large_nodes: } \int_zero_new:N \l_@@_initial_i_int \int_zero_new:N \l_@@_initial_j_int \int_zero_new:N \l_@@_final_i_int \int_zero_new:N \l_@@_final_j_int \bool_set_false:N \l_@@_initial_open_bool \bool_set_false:N \l_@@_final_open_bool % \end{macrocode} % % If the option |small| is used, the values |\l_@@_radius_dim| and % |\l_@@_inter_dots_dim| (used to draw the dotted lines created by % |\hdottedline| and |\vdotteline| and also for all the other dotted lines when % |line-style| is equal to |standard|, which is the initial value) are changed. % \begin{macrocode} \bool_if:NT \l_@@_small_bool { \dim_set:Nn \l_@@_radius_dim { 0.37 pt } \dim_set:Nn \l_@@_inter_dots_dim { 0.25 em } % \end{macrocode} % The dimension |\l_@@_xdots_shorten_dim| corresponds to the option % |xdots/shorten| available to the user. That's why we give a new value % according to the current value, and not an absolute value. % \begin{macrocode} \dim_set:Nn \l_@@_xdots_shorten_dim { 0.6 \l_@@_xdots_shorten_dim } } % \end{macrocode} % % % \bigskip % Now, we really draw the lines. % \begin{macrocode} \@@_draw_dotted_lines: % \end{macrocode} % % We draw the vertical rules of the option |vlines| before the % |internal-code-after| because the option |white| of a |\Block| may have to % erase these vertical rules. % \begin{macrocode} \bool_if:NT \l_@@_vlines_bool \@@_draw_vlines: \g_@@_internal_code_after_tl \tl_gclear:N \g_@@_internal_code_after_tl \bool_if:NT \c_@@_tikz_loaded_bool { \tikzset { every~picture / .style = { overlay , remember~picture , name~prefix = \@@_env: - } } } \cs_set_eq:NN \line \@@_line \g_@@_code_after_tl \tl_gclear:N \g_@@_code_after_tl \group_end: \str_gclear:N \g_@@_name_env_str \@@_restore_iRow_jCol: } % \end{macrocode} % % \bigskip % We recall that, when externalization is used, |\tikzpicture| and % |\endtikzpicture| (or |\pgfpicture| and |\endpgfpicture|) must be directly % ``visible''. That's why we have to define the adequate version of % |\@@_draw_dotted_lines:| whether Tikz is loaded or not (in that case, only % \textsc{pgf} is loaded). % \begin{macrocode} \AtBeginDocument { \cs_new_protected:Npx \@@_draw_dotted_lines: { \c_@@_pgfortikzpicture_tl \@@_draw_dotted_lines_i: \c_@@_endpgfortikzpicture_tl } } % \end{macrocode} % % The following command \emph{must} be protected because it will appear in the % construction of the command |\@@_draw_dotted_lines:|. % \begin{macrocode} \cs_new_protected:Npn \@@_draw_dotted_lines_i: { \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \g_@@_Hdotsfor_lines_tl \g_@@_Vdots_lines_tl \g_@@_Ddots_lines_tl \g_@@_Iddots_lines_tl \g_@@_Cdots_lines_tl \g_@@_Ldots_lines_tl } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_restore_iRow_jCol: { \cs_if_exist:NT \theiRow { \int_gset_eq:NN \c@iRow \l_@@_save_iRow_int } \cs_if_exist:NT \thejCol { \int_gset_eq:NN \c@jCol \l_@@_save_jCol_int } } % \end{macrocode} % % \bigskip % A dotted line will be said \emph{open} in one of its extremities when it stops % on the edge of the matrix and \emph{closed} otherwise. In the following % matrix, the dotted line is closed on its left extremity and open on its right. % \[ \begin{pNiceMatrix} % a+b+c & a+b & a\\ % a & \Cdots \\ % a & a+b & a+b+c % \end{pNiceMatrix}\] % % % \bigskip % The command |\@@_find_extremities_of_line:nnnn| takes four arguments: % % \begin{itemize} % \item the first argument is the row of the cell where the command was issued; % \item the second argument is the column of the cell where the command was % issued; % \item the third argument is the $x$-value of the orientation vector of the % line; % \item the fourth argument is the $y$-value of the orientation vector of the % line. % \end{itemize} % % This command computes: % % \begin{itemize} % \item |\l_@@_initial_i_int| and |\l_@@_initial_j_int| which are the % coordinates of one extremity of the line; % \item |\l_@@_final_i_int| and |\l_@@_final_j_int| which are the coordinates of % the other extremity of the line; % \item |\l_@@_initial_open_bool| and |\l_@@_final_open_bool| to indicate % whether the extremities are open or not. % \end{itemize} % % \begin{macrocode} \cs_new_protected:Npn \@@_find_extremities_of_line:nnnn #1 #2 #3 #4 { % \end{macrocode} % First, we declare the current cell as ``dotted'' because we forbide % intersections of dotted lines. % \begin{macrocode} \cs_set:cpn { @@ _ dotted _ #1 - #2 } { } % \end{macrocode} % Initialization of variables. % \begin{macrocode} \int_set:Nn \l_@@_initial_i_int { #1 } \int_set:Nn \l_@@_initial_j_int { #2 } \int_set:Nn \l_@@_final_i_int { #1 } \int_set:Nn \l_@@_final_j_int { #2 } % \end{macrocode} % We will do two loops: one when determinating the initial cell and the other % when determinating the final cell. The boolean |\l_@@_stop_loop_bool| will be % used to control these loops. In the first loop, we search the ``final'' % extremity of the line. % \begin{macrocode} \bool_set_false:N \l_@@_stop_loop_bool \bool_do_until:Nn \l_@@_stop_loop_bool { \int_add:Nn \l_@@_final_i_int { #3 } \int_add:Nn \l_@@_final_j_int { #4 } % \end{macrocode} % We test if we are still in the matrix. % \begin{macrocode} \bool_set_false:N \l_@@_final_open_bool \int_compare:nNnTF \l_@@_final_i_int > \c@iRow { \int_compare:nNnTF { #3 } = 1 { \bool_set_true:N \l_@@_final_open_bool } { \int_compare:nNnT \l_@@_final_j_int > \c@jCol { \bool_set_true:N \l_@@_final_open_bool } } } { \int_compare:nNnTF \l_@@_final_j_int < 1 { \int_compare:nNnT { #4 } = { -1 } { \bool_set_true:N \l_@@_final_open_bool } } { \int_compare:nNnT \l_@@_final_j_int > \c@jCol { \int_compare:nNnT { #4 } = 1 { \bool_set_true:N \l_@@_final_open_bool } } } } \bool_if:NTF \l_@@_final_open_bool % \end{macrocode} % If we are outside the matrix, we have found the extremity of the dotted line % and it's an \emph{open} extremity. % \begin{macrocode} { % \end{macrocode} % We do a step backwards. % \begin{macrocode} \int_sub:Nn \l_@@_final_i_int { #3 } \int_sub:Nn \l_@@_final_j_int { #4 } \bool_set_true:N \l_@@_stop_loop_bool } % \end{macrocode} % If we are in the matrix, we test whether 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} { \cs_if_exist:cTF { @@ _ dotted _ \int_use:N \l_@@_final_i_int - \int_use:N \l_@@_final_j_int } { \int_sub:Nn \l_@@_final_i_int { #3 } \int_sub:Nn \l_@@_final_j_int { #4 } \bool_set_true:N \l_@@_final_open_bool \bool_set_true:N \l_@@_stop_loop_bool } { \cs_if_exist:cTF { pgf @ sh @ ns @ \@@_env: - \int_use:N \l_@@_final_i_int - \int_use:N \l_@@_final_j_int } { \bool_set_true:N \l_@@_stop_loop_bool } % \end{macrocode} % If the case is empty, we declare that the cell as non-empty. Indeed, we will % draw a dotted line and the cell will be on that dotted line. All the cells of % a dotted line have to be mark as ``dotted'' because we don't want % intersections between dotted lines. We recall that the research of the % extremities of the lines are all done in the same TeX group (the group of the % environnement), even though, when the extremities are found, each line is % drawn in a TeX group that we will open for the options of the line. % \begin{macrocode} { \cs_set:cpn { @@ _ dotted _ \int_use:N \l_@@_final_i_int - \int_use:N \l_@@_final_j_int } { } } } } } % \end{macrocode} % % \interitem % For |\l_@@_initial_i_int| and |\l_@@_initial_j_int| the programmation is % similar to the previous one. % \begin{macrocode} \bool_set_false:N \l_@@_stop_loop_bool \bool_do_until:Nn \l_@@_stop_loop_bool { \int_sub:Nn \l_@@_initial_i_int { #3 } \int_sub:Nn \l_@@_initial_j_int { #4 } \bool_set_false:N \l_@@_initial_open_bool \int_compare:nNnTF \l_@@_initial_i_int < 1 { \int_compare:nNnTF { #3 } = 1 { \bool_set_true:N \l_@@_initial_open_bool } { \int_compare:nNnT \l_@@_initial_j_int = 0 { \bool_set_true:N \l_@@_initial_open_bool } } } { \int_compare:nNnTF \l_@@_initial_j_int < 1 { \int_compare:nNnT { #4 } = 1 { \bool_set_true:N \l_@@_initial_open_bool } } { \int_compare:nNnT \l_@@_initial_j_int > \c@jCol { \int_compare:nNnT { #4 } = { -1 } { \bool_set_true:N \l_@@_initial_open_bool } } } } \bool_if:NTF \l_@@_initial_open_bool { \int_add:Nn \l_@@_initial_i_int { #3 } \int_add:Nn \l_@@_initial_j_int { #4 } \bool_set_true:N \l_@@_stop_loop_bool } { \cs_if_exist:cTF { @@ _ dotted _ \int_use:N \l_@@_initial_i_int - \int_use:N \l_@@_initial_j_int } { \int_add:Nn \l_@@_initial_i_int { #3 } \int_add:Nn \l_@@_initial_j_int { #4 } \bool_set_true:N \l_@@_initial_open_bool \bool_set_true:N \l_@@_stop_loop_bool } { \cs_if_exist:cTF { pgf @ sh @ ns @ \@@_env: - \int_use:N \l_@@_initial_i_int - \int_use:N \l_@@_initial_j_int } { \bool_set_true:N \l_@@_stop_loop_bool } { \cs_set:cpn { @@ _ dotted _ \int_use:N \l_@@_initial_i_int - \int_use:N \l_@@_initial_j_int } { } } } } } } % \end{macrocode} % % \medskip % \begin{macrocode} \cs_new:Nn \@@_initial_cell: { \@@_env: - \int_use:N \l_@@_initial_i_int - \int_use:N \l_@@_initial_j_int } \cs_new:Nn \@@_final_cell: { \@@_env: - \int_use:N \l_@@_final_i_int - \int_use:N \l_@@_final_j_int } \cs_new_protected:Npn \@@_set_initial_coords: { \dim_set_eq:NN \l_@@_x_initial_dim \pgf@x \dim_set_eq:NN \l_@@_y_initial_dim \pgf@y } \cs_new_protected:Npn \@@_set_final_coords: { \dim_set_eq:NN \l_@@_x_final_dim \pgf@x \dim_set_eq:NN \l_@@_y_final_dim \pgf@y } \cs_new_protected:Npn \@@_set_initial_coords_from_anchor:n #1 { \pgfpointanchor \@@_initial_cell: { #1 } \@@_set_initial_coords: } \cs_new_protected:Npn \@@_set_final_coords_from_anchor:n #1 { \pgfpointanchor \@@_final_cell: { #1 } \@@_set_final_coords: } % \end{macrocode} % % \interitem % The first and the second arguments are the coordinates of the cell where the % command has been issued. The third argument is the list of the options. % \begin{macrocode} \cs_new_protected:Npn \@@_draw_Ldots:nnn #1 #2 #3 { \cs_if_free:cT { @@ _ dotted _ #1 - #2 } { \@@_find_extremities_of_line:nnnn { #1 } { #2 } 0 1 % \end{macrocode} % The previous command may have changed the current environment by marking some % cells as ``dotted'', but, fortunately, it is outside the group for the options % of the line. % \begin{macrocode} \group_begin: \int_compare:nNnTF { #1 } = 0 { \color { nicematrix-first-row } } { % \end{macrocode} % We remind that, when there is a ``last row'' |\l_@@_last_row_int| will always % be (after the construction of the array) the number of that ``last row'' even % if the option |last-row| has been used without value. % \begin{macrocode} \int_compare:nNnT { #1 } = \l_@@_last_row_int { \color { nicematrix-last-row } } } \keys_set:nn { NiceMatrix / xdots } { #3 } \tl_if_empty:VF \l_@@_xdots_color_tl { \color { \l_@@_xdots_color_tl } } \@@_actually_draw_Ldots: \group_end: } } % \end{macrocode} % % % \medskip % The command |\@@_actually_draw_Ldots:| has the following implicit arguments: % \begin{itemize} % \item |\l_@@_initial_i_int| % \item |\l_@@_initial_j_int| % \item |\l_@@_initial_open_bool| % \item |\l_@@_final_i_int| % \item |\l_@@_final_j_int| % \item |\l_@@_final_open_bool|. % \end{itemize} % % The following function is also used by |\Hdotsfor|. % \begin{macrocode} \cs_new_protected:Npn \@@_actually_draw_Ldots: { \bool_if:NTF \l_@@_initial_open_bool { \@@_qpoint: { col - \int_use:N \l_@@_initial_j_int } \dim_set_eq:NN \l_@@_x_initial_dim \pgf@x \dim_add:Nn \l_@@_x_initial_dim \arraycolsep \@@_qpoint: { row - \int_use:N \l_@@_initial_i_int - base } \dim_set_eq:NN \l_@@_y_initial_dim \pgf@y } { \@@_set_initial_coords_from_anchor:n { base~east } } \bool_if:NTF \l_@@_final_open_bool { \@@_qpoint: { col - \@@_succ:n \l_@@_final_j_int } \dim_set_eq:NN \l_@@_x_final_dim \pgf@x \dim_sub:Nn \l_@@_x_final_dim \arraycolsep \@@_qpoint: { row - \int_use:N \l_@@_final_i_int - base } \dim_set_eq:NN \l_@@_y_final_dim \pgf@y } { \@@_set_final_coords_from_anchor:n { base~west } } % \end{macrocode} % We raise the line of a quantity equal to the radius of the dots because we % want the dots really ``on'' the line of texte. % \begin{macrocode} \dim_add:Nn \l_@@_y_initial_dim \l_@@_radius_dim \dim_add:Nn \l_@@_y_final_dim \l_@@_radius_dim \@@_draw_line: } % \end{macrocode} % % \interitem % The first and the second arguments are the coordinates of the cell where the % command has been issued. The third argument is the list of the options. % \begin{macrocode} \cs_new_protected:Npn \@@_draw_Cdots:nnn #1 #2 #3 { \cs_if_free:cT { @@ _ dotted _ #1 - #2 } { \@@_find_extremities_of_line:nnnn { #1 } { #2 } 0 1 % \end{macrocode} % The previous command may have changed the current environment by marking some % cells as ``dotted'', but, fortunately, it is outside the group for the options % of the line. % \begin{macrocode} \group_begin: \int_compare:nNnTF { #1 } = 0 { \color { nicematrix-first-row } } { % \end{macrocode} % We remind that, when there is a ``last row'' |\l_@@_last_row_int| will always % be (after the construction of the array) the number of that ``last row'' even % if the option |last-row| has been used without value. % \begin{macrocode} \int_compare:nNnT { #1 } = \l_@@_last_row_int { \color { nicematrix-last-row } } } \keys_set:nn { NiceMatrix / xdots } { #3 } \tl_if_empty:VF \l_@@_xdots_color_tl { \color { \l_@@_xdots_color_tl } } \@@_actually_draw_Cdots: \group_end: } } % \end{macrocode} % % \medskip % The command |\@@_actually_draw_Cdots:| has the following implicit arguments: % \begin{itemize} % \item |\l_@@_initial_i_int| % \item |\l_@@_initial_j_int| % \item |\l_@@_initial_open_bool| % \item |\l_@@_final_i_int| % \item |\l_@@_final_j_int| % \item |\l_@@_final_open_bool|. % \end{itemize} % % \begin{macrocode} \cs_new_protected:Npn \@@_actually_draw_Cdots: { \bool_if:NTF \l_@@_initial_open_bool { \@@_qpoint: { col - \int_use:N \l_@@_initial_j_int } \dim_set_eq:NN \l_@@_x_initial_dim \pgf@x \dim_add:Nn \l_@@_x_initial_dim \arraycolsep } { \@@_set_initial_coords_from_anchor:n { mid~east } } \bool_if:NTF \l_@@_final_open_bool { \@@_qpoint: { col - \@@_succ:n \l_@@_final_j_int } \dim_set_eq:NN \l_@@_x_final_dim \pgf@x \dim_sub:Nn \l_@@_x_final_dim \arraycolsep } { \@@_set_final_coords_from_anchor:n { mid~west } } \bool_lazy_and:nnTF \l_@@_initial_open_bool \l_@@_final_open_bool { \@@_qpoint: { row - \int_use:N \l_@@_initial_i_int } \dim_set_eq:NN \l_tmpa_dim \pgf@y \@@_qpoint: { row - \@@_succ:n \l_@@_initial_i_int } \dim_set:Nn \l_@@_y_initial_dim { ( \l_tmpa_dim + \pgf@y ) / 2 } \dim_set_eq:NN \l_@@_y_final_dim \l_@@_y_initial_dim } { \bool_if:NT \l_@@_initial_open_bool { \dim_set_eq:NN \l_@@_y_initial_dim \l_@@_y_final_dim } \bool_if:NT \l_@@_final_open_bool { \dim_set_eq:NN \l_@@_y_final_dim \l_@@_y_initial_dim } } \@@_draw_line: } % \end{macrocode} % % % The first and the second arguments are the coordinates of the cell where the % command has been issued. The third argument is the list of the options. % \begin{macrocode} \cs_new_protected:Npn \@@_draw_Vdots:nnn #1 #2 #3 { \tl_if_empty:VF \l_@@_xdots_color_tl { \color { \l_@@_xdots_color_tl } } \cs_if_free:cT { @@ _ dotted _ #1 - #2 } { \@@_find_extremities_of_line:nnnn { #1 } { #2 } 1 0 % \end{macrocode} % The previous command may have changed the current environment by marking some % cells as ``dotted'', but, fortunately, it is outside the group for the options % of the line. % \begin{macrocode} \group_begin: \int_compare:nNnTF { #2 } = 0 { \color { nicematrix-first-col } } { \int_compare:nNnT { #2 } = \l_@@_last_col_int { \color { nicematrix-last-col } } } \keys_set:nn { NiceMatrix / xdots } { #3 } \@@_actually_draw_Vdots: \group_end: } } % \end{macrocode} % % \bigskip % The command |\@@_actually_draw_Vdots:| has the following implicit arguments: % \begin{itemize} % \item |\l_@@_initial_i_int| % \item |\l_@@_initial_j_int| % \item |\l_@@_initial_open_bool| % \item |\l_@@_final_i_int| % \item |\l_@@_final_j_int| % \item |\l_@@_final_open_bool|. % \end{itemize} % \begin{macrocode} \cs_new_protected:Npn \@@_actually_draw_Vdots: { % \end{macrocode} % The boolean |\l_tmpa_bool| indicates whether the column is of type |l| (|L| of % |{NiceArray}|) or may be considered as if. % \begin{macrocode} \bool_set_false:N \l_tmpa_bool \bool_lazy_or:nnF \l_@@_initial_open_bool \l_@@_final_open_bool { \@@_set_initial_coords_from_anchor:n { south~west } \@@_set_final_coords_from_anchor:n { north~west } \bool_set:Nn \l_tmpa_bool { \dim_compare_p:nNn \l_@@_x_initial_dim = \l_@@_x_final_dim } } % \end{macrocode} % Now, we try to determine whether the column is of type |c| (|C| of % |{NiceArray}|) or may be considered as if. % \begin{macrocode} \bool_if:NTF \l_@@_initial_open_bool { \@@_qpoint: { row - 1 } \dim_set_eq:NN \l_@@_y_initial_dim \pgf@y } { \@@_set_initial_coords_from_anchor:n { south } } \bool_if:NTF \l_@@_final_open_bool { \@@_qpoint: { row - \@@_succ:n \c@iRow } \dim_set_eq:NN \l_@@_y_final_dim \pgf@y } { \@@_set_final_coords_from_anchor:n { north } } \bool_if:NTF \l_@@_initial_open_bool { \bool_if:NTF \l_@@_final_open_bool { \@@_qpoint: { col - \int_use:N \l_@@_initial_j_int } \dim_set_eq:NN \l_tmpa_dim \pgf@x \@@_qpoint: { col - \@@_succ:n \l_@@_initial_j_int } \dim_set:Nn \l_@@_x_initial_dim { ( \pgf@x + \l_tmpa_dim ) / 2 } \dim_set_eq:NN \l_@@_x_final_dim \l_@@_x_initial_dim } { \dim_set_eq:NN \l_@@_x_initial_dim \l_@@_x_final_dim } } { \bool_if:NTF \l_@@_final_open_bool { \dim_set_eq:NN \l_@@_x_final_dim \l_@@_x_initial_dim } { % \end{macrocode} % Now the case where both extremities are closed. The first conditional tests % whether the column is of type |c| (|C| of |{NiceArray}|) or may be considered % as if. % \begin{macrocode} \dim_compare:nNnF \l_@@_x_initial_dim = \l_@@_x_final_dim { \dim_set:Nn \l_@@_x_initial_dim { \bool_if:NTF \l_tmpa_bool \dim_min:nn \dim_max:nn \l_@@_x_initial_dim \l_@@_x_final_dim } \dim_set_eq:NN \l_@@_x_final_dim \l_@@_x_initial_dim } } } \@@_draw_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. % % The first and the second arguments are the coordinates of the cell where the % command has been issued. The third argument is the list of the options. % \begin{macrocode} \cs_new_protected:Npn \@@_draw_Ddots:nnn #1 #2 #3 { \cs_if_free:cT { @@ _ dotted _ #1 - #2 } { \@@_find_extremities_of_line:nnnn { #1 } { #2 } 1 1 % \end{macrocode} % The previous command may have changed the current environment by marking some % cells as ``dotted'', but, fortunately, it is outside the group for the options % of the line. % \begin{macrocode} \group_begin: \keys_set:nn { NiceMatrix / xdots } { #3 } \tl_if_empty:VF \l_@@_xdots_color_tl { \color { \l_@@_xdots_color_tl } } \@@_actually_draw_Ddots: \group_end: } } % \end{macrocode} % % \bigskip % The command |\@@_actually_draw_Ddots:| has the following implicit arguments: % \begin{itemize} % \item |\l_@@_initial_i_int| % \item |\l_@@_initial_j_int| % \item |\l_@@_initial_open_bool| % \item |\l_@@_final_i_int| % \item |\l_@@_final_j_int| % \item |\l_@@_final_open_bool|. % \end{itemize} % % \begin{macrocode} \cs_new_protected:Npn \@@_actually_draw_Ddots: { \bool_if:NTF \l_@@_initial_open_bool { \@@_qpoint: { row - \int_use:N \l_@@_initial_i_int } \dim_set_eq:NN \l_@@_y_initial_dim \pgf@y \@@_qpoint: { col - \int_use:N \l_@@_initial_j_int } \dim_set_eq:NN \l_@@_x_initial_dim \pgf@x } { \@@_set_initial_coords_from_anchor:n { south~east } } \bool_if:NTF \l_@@_final_open_bool { \@@_qpoint: { row - \@@_succ:n \l_@@_final_i_int } \dim_set_eq:NN \l_@@_y_final_dim \pgf@y \@@_qpoint: { col - \@@_succ:n \l_@@_final_j_int } \dim_set_eq:NN \l_@@_x_final_dim \pgf@x } { \@@_set_final_coords_from_anchor:n { north~west } } % \end{macrocode} % We have retrieved the coordinates in the usual way (they are stored in % |\l_@@_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_gincr:N \g_@@_ddots_int % \end{macrocode} % We test if the diagonal line is the first one (the counter |\g_@@_ddots_int| % is created for this usage). % \begin{macrocode} \int_compare:nNnTF \g_@@_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_gset:Nn \g_@@_delta_x_one_dim { \l_@@_x_final_dim - \l_@@_x_initial_dim } \dim_gset:Nn \g_@@_delta_y_one_dim { \l_@@_y_final_dim - \l_@@_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 |\l_@@_x_initial_dim|. % \begin{macrocode} { \dim_set:Nn \l_@@_y_final_dim { \l_@@_y_initial_dim + ( \l_@@_x_final_dim - \l_@@_x_initial_dim ) * \dim_ratio:nn \g_@@_delta_y_one_dim \g_@@_delta_x_one_dim } } } \@@_draw_line: } % \end{macrocode} % % \bigskip % We draw the |\Iddots| diagonals in the same way. % % The first and the second arguments are the coordinates of the cell where the % command has been issued. The third argument is the list of the options. % \begin{macrocode} \cs_new_protected:Npn \@@_draw_Iddots:nnn #1 #2 #3 { \cs_if_free:cT { @@ _ dotted _ #1 - #2 } { \@@_find_extremities_of_line:nnnn { #1 } { #2 } 1 { -1 } % \end{macrocode} % The previous command may have changed the current environment by marking some % cells as ``dotted'', but, fortunately, it is outside the group for the options % of the line. % \begin{macrocode} \group_begin: \keys_set:nn { NiceMatrix / xdots } { #3 } \tl_if_empty:VF \l_@@_xdots_color_tl { \color { \l_@@_xdots_color_tl } } \@@_actually_draw_Iddots: \group_end: } } % \end{macrocode} % % \bigskip % The command |\@@_actually_draw_Iddots:| has the following implicit arguments: % \begin{itemize} % \item |\l_@@_initial_i_int| % \item |\l_@@_initial_j_int| % \item |\l_@@_initial_open_bool| % \item |\l_@@_final_i_int| % \item |\l_@@_final_j_int| % \item |\l_@@_final_open_bool|. % \end{itemize} % % \begin{macrocode} \cs_new_protected:Npn \@@_actually_draw_Iddots: { \bool_if:NTF \l_@@_initial_open_bool { \@@_qpoint: { row - \int_use:N \l_@@_initial_i_int } \dim_set_eq:NN \l_@@_y_initial_dim \pgf@y \@@_qpoint: { col - \@@_succ:n \l_@@_initial_j_int } \dim_set_eq:NN \l_@@_x_initial_dim \pgf@x } { \@@_set_initial_coords_from_anchor:n { south~west } } \bool_if:NTF \l_@@_final_open_bool { \@@_qpoint: { row - \@@_succ:n \l_@@_final_i_int } \dim_set_eq:NN \l_@@_y_final_dim \pgf@y \@@_qpoint: { col - \int_use:N \l_@@_final_j_int } \dim_set_eq:NN \l_@@_x_final_dim \pgf@x } { \@@_set_final_coords_from_anchor:n { north~east } } \bool_if:NT \l_@@_parallelize_diags_bool { \int_gincr:N \g_@@_iddots_int \int_compare:nNnTF \g_@@_iddots_int = 1 { \dim_gset:Nn \g_@@_delta_x_two_dim { \l_@@_x_final_dim - \l_@@_x_initial_dim } \dim_gset:Nn \g_@@_delta_y_two_dim { \l_@@_y_final_dim - \l_@@_y_initial_dim } } { \dim_set:Nn \l_@@_y_final_dim { \l_@@_y_initial_dim + ( \l_@@_x_final_dim - \l_@@_x_initial_dim ) * \dim_ratio:nn \g_@@_delta_y_two_dim \g_@@_delta_x_two_dim } } } \@@_draw_line: } % \end{macrocode} % % % \bigskip % The command |\NiceMatrixLastEnv| is not used by the package \pkg{nicematrix}. % It's only a facility given to the final user. It gives the number of the last % environment (in fact the number of the current environment but it's meant to % be used after the environment in order to refer to that environment --- and % its nodes --- without having to give it a name). % \begin{macrocode} \NewExpandableDocumentCommand \NiceMatrixLastEnv { } { \int_use:N \g_@@_env_int } % \end{macrocode} % % \bigskip % \subsection*{The actual instructions for drawing the dotted line with Tikz} % % The command |\@@_draw_line:| should be used in a |{pgfpicture}|. It has six % implicit arguments: % % \begin{itemize} % \item |\l_@@_x_initial_dim| % \item |\l_@@_y_initial_dim| % \item |\l_@@_x_final_dim| % \item |\l_@@_y_final_dim| % \item |\l_@@_initial_open_bool| % \item |\l_@@_final_open_bool| % \end{itemize} % % % % \begin{macrocode} \cs_new_protected:Npn \@@_draw_line: { \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \tl_if_eq:NNTF \l_@@_xdots_line_style_tl \c_@@_standard_tl \@@_draw_standard_dotted_line: \@@_draw_non_standard_dotted_line: } % \end{macrocode} % % \medskip % We have to do a special construction with |\exp_args:NV| to be able to put in % the list of options in the correct place in the Tikz instruction. % \begin{macrocode} \cs_new_protected:Npn \@@_draw_non_standard_dotted_line: { \begin { scope } \exp_args:No \@@_draw_non_standard_dotted_line:n { \l_@@_xdots_line_style_tl , \l_@@_xdots_color_tl } } % \end{macrocode} % We have used the fact that, in \textsc{pgf}, un color name can be put directly % in a list of options (that's why we have put diredtly |\l_@@_xdots_color_tl|). % % \smallskip % The argument of |\@@_draw_non_standard_dotted_line:n| is, in fact, the list of options. % \begin{macrocode} \cs_new_protected:Npn \@@_draw_non_standard_dotted_line:n #1 { \draw [ #1 , shorten~> = \l_@@_xdots_shorten_dim , shorten~< = \l_@@_xdots_shorten_dim , ] ( \l_@@_x_initial_dim , \l_@@_y_initial_dim ) -- node [ sloped , above ] { \c_math_toggle_token \scriptstyle \l_@@_xdots_up_tl \c_math_toggle_token } node [ sloped , below ] { \c_math_toggle_token \scriptstyle \l_@@_xdots_down_tl \c_math_toggle_token } ( \l_@@_x_final_dim , \l_@@_y_final_dim ) ; \end { scope } } % \end{macrocode} % % \bigskip % The command |\@@_draw_standard_dotted_line:| draws the line with our system of points % (which give a dotted line with real round points). % \begin{macrocode} \cs_new_protected:Npn \@@_draw_standard_dotted_line: { % \end{macrocode} % First, we put the labels. % \begin{macrocode} \bool_lazy_and:nnF { \tl_if_empty_p:N \l_@@_xdots_up_tl } { \tl_if_empty_p:N \l_@@_xdots_down_tl } { \pgfscope \pgftransformshift { \pgfpointlineattime { 0.5 } { \pgfpoint \l_@@_x_initial_dim \l_@@_y_initial_dim } { \pgfpoint \l_@@_x_final_dim \l_@@_y_final_dim } } \pgftransformrotate { \fp_eval:n { atand ( \l_@@_y_final_dim - \l_@@_y_initial_dim , \l_@@_x_final_dim - \l_@@_x_initial_dim ) } } \pgfnode { rectangle } { south } { \c_math_toggle_token \scriptstyle \l_@@_xdots_up_tl \c_math_toggle_token } { } { \pgfusepath { } } \pgfnode { rectangle } { north } { \c_math_toggle_token \scriptstyle \l_@@_xdots_down_tl \c_math_toggle_token } { } { \pgfusepath { } } \endpgfscope } \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \group_begin: % \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 ( ( \l_@@_x_final_dim - \l_@@_x_initial_dim ) ^ 2 + ( \l_@@_y_final_dim - \l_@@_y_initial_dim ) ^ 2 ) } } % \end{macrocode} % It seems that, during the first compilations, the value of |\l_@@_l_dim| may % be erroneous (equal to zero or very large). We must detect these cases % because they would cause errors during the drawing of the dotted line. Maybe % we should also write something in the |aux| file to say that one more % compilation should be done. % \begin{macrocode} \bool_lazy_or:nnF { \dim_compare_p:nNn { \dim_abs:n \l_@@_l_dim } > \c_@@_max_l_dim } { \dim_compare_p:nNn \l_@@_l_dim = \c_zero_dim } \@@_draw_standard_dotted_line_i: \group_end: } % \end{macrocode} % % \begin{macrocode} \dim_const:Nn \c_@@_max_l_dim { 50 cm } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_draw_standard_dotted_line_i: { % \end{macrocode} % The integer |\l_tmpa_int| is the number of dots of the dotted line. % \begin{macrocode} \bool_if:NTF \l_@@_initial_open_bool { \bool_if:NTF \l_@@_final_open_bool { \int_set:Nn \l_tmpa_int { \dim_ratio:nn \l_@@_l_dim \l_@@_inter_dots_dim } } { \int_set:Nn \l_tmpa_int { \dim_ratio:nn { \l_@@_l_dim - \l_@@_xdots_shorten_dim } \l_@@_inter_dots_dim } } } { \bool_if:NTF \l_@@_final_open_bool { \int_set:Nn \l_tmpa_int { \dim_ratio:nn { \l_@@_l_dim - \l_@@_xdots_shorten_dim } \l_@@_inter_dots_dim } } { \int_set:Nn \l_tmpa_int { \dim_ratio:nn { \l_@@_l_dim - 2 \l_@@_xdots_shorten_dim } \l_@@_inter_dots_dim } } } % \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 { ( \l_@@_x_final_dim - \l_@@_x_initial_dim ) * \dim_ratio:nn \l_@@_inter_dots_dim \l_@@_l_dim } \dim_set:Nn \l_tmpb_dim { ( \l_@@_y_final_dim - \l_@@_y_initial_dim ) * \dim_ratio:nn \l_@@_inter_dots_dim \l_@@_l_dim } % \end{macrocode} % % The length $\ell$ is the length of the dotted line. We note $\Delta$ the % length between two dots and $n$ the number of intervals between dots. We note % $\delta = \frac12(\ell - n \Delta)$. The distance between the initial % extremity of the line and the first dot will be equal to $k\cdot\delta$ where % $k=0$, $1$ or $2$. We first compute this number $k$ in |\l_tmpb_int|. % \begin{macrocode} \int_set:Nn \l_tmpb_int { \bool_if:NTF \l_@@_initial_open_bool { \bool_if:NTF \l_@@_final_open_bool 1 0 } { \bool_if:NTF \l_@@_final_open_bool 2 1 } } % \end{macrocode} % In the loop over the dots, the dimensions |\l_@@_x_initial_dim| and % |\l_@@_y_initial_dim| will be used for the coordinates of the dots. But, % before the loop, we must move until the first dot. % % \begin{macrocode} \dim_gadd:Nn \l_@@_x_initial_dim { ( \l_@@_x_final_dim - \l_@@_x_initial_dim ) * \dim_ratio:nn { \l_@@_l_dim - \l_@@_inter_dots_dim * \l_tmpa_int } { 2 \l_@@_l_dim } * \l_tmpb_int } \dim_gadd:Nn \l_@@_y_initial_dim { ( \l_@@_y_final_dim - \l_@@_y_initial_dim ) * \dim_ratio:nn { \l_@@_l_dim - \l_@@_inter_dots_dim * \l_tmpa_int } { 2 \l_@@_l_dim } * \l_tmpb_int } \pgf@relevantforpicturesizefalse \int_step_inline:nnn 0 \l_tmpa_int { \pgfpathcircle { \pgfpoint \l_@@_x_initial_dim \l_@@_y_initial_dim } { \l_@@_radius_dim } \dim_add:Nn \l_@@_x_initial_dim \l_tmpa_dim \dim_add:Nn \l_@@_y_initial_dim \l_tmpb_dim } \pgfusepathqfill } % \end{macrocode} % % \bigskip % \subsection*{User commands available in the new environments} % % % \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}|). % % The starred versions of these commands are deprecated since version~3.1 but, % as for now, they are still available with an error. % % % \medskip % The syntax of these commands uses the character |_| as embellishment and % thats' why we have to insert a character |_| in the \emph{arg spec} of these % commands. However, we don't know the future catcode of |_| in the main % document (maybe the user will use \pkg{underscore}, and, in that case, the % catcode is $13$ because \pkg{underscore} activates |_|). That's why these % commands will be defined in a |\AtBeginDocument| and the \emph{arg spec} will % be rescanned. % % \begin{macrocode} \AtBeginDocument { \tl_set:Nn \l_@@_argspec_tl { s O { } E { _ ^ } { { } { } } } \tl_set_rescan:Nno \l_@@_argspec_tl { } \l_@@_argspec_tl \exp_args:NNV \NewDocumentCommand \@@_Ldots \l_@@_argspec_tl { \bool_if:nTF { #1 } { \@@_error:n { starred~commands } } { \@@_instruction_of_type:nn { Ldots } { #2 , down = #3 , up = #4 } } \bool_if:NF \l_@@_nullify_dots_bool { \phantom \@@_ldots } \bool_gset_true:N \g_@@_empty_cell_bool } % \end{macrocode} % % \bigskip % \begin{macrocode} \exp_args:NNV \NewDocumentCommand \@@_Cdots \l_@@_argspec_tl { \bool_if:nTF { #1 } { \@@_error:n { starred~commands } } { \@@_instruction_of_type:nn { Cdots } { #2 , down = #3 , up = #4 } } \bool_if:NF \l_@@_nullify_dots_bool { \phantom \@@_cdots } \bool_gset_true:N \g_@@_empty_cell_bool } % \end{macrocode} % % \bigskip % \begin{macrocode} \exp_args:NNV \NewDocumentCommand \@@_Vdots \l_@@_argspec_tl { \bool_if:nTF { #1 } { \@@_error:n { starred~commands } } { \@@_instruction_of_type:nn { Vdots } { #2 , down = #3 , up = #4 } } \bool_if:NF \l_@@_nullify_dots_bool { \phantom \@@_vdots } \bool_gset_true:N \g_@@_empty_cell_bool } % \end{macrocode} % % \bigskip % \begin{macrocode} \exp_args:NNV \NewDocumentCommand \@@_Ddots \l_@@_argspec_tl { \bool_if:nTF { #1 } { \@@_error:n { starred~commands } } { \@@_instruction_of_type:nn { Ddots } { #2 , down = #3 , up = #4 } } \bool_if:NF \l_@@_nullify_dots_bool { \phantom \@@_ddots } \bool_gset_true:N \g_@@_empty_cell_bool } % \end{macrocode} % % \bigskip % \begin{macrocode} \exp_args:NNV \NewDocumentCommand \@@_Iddots \l_@@_argspec_tl { \bool_if:nTF { #1 } { \@@_error:n { starred~commands } } { \@@_instruction_of_type:nn { Iddots } { #2 , down = #3 , up = #4 } } \bool_if:NF \l_@@_nullify_dots_bool { \phantom \@@_iddots } \bool_gset_true:N \g_@@_empty_cell_bool } } % \end{macrocode} % End of the |\AtBeginDocument|. % % % % \bigskip % The command |\@@_Hspace:| will be linked to |\hspace| in |{NiceArray}|. % \begin{macrocode} \cs_new_protected:Npn \@@_Hspace: { \bool_gset_true:N \g_@@_empty_cell_bool \hspace } % \end{macrocode} % % % \bigskip % In the environment |{NiceArray}|, the command |\multicolumn| will be linked to % the following command |\@@_multicolumn:nnn|. % \begin{macrocode} \cs_set_eq:NN \@@_old_multicolumn \multicolumn \cs_new:Npn \@@_multicolumn:nnn #1 #2 #3 { \@@_old_multicolumn { #1 } { #2 } { #3 } \int_compare:nNnT #1 > 1 { \seq_gput_left:Nx \g_@@_multicolumn_cells_seq { \int_eval:n \c@iRow - \int_use:N \c@jCol } \seq_gput_left:Nn \g_@@_multicolumn_sizes_seq { #1 } } \int_gadd:Nn \c@jCol { #1 - 1 } } % \end{macrocode} % % % \bigskip % The command |\@@_Hdotsfor| will be linked to |\Hdotsfor| in % |{NiceArrayWithDelims}|. This command uses an optional argument (as does % |\hdotsfor|) but this argument is discarded (in |\hdotsfor|, this argument is % used for fine tuning of the space between two consecutive dots). Tikz nodes % are created also the implicit cells of the |\Hdotsfor| (maybe we should modify % that point). % % \medskip % This command must \emph{not} be protected since it begins with |\multicolumn|. % \begin{macrocode} \cs_new:Npn \@@_Hdotsfor: { \multicolumn { 1 } { C } { } \@@_Hdotsfor_i } % \end{macrocode} % % \begin{macrocode} \ExplSyntaxOff \def \@tempa { O { } m O { } E { _ ^ } { { } { } } } \ExplSyntaxOn \tl_set_eq:NN \l_@@_a_signature_tl \@tempa % \end{macrocode} % % The command |\@@_Hdotsfor_i| is defined with the tools of \pkg{xparse} because % it has an optional argument. Note that such a command defined by % |\NewDocumentCommand| is protected and that's why we have put the % |\multicolumn| before (in the definition of |\@@_Hdotsfor:|). % \begin{macrocode} \AtBeginDocument { \tl_set:Nn \l_@@_argspec_tl { O { } m O { } E { _ ^ } { { } { } } } \tl_set_rescan:Nno \l_@@_argspec_tl { } \l_@@_argspec_tl \bool_if:NTF \c_@@_draft_bool { % \end{macrocode} % We don't put |!| before the last optionnal argument for homogeneity with % |\Cdots|, etc. which have only one optional argument. % \begin{macrocode} \exp_args:NNV \NewDocumentCommand \@@_Hdotsfor_i \l_@@_argspec_tl { \prg_replicate:nn { #2 - 1 } { & \multicolumn { 1 } { C } { } } } } { \exp_args:NNV \NewDocumentCommand \@@_Hdotsfor_i \l_@@_argspec_tl { \tl_gput_right:Nx \g_@@_Hdotsfor_lines_tl { \@@_Hdotsfor:nnnn { \int_use:N \c@iRow } { \int_use:N \c@jCol } { #2 } { #1 , #3 , down = #4 , up = #5 } } \prg_replicate:nn { #2 - 1 } { & \multicolumn { 1 } { C } { } } } } } % \end{macrocode} % Enf of |\AtBeginDocument|. % % \medskip % \begin{macrocode} \cs_new_protected:Npn \@@_Hdotsfor:nnnn #1 #2 #3 #4 { \bool_set_false:N \l_@@_initial_open_bool \bool_set_false:N \l_@@_final_open_bool % \end{macrocode} % For the row, it's easy. % \begin{macrocode} \int_set:Nn \l_@@_initial_i_int { #1 } \int_set_eq:NN \l_@@_final_i_int \l_@@_initial_i_int % \end{macrocode} % For the column, it's a bit more complicated. % \begin{macrocode} \int_compare:nNnTF #2 = 1 { \int_set:Nn \l_@@_initial_j_int 1 \bool_set_true:N \l_@@_initial_open_bool } { \cs_if_exist:cTF { pgf @ sh @ ns @ \@@_env: - \int_use:N \l_@@_initial_i_int - \int_eval:n { #2 - 1 } } { \int_set:Nn \l_@@_initial_j_int { #2 - 1 } } { \int_set:Nn \l_@@_initial_j_int { #2 } \bool_set_true:N \l_@@_initial_open_bool } } \int_compare:nNnTF { #2 + #3 -1 } = \c@jCol { \int_set:Nn \l_@@_final_j_int { #2 + #3 - 1 } \bool_set_true:N \l_@@_final_open_bool } { \cs_if_exist:cTF { pgf @ sh @ ns @ \@@_env: - \int_use:N \l_@@_final_i_int - \int_eval:n { #2 + #3 } } { \int_set:Nn \l_@@_final_j_int { #2 + #3 } } { \int_set:Nn \l_@@_final_j_int { #2 + #3 - 1 } \bool_set_true:N \l_@@_final_open_bool } } % \end{macrocode} % % \begin{macrocode} \group_begin: \int_compare:nNnTF { #1 } = 0 { \color { nicematrix-first-row } } { \int_compare:nNnT { #1 } = \g_@@_row_total_int { \color { nicematrix-last-row } } } \keys_set:nn { NiceMatrix / xdots } { #4 } \tl_if_empty:VF \l_@@_xdots_color_tl { \color { \l_@@_xdots_color_tl } } \@@_actually_draw_Ldots: \group_end: % \end{macrocode} % % \medskip % We declare all the cells concerned by the |\Hdotsfor| as ``dotted'' (for the % dotted lines created by |\Cdots|, |\Ldots|, etc., this job is done by % |\@@_find_extremities_of_line:nnnn|). This declaration is done by defining a % special control sequence (to nil). % \begin{macrocode} \int_step_inline:nnn { #2 } { #2 + #3 - 1 } { \cs_set:cpn { @@ _ dotted _ #1 - ##1 } { } } } % \end{macrocode} % % % \bigskip % The control sequence |\@@_rotate:| will be linked to |\rotate| in % |{NiceArrayWithDelims}|. % % The command will exit three levels of groups in order % to execute the command % % \qquad ``|\box_rotate:Nn \l_@@_cell_box { 90 }|'' % % just after the construction of the box |\l_@@_cell_box|. % \begin{macrocode} \cs_new_protected:Npn \@@_rotate: { \group_insert_after:N \@@_rotate_i: } \cs_new_protected:Npn \@@_rotate_i: { \group_insert_after:N \@@_rotate_ii: } \cs_new_protected:Npn \@@_rotate_ii: { \group_insert_after:N \@@_rotate_iii: } \cs_new_protected:Npn \@@_rotate_iii: { \box_rotate:Nn \l_@@_cell_box { 90 } % \end{macrocode} % If we are in the last row, we want all the boxes composed with the command % |\rotate| aligned upwards. % \begin{macrocode} \int_compare:nNnT \c@iRow = \l_@@_last_row_int { \vbox_set_top:Nn \l_@@_cell_box { \vbox_to_zero:n { } % \end{macrocode} % |0.8 ex| will be the distance between the principal part of the array and our % element (which is composed with |\rotate|. % \begin{macrocode} \skip_vertical:n { - \box_ht:N \@arstrutbox + 0.8 ex } \box_use:N \l_@@_cell_box } } } % \end{macrocode} % % \bigskip % \subsection*{The command \textbackslash line accessible in code-after} % % In the |code-after|, the command |\@@_line:nn| will be linked to |\line|. This % command takes two arguments which are the specifications of two cells in the % array (in the format $i$-$j$) and draws a dotted line between these cells. % % \medskip % First, we write a command with an argument of the format $i$-$j$ and applies % the command |\int_eval:n| to $i$ and~$j$ ; this must \emph{not} be protected % (and is, of course fully expandable).\footnote{Indeed, we want that the user % may use the command |\line| in |code-after| with LaTeX counters in the % arguments --- with the command |\value|.} % \begin{macrocode} \cs_new:Npn \@@_double_int_eval:n #1-#2 \q_stop { \int_eval:n { #1 } - \int_eval:n { #2 } } % \end{macrocode} % % \begin{macrocode} \ExplSyntaxOff \def \@tempa { O { } m m ! O { } E { _ ^ } { { } { } } } \ExplSyntaxOn \tl_set_eq:NN \l_@@_a_signature_tl \@tempa % \end{macrocode} % % \medskip % With the following construction, the command |\@@_double_int_eval:n| is % applied to both arguments before the application of |\@@_line_i:nn| (the % construction uses the fact the |\@@_line_i:nn| is protected and that % |\@@_double_int_eval:n| is fully expandable). % \begin{macrocode} \AtBeginDocument { \tl_set:Nn \l_@@_argspec_tl { O { } m m ! O { } E { _ ^ } { { } { } } } \tl_set_rescan:Nno \l_@@_argspec_tl { } \l_@@_argspec_tl \exp_args:NNV \NewDocumentCommand \@@_line \l_@@_argspec_tl { \group_begin: \keys_set:nn { NiceMatrix / xdots } { #1 , #4 , down = #5 , up = #6 } \tl_if_empty:VF \l_@@_xdots_color_tl { \color { \l_@@_xdots_color_tl } } \use:x { \@@_line_i:nn { \@@_double_int_eval:n #2 \q_stop } { \@@_double_int_eval:n #3 \q_stop } } \group_end: } } % \end{macrocode} % % \begin{macrocode} \bool_if:NTF \c_@@_draft_bool { \cs_new_protected:Npn \@@_line_i:nn #1 #2 { } } { \cs_new_protected:Npn \@@_line_i:nn #1 #2 { \bool_set_false:N \l_@@_initial_open_bool \bool_set_false:N \l_@@_final_open_bool \bool_if:nTF { \cs_if_free_p:c { pgf @ sh @ ns @ \@@_env: - #1 } || \cs_if_free_p:c { pgf @ sh @ ns @ \@@_env: - #2 } } { \@@_error:nnn { unknown~cell~for~line~in~code-after } { #1 } { #2 } } { \@@_draw_line_ii:nn { #1 } { #2 } } } } % \end{macrocode} % % \begin{macrocode} \AtBeginDocument { \cs_new_protected:Npx \@@_draw_line_ii:nn #1 #2 { % \end{macrocode} % We recall that, when externalization is used, |\tikzpicture| and % |\endtikzpicture| (or |\pgfpicture| and |\endpgfpicture|) must be directly % ``visible'' and that why we do this static construction of the command % |\@@_draw_line_ii:|. % \begin{macrocode} \c_@@_pgfortikzpicture_tl \@@_draw_line_iii:nn { #1 } { #2 } \c_@@_endpgfortikzpicture_tl } } % \end{macrocode} % % \bigskip % The following command \emph{must} be protected (it's used in the % construction of |\@@_draw_line_ii:nn|). % \begin{macrocode} \cs_new_protected:Npn \@@_draw_line_iii:nn #1 #2 { \pgfrememberpicturepositiononpagetrue \pgfpointshapeborder { \@@_env: - #1 } { \@@_qpoint: { #2 } } \dim_set_eq:NN \l_@@_x_initial_dim \pgf@x \dim_set_eq:NN \l_@@_y_initial_dim \pgf@y \pgfpointshapeborder { \@@_env: - #2 } { \@@_qpoint: { #1 } } \dim_set_eq:NN \l_@@_x_final_dim \pgf@x \dim_set_eq:NN \l_@@_y_final_dim \pgf@y \@@_draw_line: } % \end{macrocode} % % % The commands |\Ldots|, |\Cdots|, |\Vdots|, |\Ddots|, and |\Iddots| don't use % this command because they have to do other settings (for example, the diagonal % lines must be parallelized). % % \bigskip % \subsection*{The vertical rules} % % We give to the user the possibility to define new types of columns (with % |\newcolumntype| of \pkg{array}) for special vertical rules (\emph{e.g.} rules % thicker than the standard ones) which will not extend in the potential % exterior rows of the array. % % We provide the command |\OnlyMainNiceMatrix| in that goal. However, that % command must be no-op outside the environments of \pkg{nicematrix} (and so the % user will be allowed to use the same new type of column in the environments % of \pkg{nicematrix} and in the standard environments of \pkg{array}). % % That's why we provide first a global definition of |\OnlyMainNiceMatrix|. % \begin{macrocode} \cs_set_eq:NN \OnlyMainNiceMatrix \use:n % \end{macrocode} % % \medskip % Another definition of |\OnlyMainNiceMatrix| will be linked to the command in % the environments of \pkg{nicematrix}. Here is that definition, called % |\@@_OnlyMainNiceMatrix:n|. % % \begin{macrocode} \cs_new_protected:Npn \@@_OnlyMainNiceMatrix:n #1 { \int_compare:nNnTF \l_@@_first_col_int = 0 { \@@_OnlyMainNiceMatrix_i:n { #1 } } { \int_compare:nNnTF \c@jCol = 0 { \int_compare:nNnF \c@iRow = { -1 } { \int_compare:nNnF \c@iRow = { \l_@@_last_row_int - 1 } { #1 } } } { \@@_OnlyMainNiceMatrix_i:n { #1 } } } } % \end{macrocode} % This definition may seem complicated by we must remind that the number of row % |\c@iRow| is incremented in the first cell of the row, \emph{after} an % potential vertical rule on the left side of the first cell. % % \smallskip % The command |\@@_OnlyMainNiceMatrix_i:n| is only a short-cut which is used % twice in the above command. This command must \emph{not} be protected. % % \begin{macrocode} \cs_new_protected:Npn \@@_OnlyMainNiceMatrix_i:n #1 { \int_compare:nNnF \c@iRow = 0 { \int_compare:nNnF \c@iRow = \l_@@_last_row_int { #1 } } } % \end{macrocode} % Remember that |\c@iRow| is not always inferior to |\l_@@_last_row_int| because % |\l_@@_last_row_int| may be equal to $-2$ or $-1$ (we can't write % |\int_compare:nNnT \c@iRow < \l_@@_last_row_int|). % % % \medskip % In fact, independently of |\OnlyMainNiceMatrix|, which is a convenience given % to the user, we have to modify the behaviour of the standard specifier ``"|"''. % % % Remark first that the natural way to do that would be to redefine the % specifier ``"|"'' with |\newcolumntype|: % \begin{Verbatim}[commandchars=\~\#\+] % \newcolumntype { | } { ! { \OnlyMainNiceMatrix \vline } } % \end{Verbatim} % % However, this code fails if the user uses "\DefineShortVerb{\|}" of % \pkg{fancyvrb}. Moreover, it would not be able to deal correctly with two % consecutive specifiers ``"|"'' (in a preambule like "ccc||ccc"). % % That's why we have done a redefinition of the macro |\@arrayrule| of % \pkg{array} and this redefinition will add |\@@_vline:| instead of |\vline| to % the preamble (that definition is in the beginning of |{NiceArrayWithDelims}|). % % Here is the definition of |\@@_vline:|. This definition \emph{must} be % protected because you don't want that macro expanded during the construction % of the preamble (the tests in |\@@_OnlyMainNiceMatrix:n| must be effective in % each row and not once for all when the preamble is constructed). % % \medskip % \begin{macrocode} \cs_new_protected:Npn \@@_vline: { \@@_OnlyMainNiceMatrix:n { \@@_vline_i: } } % \end{macrocode} % % If \pkg{colortbl} is loaded, the following macro will be redefined (in a % |\AtBeginDocument|) to take into account the color fixed by |\arrayrulecolor| % of \pkg{colortbl}. % \begin{macrocode} \cs_set_eq:NN \@@_vline_i: \vline % \end{macrocode} % % \bigskip % The command |\@@_draw_vlines| will be executed when the user uses the option % |vlines| (which draws all the vlines of the array). % \begin{macrocode} \cs_new_protected:Npn \@@_draw_vlines: { \group_begin: % \end{macrocode} % The command |\CT@arc@| is a command of color from \pkg{colortbl}. % \begin{macrocode} \bool_if:NT \c_@@_colortbl_loaded_bool \CT@arc@ \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \pgfsetlinewidth \arrayrulewidth % \end{macrocode} % First, we compute in |\l_tmpa_dim| the height of the rules we have to draw. % \begin{macrocode} \@@_qpoint: {row - 1 } \dim_set_eq:NN \l_tmpa_dim \pgf@y \pgfusepathqfill \@@_qpoint: { row - \@@_succ:n \c@iRow } \dim_sub:Nn \l_tmpa_dim \pgf@y \pgfusepathqfill % \end{macrocode} % We translate vertically to take into account the potential ``last row''. % \begin{macrocode} \dim_zero:N \l_tmpb_dim \int_compare:nNnT \l_@@_last_row_int > { -1 } { \dim_set_eq:NN \l_tmpb_dim \g_@@_dp_last_row_dim \dim_add:Nn \l_tmpb_dim \g_@@_ht_last_row_dim % \end{macrocode} % We adjust the value of |\l_tmpa_dim| by the width of the horizontal rule just % before the ``last row''. % \begin{macrocode} \@@_qpoint: { row - \@@_succ:n\c@iRow } \dim_add:Nn \l_tmpa_dim \pgf@y \@@_qpoint: { row - \@@_succ:n \g_@@_row_total_int } \dim_sub:Nn \l_tmpa_dim \pgf@y \dim_sub:Nn \l_tmpa_dim \l_tmpb_dim } % \end{macrocode} % % Now, we can draw the lines with a loop. % \begin{macrocode} \int_step_inline:nnn { \bool_if:NTF \l_@@_NiceArray_bool 1 2 } { \bool_if:NTF \l_@@_NiceArray_bool { \@@_succ:n \c@jCol } \c@jCol } { \pgfpathmoveto { \pgfpointadd { \@@_qpoint: { col - ##1 } } { \pgfpoint { -0.5 \arrayrulewidth \int_compare:nNnT { ##1 } = 1 { \int_compare:nNnT \l_@@_first_col_int = 1 { + \arrayrulewidth } } } { \l_tmpb_dim } } } \pgfpathlineto { \pgfpointadd { \@@_qpoint: { col - ##1 } } { \pgfpoint { -0.5 \arrayrulewidth \int_compare:nNnT { ##1 } = 1 { \int_compare:nNnT \l_@@_first_col_int = 1 { + \arrayrulewidth } } } { \l_tmpb_dim + \l_tmpa_dim } } } } \pgfusepathqstroke \endpgfpicture \group_end: } % \end{macrocode} % % % \bigskip % \subsection*{The commands to draw dotted lines to separate columns and rows} % % These commands don't use the normal nodes, the medium nor the large nodes. % They only use the |col|-nodes and the |row|-nodes. % % \textbf{Horizontal dotted lines}\par\nobreak % % \medskip % The following command must \emph{not} be protected because it's meant to be % expanded in a |\noalign|. % \begin{macrocode} \bool_if:NTF \c_@@_draft_bool { \cs_new:Npn \@@_hdottedline: { } } { \cs_new:Npn \@@_hdottedline: { \noalign { \skip_vertical:N 2\l_@@_radius_dim } \@@_hdottedline_i: } } % \end{macrocode} % % \medskip % On the other side, the following command should be protected. % \begin{macrocode} \cs_new_protected:Npn \@@_hdottedline_i: { % \end{macrocode} % We write in the code-after the instruction that will eventually draw the % dotted line. It's not possible to draw this dotted line now because we don't % know the length of the line (we don't even know the number of columns). % \begin{macrocode} \tl_gput_right:Nx \g_@@_internal_code_after_tl { \@@_hdottedline:n { \int_use:N \c@iRow } } } % \end{macrocode} % % % \medskip % The command |\@@_hdottedline:n| is the command written in the |code-after| % that will actually draw the dotted line. Its argument is the number of the row % \emph{before} which we will draw the row. % \begin{macrocode} \AtBeginDocument { % \end{macrocode} % We recall that, when externalization is used, |\tikzpicture| and % |\endtikzpicture| (or |\pgfpicture| and |\endpgfpicture|) must be directly % ``visible''. % \begin{macrocode} \cs_new_protected:Npx \@@_hdottedline:n #1 { \bool_set_true:N \exp_not:N \l_@@_initial_open_bool \bool_set_true:N \exp_not:N \l_@@_final_open_bool \c_@@_pgfortikzpicture_tl \@@_hdottedline_i:n { #1 } \c_@@_endpgfortikzpicture_tl } } % \end{macrocode} % % The following command \emph{must} be protected since it is used in the % construction of |\@@_hdottedline:n|. % \begin{macrocode} \cs_new_protected:Npn \@@_hdottedline_i:n #1 { \pgfrememberpicturepositiononpagetrue \@@_qpoint: { row - #1 } % \end{macrocode} % We do a translation par |-\l_@@_radius_dim| because we want the dotted line to % have exactly the same position as a vertical rule drawn by ``"|"'' % (considering the rule having a width equal to the diameter of the dots). % \begin{macrocode} \dim_set_eq:NN \l_@@_y_initial_dim \pgf@y \dim_sub:Nn \l_@@_y_initial_dim \l_@@_radius_dim \dim_set_eq:NN \l_@@_y_final_dim \l_@@_y_initial_dim % \end{macrocode} % % \medskip % The dotted line will be extended if the user uses |margin| (or |left-margin| % and |right-margin|). % % \smallskip % The aim is that, by standard the dotted line fits between square brackets % (|\hline| doesn't). % % \smallskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % \begin{bNiceMatrix} % 1 & 2 & 3 & 4 \\ % \hline % 1 & 2 & 3 & 4 \\ % \hdottedline % 1 & 2 & 3 & 4 \\ % \end{bNiceMatrix} % \end{BVerbatim} % $\begin{bNiceMatrix} % 1 & 2 & 3 & 4 \\ % \hline % 1 & 2 & 3 & 4 \\ % \hdottedline % 1 & 2 & 3 & 4 \\ % \end{bNiceMatrix}$ % % \smallskip % But, if the user uses |margin|, the dotted line extends to have the same width % as a |\hline|. % % \smallskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % \begin{bNiceMatrix}[margin] % 1 & 2 & 3 & 4 \\ % \hline % 1 & 2 & 3 & 4 \\ % \hdottedline % 1 & 2 & 3 & 4 \\ % \end{bNiceMatrix} % \end{BVerbatim} % $\begin{bNiceMatrix}[margin] % 1 & 2 & 3 & 4 \\ % \hline % 1 & 2 & 3 & 4 \\ % \hdottedline % 1 & 2 & 3 & 4 \\ % \end{bNiceMatrix}$ % % \medskip % \begin{macrocode} \@@_qpoint: { col - 1 } \dim_set:Nn \l_@@_x_initial_dim { \pgf@x + \arraycolsep - \l_@@_left_margin_dim } \@@_qpoint: { col - \@@_succ:n \c@jCol } \dim_set:Nn \l_@@_x_final_dim { \pgf@x - \arraycolsep + \l_@@_right_margin_dim } % \end{macrocode} % For reasons purely aesthetic, we do an adjustment in the case of a rounded % bracket. The correction by |0.5 \l_@@_inter_dots_dim| is \emph{ad hoc} for a % better result. % \begin{macrocode} \tl_set:Nn \l_tmpa_tl { ( } \tl_if_eq:NNF \l_@@_left_delim_tl \l_tmpa_tl { \dim_gadd:Nn \l_@@_x_initial_dim { 0.5 \l_@@_inter_dots_dim } } \tl_set:Nn \l_tmpa_tl { ) } \tl_if_eq:NNF \l_@@_right_delim_tl \l_tmpa_tl { \dim_gsub:Nn \l_@@_x_final_dim { 0.5 \l_@@_inter_dots_dim } } % \end{macrocode} % % \medskip % As for now, we have no option to control the style of the lines drawn by % |\hdottedline| and the specifier ``|:|'' in the preamble. That's why we impose % the style |standard|. % \begin{macrocode} \tl_set_eq:NN \l_@@_xdots_line_style_tl \c_@@_standard_tl \@@_draw_line: } % \end{macrocode} % % % % \bigskip % \textbf{Vertical dotted lines}\par\nobreak % % % \medskip % \begin{macrocode} \bool_if:nTF \c_@@_draft_bool { \cs_new_protected:Npn \@@_vdottedline:n #1 { } } { \cs_new_protected:Npn \@@_vdottedline:n #1 { \bool_set_true:N \l_@@_initial_open_bool \bool_set_true:N \l_@@_final_open_bool % \end{macrocode} % We recall that, when externalization is used, |\tikzpicture| and % |\endtikzpicture| (or |\pgfpicture| and |\endpgfpicture|) must be directly % ``visible''. % \begin{macrocode} \bool_if:NTF \c_@@_tikz_loaded_bool { \tikzpicture \@@_vdottedline_i:n { #1 } \endtikzpicture } { \pgfpicture \@@_vdottedline_i:n { #1 } \endpgfpicture } } } % \end{macrocode} % % \medskip % \begin{macrocode} \cs_new_protected:Npn \@@_vdottedline_i:n #1 { % \end{macrocode} % The command |\CT@arc@| is a command of color from \pkg{colortbl}. % \begin{macrocode} \bool_if:NT \c_@@_colortbl_loaded_bool \CT@arc@ \pgfrememberpicturepositiononpagetrue \@@_qpoint: { col - \int_eval:n { #1 + 1 } } % \end{macrocode} % We do a translation par |-\l_@@_radius_dim| because we want the dotted line to % have exactly the same position as a vertical rule drawn by ``"|"'' % (considering the rule having a width equal to the diameter of the dots). % \begin{macrocode} \dim_set:Nn \l_@@_x_initial_dim { \pgf@x - \l_@@_radius_dim } \dim_set:Nn \l_@@_x_final_dim { \pgf@x - \l_@@_radius_dim } \@@_qpoint: { row - 1 } % \end{macrocode} % We arbitrary decrease the height of the dotted line by a quantity equal to % |\l_@@_inter_dots_dim| in order to improve the visual impact. % \begin{macrocode} \dim_set:Nn \l_@@_y_initial_dim { \pgf@y - 0.5 \l_@@_inter_dots_dim } \@@_qpoint: { row - \@@_succ:n \c@iRow } \dim_set:Nn \l_@@_y_final_dim { \pgf@y + 0.5 \l_@@_inter_dots_dim } % \end{macrocode} % As for now, we have no option to control the style of the lines drawn by % |\hdottedline| and the specifier ``|:|'' in the preamble. That's why we impose % the style |standard|. % \begin{macrocode} \tl_set_eq:NN \l_@@_xdots_line_style_tl \c_@@_standard_tl \@@_draw_line: } % \end{macrocode} % % % % \bigskip % \subsection*{The environment \{NiceMatrixBlock\}} % % The following flag will be raised when all the columns of the environments of % the block must have the same width in ``auto'' mode. % \begin{macrocode} \bool_new:N \l_@@_block_auto_columns_width_bool % \end{macrocode} % % \bigskip % As of now, there is only one option available for the environment % |{NiceMatrixBlock}|. % \begin{macrocode} \keys_define:nn { NiceMatrix / NiceMatrixBlock } { auto-columns-width .code:n = { \bool_set_true:N \l_@@_block_auto_columns_width_bool \dim_gzero_new:N \g_@@_max_cell_width_dim \bool_set_true:N \l_@@_auto_columns_width_bool } } % \end{macrocode} % % \bigskip % \begin{macrocode} \NewDocumentEnvironment { NiceMatrixBlock } { ! O { } } { \int_gincr:N \g_@@_NiceMatrixBlock_int \dim_zero:N \l_@@_columns_width_dim \keys_set:nn { NiceMatrix / NiceMatrixBlock } { #1 } \bool_if:NT \l_@@_block_auto_columns_width_bool { \cs_if_exist:cT { @@_max_cell_width_ \int_use:N \g_@@_NiceMatrixBlock_int } { \exp_args:NNc \dim_set:Nn \l_@@_columns_width_dim { @@_max_cell_width _ \int_use:N \g_@@_NiceMatrixBlock_int } } } } % \end{macrocode} % % \medskip % At the end of the environment |{NiceMatrixBlock}|, we write in the main |.aux| % file instructions for the column width of all the environments of the block % (that's why we have stored the number of the first environment of the block in % the counter |\l_@@_first_env_block_int|). % \begin{macrocode} { \bool_if:NT \l_@@_block_auto_columns_width_bool { \iow_shipout:Nn \@mainaux \ExplSyntaxOn \iow_shipout:Nx \@mainaux { \cs_gset:cpn { @@ _ max _ cell _ width _ \int_use:N \g_@@_NiceMatrixBlock_int } % \end{macrocode} % For technical reasons, we have to include the width of an eventual rule on the % right side of the cells. % \begin{macrocode} { \dim_eval:n { \g_@@_max_cell_width_dim + \arrayrulewidth } } } \iow_shipout:Nn \@mainaux \ExplSyntaxOff } } % \end{macrocode} % % \bigskip % \subsection*{The extra nodes} % % First, two variants of the functions |\dim_min:nn| and |\dim_max:nn|. % \begin{macrocode} \cs_generate_variant:Nn \dim_min:nn { v n } \cs_generate_variant:Nn \dim_max:nn { v n } % \end{macrocode} % % \bigskip % We have three macros of creation of nodes: |\@@_create_medium_nodes:|, % |\@@_create_large_nodes:| and |\@@_create_medium_and_large_nodes:|. % % % \bigskip % We have to compute the mathematical coordinates of the ``medium nodes''. These % mathematical coordinates are also used to compute the mathematical coordinates % of the ``large nodes''. That's why we write a command % |\@@_computations_for_medium_nodes:| to do these computations. % % \bigskip % The command |\@@_computations_for_medium_nodes:| must be used in a % |{pgfpicture}|. % % \medskip % For each row $i$, we compute two dimensions % \texttt{l_@@_row_\textsl{i}_min_dim} and \texttt{l_@@_row_\textsl{i}_max_dim}. % The dimension \texttt{l_@@_row_\textsl{i}_min_dim} is the minimal % $y$-value of all the cells of the row~$i$. The dimension % \texttt{l_@@_row_\textsl{i}_max_dim} is the maximal $y$-value of all the cells % of the row~$i$. % % Similarly, for each column $j$, we compute two dimensions % \texttt{l_@@_column_\textsl{j}_min_dim} and % \texttt{l_@@_column_\textsl{j}_max_dim}. The dimension % \texttt{l_@@_column_\textsl{j}_min_dim} is the minimal $x$-value of all the % cells of the column~$j$. The dimension \texttt{l_@@_column_\textsl{j}_max_dim} % is the maximal $x$-value of all the cells of the column~$j$. % % Since these dimensions will be computed as maximum or minimum, we initialize % them to |\c_max_dim| or |-\c_max_dim|. % \begin{macrocode} \cs_new_protected:Npn \@@_computations_for_medium_nodes: { \int_step_variable:nnNn \l_@@_first_row_int \g_@@_row_total_int \@@_i: { \dim_zero_new:c { l_@@_row_\@@_i: _min_dim } \dim_set_eq:cN { l_@@_row_\@@_i: _min_dim } \c_max_dim \dim_zero_new:c { l_@@_row_\@@_i: _max_dim } \dim_set:cn { l_@@_row_\@@_i: _max_dim } { - \c_max_dim } } \int_step_variable:nnNn \l_@@_first_col_int \g_@@_col_total_int \@@_j: { \dim_zero_new:c { l_@@_column_\@@_j: _min_dim } \dim_set_eq:cN { l_@@_column_\@@_j: _min_dim } \c_max_dim \dim_zero_new:c { l_@@_column_\@@_j: _max_dim } \dim_set:cn { l_@@_column_\@@_j: _max_dim } { - \c_max_dim } } % \end{macrocode} % We begin the two nested loops over the rows and the columns of the array. % \begin{macrocode} \int_step_variable:nnNn \l_@@_first_row_int \g_@@_row_total_int \@@_i: { \int_step_variable:nnNn \l_@@_first_col_int \g_@@_col_total_int \@@_j: % \end{macrocode} % If the cell ($i$-$j$) is empty or an implicit cell (that is to say a cell % after implicit ampersands |&|) we don't update the dimensions we want to % compute. % \begin{macrocode} { \cs_if_exist:cT { pgf @ sh @ ns @ \@@_env: - \@@_i: - \@@_j: } % \end{macrocode} % We retrieve the coordinates of the anchor |south west| of the (normal) node of % the cell ($i$-$j$). They will be stored in |\pgf@x| and |\pgf@y|. % \begin{macrocode} { \pgfpointanchor { \@@_env: - \@@_i: - \@@_j: } { south~west } \dim_set:cn { l_@@_row_\@@_i: _min_dim} { \dim_min:vn { l_@@_row _ \@@_i: _min_dim } \pgf@y } \seq_if_in:NxF \g_@@_multicolumn_cells_seq { \@@_i: - \@@_j: } { \dim_set:cn { l_@@_column _ \@@_j: _min_dim} { \dim_min:vn { l_@@_column _ \@@_j: _min_dim } \pgf@x } } % \end{macrocode} % We retrieve the coordinates of the anchor |north east| of the (normal) node of % the cell ($i$-$j$). They will be stored in |\pgf@x| and |\pgf@y|. % \begin{macrocode} \pgfpointanchor { \@@_env: - \@@_i: - \@@_j: } { north~east } \dim_set:cn { l_@@_row _ \@@_i: _ max_dim } { \dim_max:vn { l_@@_row _ \@@_i: _ max_dim } \pgf@y } \seq_if_in:NxF \g_@@_multicolumn_cells_seq { \@@_i: - \@@_j: } { \dim_set:cn { l_@@_column _ \@@_j: _ max_dim } { \dim_max:vn { l_@@_column _ \@@_j: _max_dim } \pgf@x } } } } } % \end{macrocode} % Now, we have to deal with empty rows or empty columns since we don't have % created nodes in such rows and columns. % \begin{macrocode} \int_step_variable:nnNn \l_@@_first_row_int \g_@@_row_total_int \@@_i: { \dim_compare:nNnT { \dim_use:c { l_@@_row _ \@@_i: _ min _ dim } } = \c_max_dim { \@@_qpoint: { row - \@@_i: - base } \dim_set:cn { l_@@_row _ \@@_i: _ max _ dim } \pgf@y \dim_set:cn { l_@@_row _ \@@_i: _ min _ dim } \pgf@y } } \int_step_variable:nnNn \l_@@_first_col_int \g_@@_col_total_int \@@_j: { \dim_compare:nNnT { \dim_use:c { l_@@_column _ \@@_j: _ min _ dim } } = \c_max_dim { \@@_qpoint: { col - \@@_j: } \dim_set:cn { l_@@_column _ \@@_j: _ max _ dim } \pgf@y \dim_set:cn { l_@@_column _ \@@_j: _ min _ dim } \pgf@y } } } % \end{macrocode} % % % \bigskip % Here is the command |\@@_create_medium_nodes:|. When this command is used, the % ``medium nodes'' are created. % % \begin{macrocode} \cs_new_protected:Npn \@@_create_medium_nodes: { \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \@@_computations_for_medium_nodes: % \end{macrocode} % Now, we can create the ``medium nodes''. We use a command |\@@_create_nodes:| % because this command will also be used for the creation of the ``large nodes''. % \begin{macrocode} \tl_set:Nn \l_@@_suffix_tl { -medium } \@@_create_nodes: \endpgfpicture } % \end{macrocode} % % % \medskip % The command |\@@_create_large_nodes:| must be used when we want to create only % the ``large nodes'' and not the medium ones\footnote{If we want to create % both, we have to use |\@@_create_medium_and_large_nodes:|}. However, the % computation of the mathematical coordinates of the ``large nodes'' needs the % computation of the mathematical coordinates of the ``medium nodes''. Hence, we % use first |\@@_computations_for_medium_nodes:| and then the command % |\@@_computations_for_large_nodes:|. % \begin{macrocode} \cs_new_protected:Npn \@@_create_large_nodes: { \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \@@_computations_for_medium_nodes: \@@_computations_for_large_nodes: \tl_set:Nn \l_@@_suffix_tl { - large } \@@_create_nodes: \endpgfpicture } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_create_medium_and_large_nodes: { \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \@@_computations_for_medium_nodes: % \end{macrocode} % Now, we can create the ``medium nodes''. We use a command |\@@_create_nodes:| % because this command will also be used for the creation of the ``large nodes''. % \begin{macrocode} \tl_set:Nn \l_@@_suffix_tl { - medium } \@@_create_nodes: \@@_computations_for_large_nodes: \tl_set:Nn \l_@@_suffix_tl { - large } \@@_create_nodes: \endpgfpicture } % \end{macrocode} % % % \bigskip % For ``large nodes'', the exterior rows and columns don't interfer. That's why % the loop over the columns will start at 1 and stop at $|\c@jCol|$ (and not % |\g_@@_col_total_int|). Idem for the rows. % \begin{macrocode} \cs_new_protected:Npn \@@_computations_for_large_nodes: { \int_set:Nn \l_@@_first_row_int 1 \int_set:Nn \l_@@_first_col_int 1 % \end{macrocode} % We have to change the values of all the dimensions % \texttt{l_@@_row_\textsl{i}_min_dim}, \texttt{l_@@_row_\textsl{i}_max_dim}, % \texttt{l_@@_column_\textsl{j}_min_dim} and % \texttt{l_@@_column_\textsl{j}_max_dim}. % \begin{macrocode} \int_step_variable:nNn { \c@iRow - 1 } \@@_i: { \dim_set:cn { l_@@_row _ \@@_i: _ min _ dim } { ( \dim_use:c { l_@@_row _ \@@_i: _ min _ dim } + \dim_use:c { l_@@_row _ \@@_succ:n \@@_i: _ max _ dim } ) / 2 } \dim_set_eq:cc { l_@@_row _ \@@_succ:n \@@_i: _ max _ dim } { l_@@_row_\@@_i: _min_dim } } \int_step_variable:nNn { \c@jCol - 1 } \@@_j: { \dim_set:cn { l_@@_column _ \@@_j: _ max _ dim } { ( \dim_use:c { l_@@_column _ \@@_j: _ max _ dim } + \dim_use:c { l_@@_column _ \@@_succ:n \@@_j: _ min _ dim } ) / 2 } \dim_set_eq:cc { l_@@_column _ \@@_succ:n \@@_j: _ min _ dim } { l_@@_column _ \@@_j: _ max _ dim } } % \end{macrocode} % Here, we have to use |\dim_sub:cn| because of the number 1 in the name. % \begin{macrocode} \dim_sub:cn { l_@@_column _ 1 _ min _ dim } \l_@@_left_margin_dim \dim_add:cn { l_@@_column _ \int_use:N \c@jCol _ max _ dim } \l_@@_right_margin_dim } % \end{macrocode} % % % % \bigskip % The control sequence |\@@_create_nodes:| is used twice: for the construction % of the ``medium nodes'' and for the construction of the ``large nodes''. The % nodes are constructed with the value of all the dimensions % \texttt{l_@@_row_\textsl{i}_min_dim}, \texttt{l_@@_row_\textsl{i}_max_dim}, % \texttt{l_@@_column_\textsl{j}_min_dim} and % \texttt{l_@@_column_\textsl{j}_max_dim}. Between the construction of the % ``medium nodes'' and the ``large nodes'', the values of these dimensions are % changed. % % The function also uses |\l_@@_suffix_tl| (|-medium| or |-large|). % \begin{macrocode} \cs_new_protected:Npn \@@_create_nodes: { \int_step_variable:nnNn \l_@@_first_row_int \g_@@_row_total_int \@@_i: { \int_step_variable:nnNn \l_@@_first_col_int \g_@@_col_total_int \@@_j: { % \end{macrocode} % We draw the rectangular node for the cell (|\@@_i|-|\@@_j|). % \begin{macrocode} \@@_pgf_rect_node:nnnnn { \@@_env: - \@@_i: - \@@_j: \l_@@_suffix_tl } { \dim_use:c { l_@@_column_ \@@_j: _min_dim } } { \dim_use:c { l_@@_row_ \@@_i: _min_dim } } { \dim_use:c { l_@@_column_ \@@_j: _max_dim } } { \dim_use:c { l_@@_row_ \@@_i: _max_dim } } \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \l_@@_name_str - \@@_i: - \@@_j: \l_@@_suffix_tl } { \@@_env: - \@@_i: - \@@_j: \l_@@_suffix_tl } } } } % \end{macrocode} % Now, we create the nodes for the cells of the |\multicolumn|. We recall that % we have stored in |\g_@@_multicolumn_cells_seq| the list of the cells where a % |\multicolumn{|$n$|}{...}{...}| with $n$>1 was issued and in % |\g_@@_multicolumn_sizes_seq| the correspondant values of $n$. % \begin{macrocode} \seq_mapthread_function:NNN \g_@@_multicolumn_cells_seq \g_@@_multicolumn_sizes_seq \@@_node_for_multicolumn:nn } % \end{macrocode} % % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_extract_coords_values: #1 - #2 \q_stop { \cs_set:Npn \@@_i: { #1 } \cs_set:Npn \@@_j: { #2 } } % \end{macrocode} % % The command |\@@_node_for_multicolumn:nn| takes two arguments. The first is % the position of the cell where the command |\multicolumn{|$n$|}{...}{...}| was % issued in the format $i$|-|$j$ and the second is the value of~$n$ (the length % of the ``multi-cell''). % \begin{macrocode} \cs_new_protected:Npn \@@_node_for_multicolumn:nn #1 #2 { \@@_extract_coords_values: #1 \q_stop \@@_pgf_rect_node:nnnnn { \@@_env: - \@@_i: - \@@_j: \l_@@_suffix_tl } { \dim_use:c { l_@@_column _ \@@_j: _ min _ dim } } { \dim_use:c { l_@@_row _ \@@_i: _ min _ dim } } { \dim_use:c { l_@@_column _ \int_eval:n { \@@_j: +#2-1 } _ max _ dim } } { \dim_use:c { l_@@_row _ \@@_i: _ max _ dim } } \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \l_@@_name_str - \@@_i: - \@@_j: \l_@@_suffix_tl } { \int_use:N \g_@@_env_int - \@@_i: - \@@_j: \l_@@_suffix_tl} } } % \end{macrocode} % % \bigskip % \subsection*{Block matrices} % % The code in this section if for the construction of \emph{block matrices}. It % has no direct link with the environment |{NiceMatrixBlock}|. % % % The following command will be linked to |\Block| in the environments of % \pkg{nicematrix}. We define it with |\NewDocumentCommand| of \pkg{xparse} % because it has an optional argument between |<| and |>| (for TeX instructions % put before the math mode of the label) % % \begin{macrocode} \NewDocumentCommand \@@_Block: { O { } m D < > { } m } { \@@_Block_i #2 \q_stop { #1 } { #3 } { #4 } } % \end{macrocode} % % \medskip % The first mandatory argument of |\@@_Block:| has a special syntax. It must be % of the form $i$|-|$j$ where $i$ and $j$ are the size (in rows and columns) of % the block. % \begin{macrocode} \cs_new:Npn \@@_Block_i #1-#2 \q_stop { \@@_Block_ii:nnnnn { #1 } { #2 } } % \end{macrocode} % % \medskip % Now, the arguments have been extracted: |#1| is $i$ (the number of rows of the % block), |#2| is $j$ (the number of columns of the block), |#3| is the list of % key-values, |#4| are the tokens to put before the math mode and |#5| is the % label of the block. % \begin{macrocode} \cs_new_protected:Npn \@@_Block_ii:nnnnn #1 #2 #3 #4 #5 { % \end{macrocode} % We write an instruction in the |code-after|. We write the instruction in the % beginning of the |code-after| (the |left| in |\tl_gput_left:Nx|) because we % want the Tikz nodes corresponding of the block created \emph{before} potential % instructions written by the user in the |code-after| (these instructions may % use the Tikz node of the created block). % \begin{macrocode} \tl_gput_left:Nx \g_@@_internal_code_after_tl { \@@_Block_iii:nnnnnn { \int_use:N \c@iRow } { \int_use:N \c@jCol } { \int_eval:n { \c@iRow + #1 - 1 } } { \int_eval:n { \c@jCol + #2 - 1 } } { #3 } \exp_not:n { { #4 $ #5 $ } } } % \end{macrocode} % It's not allowed to use the command |\Block| twice in the same cell of the % array. That's why, at the first use, we link the command |\Block| % to a special version. The scope of this link is the cell of the array. % \begin{macrocode} \cs_set_eq:NN \Block \@@_Block_error:nn } % \end{macrocode} % % \begin{macrocode} \cs_new:Npn \@@_Block_error:nn #1 #2 { \@@_error:n { Second~Block } \cs_set_eq:NN \Block \use:nn } % \end{macrocode} % % \medskip % \begin{macrocode} \keys_define:nn { NiceMatrix / Block } { tikz .tl_set:N = \l_@@_tikz_tl , tikz .value_required:n = true , white .bool_set:N = \l_@@_white_bool , white .default:n = true , white .value_forbidden:n = true , } % \end{macrocode} % % % \medskip % The following command |\@@_Block_iii:nnnnnn| will be used in the |code-after|. % \begin{macrocode} \cs_new_protected:Npn \@@_Block_iii:nnnnnn #1 #2 #3 #4 #5 #6 { % \end{macrocode} % The group is for the keys. % \begin{macrocode} \group_begin: \keys_set:nn { NiceMatrix / Block } { #5 } % \end{macrocode} % % \begin{macrocode} \bool_if:nTF { \int_compare_p:nNn { #3 } > \c@iRow || \int_compare_p:nNn { #4 } > \c@jCol } { \msg_error:nnnn { nicematrix } { Block~too~large } { #1 } { #2 } } { % \end{macrocode} % We put the contents of the cell in the box |\l_@@_cell_box| because we want % the command |\rotate| used in the content to be able to rotate the box. % \begin{macrocode} \hbox_set:Nn \l_@@_cell_box { #6 } % \end{macrocode} % % \medskip % The construction of the node corresponding to the merged cells. % \begin{macrocode} \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \@@_qpoint: { row - #1 } \dim_set_eq:NN \l_tmpa_dim \pgf@y \@@_qpoint: { col - #2 } \dim_set_eq:NN \l_tmpb_dim \pgf@x \@@_qpoint: { row - \@@_succ:n { #3 } } \dim_set_eq:NN \l_tmpc_dim \pgf@y \@@_qpoint: { col - \@@_succ:n { #4 } } \dim_set_eq:NN \l_tmpd_dim \pgf@x % \end{macrocode} % % \medskip % The following code doesn't work for the first vertical rule. You should allow % the option |white| if and only if the option |vlines| and |hlines| has been used. % \begin{macrocode} \bool_if:NT \l_@@_white_bool { \begin { pgfscope } \pgfsetfillcolor { white } % \end{macrocode} % Usually, the vertical rules are \emph{before} the |col|-nodes. But there is an % exception: if there is no ``first col'', the first vertical rule is after the % col node.\footnote{That's true for the vertical rules drawn by ``"|"'' due to % the conception of |{array}| (of \pkg{array}) and we have managed to have the % same behaviour with |vlines|.} % % Since we don't want the white rectangle to erase a part of this % first rule, we have to do an adjustment in this case. % \emph{after} the ``col node''. % \begin{macrocode} \int_compare:nNnT { #2 } = 1 { \int_compare:nNnT \l_@@_first_col_int = 1 { \dim_add:Nn \l_tmpb_dim \arrayrulewidth } } \pgfpathrectanglecorners { \pgfpoint \l_tmpb_dim { \l_tmpa_dim - \arrayrulewidth } } { \pgfpoint { \l_tmpd_dim - \arrayrulewidth } \l_tmpc_dim } \pgfusepathqfill \end { pgfscope } } % \end{macrocode} % % We construct the node for the block with the name |(#1-#2-block)|. % % The function |\@@_pgf_rect_node:nnnnn| takes as arguments the name of the node % and the four coordinates of two opposite corner points of the rectangle. % \begin{macrocode} \begin { pgfscope } \exp_args:Nx \pgfset { \l_@@_tikz_tl } \@@_pgf_rect_node:nnnnn { \@@_env: - #1 - #2 - block } \l_tmpb_dim \l_tmpa_dim \l_tmpd_dim \l_tmpc_dim \end { pgfscope } % \end{macrocode} % % % \medskip % If the creation of the ``medium nodes'' is required, we create a ``medium % node'' for the block. The function |\@@_pgf_rect_node:nnnnn| takes as % arguments the name of the node and two \textsc{pgf} points. % \begin{macrocode} \bool_if:NT \l_@@_medium_nodes_bool { \@@_pgf_rect_node:nnn { \@@_env: - #1 - #2 - block - medium } { \pgfpointanchor { \@@_env: - #1 - #2 - medium } { north~west } } { \pgfpointanchor { \@@_env: - #3 - #4 - medium } { south~east } } } % \end{macrocode} % \medskip % Now, we will put the label of the block. % \begin{macrocode} \int_compare:nNnTF { #1 } = { #3 } { % \end{macrocode} % If the block has only one row, we want the label of the block perfectly % aligned on the baseline of the row. That's why we have constructed a % |\pgfcoordinate| on the baseline of the row, in the first column of the array. % Now, we retrieve the $y$-value of that node and we store it in |\l_tmpa_dim|. % \begin{macrocode} \pgfextracty \l_tmpa_dim { \@@_qpoint: { row - #1 - base } } % \end{macrocode} % We retrieve (in |\pgf@x|) the $x$-value of the center of the block. % \begin{macrocode} \@@_qpoint: { #1 - #2 - block } % \end{macrocode} % We put the label of the block which has been composed in |\l_@@_cell_box|. % \begin{macrocode} \pgftransformshift { \pgfpoint \pgf@x \l_tmpa_dim } \pgfnode { rectangle } { base } { \box_use_drop:N \l_@@_cell_box } { } { } } % \end{macrocode} % % \medskip % If the number of rows is different of $1$, we put the label of the block in % the center of the node (the label of the block has been composed in % |\l_@@_cell_box|). % \begin{macrocode} { \pgftransformshift { \@@_qpoint: { #1 - #2 - block } } \pgfnode { rectangle } { center } { \box_use_drop:N \l_@@_cell_box } { } { } } \endpgfpicture } \group_end: } % \end{macrocode} % % \bigskip % \subsection*{How to draw the dotted lines transparently} % \begin{macrocode} \cs_set_protected:Npn \@@_renew_matrix: { \RenewDocumentEnvironment { pmatrix } { } { \pNiceMatrix } { \endpNiceMatrix } \RenewDocumentEnvironment { vmatrix } { } { \vNiceMatrix } { \endvNiceMatrix } \RenewDocumentEnvironment { Vmatrix } { } { \VNiceMatrix } { \endVNiceMatrix } \RenewDocumentEnvironment { bmatrix } { } { \bNiceMatrix } { \endbNiceMatrix } \RenewDocumentEnvironment { Bmatrix } { } { \BNiceMatrix } { \endBNiceMatrix } } % \end{macrocode} % % % \bigskip % \subsection*{Automatic arrays} % % % \begin{macrocode} \cs_new_protected:Npn \@@_set_size:n #1-#2 \q_stop { \int_set:Nn \l_@@_nb_rows_int { #1 } \int_set:Nn \l_@@_nb_cols_int { #2 } } % \end{macrocode} % % % \begin{macrocode} \NewDocumentCommand \AutoNiceMatrixWithDelims { m m O { } m O { } m ! O { } } { \int_zero_new:N \l_@@_nb_rows_int \int_zero_new:N \l_@@_nb_cols_int \@@_set_size:n #4 \q_stop \begin { NiceArrayWithDelims } { #1 } { #2 } { * { \l_@@_nb_cols_int } { C } } [ #3 , #5 , #7 ] \int_compare:nNnT \l_@@_first_row_int = 0 { \int_compare:nNnT \l_@@_first_col_int = 0 { & } \prg_replicate:nn { \l_@@_nb_cols_int - 1 } { & } \int_compare:nNnT \l_@@_last_col_int > { -1 } { & } \\ } \prg_replicate:nn \l_@@_nb_rows_int { \int_compare:nNnT \l_@@_first_col_int = 0 { & } % \end{macrocode} % You put |{ }| before |#6| to avoid a hasty expansion of an eventual % |\arabic{iRow}| at the beginning of the row which would result in an incorrect % value of that |iRow| (since |iRow| is incremented in the first cell of the row % of the |\halign|). % \begin{macrocode} \prg_replicate:nn { \l_@@_nb_cols_int - 1 } { { } #6 & } #6 \int_compare:nNnT \l_@@_last_col_int > { -1 } { & } \\ } \int_compare:nNnT \l_@@_last_row_int > { -2 } { \int_compare:nNnT \l_@@_first_col_int = 0 { & } \prg_replicate:nn { \l_@@_nb_cols_int - 1 } { & } \int_compare:nNnT \l_@@_last_col_int > { -1 } { & } \\ } \end { NiceArrayWithDelims } } % \end{macrocode} % % \begin{macrocode} \cs_set_protected:Npn \@@_define_com:nnn #1 #2 #3 { \cs_set_protected:cpn { #1 AutoNiceMatrix } { \str_gset:Nx \g_@@_name_env_str { #1 AutoNiceMatrix } \AutoNiceMatrixWithDelims { #2 } { #3 } } } % \end{macrocode} % % \begin{macrocode} \@@_define_com:nnn p ( ) \@@_define_com:nnn b [ ] \@@_define_com:nnn v | | \@@_define_com:nnn V \| \| \@@_define_com:nnn B \{ \} % \end{macrocode} % % \subsection*{The command \textbackslash CodeAfter} % % The command |\CodeAfter| catches everything until the end of the current % environment (of \pkg{nicematrix}). % % First, we go until the next command |\end|. % \begin{macrocode} \cs_new_protected:Npn \@@_CodeAfter:n #1 \end { \tl_gput_right:Nn \g_@@_code_after_tl { #1 } \@@_CodeAfter_i:n } % \end{macrocode} % % We catch the argument of the command |\end| (in |#1|). % \begin{macrocode} \cs_new_protected:Npn \@@_CodeAfter_i:n #1 { % \end{macrocode} % If this is really the end of the current environment (of \pkg{nicematrix}), we % put back the command |\end| and its argument in the TeX flow. % \begin{macrocode} \bool_if:NTF { \str_if_eq_p:Vn \g_@@_name_env_str { #1 } } { \end { #1 } } % \end{macrocode} % It this is not the |\end| we are looking for, we put those tokens in % |\g_@@_code_after_tl| and we go on searching for the next command |\end| with % a recursive call to the command |\@@_CodeAfter:n|. % \begin{macrocode} { \tl_gput_right:Nn \g_@@_code_after_tl { \end { #1 } } \@@_CodeAfter:n } } % \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| executes 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} \bool_new:N \c_@@_obsolete_environments_bool \keys_define:nn { NiceMatrix / Package } { renew-dots .bool_set:N = \l_@@_renew_dots_bool , renew-dots .value_forbidden:n = true , renew-matrix .code:n = \@@_renew_matrix: , renew-matrix .value_forbidden:n = true , transparent .meta:n = { renew-dots , renew-matrix } , transparent .value_forbidden:n = true, obsolete-environments .bool_set:N = \c_@@_obsolete_environments_bool , obsolete-environments .value_forbidden:n = true , obsolete-environments .default:n = true , starred-commands .code:n = \@@_msg_redirect_name:nn { starred~commands } { none } , starred-commands .value_forbidden:n = true , } \ProcessKeysOptions { NiceMatrix / Package } % \end{macrocode} % % \bigskip % \subsection*{Error messages of the package} % % The following command converts all the elements of a sequence (which are token % lists) into strings. % \begin{macrocode} \cs_new_protected:Npn \@@_convert_to_str_seq:N #1 { \seq_clear:N \l_tmpa_seq \seq_map_inline:Nn #1 { \seq_put_left:Nx \l_tmpa_seq { \tl_to_str:n { ##1 } } } \seq_set_eq:NN #1 \l_tmpa_seq } % \end{macrocode} % % The following command creates a sequence of strings (|str|) from a |clist|. % \begin{macrocode} \cs_new_protected:Npn \@@_set_seq_of_str_from_clist:Nn #1 #2 { \seq_set_from_clist:Nn #1 { #2 } \@@_convert_to_str_seq:N #1 } % \end{macrocode} % % \begin{macrocode} \@@_set_seq_of_str_from_clist:Nn \c_@@_types_of_matrix_seq { NiceMatrix , pNiceMatrix , bNiceMatrix , vNiceMatrix, BNiceMatrix, VNiceMatrix } % \end{macrocode} % % \bigskip % If the user uses too much columns, the command |\@@_error_too_much_cols:| is % executed. This command raises an error but try to give the best information to % the user in the error message. The command |\seq_if_in:NVTF| is not expandable % and that's why we can't put it in the error message itself. We have to do the % test before the |\@@_fatal:n|. % \begin{macrocode} \cs_new_protected:Npn \@@_error_too_much_cols: { \seq_if_in:NVTF \c_@@_types_of_matrix_seq \g_@@_name_env_str { \int_compare:nNnTF \l_@@_last_col_int = { -2 } { \@@_fatal:n { too~much~cols~for~matrix } } { \bool_if:NF \l_@@_last_col_without_value_bool { \@@_fatal:n { too~much~cols~for~matrix~with~last~col } } } } { \@@_fatal:n { too~much~cols~for~array } } } % \end{macrocode} % % The following command must \emph{not} be protected since it's used in an error message. % \begin{macrocode} \cs_new:Npn \@@_message_hdotsfor: { \tl_if_empty:VF \g_@@_Hdotsfor_lines_tl { ~Maybe~your~use~of~\token_to_str:N \Hdotsfor\ is~incorrect.} } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { too~much~cols~for~matrix~with~last~col } { You~try~to~use~more~columns~than~allowed~by~your~ \@@_full_name_env:.\@@_message_hdotsfor:\ The~maximal~number~of~ columns~is~\int_eval:n { \l_@@_last_col_int - 1 }~(plus~the~potential~ exterior~ones).~This~error~is~fatal. } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { too~much~cols~for~matrix } { You~try~to~use~more~columns~than~allowed~by~your~ \@@_full_name_env:.\@@_message_hdotsfor:\ Recall~that~the~maximal~ number~of~columns~for~a~matrix~is~fixed~by~the~LaTeX~counter~ 'MaxMatrixCols'.~Its~actual~value~is~\int_use:N \c@MaxMatrixCols.~ This~error~is~fatal. } % \end{macrocode} % % \medskip % For the following message, remind that the test is not done after the % construction of the array but in each row. That's why we have to put % |\c@jCol-1| and not |\c@jCol|. % \begin{macrocode} \@@_msg_new:nn { too~much~cols~for~array } { You~try~to~use~more~columns~than~allowed~by~your~ \@@_full_name_env:.\@@_message_hdotsfor:\ The~maximal~number~of~columns~is~ \int_eval:n { \c@jCol - 1 }~(plus~the~potential~exterior~ones).~ This~error~is~fatal. } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { bad~option~for~line-style } { Since~you~haven't~loaded~Tikz,~the~only~value~you~can~give~to~'line-style'~ is~'standard'.~If~you~go~on,~this~option~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Unknown~option~for~xdots } { As~for~now~there~is~only~three~options~available~here:~'color',~'line-style'~ and~'shorten'~(and~you~try~to~use~'\l_keys_key_str').~If~you~go~on,~ this~option~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { ampersand~in~light-syntax } { You~can't~use~an~ampersand~(\token_to_str &)~to~separate~columns~because ~you~have~used~the~option~'light-syntax'.~This~error~is~fatal. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { double-backslash~in~light-syntax } { You~can't~use~\token_to_str:N \\~to~separate~rows~because~you~have~used~ the~option~'light-syntax'.~You~must~use~the~character~'\l_@@_end_of_row_tl'~ (set~by~the~option~'end-of-row').~This~error~is~fatal. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { starred~commands } { The~starred~versions~of~\token_to_str:N \Cdots,~\token_to_str:N \Ldots,~ \token_to_str:N \Vdots,~\token_to_str:N\Ddots\ and~\token_to_str:N\Iddots\ are~deprecated.~However,~you~can~go~on~for~this~time.~If~you~don't~want~to~ see~this~error~we~should~load~'nicematrix'~with~the~option~ 'starred-commands'. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { bad~value~for~baseline } { The~value~given~to~'baseline'~(\int_use:N \l_tmpa_int)~is~not~ valid.~The~value~must~be~between~\int_use:N \l_@@_first_row_int\ and~ \int_use:N \g_@@_row_total_int\ or~equal~to~'t',~'c'~or~'b'.\\ If~you~go~on,~a~value~of~1~will~be~used. } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { Second~Block } { You~can't~use~\token_to_str:N \Block\ twice~in~the~same~cell~of~the~array.\\ If~you~go~on,~this~command~(and~the~other)~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { empty~environment } { Your~\@@_full_name_env:\ is~empty.~This~error~is~fatal. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { unknown~cell~for~line~in~code-after } { Your~command~\token_to_str:N\line\{#1\}\{#2\}~in~the~'code-after'~ can't~be~executed~because~a~cell~doesn't~exist.\\ If~you~go~on~this~command~will~be~ignored. } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { last-col~non~empty~for~NiceArray } { In~the~\@@_full_name_env:,~you~must~use~the~option~ 'last-col'~without~value.\\ However,~you~can~go~on~for~this~time~ (the~value~'\l_keys_value_tl'~will~be~ignored). } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { Block~too~large } { You~try~to~draw~a~block~in~the~cell~#1-#2~of~your~matrix~but~the~matrix~is~ too~small~for~that~block. \\ If~you~go~on,~this~command~will~be~ignored. } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { Wrong~last~row } { You~have~used~'last-row=\int_use:N \l_@@_last_row_int'~but~your~ \@@_full_name_env:\ seems~to~have~\int_use:N \c@iRow \ rows.~ If~you~go~on,~the~value~of~\int_use:N \c@iRow \ will~be~used~for~ last~row.~You~can~avoid~this~problem~by~using~'last-row'~ without~value~(more~compilations~might~be~necessary). } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { Yet~in~env } { Environments~\{NiceArray\}~(or~\{NiceMatrix\},~etc.)~can't~be~nested.\\ This~error~is~fatal. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Outside~math~mode } { The~\@@_full_name_env:\ can~be~used~only~in~math~mode~ (and~not~in~\token_to_str:N \vcenter).\\ This~error~is~fatal. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Bad~value~for~letter~for~dotted~lines } { The~value~of~key~'\tl_use:N\l_keys_key_str'~must~be~of~length~1.\\ If~you~go~on,~it~will~be~ignored. } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nnn { Unknown~key~for~NiceMatrixOptions } { The~key~'\tl_use:N\l_keys_key_str'~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~options~are~(in~alphabetic~order):~ allow-duplicate-names,~ code-for-first-col,~ code-for-first-row,~ code-for-last-col,~ code-for-last-row,~ create-extra-nodes,~ create-medium-nodes,~ create-large-nodes,~ end-of-row,~ exterior-arraycolsep,~ hlines,~ hvlines,~ left-margin,~ letter-for-dotted-lines,~ light-syntax,~ nullify-dots,~ parallelize-diags,~ renew-dots,~ renew-matrix,~ right-margin,~ small,~ transparent,~ vlines,~ xdots/color,~ xdots/shorten~and~ xdots/line-style. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nnn { Unknown~option~for~NiceArray } { The~option~'\tl_use:N\l_keys_key_str'~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,~ baseline,~ c,~ code-after,~ code-for-first-col,~ code-for-first-row,~ code-for-last-col,~ code-for-last-row,~ columns-width,~ create-extra-nodes,~ create-medium-nodes,~ create-large-nodes,~ end-of-row,~ extra-left-margin,~ extra-right-margin,~ first-col,~ first-row,~ hlines,~ hvlines,~ last-col,~ last-row,~ left-margin,~ light-syntax,~ name,~ nullify-dots,~ parallelize-diags,~ renew-dots,~ right-margin,~ small,~ t,~ vlines,~ xdots/color,~ xdots/shorten~and~ xdots/line-style. } % \end{macrocode} % % \medskip % This error message is used for the set of keys |NiceMatrix/NiceMatrix| and % |NiceMatrix/pNiceArray| (but not by |NiceMatrix/NiceArray| because, for this % set of keys, there is also the options |t|, |c| and~|b|). % \begin{macrocode} \@@_msg_new:nnn { Unknown~option~for~NiceMatrix } { The~option~'\tl_use:N\l_keys_key_str'~is~unknown~for~the~ \@@_full_name_env:. \\ 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,~ baseline,~ c,~ code-after,~ code-for-first-col,~ code-for-first-row,~ code-for-last-col,~ code-for-last-row,~ columns-width,~ create-extra-nodes,~ create-medium-nodes,~ create-large-nodes,~ end-of-row,~ extra-left-margin,~ extra-right-margin,~ first-col,~ first-row,~ hlines,~ hvlines,~ l~(=L),~ last-col,~ last-row,~ left-margin,~ light-syntax,~ name,~ nullify-dots,~ parallelize-diags,~ r~(=R),~ renew-dots,~ right-margin,~ small,~ t,~ vlines,~ xdots/color,~ xdots/shorten~and~ xdots/line-style. } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nnn { Duplicate~name } { The~name~'\l_keys_value_tl'~is~already~used~and~you~shouldn't~use~ the~same~environment~name~twice.~You~can~go~on,~but,~ maybe,~you~will~have~incorrect~results~especially~ if~you~use~'columns-width=auto'.~If~you~don't~want~to~see~this~ message~again,~use~the~option~'allow-duplicate-names'.\\ For~a~list~of~the~names~already~used,~type~H~. \\ } { The~names~already~defined~in~this~document~are:~ \seq_use:Nnnn \g_@@_names_seq { ,~ } { ,~ } { ~and~ }. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Option~auto~for~columns-width } { You~can't~give~the~value~'auto'~to~the~option~'columns-width'~here.~ If~you~go~on,~the~option~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Zero~row } { There~is~a~problem.~Maybe~you~have~used~l,~c~and~r~instead~of~L,~C~ and~R~in~the~preamble~of~your~environment. \\ This~error~is~fatal. } % \end{macrocode} % % % \bigskip % \subsection*{Obsolete environments} % % The following environments are loaded only when the package \pkg{nicematrix} % has been loaded with the option |obsolete-environments|. However, they will be % completly deleted in a future version. % % \begin{macrocode} \bool_if:NT \c_@@_obsolete_environments_bool { \NewDocumentEnvironment { pNiceArrayC } { } { \int_zero:N \l_@@_last_col_int \pNiceArray } { \endpNiceArray } \NewDocumentEnvironment { bNiceArrayC } { } { \int_zero:N \l_@@_last_col_int \bNiceArray } { \endbNiceArray } \NewDocumentEnvironment { BNiceArrayC } { } { \int_zero:N \l_@@_last_col_int \BNiceArray } { \endBNiceArray } \NewDocumentEnvironment { vNiceArrayC } { } { \int_zero:N \l_@@_last_col_int \vNiceArray } { \endvNiceArray } \NewDocumentEnvironment { VNiceArrayC } { } { \int_zero:N \l_@@_last_col_int \VNiceArray } { \endVNiceArray } \NewDocumentEnvironment { pNiceArrayRC } { } { \int_zero:N \l_@@_last_col_int \int_zero:N \l_@@_first_row_int \pNiceArray } { \endpNiceArray } \NewDocumentEnvironment { bNiceArrayRC } { } { \int_zero:N \l_@@_last_col_int \int_zero:N \l_@@_first_row_int \bNiceArray } { \endbNiceArray } \NewDocumentEnvironment { BNiceArrayRC } { } { \int_zero:N \l_@@_last_col_int \int_zero:N \l_@@_first_row_int \BNiceArray } { \endBNiceArray } \NewDocumentEnvironment { vNiceArrayRC } { } { \int_zero:N \l_@@_last_col_int \int_zero:N \l_@@_first_row_int \vNiceArray } { \endvNiceArray } \NewDocumentEnvironment { VNiceArrayRC } { } { \int_zero:N \l_@@_last_col_int \int_zero:N \l_@@_first_row_int \VNiceArray } { \endVNiceArray } \NewDocumentEnvironment { NiceArrayCwithDelims } { } { \int_zero:N \l_@@_last_col_int \NiceArrayWithDelims } { \endNiceArrayWithDelims } \NewDocumentEnvironment { NiceArrayRCwithDelims } { } { \int_zero:N \l_@@_last_col_int \int_zero:N \l_@@_first_row_int \NiceArrayWithDelims } { \endNiceArrayWithDelims } } % \end{macrocode} % % % % \vspace{1cm} % \section{History} % % \subsection*{Changes between versions 1.0 and 1.1} % % 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. % % 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''. % % \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. % % % \subsection*{Changes between version 1.4 and 2.0} % % The versions 1.0 to 1.4 of \pkg{nicematrix} were focused on the continuous % dotted lines whereas the version 2.0 of \pkg{nicematrix} provides different % features to improve the typesetting of mathematical matrices. % % \subsection*{Changes between version 2.0 and 2.1} % % New implementation of the environment |{pNiceArrayRC}|. With this new % implementation, there is no restriction on the width of the columns. % % The package \pkg{nicematrix} no longer loads \pkg{mathtools} but only % \pkg{amsmath}. % % Creation of ``medium nodes'' and ``large nodes''. % % \subsection*{Changes between version 2.1 and 2.1.1} % % Small corrections: for example, the option |code-for-first-row| is now % available in the command |\NiceMatrixOptions|. % % Following a discussion on % TeX StackExchange\footnote{cf. % |tex.stackexchange.com/questions/450841/tikz-externalize-and-nicematrix-package|}, % Tikz externalization is now deactivated in the environments of the % package \pkg{nicematrix}.\footnote{Before this version, there was an error % when using \pkg{nicematrix} with Tikz externalization. In any case, it's not % possible to externalize the Tikz elements constructed by \pkg{nicematrix} % because they use the options |overlay| and |remember picture|.} % % \subsection*{Changes between version 2.1 and 2.1.2} % Option |draft|: with this option, the dotted lines are not drawn (quicker). % % \subsection*{Changes between version 2.1.2 and 2.1.3} % % When searching the end of a dotted line from a command like |\Cdots| issued in % the ``main matrix'' (not in the exterior column), the cells in the exterior % column are considered as outside the matrix. That means that it's possible to % do the following matrix with only a |\Cdots| command (and a single |\Vdots|). % \[\begin{pNiceArray}{Wc{5mm}CWc{5mm}}[first-row,last-col] % & C_j & \\ % \mbox{\Large $0$} & \Vdots & \mbox{\Large $0$} \\ % \strut & a & \Cdots & L_i \\ % \mbox{\Large $0$} & & \mbox{\Large $0$} \\ % \end{pNiceArray}\] % % \subsection*{Changes between version 2.1.3 and 2.1.4} % % Replacement of some options |O { }| in commands and environments defined with % \pkg{xparse} by |! O { }| (because a recent version of \pkg{xparse} introduced % the specifier |!| and modified the default behaviour of the last optional % arguments). % % See |www.texdev.net/2018/04/21/xparse-optional-arguments-at-the-end| % % \subsection*{Changes between version 2.1.4 and 2.1.5} % % Compatibility with the classes \cls{revtex4-1} and \cls{revtex4-2}. % % Option |allow-duplicate-names|. % % \subsection*{Changes between version 2.1.5 and 2.2} % % Possibility to draw horizontal dotted lines to separate rows with the command % |\hdottedline| (similar to the classical command |\hline| and the command % |\hdashline| of \pkg{arydshln}). % % Possibility to draw vertical dotted lines to separate columns with the % specifier ``|:|'' in the preamble (similar to the classical specifier % ``"|"'' and the specifier ``|:|'' of \pkg{arydshln}). % % \subsection*{Changes between version 2.2 and 2.2.1} % % Improvment of the vertical dotted lines drawn by the specifier ``:'' in the % preamble. % % Modification of the position of the dotted lines drawn by |\hdottedline|. % % \subsection*{Changes between version 2.2.1 and 2.3} % % Compatibility with the column type |S| of \pkg{siunitx}. % % Option |hlines|. % % A warning is issued when the |draft| mode is used. In this case, the dotted % lines are not drawn. % % % \subsection*{Changes between version 2.3 and 3.0} % % Modification of |\Hdotsfor|. Now |\Hdotsfor| erases the |\vlines| (of ``"|"'') % as |\hdotsfor| does. % % Composition of exterior rows and columns on the four sides of the matrix (and % not only on two sides) with the options |first-row|, |last-row|, |first-col| % and |last-col|. % % \subsection*{Changes between version 3.0 and 3.1} % % Command |\Block| to draw block matrices. % % Error message when the user gives an incorrect value for |last-row|. % % A dotted line can no longer cross another dotted line (excepted the dotted % lines drawn by |\cdottedline|, the symbol ``|:|'' (in the preamble of the % array) and |\line| in |code-after|). % % The starred versions of |\Cdots|, |\Ldots|, etc. are now deprecated because, % with the new implementation, they become pointless. These starred versions % are no longer documented. % % The vertical rules in the matrices (drawn by ``"|"'') are now compatible with % the color fixed by \pkg{colortbl}. % % Correction of a bug: it was not possible to use the colon ``|:|'' in the % preamble of an array when |pdflatex| was used with \pkg{french-babel} (because % \pkg{french-babel} activates the colon in the beginning of the document). % % % \subsection*{Changes between version 3.1 and 3.2 (and 3.2a)} % % Option |small|. % % \subsection*{Changes between version 3.2 and 3.3} % % The options |first-row|, |last-row|, |first-col| and |last-col| are now % available in the environments |{NiceMatrix}|, |{pNiceMatrix}|, % |{bNiceMatrix}|, etc. % % The option |columns-width=auto| doesn't need any more a second compilation. % % The options |renew-dots|, |renew-matrix| and |transparent| are now available % as package options (as said in the documentation). % % The previous version of \pkg{nicematrix} was incompatible with a recent % version of \pkg{expl3} (released 2019/09/30). This version is compatible. % % % \subsection*{Changes between version 3.3 and 3.4} % % Following a discussion on TeX StackExchange\footnote{cf. % |tex.stackexchange.com/questions/510841/nicematrix-and-tikz-external-optimize|}, % optimization of Tikz externalization is disabled in the environments of % \pkg{nicematrix} when the class \cls{standalone} or the package % \pkg{standalone} is used. % % \subsection*{Changes between version 3.4 and 3.5} % % Correction on a bug on the two previous versions where the |code-after| was % not executed. % % \subsection*{Changes between version 3.5 and 3.6} % % LaTeX counters |iRow| and |jCol| available in the cells of the array. % % Addition of |\normalbaselines| before the construction of the array: in % environments like |{align}| of \pkg{amsmath} the value of |\baselineskip| is % changed and if the options |first-row| and |last-row| were used in an % environment of \pkg{nicematrix}, the position of the delimiters was wrong. % % A warning is written in the |.log| file if an obsolete environment is used. % % There is no longer artificial errors |Duplicate~name| in the environments of % \pkg{amsmath}. % % \subsection*{Changes between version 3.6 and 3.7} % % The four ``corners'' of the matrix are correctly protected against the four % codes: |code-for-first-col|, |code-for-last-col|, |code-for-first-row| and % |code-for-last-row|. % % New command |\pAutoNiceMatrix| and its variants (suggestion of Christophe % Bal). % % \subsection*{Changes between version 3.7 and 3.8} % % New programmation for the command |\Block| when the block has only one row. % With this programmation, the vertical rules drawn by the specifier % ``\verb+|+'' at the end of the block is actually drawn. In previous versions, % they were not because the block of one row was constructed with % |\multicolumn|. % % An error is raised when an obsolete environment is used. % % % \subsection*{Changes between version 3.8 and 3.9} % % New commands |\NiceMatrixLastEnv| and |\OnlyMainNiceMatrix|. % % New options |create-medium-nodes| and |create-large-nodes|. % % \subsection*{Changes between version 3.9 and 3.10} % % New option |light-syntax| (and |end-of-row|). % % New option |dotted-lines-margin| for fine tuning of the dotted lines. % % \subsection*{Changes between versions 3.10 and 3.11} % % Correction of a bug linked to |first-row| and |last-row|. % % \subsection*{Changes between versions 3.11 and 3.12} % % Command |\rotate| in the cells of the array. % % Options |vlines|, |hlines| and |hvlines|. % % Option |baseline| pour |{NiceArray}| (not for the other environments). % % The name of the Tikz nodes created by the command |\Block| has changed: when % the command has been issued in the cell $i$|-|$j$, the name is % $i$|-|$j$|-block| and, if the creation of the ``medium nodes'' is required, a % node $i$|-|$j$|-block-medium| is created. % % If the user try to use more columns than allowed by its environment, an error % is raised by nicematrix (instead of a low-level error). % % The package must be loaded with the option |obsolete-environments| if we want % to use the deprecated environments. % % \subsection*{Changes between versions 3.12 and 3.13} % % The behaviour of the command |\rotate| is improved when used in the ``last % row''. % % The option |dotted-lines-margin| has been renamed in |xdots/shorten| and the % options |xdots/color| and |xdots/line-style| have been added for a complete % customization of the dotted lines. % % In the environments without preamble (|{NiceMatrix}|, |{pNiceMatrix}|, etc.), % it's possible to use the options |l| (=|L|) or |r| (=|R|) to specify the type % of the columns. % % The starred versions of the commands |\Cdots|, |\Ldots|, |\Vdots|, |\Ddots| % and |\Iddots| are deprecated since the version 3.1 of \pkg{nicematrix}. Now, % one should load \pkg{nicematrix} with the option |starred-commands| to avoid % an error at the compilation. % % The code of \pkg{nicematrix} no longer uses Tikz but only \textsc{pgf}. By % default, Tikz is \emph{not} loaded by \pkg{nicematrix}. % % \subsection*{Changes between versions 3.13 and 3.14} % % Correction of a bug (question 60761504 on |stackoverflow|). % % Better error messages when the user uses |&| or |\\| when |light-syntax| is in % force. % % \subsection*{Changes between versions 3.14 and 3.15} % % It's possible to put labels on the dotted lines drawn by |\Ldots|, |\Cdots|, % |\Vdots|, |\Ddots|, |\Iddots|, |\Hdotsfor| and the command |\line| in the % |code-after| with the tokens |_| and |^|. % % The option |baseline| is now available in all the environments of % \pkg{nicematrix}. Before, it was available only in |{NiceArray}|. % % New command |\CodeAfter| (in the environments of \pkg{nicematrix}). % % \PrintIndex % % \tableofcontents % % \endinput % Local Variables: % TeX-fold-mode: t % TeX-fold-preserve-comments: nil % flyspell-mode: nil % fill-column: 80 % End: