From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 2 Sep 2019 13:46:59 +0900 Subject: Initial commit --- macros/latex/contrib/nicematrix/README.md | 29 + .../latex/contrib/nicematrix/nicematrix-french.pdf | Bin 0 -> 300142 bytes .../latex/contrib/nicematrix/nicematrix-french.tex | 2121 +++++++ macros/latex/contrib/nicematrix/nicematrix.dtx | 6391 ++++++++++++++++++++ macros/latex/contrib/nicematrix/nicematrix.ins | 47 + macros/latex/contrib/nicematrix/nicematrix.pdf | Bin 0 -> 621774 bytes 6 files changed, 8588 insertions(+) create mode 100644 macros/latex/contrib/nicematrix/README.md create mode 100644 macros/latex/contrib/nicematrix/nicematrix-french.pdf create mode 100644 macros/latex/contrib/nicematrix/nicematrix-french.tex create mode 100644 macros/latex/contrib/nicematrix/nicematrix.dtx create mode 100644 macros/latex/contrib/nicematrix/nicematrix.ins create mode 100644 macros/latex/contrib/nicematrix/nicematrix.pdf (limited to 'macros/latex/contrib/nicematrix') diff --git a/macros/latex/contrib/nicematrix/README.md b/macros/latex/contrib/nicematrix/README.md new file mode 100644 index 0000000000..aadca62b15 --- /dev/null +++ b/macros/latex/contrib/nicematrix/README.md @@ -0,0 +1,29 @@ +# Readme for the package nicematrix + +Author : F. Pantigny (`fpantigny@wanadoo.fr`). + +CTAN page : `https://ctan.org/pkg/nicematrix` + +## License +The LaTeX extension `nicematrix` is distributed under the LPPL 1.3 license. + +## Presentation + +The LaTeX package `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, to draw continuous ellipsis dots between the cells +of the array and to add an exterior line and an exterior column. + + +## Installation + +The package `nicematrix` is present in the distributions MiKTeX, TeXLive and MacTeX. + +For a manual installation: + +* put the files `nicematrix.ins` and `nicematrix.dtx` in the same directory; +* run `latex nicematrix.ins`. + +The file `nicematrix.sty` will be generated. + +The file `nicematrix.sty` is the only file necessary to use the extension `nicematrix`. diff --git a/macros/latex/contrib/nicematrix/nicematrix-french.pdf b/macros/latex/contrib/nicematrix/nicematrix-french.pdf new file mode 100644 index 0000000000..e0d14dea9c Binary files /dev/null and b/macros/latex/contrib/nicematrix/nicematrix-french.pdf differ diff --git a/macros/latex/contrib/nicematrix/nicematrix-french.tex b/macros/latex/contrib/nicematrix/nicematrix-french.tex new file mode 100644 index 0000000000..70064ad807 --- /dev/null +++ b/macros/latex/contrib/nicematrix/nicematrix-french.tex @@ -0,0 +1,2121 @@ +\documentclass[dvipsnames]{article}% dvipsnames is for xcolor (loaded by Tikz, loaded by nicematrix) +\usepackage{xltxtra} +\usepackage[french]{babel} + +\usepackage{geometry} +\geometry{left=2.8cm,right=2.8cm,top=2.5cm,bottom=2.5cm,papersize={21cm,29.7cm}} + +\usepackage{amsmath} +\usepackage{color} +\usepackage{array} + +\usepackage{colortbl} + +\usepackage{nicematrix} + + +\usepackage{siunitx} + +\newbox\ExampleOne + +\setbox\ExampleOne\hbox{% +$\begin{NiceArray}{|*{4}{C|}}[hlines,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}$} + +\usepackage{arydshln} +\usepackage{verbatim} + + +\usepackage{fancyvrb} +\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} +\setlength{\columnseprule}{0.4pt} + +\def\interitem{\vskip 7mm plus 2 mm minus 3mm} +\def\emphase{\bgroup\color{RoyalPurple}\let\next=} + +\usepackage{footnote} + +\usepackage[hyperfootnotes = false]{hyperref} + +\hypersetup{ + pdfinfo = { + Title = { L’extension nicematrix }, + Subject = { Une extension LaTeX } , + Author = { F. Pantigny } + } +} + + +\NewDocumentEnvironment {scope} {} {} {} + +\NewDocumentCommand {\pkg} {m} {\textsf{#1}} +\NewDocumentCommand {\cls} {m} {\textsf{#1}} + +\setlength{\parindent}{0pt} + + +\begin{document} + +\VerbatimFootnotes + +\title{L'extension \pkg{nicematrix}\thanks{Ce document correspond à la version~\myfileversion\space of \pkg{nicematrix}, +en date du~\myfiledate.}} \author{F. Pantigny \\ \texttt{fpantigny@wanadoo.fr}} + + +\maketitle + +\begin{abstract} +L'extension LaTeX \pkg{nicematrix} fournit de nouveaux environnements +similaires aux environnements classiques \verb|{array}| et \verb|{matrix}| mais avec des +fonctionnalités supplémentaires. Parmi ces fonctionnalités figurent la +possibilité de fixer la largeur des colonnes et de tracer des traits en +pointillés continus entre les cases du tableau. +\end{abstract} + +\vspace{1cm} +\section{Présentation} + +Cette extension peut être utilisée avec \verb|xelatex|, \verb|lualatex| et \verb|pdflatex| mais +aussi avec le cheminement classique \verb|latex|-\verb|dvips|-\verb|ps2pdf| (ou Adobe +Distiller). Deux ou trois compilations successives peuvent être nécessaires. +Cette extension nécessite et charge les extensions \pkg{expl3}, \pkg{l3keys2e}, +\pkg{xparse}, \pkg{array}, \pkg{amsmath} et \pkg{tikz} . Elle charge aussi la +bibliothèque Tikz \pkg{fit}. + + + +\medskip +\begin{savenotes} +\begin{minipage}{0.6\linewidth} +Cette extension fournit quelques outils supplémentaires pour dessiner des +matrices (au sens mathématique). Les principales caractéristiques sont les +suivantes : + +\textbullet\ lignes en pointillés continues\footnote{Si l'option de classe +\texttt{draft} est utilisée, ces lignes en pointillés ne sont pas tracées pour +accélérer la compilation.} ; + +\textbullet\ des rangées et colonnes extérieures pour les labels ; + +\textbullet\ un contrôle sur la largeur des colonnes. +\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 +Une commande\verb|\NiceMatrixOptions| est fournie pour régler les options (la +portée des options fixées par cette commande est le groupe TeX courant). + + +\bigskip +\textbf{Un exemple d'utilisation pour les lignes en pointillés continues} + +\medskip +\begin{minipage}{10cm} +Considérons par exemple le code suivant qui utilise un environnement +\verb|{pmatrix}| de l'extension \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 +Ce code compose la matrice $A$ représentée à droite. +\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} +Maintenant, si nous utilisons l'extension \pkg{nicematrix} avec l'option +\verb|transparent|, le même code va donner le résultat ci-contre à droite. +\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{Les environnements de cette extension} + +L'extension \pkg{nicematrix} définit les nouveaux environnements suivants : + +\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 +Par défaut, les environnements \verb|{NiceMatrix}|, \verb|{pNiceMatrix}|, \verb|{bNiceMatrix}|, \verb|{BNiceMatrix}|, +\verb|{vNiceMatrix}| et \verb|{VNiceMatrix}| se comportent quasiment comme les environnements correspondants de +\pkg{amsmath} : \verb|{matrix}|, \verb|{pmatrix}|, \verb|{bmatrix}|, \verb|{Bmatrix}|, \verb|{vmatrix}| et +\verb|{Vmatrix}|. + + +\medskip +L'environnement \verb|{NiceArray}| est similaire à l'environnement \verb|{array}| de l'extension \verb|{array}|. +Néanmoins, pour des raisons techniques, dans le préambule de l'environnement \verb|{NiceArray}|, l'utilisateur doit +utiliser les lettres \verb|L|, \verb|C| et~\verb|R| au lieu de \verb|l|, \verb|c| et \verb|r|. Il est possible +d'utiliser les constructions \verb|w{...}{...}|, \verb|W{...}{...}|\footnote{Pour les colonnes de type \verb|w| et + \verb|W|, les cases sont composées en mode mathématique (dans les environnements de \pkg{nicematrix}) alors que + dans \verb|{array}| de \pkg{array}, elles sont composées en mode texte.}, \verb+|+, \verb|>{...}|, \verb|<{...}|, +\verb|@{...}|, \verb|!{...}| et \verb|*{n}{...}| mais les lettres \verb|p|, \verb|m| et \verb|b| ne doivent pas +être employées. L'environnement \verb|{NiceArray}| et ses variantes fournissent des options qui permettent de +tracer des rangées et colonnes extérieures. Voir p.~\pageref{NiceArray} la partie concernant \verb|{NiceArray}|. + +\section{Les lignes en pointillés continues} + +À l'intérieur des environnements de l'extension \pkg{nicematrix}, de nouvelles commandes sont définies : +\verb|\Ldots|, \verb|\Cdots|, \verb|\Vdots|, \verb|\Ddots|, and \verb|\Iddots|. Ces commandes sont conçues pour +être utilisées à la place de \verb|\dots|, \verb|\cdots|, \verb|\vdots|, \verb|\ddots| et \verb|\iddots|.\footnote{La + commande \verb|\iddots|, définie dans \pkg{nicematrix}, est une variante de \verb|\ddots| avec les points allant + vers le haut : \smash{$\iddots$}. Si \pkg{mathdots} est chargée, la version de \pkg{mathdots} est utilisée. Elle + correspond à la commande \verb|\adots| de \pkg{unicode-math}.} +\newcounter{fniddots} +\setcounter{fniddots}{\thefootnote} + +\smallskip +Chacune de ces commandes doit être utilisée seule dans la case du tableau et elle trace une ligne en pointillés +entre les premières cases non vides\footnote{La définition précise de ce qui est considéré comme une «case + vide» est donnée plus loin (cf. p.~\pageref{empty-cells}).} situées de part et d'autre de la case courante. +Bien entendu, pour \verb|\Ldots| et \verb|\Cdots|, c'est une ligne horizontale ; pour \verb|\Vdots|, c'est une +ligne verticale et pour \verb|\Ddots| et \verb|\Iddots|, ce sont des lignes diagonales.\par\nobreak\bigskip + +\begin{BVerbatim}[baseline=c,boxwidth=10cm] +\begin{bNiceMatrix} +a_1 & \Cdots & & & a_1 \\ +\Vdots & a_2 & \Cdots & & a_2 \\ + & \Vdots & \Ddots \\ +\\ +a_1 & a_2 & & & a_n +\end{bNiceMatrix} +\end{BVerbatim} +$\begin{bNiceMatrix} +a_1 & \Cdots & & & a_1 \\ +\Vdots & a_2 & \Cdots & & a_2 \\ + & \Vdots & \Ddots \\ +\\ +a_1 & a_2 & & & a_n +\end{bNiceMatrix}$ + +\interitem +Pour représenter la matrice nulle, on peut choisir d'utiliser le codage +suivant :\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 +On peut néanmoins souhaiter une matrice plus grande. Habituellement, dans un +tel cas, les utilisateurs de LaTeX ajoutent une nouvelle ligne et une nouvelle +colonne. Il est possible d'utiliser la même méthode avec \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 +Dans la première colonne de cet exemple, il y a deux instructions \verb|\Vdots| mais +une seule ligne en pointillés sera tracée (il n'y a pas d'objets qui se +superposent dans le fichier \textsc{pdf} résultant\footnote{Et il n'est pas +possible de tracer une ligne \verb|\Ldots| et une ligne \verb|\Cdots| entre les mêmes cases.}). + +Néanmoins, des calculs inutiles sont effectués par TeX avant qu'il ne détecte +que les deux instructions définissent la même ligne en pointillés. C'est +pourquoi l'extension \pkg{nicematrix} fournit des versions étoilées de +\verb|\Ldots|, \verb|\Cdots|, etc. : \verb|\Ldots*|, \verb|\Cdots*|, etc. Ces versions sont +simplement équivalentes à \verb|\hphantom{\ldots}|, \verb|\hphantom{\cdots}|, etc. +L'utilisateur devrait utiliser des versions étoilées à chaque fois qu'une +version classique (sans étoile) a déjà été utilisée pour la même ligne en pointillés.\par\nobreak + +\bigskip +\begin{BVerbatim}[baseline=c,boxwidth=10cm] +\begin{bNiceMatrix} +0 & \Cdots & ~emphase#\Cdots*@ & 0 \\ +\Vdots & & & \Vdots \\ +~emphase#\Vdots*@ & & & ~emphase#\Vdots*@ \\ +0 & \Cdots & ~emphase#\Cdots*@ & 0 +\end{bNiceMatrix} +\end{BVerbatim} +$\begin{bNiceMatrix} +0 & \Cdots & & 0 \\ +\Vdots & & & \\ + & & & \Vdots \\ +0 & & \Cdots & 0 +\end{bNiceMatrix}$ + +\bigskip +En fait, dans cet exemple, il aurait été possible de tracer la même matrice +sans commande étoilée avec le codage suivant :\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 +Il y a aussi d'autres moyens de changer la taille d'une matrice. On pourrait vouloir utiliser l'argument optionnel +de la commande~\verb|\\| pour l'espacement vertical et la commande~\verb|\hspace*| dans une case pour l'espacement +horizontal.\footnote{Le meilleur moyen de régler la largeur des colonnes est, de toutes manières, d'utiliser + l'environnement \verb|{NiceArray}| (ou une de ses variantes) avec une colonne de type~\verb|w| ou \verb|W|: cf. + p.~\pageref{width}} + +Toutefois, une commande~\verb|\hspace*| pourrait interférer dans la construction des lignes en pointillés. C'est +pourquoi l'extension \pkg{nicematrix} fournit une commande~\verb|\Hspace| qui est une variante de \verb|\hspace| +transparente pour la construction des lignes en pointillés de \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{L'option nullify-dots} + +Considérons la matrice suivante qui a été composée classiquement avec l'environnement +\verb|{pmatrix}| de \pkg{amsmath}.\par\nobreak + +\medskip +\begin{BVerbatim}[baseline=c,boxwidth=8cm] +$A = \begin{pmatrix} +a_0 & b \\ +a_1 & \\ +a_2 & \\ +a_3 & \\ +a_4 & \\ +a_5 & b +\end{pmatrix}$ +\end{BVerbatim} +$A = \begin{pmatrix} +a_0 & b \\ +a_1 & \\ +a_2 & \\ +a_3 & \\ +a_4 & \\ +a_5 & b +\end{pmatrix}$ + + +\bigskip +Si nous ajoutons des instructions \verb|\vdots| dans la seconde colonne, la +géométrie de la matrice est modifiée.\par\nobreak +\medskip +\begin{BVerbatim}[baseline=c,boxwidth=8cm] +$B = \begin{pmatrix} +a_0 & b \\ +a_1 & \vdots \\ +a_2 & \vdots \\ +a_3 & \vdots \\ +a_4 & \vdots \\ +a_5 & b +\end{pmatrix}$ +\end{BVerbatim} +$B = \begin{pmatrix} +a_0 & b \\ +a_1 & \vdots \\ +a_2 & \vdots \\ +a_3 & \vdots \\ +a_4 & \vdots \\ +a_5 & b +\end{pmatrix}$ + +\bigskip +Par défaut, avec \pkg{nicematrix}, si nous remplaçons \verb|{pmatrix}| par \verb|{pNiceMatrix}| et \verb|\vdots| par +\verb|\Vdots| (or \verb|\Vdots*| pour la rapidité de compilation), la géométrie de la matrice n'est pas +changée.\par\nobreak +\medskip +\begin{BVerbatim}[baseline=c,boxwidth=8cm] +$C = \begin{pNiceMatrix} +a_0 & b \\ +a_1 & \Vdots \\ +a_2 & \Vdots* \\ +a_3 & \Vdots* \\ +a_4 & \Vdots* \\ +a_5 & b +\end{pNiceMatrix}$ +\end{BVerbatim} +$C = \begin{pNiceMatrix} +a_0 & b \\ +a_1 & \Vdots \\ +a_2 & \Vdots* \\ +a_3 & \Vdots* \\ +a_4 & \Vdots* \\ +a_5 & b +\end{pNiceMatrix}$ + +\bigskip +On pourrait toutefois préférer la géométrie de la première matrice $A$ et +vouloir avoir la même géométrie avec une ligne en pointillés continue dans la +seconde colonne. C'est possible en utilisant l'option \verb|nullify-dots| (et une +seule instruction \verb|\Vdots| suffit).\par\nobreak +\medskip +\begin{BVerbatim}[baseline=c,boxwidth=8cm] +$D = \begin{pNiceMatrix}[~emphase#nullify-dots@] +a_0 & b \\ +a_1 & \Vdots \\ +a_2 & \\ +a_3 & \\ +a_4 & \\ +a_5 & b +\end{pNiceMatrix}$ +\end{BVerbatim} +$D = \begin{pNiceMatrix}[nullify-dots] +a_0 & b \\ +a_1 & \Vdots \\ +a_2 & \\ +a_3 & \\ +a_4 & \\ +a_5 & b +\end{pNiceMatrix}$ + +\medskip +L'option \verb|nullify-dots| «smashe» les instructions \verb|\Ldots| (et ses variantes) +verticalement mais aussi horizontalement. + +\medskip +{\bfseries Il doit n'y avoir aucun espace devant le crochet ouvrant (\verb|[|) des +options de l'environnement.} + +\subsection{La commande \textbackslash Hdotsfor} + +Certaines personnes utilisent habituellement la commande \verb|\hdotsfor| de +l'extension \pkg{amsmath} pour tracer des lignes en pointillés horizontales +dans une matrice. Dans les environnements de \pkg{nicematrix}, il convient +d'utiliser \verb|\Hdotsfor| à la place pour avoir les lignes en pointillés +similaires à toutes celles tracées par l'extension \pkg{nicematrix}. + +Comme avec les autres commandes de \pkg{nicematrix} (comme \verb|\Cdots|, \verb|\Ldots|, \verb|\Vdots|, etc.), la ligne +en pointillés tracée par \verb|\Hdotsfor| s'étend jusqu'au contenu des cases de part et d'autre. + +\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 +Néanmoins, si ces cases sont vides, la ligne en pointillés s'étend seulement dans les cases spécifiées par +l'argument de \verb|\Hdotsfor| (par conception). + +\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}$ + +\bigskip +La commande \verb|\hdotsfor| de \pkg{amsmath} prend un argument optionnel (entre +crochets) qui est utilisé pour un réglage fin de l'espace entre deux points +consécutifs. Par homogénéité, \verb|\Hdotsfor| prend aussi un argument optionnel +mais cet argument est écarté silencieusement. + +Remarque : Contrairement à la commande \verb|\hdotsfor| de \pkg{amsmath}, la commande \verb|\Hdotsfor| est +utilisable lorsque l'extension \pkg{colortbl} est chargée (mais vous risquez d'avoir des problèmes si vous utilisez +\verb|\rowcolor| sur la même rangée que \verb|\Hdotsfor|). + +\subsection{Comment créer les lignes en pointillés de manière transparente} + +L'extension \pkg{nicematrix} fournit une option appelée \verb|transparent| qui permet d'utiliser du code existant +de manière transparente dans les environnements \verb|{matrix}|. Cette option peut être passée en option du +\verb|\usepackage| ou bien être fixée avec la commande \verb|\NiceMatrixOptions|. + +En fait, cette option est un alias pour la conjonction de deux options : \verb|renew-dots| et \verb|renew-matrix|. + +\smallskip + +\begin{itemize} +\item L'option \verb|renew-dots|\par\nobreak Avec cette option, les commandes \verb|\ldots|, \verb|\cdots|, +\verb|\vdots|, \verb|\ddots|, \verb|\iddots|\footnotemark[\thefniddots] et \verb|\hdotsfor| sont redéfinies dans +les environnements de \pkg{nicematrix} et agissent comme \verb|\Ldots|, \verb|\Cdots|, \verb|\Vdots|, +\verb|\Ddots|, \verb|\Iddots| et \verb|\Hdotsfor| ; la commande \verb|\dots| (points de suspension «automatiques» +de \verb|amsmath|) est aussi redéfinie et se comporte comme \verb|\Ldots|. + +\item L'option \verb|renew-matrix|\par\nobreak +Avec cette option, l'environnement \verb|{matrix}| est redéfini et +se comporte comme \verb|{NiceMatrix}| et il en est de même pour les cinq variantes. +\end{itemize} + +\bigskip +Par conséquent, avec l'option \verb|transparent|, un code classique donne directement le résultat fourni par +\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} + + + + +\section{Les nœuds Tikz créés par l'extension nicematrix} + +L'extension \pkg{nicematrix} crée un nœud Tikz pour chaque case du tableau considéré. Ces nœuds sont utilisés +pour tracer les lignes en pointillés entre les cases du tableau. Toutefois, l'utilisateur peut utiliser +directement ces nœuds. On commence par donner un nom au tableau (avec l'option \verb|name|). Cela étant fait, les +nœuds sont accessibles à travers les noms «\textsl{nom}-$i$-$j$» où \textsl{nom} est le nom donné au tableau et $i$ +et $j$ les numéros de ligne et de colonne de la case considérée. + +\medskip +\begin{BVerbatim}[baseline=c,boxwidth=11cm] +$\begin{pNiceMatrix}[name=~emphase#ma-matrice@] +1 & 2 & 3 \\ +4 & 5 & 6 \\ +7 & 8 & 9 +\end{pNiceMatrix}$ +\tikz[remember picture,overlay] + \draw ~emphase#(ma-matrice-2-2)@ circle (2mm) ; +\end{BVerbatim} +$\begin{pNiceMatrix}[name=ma-matrice] +1 & 2 & 3 \\ +4 & 5 & 6 \\ +7 & 8 & 9 +\end{pNiceMatrix}$ +\tikz[remember picture,overlay] + \draw (ma-matrice-2-2) circle (2mm) ; + +\medskip +Ne pas oublier les options \verb|remember picture| et \verb|overlay|. + +\bigskip +Dans l'exemple suivant, nous avons surligné toutes les cases de la matrice. +\begin{scope} +\tikzset{every node/.style = {fill = red!15, inner sep = 0pt}} +\[\begin{pNiceMatrix} +a & a + b & a + b + c \\ +a & a & a + b \\ +a & a & a +\end{pNiceMatrix}\] +\end{scope} + + +\bigskip +En fait, l'extension \pkg{nicematrix} peut créer des nœuds supplémentaires (\emph{extra nodes} en anglais). Ces +nouveaux nœuds sont créés si l'option \verb|create-extra-nodes| est utilisée. Il y a deux séries de nœuds +supplémentaires : les «nœuds moyens» (\emph{medium nodes} en anglais) et les «nœuds larges» (\emph{large nodes} en +anglais). + +\medskip +Les noms des «nœuds moyens» s'obtiennent en ajoutant le suffixe «\verb|-medium|» au nom des nœuds normaux. Dans +l'exemple suivant, on a surligné tous les «nœuds moyens». Nous considérons que cet exemple se suffit à lui-même +comme définition de ces nœuds. +\[\begin{pNiceMatrix}[ + create-extra-nodes, + code-after = {\begin{tikzpicture} + [every node/.style = {fill = red!15, + blend mode = multiply, + inner sep = -\pgflinewidth/2}, + 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 +Les noms des «nœuds larges» s'obtiennent en ajoutant le suffixe «\verb|-large|» au nom des nœuds normaux. Dans l'exemple +suivant, on a surligné tous les «nœuds larges». Nous considérons que cet exemple se suffit à lui-même comme +définition de ces nœuds.\footnote{Il n'y a pas de «nœuds larges» créés dans les lignes et colonnes extérieures + (pour ces lignes et colonnes, voir p.~\pageref{exterior}).} + +\[\begin{pNiceMatrix}[ + create-extra-nodes, + code-after = {\begin{tikzpicture} + [every node/.style = {blend mode = multiply, + inner sep = -\pgflinewidth/2}, + 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 +Les «nœuds larges» de la première colonne et de la dernière colonne peuvent apparaître trop petits pour certains +usages. C'est pourquoi il est possible d'utiliser les options \verb|left-margin| et \verb|right-margin| pour +ajouter de l'espace des deux côtés du tableau et aussi de l'espace dans les «nœuds larges» de la première colonne et +de la dernière colonne. Dans l'exemple suivant, nous avons utilisé les options \verb|left-margin| et \verb|right-margin|. +\footnote{Les options \verb|left-margin| et \verb|right-margin| prennent des dimensions comme valeurs mais, si + aucune valeur n'est donnée, c'est la valeur par défaut qui est utilisée et elle est égale à \verb|\arraycolsep|.} +\[\begin{pNiceMatrix}[ + create-extra-nodes,left-margin,right-margin, + code-after = {\begin{tikzpicture} + [every node/.style = {blend mode = multiply, + inner sep = -\pgflinewidth/2}, + 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 +Il est aussi possible d'ajouter de l'espace sur les côtés du tableau avec les options +\verb|extra-left-margin| et \verb|extra-right-margin|. Ces marges ne sont pas incorporées dans les «nœuds larges». +Dans l'exemple suivant, nous avons utilisé \verb|extra-left-margin| et \verb|extra-right-margin| avec la valeur $3$~pt. +\[\begin{pNiceMatrix}[ + create-extra-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 = -\pgflinewidth/2}, + 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 +Dans le cas présent, si on veut un contrôle sur la hauteur des rangées, on peut ajouter un \verb|\strut| dans +chaque rangée du tableau. +\[\begin{pNiceMatrix}[ + create-extra-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 = -\pgflinewidth/2}, + 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 +On explique plus loin comment surligner les nœuds créés par Tikz (cf. p. \pageref{highlight}). + +\section{Le code-after} + +L'option \verb|code-after| peut être utilisée pour indiquer du code qui sera exécuté après la construction de la +matrice (et donc, en particulier, après la construction de tous les nœuds). + +Dans le \verb|code-after|, les nœuds Tikz doivent être désignés sous la forme $i$-$j$ (sans le préfixe +correspondant au nom de l'environnement). + +De plus, une commande spéciale, nommée \verb|\line| est disponible pour tracer directement des lignes en pointillés +entre les nœuds). + +\medskip +\begin{BVerbatim}[baseline=c,boxwidth=12cm] +$\begin{pNiceMatrix}[~emphase#code-after = {\line {1-1} {3-3}}@] +0 & 0 & 0 \\ +0 & & 0 \\ +0 & 0 & 0 +\end{pNiceMatrix}$ +\end{BVerbatim} +$\begin{pNiceMatrix}[code-after = {\line {1-1} {3-3}}] +0 & 0 & 0 \\ +0 & & 0 \\ +0 & 0 & 0 +\end{pNiceMatrix}$ + + +\section{L'environnement \{NiceArray\}} +\label{NiceArray} + +L'environnement \verb|{NiceArray}| est similaire à l'environnement \verb|{array}|. Comme pour \verb|{array}|, +l'argument obligatoire est le préambule du tableau. Néanmoins, pour des raisons techniques, l'utilisateur doit +utiliser les lettres \verb|L|, \verb|C| et \verb|R|\footnote{Les types de colonnes \verb|L|, \verb|C| et \verb|R| + sont définis localement à l'intérieur de \verb|{NiceArray}| avec la commande \verb|\newcolumntype| de + \pkg{array}. Cette définition masque une éventuelle définition précédente. En fait, les types de colonnes + \verb|w| and \verb|W| sont également redéfinis.} au lieu de \verb|l|, \verb|c| et \verb|r|. + +Il est possible d'utiliser les constructions \verb|w{...}{...}|, \verb|W{...}{...}|, \verb+|+, \verb|>{...}|, +\verb|<{...}|, \verb|@{...}|, \verb|!{...}| et \verb|*{n}{...}| mais les lettres \verb|p|, \verb|m| et \verb|b| ne +doivent pas être employées.\footnote{Dans une commande \verb|\multicolumn|, on doit également utiliser les lettres + \verb|L|, \verb|C| et + \verb|R|.} + +\medskip +L'environnement \verb|{NiceArray}| accepte les options classiques \verb|t|, \verb|c| et \verb|b| de \verb|{array}| +mais aussi d'autres options définies par \pkg{nicematrix} (\verb|renew-dots|, \verb|columns-width|, etc.). + + +\vspace{1cm} +Un exemple avec un système linéaire (on a besoin de \verb|{NiceArray}| pour le trait vertical): + +\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]$ + +\vspace{1cm} +Il existe également des variantes pour l'environnement \verb|{NiceArray}|: +\verb|{pNiceArray}|, \verb|{bNiceArray}|, \verb|{BNiceArray}|, \verb|{vNiceArray}| et +\verb|{VNiceArray}|. + + +Dans l'exemple suivant, on utilise un environnment \verb|{pNiceArray}| (on n'utilise pas \verb|{pNiceMatrix}| car +on souhaite utiliser les types de colonne \verb|L| et \verb|R| --- avec \verb|{pNiceMatrix}|, toutes les +colonnes sont de type \verb|C|). + + +\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}$ + +\vspace{1cm} +L'environnement \verb|{NiceArray}| et ses variantes permettent de composer des rangées et des colonnes «extérieures» grâce aux options +\verb|first-row|, \verb|last-row|, \verb|first-col| et \verb|last-col|. +\label{exterior} + +Il n'y a pas de spécification de colonne à fournir pour l'éventuelle «première colonne» (qui sera automatiquement +une colonne de type \verb|R|) ou pour l'éventuelle «dernière colonne» (qui sera automatiquement de type \verb|L|). + + +\begin{Verbatim} +$\begin{pNiceArray}{CCCC}[~emphase#first-row,last-row,first-col,last-col@] + & C_1 & C_2 & C_3 & C_4 & \\ +L_1 & a_{11} & a_{12} & a_{13} & a_{14} & L_1 \\ +L_2 & a_{21} & a_{22} & a_{23} & a_{24} & L_2 \\ +L_3 & a_{31} & a_{32} & a_{33} & a_{34} & L_3 \\ +L_4 & a_{41} & a_{42} & a_{43} & a_{44} & L_4 \\ + & C_1 & C_2 & C_3 & C_4 & +\end{pNiceArray}$ +\end{Verbatim} +% +\[\begin{pNiceArray}{CCCC}[first-row,last-row,first-col,last-col] + & C_1 & C_2 & C_3 & C_4 & \\ +L_1 & a_{11} & a_{12} & a_{13} & a_{14} & L_1 \\ +L_2 & a_{21} & a_{22} & a_{23} & a_{24} & L_2 \\ +L_3 & a_{31} & a_{32} & a_{33} & a_{34} & L_3 \\ +L_4 & a_{41} & a_{42} & a_{43} & a_{44} & L_4 \\ + & C_1 & C_2 & C_3 & C_4 & +\end{pNiceArray}\] + +\bigskip + +Néanmoins, il y a une particularité avec l'option \verb|last-row| : quand LaTeX compose un tableau \verb|{array}| +(via une commande \verb|\halign| de TeX), il le compose rangée par rangée et il n'y a pas de moyen direct de savoir +que l'on est arrivé à la dernière rangée avant la composition de celle-ci. Pour remédier à ce problème, +\pkg{nicematrix} écrit dans le fichier \verb|aux| le nombre de rangées du tableau pour pouvoir l'utiliser à la +compilation suivante. Il est néanmoins également possible de passer directement le nombre de rangées en argument de +l'option \verb|last-row| et, ainsi, \pkg{nicematrix} le connaîtra dès la première compilation. + +\bigskip +On peut contrôler l'apparence de ces rangées et colonnes avec les options \verb|code-for-first-row|, +\verb|code-for-last-row|, \verb|code-for-first-col| et \verb|code-for-last-col|. Ces options sont des listes de +tokens qui seront insérées au début de chaque case de la rangée ou de la colonne considérée. + +\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] + & C_1 & C_2 & C_3 & C_4 & \\ +L_1 & a_{11} & a_{12} & a_{13} & a_{14} & L_1 \\ +L_2 & a_{21} & a_{22} & a_{23} & a_{24} & L_2 \\ +\hline +L_3 & a_{31} & a_{32} & a_{33} & a_{34} & L_3 \\ +L_4 & a_{41} & a_{42} & a_{43} & a_{44} & L_4 \\ + & C_1 & C_2 & C_3 & 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{pNiceArray}{CC|CC}[first-row,last-row=5,first-col,last-col] + & C_1 & \multicolumn1C{C_2} & C_3 & C_4 & \\ +L_1 & a_{11} & a_{12} & a_{13} & a_{14} & L_1 \\ +L_2 & a_{21} & a_{22} & a_{23} & a_{24} & L_2 \\ +\hline +L_3 & a_{31} & a_{32} & a_{33} & a_{34} & L_3 \\ +L_4 & a_{41} & a_{42} & a_{43} & a_{44} & L_4 \\ + & C_1 & \multicolumn1C{C_2} & C_3 & C_4 & +\end{pNiceArray}\] +\end{scope} + + + +\emph{Remarques} +\begin{itemize} +\item Comme on peut le voir dans l'exemple précédent, un filet horizontal (tracé avec \verb|\hline|) ne s'étend pas +dans les colonnes extérieures et un filet vertical (spécifié par un caractère «\verb+|+» dans le préambule du +tableau) ne s'étend pas dans les rangées extérieures.\footnote{Ce dernier point n'est pas valable si on a chargé, + en plus de \pkg{nicematrix}, l'extension \pkg{arydshln}. Les extensions \pkg{nicematrix} et \pkg{arydshln} ne + sont pas parfaitement compatibles car \pkg{arydshln} redéfinit beaucoup de structures internes à \pkg{array}.} +\item La «première rangée» d'un environnement \verb|{pNiceArray}| porte le numéro $0$, et non $1$ (de même pour la +«première colonne»). Ce numéro est utilisé, par exemple, pour les noms des nœuds Tikz (les noms de ces nœuds sont +utilisés, par exemple, par la commande \verb|\line| dans le \verb|code-after|). +\item Sans surprise, une éventuelle option \verb|columns-width| (décrite p.~\pageref{width}) ne s'applique pas à la +«première colonne» ni à la «dernière colonne». +\item Pour des raisons techniques, il n'est pas possible d'utiliser l'option de la commande \verb|\\| après la +«première rangée» ou avant la «dernière rangée» (le placement des délimiteurs serait erroné). +\end{itemize} + + +\bigskip +En fait, l'environnement \verb|{pNiceArray}| et ses variantes sont fondés sur un environnement plus général, appelé +\verb|{NiceArrayWithDelims}|. Les deux premiers arguments obligatoires de cet environnement sont les délimiteurs +gauche et droit qui seront utilisés dans la construction de la matrice. Il est possible d'utiliser +\verb|{NiceArrayWithDelims}| si on a besoin de délimiteurs atypiques. + +\medskip +\begin{BVerbatim}[baseline=c,boxwidth=11cm] +$\begin{~emphase#NiceArrayWithDelims@} + {\downarrow}{\downarrow}{CCC}[last-col] +1 & 2 & 3 & L_1 \\ +4 & 5 & 6 & L_2 \\ +7 & 8 & 9 & L_3 +\end{~emphase#NiceArrayWithDelims@}$ +\end{BVerbatim} +$\begin{NiceArrayWithDelims} + {\downarrow}{\downarrow}{CCC}[last-col] +1 & 2 & 3 & L_1 \\ +4 & 5 & 6 & L_2 \\ +7 & 8 & 9 & L_3 +\end{NiceArrayWithDelims}$ + + + + +\section[Les lignes en pointillés pour séparer les rangées et les colonnes]{Les lignes en pointillés pour séparer les rangées\\ et les colonnes} + + +Dans les environnements de \pkg{nicematrix}, il est possible d'utiliser la commande \verb|\hdottedline| (fournie +par \pkg{nicematrix}) qui est l'équivalent pour les pointillés des commandes \verb|\hline| et \verb|\hdashline| +(cette dernière étant une commande de \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 +Dans les environnements avec un préambule explicite (comme \verb|{NiceArray}|, \verb|{pNiceArray}|, etc.), il est +possible de dessiner un trait vertical en pointillés avec le spécificateur «\verb|:|». + +\medskip +\begin{BVerbatim}[baseline=c,boxwidth=9.5cm] +\begin{pNiceArray}{CCCC~emphase#:@C} +1 & 2 & 3 & 4 & 5 \\ +6 & 7 & 8 & 9 & 10 \\ +11 & 12 & 13 & 14 & 15 +\end{pNiceArray} +\end{BVerbatim} +$\begin{pNiceArray}{CCCC:C} +1 & 2 & 3 & 4 & 5 \\ +6 & 7 & 8 & 9 & 10 \\ +11 & 12 & 13 & 14 & 15 +\end{pNiceArray}$ + + +\bigskip +Ces lignes en pointillés ne s'étendent pas dans les rangées et colonnes extérieures. + + +\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 +Il est possible de changer dans \pkg{nicematrix} la lettre utilisée pour indiquer dans le préambule un trait +vertical en pointillés avec l'option \verb|letter-for-dotted-lines| disponible dans \verb|\NiceMatrixOptions|. Par +exemple, dans ce document, nous avons chargé l'extension \pkg{arydshln} qui utilise la lettre «\verb|:|» pour +indiquer un trait vertical en tiretés. Par conséquent, en utilisant l'option \verb|letter-for-dotted-lines|, on +peut utiliser les traits verticaux fournis à la fois par \pkg{arydshln} et par \pkg{nicematrix}. + + +\medskip +\begin{BVerbatim}[baseline=c,boxwidth=9.5cm] +\NiceMatrixOptions{letter-for-dotted-lines = V} +\begin{pNiceArray}{~emphase#C|C:CVC@} +1 & 2 & 3 & 4 \\ +5 & 6 & 7 & 8 \\ +9 & 10 & 11 & 12 +\end{pNiceArray} +\end{BVerbatim} +\begin{scope} +\NiceMatrixOptions{letter-for-dotted-lines = V} +$\begin{pNiceArray}{C|C:CVC} +1 & 2 & 3 & 4 \\ +5 & 6 & 7 & 8 \\ +9 & 10 & 11 & 12 +\end{pNiceArray}$ +\end{scope} + +\section{La largeur des colonnes} +\label{width} + +Dans les environnements avec un préambule explicite (comme \verb|{NiceArray}|, \verb|{pNiceArray}|, etc.), il est +possible de fixer la largeur d'une colonne avec les lettres classiques \verb|w| et \verb|W| de l'extension +\pkg{array}. Dans les environnements de \pkg{nicematrix}, les cases des colonnes de ce type sont composées en mode +mathématique (alors que dans \verb|{array}| de \pkg{array}, elles sont composées en mode texte). + +\medskip +\begin{BVerbatim}[baseline=c,boxwidth=10cm] +$\begin{pNiceArray}{~emphase#Wc{1cm}@CC} +1 & 12 & -123 \\ +12 & 0 & 0 \\ +4 & 1 & 2 +\end{pNiceArray}$ +\end{BVerbatim} +$\begin{pNiceArray}{Wc{1cm}CC} +1 & 12 & -123 \\ +12 & 0 & 0 \\ +4 & 1 & 2 +\end{pNiceArray}$ + + +\bigskip +Avec \pkg{nicematrix}, il est aussi possible de fixer la largeur de toutes les colonnes de la matrice directement +avec l'option \verb|columns-width| (disponible dans tous les environnements de \pkg{nicematrix}). + +\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 +Noter que l'espace inséré entre deux colonnes (égal à 2 \verb|\arraycolsep|) n'est pas supprimé (il est évidemment +possible de le supprimer en mettant \verb|\arraycolsep| à~$0$). + +\bigskip +Il est possible de donner la valeur \verb|auto| à l'option \verb|columns-width| : toutes les colonnes du tableau +auront alors une largeur égale à la largeur de la case la plus large du tableau. \textbf{Deux ou trois + compilations successives peuvent être nécessaires.}\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 +Il est possible de fixer la largeur de toutes les colonnes de toutes les matrices dans une certaine portion de +document avec la commande \verb|\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 +Mais il est aussi possible de fixer une zone dans laquelle toutes les matrices auront leurs colonnes de la même +largeur, égale à la largeur de la case la plus large de toutes les matrices de la zone. Cette construction +utilise l'environnement \verb|{NiceMatrixBlock}| avec l'option \verb|auto-columns-width|.\footnote{Pour le moment, + c'est le seul usage de l'environnement \verb|{NiceMatrixBlock}| mais il pourrait y en avoir davantage dans le futur.} + +\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} + + +\section{L'option hlines} + +Dans les environnements de \pkg{nicematrix}, on peut bien entendu ajouter des filets horizontaux entre les lignes +avec la commande~\verb|\hline|. Par souci de commodité, l'extension \pkg{nicemarix} fournit l'option \verb|hlines| +qui impose directement que tous les filets horizontaux soient tracés (à l'exception, très naturelle, du +filet avant l'éventuelle «première rangée» et après l'éventuelle «dernière rangée»). + +\medskip +\begin{BVerbatim}[baseline=c,boxwidth=10.6cm] +$\begin{NiceArray}{|*{4}{C|}}[~emphase#hlines@,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}$ +\end{BVerbatim} +\raisebox{-5mm}{\box\ExampleOne} + + +\section{Utilisation du type de colonne S de siunitx} + +Si l'extension \pkg{siunitx} est chargée (avant ou après \pkg{nicematrix}), il est possible d'utiliser les colonnes +de type \verb|S| de \pkg{siunitx} dans les environnements de \pkg{nicematrix}. L'implémentation n'utilise +explicitement aucune macro privée de \pkg{siunitx}. Les colonnes \verb|d| de \pkg{dcolumn} ne sont pas prises en +charge par \pkg{nicematrix}. + +\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}$ + + +\section{Remarques techniques} + +\subsection{Lignes diagonales} + +Par défaut, toutes les lignes diagonales\footnote{On parle des lignes créées par \verb|\Ddots| et non des lignes + créées par une commande \verb|\line| dans le \verb|code-after|.} d'un même tableau sont «parallélisées». Cela signifie que la première +diagonale est tracée et que, ensuite, les autres lignes sont tracées parallèlement à la première (par rotation +autour de l'extrémité la plus à gauche de la ligne). C'est pourquoi la position des instructions \verb|\Ddots| dans +un tableau peut avoir un effet marqué sur le résultat final. + +\medskip +Dans les exemples suivants, la première instruction \verb|\Ddots| est marquée en couleur : + +\medskip +\begin{scope} +\begin{minipage}{9.5cm} +Exemple avec parallélisation (comportement par défaut): +\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 +Il est possible de désactiver la parallélisation avec l'option +\verb|parallelize-diags| mise à \verb|false|: \par\nobreak + +\medskip +\NiceMatrixOptions{parallelize-diags=false}% +\begin{minipage}{9.5cm} +Le même exemple sans parallélisation : +\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{Les cases «vides»} + +\label{empty-cells} +Une instruction comme +\verb|\Ldots|, \verb|\Cdots|, etc. essaye de déterminer la première case vide de part et d'autre de la case +considérée. Néanmoins, une case vide n'est pas nécessairement sans contenu dans le codage TeX (c'est-à-dire sans +aucun token entre les deux esperluettes~\verb|&|). En effet, une case dont le contenu est \verb|\hspace*{1cm}| peut +être considérée comme vide. + +\interitem +Pour \pkg{nicematrix}, les règles précises sont les suivantes : + +\begin{itemize} +\item Une case implicite est vide. Par exemple, dans la matrice suivante + +\begin{Verbatim} +\begin{pmatrix} +a & b \\ +c \\ +\end{pmatrix} +\end{Verbatim} + +la dernière case (deuxième rangée et deuxième colonne) est vide. + +\medskip +\item Chaque case avec un rendu par TeX de largeur inférieure à 0.5~pt est vide. + +\medskip +\item Une case qui contient une commande \verb|\Ldots|, \verb|\Cdots|, \verb|\Vdots|, \verb|\Ddots| +ou \verb|\Iddots| (ou une des versions étoilées) est vide. On rappelle que ces commandes doivent être employées seules +dans une case. + + +\medskip +\item Une case avec une commande \verb|\Hspace| (ou \verb|\Hspace*|) est vide. Cette commande +\verb|\Hspace| est une commande définie par l'extension \pkg{nicematrix} avec la même signification +que \verb|\hspace| excepté que la case où cette commande est utilisée est considérée comme vide. +Cette commande peut être utilisée pour fixer la largeur des colonnes sans interférer avec le tracé des lignes en +pointillés par \pkg{nicematrix}. + +\end{itemize} + + +\subsection{L'option exterior-arraycolsep} + +L'environnement \verb|{array}| insère un espace horizontal égal à \verb|\arraycolsep| +avant et après chaque colonne. En particulier, il y a un espace égal à +\verb|\arraycolsep| avant et après le tableau. Cette caractéristique de l'environnement \verb|{array}| +n'était probablement pas une bonne idée.\footnote{Dans la documentation de +\verb|{amsmath}|, on peut lire : {\itshape The extra space of \verb|\arraycolsep| that +\pkg{array} adds on each side is a waste so we remove it [in \verb|{matrix}|] +(perhaps we should instead remove it from array in general, but that's a +harder task).} Il est possible de supprimer les espaces pour un environnement \verb|{array}| donné par une +construction du type \verb|\begin{array}{@{}ccccc@{}}|.} + +L'environnement \verb|{matrix}| et ses variantes (\verb|{pmatrix}|, \verb|{vmatrix}|, etc.) +de \pkg{amsmath} prefèrent supprimer ces espaces avec des instructions explicites +\verb|\hskip -\arraycolsep| et \verb|{NiceArray}| agit de même. + +Néanmoins, l'utilisateur peut changer ce comportement avec l'option +\verb|exterior-arraycolsep| de la commande \verb|\NiceMatrixOptions|. Avec cette option, +\verb|{NiceArray}| va insérer le même espacement horizontal que \verb|{array}|. + +Cette option est seulement pour la «compatibilité» puisque l'extension \pkg{nicematrix} +fournit un contrôle plus précis avec les options \verb|left-margin|, +\verb|extra-left-margin|, etc. + + +\subsection{L'option de classe draft} + +L'extension \pkg{nicematrix} est relativement lente pour tracer les lignes en pointillés +(créées par \verb|\Cdots|, \verb|\Ldots|, \verb|\Ddots|, etc. mais aussi par le spécificateur +«\verb|:|»).\footnote{La principale raison est que nous voulons des lignes + en pointillés avec des points ronds et non carrés. Pour atteindre ce + but, il a fallu construire notre propre système de lignes en pointillés.} + + +C'est pourquoi, avec l'option de classe \verb|draft|, les lignes en pointillés ne sont pas tracées, +pour accélérer la compilation. + + +\subsection{Un problème technique avec l'argument de \textbackslash\textbackslash} + + +Pour des raisons techniques, si vous utilisez l'argument optionnel de la commande \verb|\\|, +l'espace vertical sera aussi ajouté au nœud («normal») correspondant à la case précédente. + + +\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 +Il y a deux solutions pour résoudre ce problème. La première solution est d'utiliser une commande TeX pour insérer + l'espace entre les deux rangées. + +\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 +L'autre solution est d'utiliser la commande \verb|\multicolumn| dans la case précédente : + +\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{Environnements obsolètes} + +La version 3.0 de \pkg{nicematrix} a introduit l'environnement +\verb|{pNiceArray}| (et ses variantes) avec les options \verb|first-row|, \verb|last-row|, +\verb|first-col| et \verb|last-col|. + +Par conséquent, les environnements suivants, présents dans les versions précédentes de \pkg{nicematrix} sont devenus +obsolètes : +% +\begin{itemize} +\item \verb|{NiceArrayCwithDelims}| ; +\item \verb|{pNiceArrayC}|, \verb|{bNiceArrayC}|, \verb|{BNiceArrayC}|, \verb|{vNiceArrayC}|, +\verb|{VNiceArrayC}| ; +\item \verb|{NiceArrayRCwithDelims}| ; +\item \verb|{pNiceArrayRC}|, \verb|{bNiceArrayRC}|, \verb|{BNiceArrayRC}|, \verb|{vNiceArrayRC}|, +\verb|{VNiceArrayRC}|. +\end{itemize} + +Ils seront peut-être supprimés dans une version future de \pkg{nicematrix}. + + +\section{Exemples} + +\subsection{Lignes en pointillés} + +\medskip +Une matrice tridiagonale : + +\bigskip +\begin{BVerbatim}[baseline=c] +$\begin{pNiceMatrix}[nullify-dots] +a & b & 0 & & \Cdots & 0 \\ +b & a & b & \Ddots & & \Vdots \\ +0 & b & a & \Ddots & & \\ + & \Ddots & \Ddots & \Ddots & & 0 \\ +\Vdots & & & & & b \\ +0 & \Cdots & & 0 & b & a +\end{pNiceMatrix}$ +\end{BVerbatim} +\hspace{1.5cm} +$\begin{pNiceMatrix}[nullify-dots] +a & b & 0 & & \Cdots & 0 \\ +b & a & b & \Ddots & & \Vdots \\ +0 & b & a & \Ddots & & \\ + & \Ddots & \Ddots & \Ddots & & 0 \\ +\Vdots & & & & & b \\ +0 & \Cdots & & 0 & b & a +\end{pNiceMatrix}$ + +\vspace{2cm} + +Une matrice de permutation : + +\bigskip +\begin{BVerbatim}[baseline=c] +$\begin{pNiceMatrix} +0 & 1 & 0 & & \Cdots & 0 \\ +\Vdots & & & \Ddots & & \Vdots \\ + & & & \Ddots & & \\ + & & & \Ddots & & 0 \\ +0 & 0 & & & & 1 \\ +1 & 0 & & \Cdots & & 0 +\end{pNiceMatrix}$ +\end{BVerbatim} +\hspace{2.5cm} +$\begin{pNiceMatrix} +0 & 1 & 0 & & \Cdots & 0 \\ +\Vdots & & & \Ddots & & \Vdots \\ + & & & \Ddots & & \\ + & & & \Ddots & & 0 \\ +0 & 0 & & & & 1 \\ +1 & 0 & & \Cdots & & 0 +\end{pNiceMatrix}$ + +\vspace{2cm} + +Un exemple avec \verb|\Iddots|: \par\nobreak +\bigskip +\begin{BVerbatim}[baseline=c] +$\begin{pNiceMatrix} +1 & \Cdots & & 1 \\ +\Vdots & & & 0 \\ + & ~emphase#\Iddots@ & ~emphase#\Iddots@ & \Vdots \\ +1 & 0 & \Cdots & 0 +\end{pNiceMatrix}$ +\end{BVerbatim} +\hspace{4cm} +$\begin{pNiceMatrix} +1 & \Cdots & & 1 \\ +\Vdots & & & 0 \\ + & \Iddots & \Iddots & \Vdots \\ +1 & 0 & \Cdots & 0 +\end{pNiceMatrix}$ + + +\vspace{2cm} +Un exemple avec \verb|\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{ autres lignes}}@ & \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{ autres lignes}} & \Cdots \\ +1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 +\end{BNiceMatrix}\] + +\vspace{2cm} +Un exemple avec \verb|\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} +Un exemple pour le résultant de deux polynômes : +\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} +Un exemple avec un système linéaire:\par\nobreak + +\begin{Verbatim} +$\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}$ +\end{Verbatim} + +\[\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}\] + + + +\subsection{Largeur des colonnes} + +\medskip +Dans l'exemple suivant, nous utilisons +\verb|{NiceMatrixBlock}| avec l'option \verb|auto-columns-width| parce que +nous voulons la même largeur (automatique) pour toutes les colonnes. + +\bigskip +\begin{BVerbatim} +~emphase#\begin{NiceMatrixBlock}[auto-columns-width]@ +\NiceMatrixOptions{code-for-last-col = \color{blue}\scriptstyle} +\setlength{\extrarowheight}{1mm} +\quad $\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}$ +... +~emphase#\end{NiceMatrixBlock}@ +\end{BVerbatim} + +\bigskip + +\begin{multicols}{2} +\begin{NiceMatrixBlock}[auto-columns-width] +\NiceMatrixOptions{code-for-last-col = \color{blue}\scriptstyle} +\setlength{\extrarowheight}{1mm} + +\quad $\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-2L_1+L_2 \\ +0&6&24&78&33&L_3\gets-3L_1+L_3 \\ +0&12&60&252&96&L_4\gets-4L_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\frac12L_2\\ +0&3&12&39&\frac{33}2&L_3\gets\frac12L_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 -3L_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 \frac13L_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 2L_3+L_4 +\end{pNiceArray}$ +\end{NiceMatrixBlock} +\end{multicols} + + +\subsection{Comment surligner les cases} + +\label{highlight} + +\medskip +Pour mettre en évidence une case, il est possible de «dessiner» l'un des nœuds (le «nœud normal», le «nœud +moyen» ou le «nœud large»). Dans l'exemple suivant, on utilise les «nœuds larges» de la diagonale de la matrice +(avec la clé de Tikz «\verb|name suffix|», il est facile d'utiliser les «nœuds larges»). Pour avoir la continuité +des lignes, on doit fixer \verb|inner sep = -\pgflinewidth/2|. + +\begin{Verbatim} +$\begin{pNiceArray}{>{\strut}CCCC}% + [create-extra-nodes,margin,extra-margin=2pt, + code-after = {\begin{tikzpicture} + [~emphase#name suffix = -large@, + every node/.style = {draw, + ~emphase#inner sep = -\pgflinewidth/2@}] + \node [fit = (1-1)] {} ; + \node [fit = (2-2)] {} ; + \node [fit = (3-3)] {} ; + \node [fit = (4-4)] {} ; + \end{tikzpicture}}] +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} +\end{pNiceArray}$ +\end{Verbatim} + + +\[\begin{pNiceArray}{>{\strut}CCCC}[ + create-extra-nodes,margin,extra-margin=2pt, + code-after = {\begin{tikzpicture}[name suffix = -large, + every node/.style = {draw, + inner sep = -\pgflinewidth/2}] + \node [fit = (1-1)] {} ; + \node [fit = (2-2)] {} ; + \node [fit = (3-3)] {} ; + \node [fit = (4-4)] {} ; + \end{tikzpicture}}] +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} +\end{pNiceArray}\] + + +\vspace{1cm} + +L'extension \pkg{nicematrix} est construite au-dessus de l'environnement \verb|{array}| et, par conséquent, il est +possible d'utiliser l'extension \pkg{colortbl} dans les environnements de \pkg{nicematrix}. Les possibilités de +réglage de \pkg{colortbl} sont néanmoins assez limitées. C'est pourquoi nous proposons une autre méthode pour +surligner une rangée de la matrice. Nous créons un nœud Tikz rectangulaire qui englobe les nœuds de la deuxième +rangée en utilisant les outils de la bibliothèque Tikz \pkg{fit}. Ce nœud est rempli après la construction de la +matrice. Pour que l'on puisse voir le texte \emph{sous} le nœud, nous devons utiliser la transparence avec le +\verb|blend mode| égal à \verb|multiply|. Attention : certains lecteurs de \textsc{pdf} ne sont pas capables de +rendre la transparence correctement. + + +\tikzset{highlight/.style={rectangle, + fill=red!15, + blend mode = multiply, + rounded corners = 0.5 mm, + inner sep=1pt}} + +\medskip +\begin{Verbatim} +\tikzset{highlight/.style={rectangle, + fill=red!15, + ~emphase#blend mode = multiply@, + rounded corners = 0.5 mm, + inner sep=1pt}} + +$\begin{bNiceMatrix}[~emphase#code-after = {\tikz \node[highlight, fit = (2-1) (2-3)] {} ;}@] +0 & \Cdots & 0 \\ +1 & \Cdots & 1 \\ +0 & \Cdots & 0 +\end{bNiceMatrix}$ +\end{Verbatim} + +\[\begin{bNiceMatrix}[code-after = {\tikz \node[highlight, fit = (2-1) (2-3)] {} ;}] +0 & \Cdots & 0 \\ +1 & \Cdots & 1 \\ +0 & \Cdots & 0 +\end{bNiceMatrix}\] + + +\bigskip +Ce code échoue avec +\verb|latex|-\verb|dvips|-\verb|ps2pdf| parce que Tikz pour \verb|dvips|, pour le moment, ne prend pas en charge +les \emph{blend modes}. Néanmoins, le code suivant, dans le préambule du document LaTeX, devrait activer les \emph{blend modes} +pour ce mode de compilation. + + +\begin{scope} \small +\verb|\ExplSyntaxOn| + +\verb|\makeatletter| + +\verb|\tl_set:Nn \l_tmpa_tl {pgfsys-dvips.def}| + +\verb|\tl_if_eq:NNT \l_tmpa_tl \pgfsysdriver| + +\verb| {\cs_set:Npn\pgfsys@blend@mode#1{\special{ps:~/\tl_upper_case:n #1~.setblendmode}}}| + +\verb|\makeatother| + +\verb|\ExplSyntaxOff| +\end{scope} + +\vspace{1cm} +On considère maintenant la matrice suivante que l'on a appelée \verb|exemple|. + +\medskip +\begin{Verbatim} +$\begin{pNiceArray}{CCC}[~emphase#name=exemple@,create-extra-nodes,last-col] +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 +Si on veut surligner chaque rangée de la matrice, on peut utiliser la technique précédente trois fois. + +\begin{Verbatim} +\tikzset{mes-options/.style={remember picture, + overlay, + name prefix = exemple-, + every node/.style = {fill = red!15, + blend mode = multiply, + inner sep = 0pt}}} +\end{Verbatim} + + +\tikzset{mes-options/.style={remember picture, + overlay, + name prefix = exemple-, + every node/.style = {fill = red!15, + blend mode = multiply, + inner sep = 0pt}}} + + +\begin{Verbatim} +\begin{tikzpicture}[mes-options] +\node [fit = (1-1) (1-3)] {} ; +\node [fit = (2-1) (2-3)] {} ; +\node [fit = (3-1) (3-3)] {} ; +\end{tikzpicture} +\end{Verbatim} + +\medskip +On obtient la matrice suivante. + +\[\begin{pNiceArray}{CCC}[ + last-col, + create-extra-nodes, + 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 +Le résultat peut paraître décevant. On peut l'améliorer en utilisant les «nœuds moyens» au lieu des «nœuds normaux». + +\begin{Verbatim} +\begin{tikzpicture}[mes-options, ~emphase#name suffix = -medium@] +\node [fit = (1-1) (1-3)] {} ; +\node [fit = (2-1) (2-3)] {} ; +\node [fit = (3-1) (3-3)] {} ; +\end{tikzpicture} +\end{Verbatim} + +\medskip +On obtient la matrice suivante. + +\[\begin{pNiceArray}{CCC}[ + last-col, + create-extra-nodes, + code-after = {\begin{tikzpicture}[every node/.style = {fill = red!15, + blend mode = multiply, + inner sep = 0pt}, + name suffix = -medium] + \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}\] + + +\vspace{1cm} + +Dans l'exemple suivant, on utilise les «nœuds larges» pour surligner une zone de la matrice.\par\nobreak +\begin{Verbatim} +\left(\,\begin{NiceArray}{>{\strut}CCCC}% + [create-extra-nodes,left-margin,right-margin, + code-after = {\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) ; } ] +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} +\end{NiceArray}\,\right) +\end{Verbatim} + +\[\left(\,\begin{NiceArray}{>{\strut}CCCC}[ + create-extra-nodes,left-margin,right-margin, + code-after = {\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) ; } ] +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} +\end{NiceArray}\,\right)\] + + +\subsection{Utilisation directe des nœuds Tikz} + +Dans l'exemple suivant, on souhaite illustrer le produit mathématique de deux matrices. + +\medskip +L'utilisation de \verb|{NiceMatrixBlock}| avec l'option \verb|auto-columns-width| va permettre que toutes les +colonnes aient la même largeur ce qui permettra un alignement des deux matrices superposées. +\begin{Verbatim} +\begin{NiceMatrixBlock}[auto-columns-width] +\end{Verbatim} + +\begin{Verbatim} +\NiceMatrixOptions{nullify-dots} +\end{Verbatim} + +Les trois matrices vont être disposées les unes par rapport aux autres grâce à un tableau de LaTeX. +\begin{Verbatim} +$\begin{array}{cc} +& +\end{Verbatim} + +La matrice $B$ a une ``première rangée'' (pour $C_j$) d'où l'option \verb|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} + +La matrice $A$ a une ``première colonne'' (pour $L_i$) d'où l'option \verb|first-col|. +\begin{Verbatim} +\begin{bNiceArray}{CC>{\strut}CCC}[name=A,first-col] + & a_{11} & \Cdots & & & a_{nn} \\ + & \Vdots & & & & \Vdots \\ +L_i & a_{i1} & \Cdots & a_{ik} & \Cdots & a_{in} \\ + & \Vdots & & & & \Vdots \\ + & a_{n1} & \Cdots & & & a_{nn} \\ +\end{bNiceArray} +& +\end{Verbatim} + +Dans la matrice produit, on remarquera que les lignes en pointillés sont «semi-ouvertes». +\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, fit = (A-3-1) (A-3-5) ] {} ; + \node [highlight, fit = (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_{nn} \\ + & \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, fit = (A-3-1) (A-3-5) ] {} ; + \node [highlight, fit = (B-1-3) (B-5-3) ] {} ; + \draw [color = gray] (A-3-3) to [bend left] (B-3-3) ; +\end{tikzpicture} + + + + +\subsection{Matrices par blocs} + +\medskip +Dans l'exemple suivant, on utilise les «nœuds larges» pour construire une matrice par blocs (les lignes en tiretés +ont été tracées avec \pkg{arydshln}). +\begin{Verbatim} +\NiceMatrixOptions{letter-for-dotted-lines = V} +\begin{pNiceArray}{CC:CC}% ici, % est obligatoire + [create-extra-nodes, + ~emphase#code-after = { \tikz \node [fit = (1-1-large) (2-2-large), inner sep = 0 pt]@ + ~emphase# {$0_{22}$} ; }@ ] + & & a_{13} & a_{14} \\ + & & a_{23} & a_{24} \\ +\hdashline +a_{31} & a_{32} & a_{33} & a_{34} \\ +a_{41} & a_{42} & a_{34} & a_{44} +\end{pNiceArray} +\end{Verbatim} + + +\begin{scope} +\NiceMatrixOptions{letter-for-dotted-lines = V} +\[D = \begin{pNiceArray}{CC:CC}% + [create-extra-nodes, + code-after = { \tikz \node [fit = (1-1-large) (2-2-large), inner sep = 0 pt] + {$0_{22}$} ; } ] + & & a_{13} & a_{14} \\ + & & a_{23} & a_{24} \\ +\hdashline +a_{31} & a_{32} & a_{33} & a_{34} \\ +a_{41} & a_{42} & a_{34} & a_{44} +\end{pNiceArray}\] +\end{scope} + + +\end{document} diff --git a/macros/latex/contrib/nicematrix/nicematrix.dtx b/macros/latex/contrib/nicematrix/nicematrix.dtx new file mode 100644 index 0000000000..8709af977d --- /dev/null +++ b/macros/latex/contrib/nicematrix/nicematrix.dtx @@ -0,0 +1,6391 @@ +% \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.0} +\def\myfiledate{2019/08/15} +% +% +%<*batchfile> +\begingroup +\input l3docstrip.tex +\keepsilent +\usedir{tex/latex/nicematrix} +\preamble + +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. + +\endpreamble +\askforoverwritefalse +\endgroup +% +% +%<*driver> +\documentclass[dvipsnames]{l3doc}% dvipsnames is for xcolor (loaded by Tikz, loaded by nicematrix) +\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{nicematrix} +\usepackage{siunitx} + +\newbox\ExampleOne + +\setbox\ExampleOne\hbox{$\begin{NiceArray}{|*{4}{C|}}[hlines,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}$} + + +\NewDocumentEnvironment {scope} {} {} {} +\def\interitem{\vskip 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} +\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 extension 'nicematrix' }, +% Subject = { A LaTeX extension } , +% 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 loads the +% packages \pkg{expl3}, \pkg{l3keys2e}, \pkg{xparse}, \pkg{array}, \pkg{amsmath} +% and \pkg{tikz}. It also loads the Tikz library \pkg{fit}. +% +% +% +% \medskip +% \begin{savenotes} +% \begin{minipage}{0.6\linewidth} +% This package provides some new tools to draw mathematical matrices. The main +% features are the following: +% +% \textbullet\ continuous dotted lines\footnote{If the class option |draft| is +% used, these dotted lines will not be drawn for a faster compilation.}; +% +% \textbullet\ exterior row and columns for labels; +% +% \textbullet\ a control of the width of the columns. +% \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 extension} +% +% The extension \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. The environment |{NiceArray}| and its variants +% provide also options to draw exterior rows and columns. See p.~\pageref{NiceArray} +% the section relating to |{NiceArray}| +% +% +% \section{The continuous dotted lines} +% +% Inside the environments of the extension \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: \smash{$\iddots$}. 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.\par\nobreak \bigskip +% \begin{BVerbatim}[baseline=c,boxwidth=10cm] +% \begin{bNiceMatrix} +% a_1 & \Cdots & & & a_1 \\ +% \Vdots & a_2 & \Cdots & & a_2 \\ +% & \Vdots & \Ddots \\ +% \\ +% a_1 & a_2 & & & a_n +% \end{bNiceMatrix} +% \end{BVerbatim} +% $\begin{bNiceMatrix} +% a_1 & \Cdots & & & a_1 \\ +% \Vdots & a_2 & \Cdots & & a_2 \\ +% & \Vdots & \Ddots \\ +% \\ +% a_1 & a_2 & & & a_n +% \end{bNiceMatrix}$ +% +% \interitem +% In order to represent the null matrix, one can use the following +% codage:\par\nobreak \bigskip +% \begin{BVerbatim}[baseline=c,boxwidth=10cm] +% \begin{bNiceMatrix} +% 0 & \Cdots & 0 \\ +% \Vdots & & \Vdots \\ +% 0 & \Cdots & 0 +% \end{bNiceMatrix} +% \end{BVerbatim} +% $\begin{bNiceMatrix} +% 0 & \Cdots & 0 \\ +% \Vdots & & \Vdots \\ +% 0 & \Cdots & 0 +% \end{bNiceMatrix}$ +% +% \bigskip +% However, one may want a larger matrix. Usually, in such a case, the users of +% LaTeX add a new row and a new column. It's possible to use the same method +% with \pkg{nicematrix}:\par\nobreak \bigskip +% \begin{BVerbatim}[baseline=c,boxwidth=10cm] +% \begin{bNiceMatrix} +% 0 & \Cdots & \Cdots & 0 \\ +% \Vdots & & & \Vdots \\ +% \Vdots & & & \Vdots \\ +% 0 & \Cdots & \Cdots & 0 +% \end{bNiceMatrix} +% \end{BVerbatim} +% $\begin{bNiceMatrix} +% 0 & \Cdots & \Cdots & 0 \\ +% \Vdots & & & \Vdots \\ +% \Vdots & & & \Vdots \\ +% 0 & \Cdots & \Cdots & 0 +% \end{bNiceMatrix}$ +% +% \bigskip +% In the first column of this exemple, there are two instructions |\Vdots| but +% only one dotted line is drawn (there is no overlapping graphic objects in the +% resulting \textsc{pdf}\footnote{And it's not possible to draw a |\Ldots| and a +% |\Cdots| line between the same cells.}). +% +% However, useless computations are performed by TeX before detecting that both +% instructions would eventually yield the same dotted line. That's why the +% package \pkg{nicematrix} provides starred versions of |\Ldots|, |\Cdots|, +% etc.: |\Ldots*|, |\Cdots*|, etc. These versions are simply equivalent to +% |\hphantom{\ldots}|, |\hphantom{\cdots}|, etc. The user should use these +% starred versions whenever a classical version has already been used for the +% same dotted line.\par\nobreak +% +% \bigskip +% \begin{BVerbatim}[baseline=c,boxwidth=10cm] +% \begin{bNiceMatrix} +% 0 & \Cdots & ~emphase#\Cdots*@ & 0 \\ +% \Vdots & & & \Vdots \\ +% ~emphase#\Vdots*@ & & & ~emphase#\Vdots*@ \\ +% 0 & \Cdots & ~emphase#\Cdots*@ & 0 +% \end{bNiceMatrix} +% \end{BVerbatim} +% $\begin{bNiceMatrix} +% 0 & \Cdots & & 0 \\ +% \Vdots & & & \\ +% & & & \Vdots \\ +% 0 & & \Cdots & 0 +% \end{bNiceMatrix}$ +% +% \bigskip +% In fact, in this example, it would be possible to draw the same matrix without +% starred commands with the following code:\par\nobreak +% \bigskip +% \begin{BVerbatim}[baseline=c,boxwidth=10cm] +% \begin{bNiceMatrix} +% 0 & \Cdots & & 0 \\ +% \Vdots & & & \\ +% & & & \Vdots \\ +% 0 & & \Cdots & 0 +% \end{bNiceMatrix} +% \end{BVerbatim} +% $\begin{bNiceMatrix} +% 0 & \Cdots & & 0 \\ +% \Vdots & & & \\ +% & & & \Vdots \\ +% 0 & & \Cdots & 0 +% \end{bNiceMatrix}$ +% +% \bigskip +% There are also other means to change the size of the matrix. Someone might +% want to use the optional argument of the command~|\\| for the vertical +% dimension and a command~|\hspace*| in a cell for the horizontal +% dimension.\footnote{Nevertheless, the best way to fix the width of a column is +% to use the environment |{NiceArray}| (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 +% |{pmatrix}| of \pkg{amsmath}.\par\nobreak +% +% \medskip +% \begin{BVerbatim}[baseline=c,boxwidth=8cm] +% $A = \begin{pmatrix} +% a_0 & b \\ +% a_1 & \\ +% a_2 & \\ +% a_3 & \\ +% a_4 & \\ +% a_5 & b +% \end{pmatrix}$ +% \end{BVerbatim} +% $A = \begin{pmatrix} +% a_0 & b \\ +% a_1 & \\ +% a_2 & \\ +% a_3 & \\ +% a_4 & \\ +% a_5 & b +% \end{pmatrix}$ +% +% +% \bigskip +% If we add |\vdots| instructions in the second column, the geometry of the +% matrix is modified.\par\nobreak +% \medskip +% \begin{BVerbatim}[baseline=c,boxwidth=8cm] +% $B = \begin{pmatrix} +% a_0 & b \\ +% a_1 & \vdots \\ +% a_2 & \vdots \\ +% a_3 & \vdots \\ +% a_4 & \vdots \\ +% a_5 & b +% \end{pmatrix}$ +% \end{BVerbatim} +% $B = \begin{pmatrix} +% a_0 & b \\ +% a_1 & \vdots \\ +% a_2 & \vdots \\ +% a_3 & \vdots \\ +% a_4 & \vdots \\ +% a_5 & b +% \end{pmatrix}$ +% +% \bigskip +% By default, with \pkg{nicematrix}, if we replace |{pmatrix}| by +% |{pNiceMatrix}| and |\vdots| by |\Vdots| (or |\Vdots*| for efficiency), the +% geometry of the matrix is not changed.\par\nobreak +% \medskip +% \begin{BVerbatim}[baseline=c,boxwidth=8cm] +% $C = \begin{pNiceMatrix} +% a_0 & b \\ +% a_1 & \Vdots \\ +% a_2 & \Vdots* \\ +% a_3 & \Vdots* \\ +% a_4 & \Vdots* \\ +% a_5 & b +% \end{pNiceMatrix}$ +% \end{BVerbatim} +% $C = \begin{pNiceMatrix} +% a_0 & b \\ +% a_1 & \Vdots \\ +% a_2 & \Vdots* \\ +% a_3 & \Vdots* \\ +% a_4 & \Vdots* \\ +% a_5 & b +% \end{pNiceMatrix}$ +% +% \bigskip +% However, one may prefer the geometry of the first matrix $A$ and would like to +% have such a geometry with a dotted line in the second column. It's possible by +% using the option |nullify-dots| (and only one instruction |\Vdots| is +% necessary).\par\nobreak +% \medskip +% \begin{BVerbatim}[baseline=c,boxwidth=8cm] +% $D = \begin{pNiceMatrix}[~emphase#nullify-dots@] +% a_0 & b \\ +% a_1 & \Vdots \\ +% a_2 & \\ +% a_3 & \\ +% a_4 & \\ +% a_5 & b +% \end{pNiceMatrix}$ +% \end{BVerbatim} +% $D = \begin{pNiceMatrix}[nullify-dots] +% a_0 & b \\ +% a_1 & \Vdots \\ +% a_2 & \\ +% a_3 & \\ +% a_4 & \\ +% a_5 & b +% \end{pNiceMatrix}$ +% +% \medskip +% The option |nullify-dots| smashes the instructions |\Ldots| (and the variants) +% vertically but also horizontally. +% +% \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}$ +% +% \bigskip +% The command |\hdotsfor| of \pkg{amsmath} takes an optional argument (between +% square brackets) which is used for fine tuning of the space beetween two +% consecutive dots. For homogeneity, |\Hdotsfor| has also an optional argument +% but this argument is discarded silently. +% +% Remark: Unlike the command |\hdotsfor| of \pkg{amsmath}, the command +% |\Hdotsfor| may be used when the extension \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 |{matrix}|. This option can be +% set as option of |\usepackage| or with the command |\NiceMatrixOptions|. +% +% +% In fact, this option is an alias for the conjonction of two options: +% |renew-dots| and |renew-matrix|. +% +% \smallskip +% +% \begin{itemize} +% \item The option |renew-dots|\par\nobreak +% With this option, the commands |\ldots|, |\cdots|, |\vdots|, |\ddots|, +% |\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} +% +% +% +% +% \section{The Tikz nodes created by nicematrix} +% +% The package \pkg{nicematrix} creates a Tikz node for each 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. 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{scope} +% \tikzset{every node/.style = {fill = red!15, inner sep = 0pt}} +% \[\begin{pNiceMatrix} +% a & a + b & a + b + c \\ +% a & a & a + b \\ +% a & a & a +% \end{pNiceMatrix}\] +% \end{scope} +% +% +% \bigskip +% In fact, the package \pkg{nicematrix} can create ``extra nodes''. These new +% nodes are created if the option |create-extra-nodes| is used. There are two +% series of extra nodes: the ``medium nodes'' and the ``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-extra-nodes, +% code-after = {\begin{tikzpicture} +% [every node/.style = {fill = red!15, +% blend mode = multiply, +% inner sep = -\pgflinewidth/2}, +% 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-extra-nodes, +% code-after = {\begin{tikzpicture} +% [every node/.style = {blend mode = multiply, +% inner sep = -\pgflinewidth/2}, +% 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|. There is +% also an option |margin| to fix both |left-margin| and |right-margin| to the +% same value.} +% \[\begin{pNiceMatrix}[ +% create-extra-nodes,left-margin,right-margin, +% code-after = {\begin{tikzpicture} +% [every node/.style = {blend mode = multiply, +% inner sep = -\pgflinewidth/2}, +% 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-extra-nodes,margin,extra-margin=3pt, +% code-after = {\begin{tikzpicture} +% [every node/.style = {blend mode = multiply, +% inner sep = -\pgflinewidth/2}, +% 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-extra-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 = -\pgflinewidth/2}, +% 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} +% +% The option |code-after| may be used to give some code that will be excuted +% after the construction of the matrix (and, hence, after the construction of +% all the Tikz nodes). +% +% In the |code-after|, the Tikz nodes should be accessed by a name of the form +% $i$-$j$ (without the prefix of the name of the environment). +% +% Moreover, a special command, called |\line| is available to draw directly +% dotted lines between nodes. +% +% \medskip +% \begin{BVerbatim}[baseline=c,boxwidth=12cm] +% $\begin{pNiceMatrix}[~emphase#code-after = {\line {1-1} {3-3}}@] +% 0 & 0 & 0 \\ +% 0 & & 0 \\ +% 0 & 0 & 0 +% \end{pNiceMatrix}$ +% \end{BVerbatim} +% $\begin{pNiceMatrix}[code-after = {\line {1-1} {3-3}}] +% 0 & 0 & 0 \\ +% 0 & & 0 \\ +% 0 & 0 & 0 +% \end{pNiceMatrix}$ +% +% +% \section{The environment \{NiceArray\}} +% \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|.} +% +% \medskip +% The environment |{NiceArray}| accepts the classical options |t|, |c| and |b| +% of |{array}| but also other options defined by \pkg{nicematrix} (|renew-dots|, +% |columns-width|, etc.). +% +% +% \vspace{1cm} +% An example with a linear system (we need |{NiceArray}| for the vertical rule): +% +% \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 +% In fact, there is also variants for the environment |{NiceArray}|: +% |{pNiceArray}|, |{bNiceArray}|, |{BNiceArray}|, |{vNiceArray}| and +% |{VNiceArray}|. +% +% In the following example, we use an environment |{pNiceArray}| (we don't use +% |{pNiceMatrix}| because we want to use the types |L| and |R| +% --- in |{pNiceMatrix}|, all the columns are of type |C|). +% +% \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}$ +% +% +% \vspace{1cm} +% With the environment |{NiceArray}| and its the variants, it's possible to +% compose exterior rows and columns with the options |first-row|, |last-row|, +% |first-col| and |last-col|. +% \label{exterior} +% +% There is no specification of column to provide for the potential ``first +% column'' (it will automatically be a |R| column) and for the potential ``last +% column'' (it will automatically be a |L| column). +% +% \begin{Verbatim} +% $\begin{pNiceArray}{CCCC}[~emphase#first-row,last-row,first-col,last-col@] +% & C_1 & C_2 & C_3 & C_4 & \\ +% L_1 & a_{11} & a_{12} & a_{13} & a_{14} & L_1 \\ +% L_2 & a_{21} & a_{22} & a_{23} & a_{24} & L_2 \\ +% L_3 & a_{31} & a_{32} & a_{33} & a_{34} & L_3 \\ +% L_4 & a_{41} & a_{42} & a_{43} & a_{44} & L_4 \\ +% & C_1 & C_2 & C_3 & C_4 & +% \end{pNiceArray}$ +% \end{Verbatim} +% +% \[\begin{pNiceArray}{CCCC}[first-row,last-row,first-col,last-col] +% & C_1 & C_2 & C_3 & C_4 & \\ +% L_1 & a_{11} & a_{12} & a_{13} & a_{14} & L_1 \\ +% L_2 & a_{21} & a_{22} & a_{23} & a_{24} & L_2 \\ +% L_3 & a_{31} & a_{32} & a_{33} & a_{34} & L_3 \\ +% L_4 & a_{41} & a_{42} & a_{43} & a_{44} & L_4 \\ +% & C_1 & C_2 & C_3 & C_4 & +% \end{pNiceArray}\] +% +% \bigskip +% However, there is a particularity for the option |last-row|: when LaTeX +% composes an array (with the TeX command |\halign|) it composes it row by row +% and there is no direct way to know if we are at the last row before the +% composition of that row. That's why \pkg{nicematrix} writes in the |aux| file +% the number of rows of the array in order to use it at the next run. +% Nevertheless, it's possible to give directly the number of rows as the value +% of the key |last-row|. It that way, \pkg{nicematrix} will know the correct +% value by the first compilation. +% +% \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] +% & C_1 & C_2 & C_3 & C_4 & \\ +% L_1 & a_{11} & a_{12} & a_{13} & a_{14} & L_1 \\ +% L_2 & a_{21} & a_{22} & a_{23} & a_{24} & L_2 \\ +% \hline +% L_3 & a_{31} & a_{32} & a_{33} & a_{34} & L_3 \\ +% L_4 & a_{41} & a_{42} & a_{43} & a_{44} & L_4 \\ +% & C_1 & C_2 & C_3 & 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{pNiceArray}{CC|CC}[first-row,last-row=5,first-col,last-col] +% & C_1 & \multicolumn1C{C_2} & C_3 & C_4 & \\ +% L_1 & a_{11} & a_{12} & a_{13} & a_{14} & L_1 \\ +% L_2 & a_{21} & a_{22} & a_{23} & a_{24} & L_2 \\ +% \hline +% L_3 & a_{31} & a_{32} & a_{33} & a_{34} & L_3 \\ +% L_4 & a_{41} & a_{42} & a_{43} & a_{44} & L_4 \\ +% & C_1 & \multicolumn1C{C_2} & C_3 & C_4 & +% \end{pNiceArray}\] +% \end{scope} +% +% +% \emph{Remarks} +% \begin{itemize} +% \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 extension \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}.} +% \item The ``first row'' of an environment |{pNiceArray}| has the number $0$, and not +% $1$. Idem for the ``first column''. This number is used for the names of the Tikz +% nodes (the names of these nodes are used, for example, by the command |\line| +% in |code-after|). +% \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} +% +% +% +% +% \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 delimiters. +% +% \medskip +% \begin{BVerbatim}[baseline=c,boxwidth=11cm] +% $\begin{~emphase#NiceArrayWithDelims@} +% {\downarrow}{\downarrow}{CCC}[last-col] +% 1 & 2 & 3 & L_1 \\ +% 4 & 5 & 6 & L_2 \\ +% 7 & 8 & 9 & L_3 +% \end{~emphase#NiceArrayWithDelims@}$ +% \end{BVerbatim} +% $\begin{NiceArrayWithDelims} +% {\downarrow}{\downarrow}{CCC}[last-col] +% 1 & 2 & 3 & L_1 \\ +% 4 & 5 & 6 & L_2 \\ +% 7 & 8 & 9 & L_3 +% \end{NiceArrayWithDelims}$ +% +% +% +% \section{The dotted lines to separate rows or columns} +% +% +% In the environments of the extension \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 +% extension \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 = V} +% \left(\begin{NiceArray}{~emphase#C|C:CVC@} +% 1 & 2 & 3 & 4 \\ +% 5 & 6 & 7 & 8 \\ +% 9 & 10 & 11 & 12 +% \end{NiceArray}\right) +% \end{BVerbatim} +% \begin{scope} +% \NiceMatrixOptions{letter-for-dotted-lines = V} +% $\left(\begin{NiceArray}{C|C:CVC} +% 1 & 2 & 3 & 4 \\ +% 5 & 6 & 7 & 8 \\ +% 9 & 10 & 11 & 12 +% \end{NiceArray}\right)$ +% \end{scope} +% +% \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}. +% +% \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 +% It's also possible to fix the width of all the columns of a matrix directly +% with the option |columns-width| (in all the environments of \pkg{nicematrix}). +% +% \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 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. +% \textbf{Two or three compilations may be necessary.}\par\nobreak +% \medskip +% \begin{BVerbatim}[baseline=c,boxwidth=10cm] +% $\begin{pNiceMatrix}[~emphase#columns-width = auto@] +% 1 & 12 & -123 \\ +% 12 & 0 & 0 \\ +% 4 & 1 & 2 +% \end{pNiceMatrix}$ +% \end{BVerbatim} +% $\begin{pNiceMatrix}[columns-width = auto] +% 1 & 12 & -123 \\ +% 12 & 0 & 0 \\ +% 4 & 1 & 2 +% \end{pNiceMatrix}$ +% +% \bigskip +% It's possible to fix the 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.} +% +% \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} +% +% +% +% \section{The option hlines} +% +% You can add horizontal rules between rows in the environments of +% \pkg{nicematrix} with the usual command |\hline|. But, by convenience, the +% extension \pkg{nicematrix} provides the option |hlines|. With this option, all +% the horizontal rules will be drawn (excepted, of course the rule before the +% potential ``first row'' and the rule after the potential ``last row''). +% +% \medskip +% \begin{BVerbatim}[baseline=c,boxwidth=10.6cm] +% $\begin{NiceArray}{|*{4}{C|}}[~emphase#hlines@,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}$ +% \end{BVerbatim} +% \raise-5mm\box\ExampleOne +% +% \section{Utilisation 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}. The |d| columns of \pkg{dcolumn} are not supported by +% \pkg{nicematrix}. +% +% +% \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}$ +% +% +% \section{Technical remarks} +% +% \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 with contents |\hspace*{1cm}| may be +% considered as empty. +% +% \interitem +% For \pkg{nicematrix}, the precise rules are as follow. +% +% \begin{itemize} +% \item An implicit cell is empty. For example, in the following matrix: +% +% \begin{Verbatim} +% \begin{pmatrix} +% a & b \\ +% c \\ +% \end{pmatrix} +% \end{Verbatim} +% +% the last cell (second row and second column) is empty. +% +% \medskip +% \item Each cell whose TeX ouput has a width less than 0.5~pt is empty. +% +% \medskip +% \item A cell which contains a command |\Ldots|, |\Cdots|, |\Vdots|, |\Ddots| +% or |\Iddots| and their starred versions is empty. We recall that these +% commands should be used alone in a cell. +% +% \medskip +% \item A cell with a command |\Hspace| (or |\Hspace*|) is empty. This command +% |\Hspace| is a command defined by the package \pkg{nicematrix} with the same +% meaning as |\hspace| except that the cell where it is used is considered as +% empty. This command can be used to fix the width of some columns of the matrix +% without interfering with \pkg{nicematrix}. +% % \end{itemize} +% +% +% \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).} It's possible to suppress these spaces for a given environment +% |{array}| with a construction like |\begin{array}{@{}ccccc@{}}|.} +% +% The environment |{matrix}| and its variants (|{pmatrix}|, |{vmatrix}|, etc.) +% of \pkg{amsmath} prefer to delete these spaces with explicit instructions +% |\hskip -\arraycolsep| and |{NiceArray}| does likewise. +% +% However, the user can change this behaviour with the boolean option +% |exterior-arraycolsep| of the command |\NiceMatrixOptions|. With this option, +% |{NiceArray}| will insert the same horizontal spaces as the environment +% |{array}|. +% +% This option is only for ``compatibility'' since the package \pkg{nicematrix} +% provides a more precise control with the options |left-margin|, +% |right-margin|, |extra-left-margin| and |extra-right-margin|. +% +% +% \subsection{The class option draft} +% +% The package \pkg{nicematrix} is rather slow when drawing the dotted lines +% (generated by |\Cdots|, |\Ldots|, |\Ddots|, etc. but also by |\hdottedline| or +% the specifier |:|).\footnote{The main reason is that we want dotted lines with +% round dots (and not square dots) with the same space on both extremities of +% the lines. To achieve this goal, we have to construct our own system of dotted +% lines.} +% +% That's why, 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} +% +% They might be deleted in a future version of \pkg{nicematrix}. +% +% \section{Examples} +% +% \subsection{Dotted lines} +% +% \medskip +% A tridiagonal matrix: +% +% \bigskip +% \begin{BVerbatim}[baseline=c] +% $\begin{pNiceMatrix}[nullify-dots] +% a & b & 0 & & \Cdots & 0 \\ +% b & a & b & \Ddots & & \Vdots \\ +% 0 & b & a & \Ddots & & \\ +% & \Ddots & \Ddots & \Ddots & & 0 \\ +% \Vdots & & & & & b \\ +% 0 & \Cdots & & 0 & b & a +% \end{pNiceMatrix}$ +% \end{BVerbatim} +% \hspace{1.5cm} +% $\begin{pNiceMatrix}[nullify-dots] +% a & b & 0 & & \Cdots & 0 \\ +% b & a & b & \Ddots & & \Vdots \\ +% 0 & b & a & \Ddots & & \\ +% & \Ddots & \Ddots & \Ddots & & 0 \\ +% \Vdots & & & & & b \\ +% 0 & \Cdots & & 0 & b & a +% \end{pNiceMatrix}$ +% +% \vspace{2cm} +% +% A permutation matrix: +% +% \bigskip +% \begin{BVerbatim}[baseline=c] +% $\begin{pNiceMatrix} +% 0 & 1 & 0 & & \Cdots & 0 \\ +% \Vdots & & & \Ddots & & \Vdots \\ +% & & & \Ddots & & \\ +% & & & \Ddots & & 0 \\ +% 0 & 0 & & & & 1 \\ +% 1 & 0 & & \Cdots & & 0 +% \end{pNiceMatrix}$ +% \end{BVerbatim} +% \hspace{2.5cm} +% $\begin{pNiceMatrix} +% 0 & 1 & 0 & & \Cdots & 0 \\ +% \Vdots & & & \Ddots & & \Vdots \\ +% & & & \Ddots & & \\ +% & & & \Ddots & & 0 \\ +% 0 & 0 & & & & 1 \\ +% 1 & 0 & & \Cdots & & 0 +% \end{pNiceMatrix}$ +% +% \vspace{2cm} +% +% An example with |\Iddots|: \par\nobreak +% \bigskip +% \begin{BVerbatim}[baseline=c] +% $\begin{pNiceMatrix} +% 1 & \Cdots & & 1 \\ +% \Vdots & & & 0 \\ +% & ~emphase#\Iddots@ & ~emphase#\Iddots@ & \Vdots \\ +% 1 & 0 & \Cdots & 0 +% \end{pNiceMatrix}$ +% \end{BVerbatim} +% \hspace{4cm} +% $\begin{pNiceMatrix} +% 1 & \Cdots & & 1 \\ +% \Vdots & & & 0 \\ +% & \Iddots & \Iddots & \Vdots \\ +% 1 & 0 & \Cdots & 0 +% \end{pNiceMatrix}$ +% +% +% \vspace{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:\par\nobreak +% +% \begin{Verbatim} +% $\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}$ +% \end{Verbatim} +% +% \[\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}\] +% +% +% \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} +% \setlength{\extrarowheight}{1mm} +% \quad $\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}$ +% ... +% ~emphase#\end{NiceMatrixBlock}@ +% \end{BVerbatim} +% +% \bigskip +% +% \begin{multicols}{2} +% \begin{NiceMatrixBlock}[auto-columns-width] +% \NiceMatrixOptions{code-for-last-col = \color{blue}\scriptstyle} +% \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-2L_1+L_2 \\ +% 0&6&24&78&33&L_3\gets-3L_1+L_3 \\ +% 0&12&60&252&96&L_4\gets-4L_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\frac12L_2\\ +% 0&3&12&39&\frac{33}2&L_3\gets\frac12L_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 -3L_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 \frac13L_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 2L_3+L_4 +% \end{pNiceArray}$ +% \end{NiceMatrixBlock} +% \end{multicols} +% +% +% \subsection{How to highlight cells of the matrix} +% +% \label{highlight} +% \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''). +% +% In order to have the continuity of the lines, we have to set |inner sep = -\pgflinewidth/2|. +% +% \begin{Verbatim} +% $\begin{pNiceArray}{>{\strut}CCCC}% +% [create-extra-nodes,margin,extra-margin = 2pt , +% code-after = {\begin{tikzpicture} +% [~emphase#name suffix = -large@, +% every node/.style = {draw, +% ~emphase#inner sep = -\pgflinewidth/2@}] +% \node [fit = (1-1)] {} ; +% \node [fit = (2-2)] {} ; +% \node [fit = (3-3)] {} ; +% \node [fit = (4-4)] {} ; +% \end{tikzpicture}}] +% 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} +% \end{pNiceArray}$ +% \end{Verbatim} +% +% +% \[\begin{pNiceArray}{>{\strut}CCCC}[ +% create-extra-nodes,margin,extra-margin = 2pt, +% code-after = {\begin{tikzpicture}[name suffix = -large, +% every node/.style = {draw, +% inner sep = -\pgflinewidth/2}] +% \node [fit = (1-1)] {} ; +% \node [fit = (2-2)] {} ; +% \node [fit = (3-3)] {} ; +% \node [fit = (4-4)] {} ; +% \end{tikzpicture}}] +% 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} +% \end{pNiceArray}\] +% +% +% \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|. Warning: some \textsc{pdf} readers are not able to render +% transparency correctly. +% +% \tikzset{highlight/.style={rectangle, +% fill=red!15, +% blend mode = multiply, +% rounded corners = 0.5 mm, +% inner sep=1pt}} +% +% \medskip +% \begin{Verbatim} +% \tikzset{highlight/.style={rectangle, +% fill=red!15, +% ~emphase#blend mode = multiply@, +% rounded corners = 0.5 mm, +% inner sep=1pt}} +% +% $\begin{bNiceMatrix}[~emphase#code-after = {\tikz \node[highlight, fit = (2-1) (2-3)] {} ;}@] +% 0 & \Cdots & 0 \\ +% 1 & \Cdots & 1 \\ +% 0 & \Cdots & 0 +% \end{bNiceMatrix}$ +% \end{Verbatim} +% +% \[\begin{bNiceMatrix}[code-after = {\tikz \node[highlight, fit = (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} +% Considerer now the following matrix which we have named |example|. +% +% \medskip +% \begin{Verbatim} +% $\begin{pNiceArray}{CCC}[~emphase#name=example@,last-col,create-extra-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{myoptions/.style={remember picture, +% overlay, +% name prefix = example-, +% every node/.style = {fill = red!15, +% blend mode = multiply, +% inner sep = 0pt}}} +% \end{Verbatim} +% +% +% \tikzset{myoptions/.style={remember picture, +% overlay, +% name prefix = example-, +% every node/.style = {fill = red!15, +% blend mode = multiply, +% inner sep = 0pt}}} +% +% \begin{Verbatim} +% \begin{tikzpicture}[myoptions] +% \node [fit = (1-1) (1-3)] {} ; +% \node [fit = (2-1) (2-3)] {} ; +% \node [fit = (3-1) (3-3)] {} ; +% \end{tikzpicture} +% \end{Verbatim} +% +% \medskip +% We obtain the following matrix. +% +% \[\begin{pNiceArray}{CCC}[ +% last-col, +% create-extra-nodes, +% 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}[myoptions, ~emphase#name suffix = -medium@] +% \node [fit = (1-1) (1-3)] {} ; +% \node [fit = (2-1) (2-3)] {} ; +% \node [fit = (3-1) (3-3)] {} ; +% \end{tikzpicture} +% \end{Verbatim} +% +% \medskip +% We obtain the following matrix. +% +% \[\begin{pNiceArray}{CCC}[ +% last-col, +% create-extra-nodes, +% code-after = {\begin{tikzpicture}[every node/.style = {fill = red!15, +% blend mode = multiply, +% inner sep = 0pt}, +% name suffix = -medium] +% \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}\] +% +% +% \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-extra-nodes,margin,extra-margin=2pt, +% code-after = {\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) ; } ] +% 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} +% \end{pNiceArray} +% \end{Verbatim} +% +% \[ \begin{pNiceArray}{>{\strut}CCCC}[ +% create-extra-nodes,margin,extra-margin=2pt, +% code-after = {\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) ; } ] +% 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} +% \end{pNiceArray}\] +% +% +% \subsection{Direct utilisation of the Tikz nodes} +% +% In the following example, we illustrate the mathematical product of two matrices. +% +% \medskip +% The utilisation 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_{nn} \\ +% & \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, fit = (A-3-1) (A-3-5) ] {} ; +% \node [highlight, fit = (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_{nn} \\ +% & \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, fit = (A-3-1) (A-3-5) ] {} ; +% \node [highlight, fit = (B-1-3) (B-5-3) ] {} ; +% \draw [color = gray] (A-3-3) to [bend left] (B-3-3) ; +% \end{tikzpicture} +% +% +% \subsection{Block matrices} +% +% \medskip +% In the following example, we use the ``large nodes'' to construct a block matrix (the dashed lines have been +% drawn with \pkg{arydshln}). +% \begin{Verbatim} +% \NiceMatrixOptions{letter-for-dotted-lines = V} +% \begin{pNiceArray}{CC:CC}[ +% create-extra-nodes, +% ~emphase#code-after = { \tikz \node [fit = (1-1-large) (2-2-large), inner sep = 0 pt]@ +% ~emphase# {$0_{22}$} ; }@ ] +% & & a_{13} & a_{14} \\ +% & & a_{23} & a_{24} \\ +% \hdashline +% a_{31} & a_{32} & a_{33} & a_{34} \\ +% a_{41} & a_{42} & a_{34} & a_{44} +% \end{pNiceArray} +% \end{Verbatim} +% +% +% \begin{scope} +% \NiceMatrixOptions{letter-for-dotted-lines = V} +% \[D = \begin{pNiceArray}{CC:CC}[ +% create-extra-nodes, +% code-after = { \tikz \node [fit = (1-1-large) (2-2-large), inner sep = 0 pt] +% {$0_{22}$} ; } ] +% & & a_{13} & a_{14} \\ +% & & a_{23} & a_{24} \\ +% \hdashline +% a_{31} & a_{32} & a_{33} & a_{34} \\ +% a_{41} & a_{42} & a_{34} & a_{44} +% \end{pNiceArray}\] +% \end{scope} +% +% +% +% \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 independant of its implementation. Unfortunately, +% it was not possible to be strictly independant: the package \pkg{nicematrix} +% relies upon the fact that the package |{array}| uses |\ialign| to begin the |\halign|. +% +% \smallskip +% The desire to do no modification to existing code leads to complications in +% the code of this extension. +% +% \subsection{Declaration of the package and extensions loaded} +% +% First, \pkg{tikz} and the Tikz library |fit| are loaded before the |\ProvidesExplPackage|. +% They are loaded this way because |\usetikzlibrary| in |expl3| code fails.\footnote{cf. +% |tex.stackexchange.com/questions/57424/using-of-usetikzlibrary-in-an-expl3-package-fails|} +% +% \begin{macrocode} +%<@@=nm> +% \end{macrocode} +% +% \begin{macrocode} +\RequirePackage{tikz} +\usetikzlibrary{fit} +\RequirePackage{expl3}[2019/02/15] +% \end{macrocode} +% +% We give the traditionnal declaration of a package written with |expl3|: +% \begin{macrocode} +\RequirePackage{l3keys2e} +\ProvidesExplPackage + {nicematrix} + {\myfiledate} + {\myfileversion} + {Several features to improve the typesetting of mathematical matrices with TikZ} +% \end{macrocode} +% +% \bigskip +% We test if the class option |draft| has been used. 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 \pkg{array} and \pkg{amsmath}. +% \begin{macrocode} +\RequirePackage { array } +\RequirePackage { amsmath } +\RequirePackage { xparse } [ 2018-10-17 ] +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\cs_new_protected:Npn \@@_error:n { \msg_error:nn { nicematrix } } +\cs_new_protected:Npn \@@_error:nn { \msg_error:nn { nicematrix } } +\cs_new_protected:Npn \@@_fatal:n { \msg_fatal:nn { nicematrix } } +\cs_new_protected:Npn \@@_fatal:nn { \msg_fatal:nn { 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} +% +% +% \subsection{Technical definitions} +% +% 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} +% +% \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 + { + \mkern 1 mu + \raise \p@ \hbox:n { . } + \mkern 2 mu + \raise 4 \p@ \hbox:n { . } + \mkern 2 mu + \raise 7 \p@ \vbox { \kern 7 pt \hbox:n { . } } \mkern 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} +% +% \bigskip +% The dimension |\l_@@_columns_width_dim| will be used when the options specify +% that all the columns must have the same width. +% \begin{macrocode} +\dim_new:N \l_@@_columns_width_dim +% \end{macrocode} +% +% \bigskip +% 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 +\bool_new:N \g_@@_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 +% \begin{macrocode} +\@@_msg_new:nn { Yet~in~env } + { + Environments~\{NiceArray\}~(or~\{NiceMatrix\},~etc.)~can't~be~ + nested.\\ + This~error~is~fatal. + } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\@@_msg_new:nn { Outside~math~mode } + { + The~environment~\{\@currenvir\}~can~be~used~only~in~math~mode~ + (and~not~in~\token_to_str:N \vcenter).\\ + This~error~is~fatal. + } +% \end{macrocode} +% +% \bigskip +% We have to known whether if \pkg{colortbl} is loaded for the redefinition of +% |\everycr|. +% \begin{macrocode} +\bool_new:N \c_@@_colortbl_loaded_bool +\AtBeginDocument + { + \@ifpackageloaded { colortbl } + { \bool_set_true:N \c_@@_colortbl_loaded_bool } + { } + } +% \end{macrocode} +% +% \bigskip +% \subsubsection{Variables for the exterior rows and columns} +% +% 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 +\int_new:N \g_@@_first_row_int +% \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 +\int_new:N \g_@@_first_col_int +% \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 has not still been read in the |aux|). +% \begin{macrocode} +\int_new:N \l_@@_last_row_int +\int_set:Nn \l_@@_last_row_int { -2 } +\int_new:N \g_@@_last_row_int +% \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 +\bool_new:N \g_@@_last_row_without_value_bool +% \end{macrocode} +% +% \medskip +% \item \textbf{Last column}\par\nobreak +% +% For the eventual ``last column'', we have a boolean an not an integer. +% \begin{macrocode} +\bool_new:N \l_@@_last_col_bool +% \end{macrocode} +% +% However, we have also another 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 +% \subsubsection{The column S of siunitx} +% +% +% 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 utilisation of an environment of +% \pkg{nicematrix} with the command |\@@_adapt_S_column:|. +% \begin{macrocode} +\cs_set_protected:Npn \@@_adapt_S_column: + { +% \end{macrocode} +% In the preamble of the LaTeX document, the boolean |\c_@@_siunitx_loaded_bool| +% won't be known. That's why we test the existence of |\c_@@_siunitx_loaded_bool| +% and not its value.\footnote{Indeed, \pkg{nicematrix} may be used +% in the preamble of the LaTeX document. For example, in this document, we compose a +% matrix in the box |\ExampleOne| before loading \pkg{arydshln} (because +% \pkg{arydshln} is not totally compatible with \pkg{nicematrix}).} +% \begin{macrocode} + \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 +% \subsection{The options} +% +% \begin{macrocode} +\@@_msg_new:nn { Option~Transparent~suppressed } + { + The~option~'Transparent'~has~been~renamed~'transparent'.\\ + However,~you~can~go~on~for~this~time. + } +\@@_msg_new:nn { Option~RenewMatrix~suppressed } + { + The~option~'RenewMatrix'~has~been~renamed~'renew-matrix'.\\ + However,~you~can~go~on~for~this~time. + } +% \end{macrocode} +% +% +% The token list |\l_@@_pos_env_str| will contain one of the three values |t|, +% |c| or |b| and will indicate the position of the environment as in the option +% of the environment |{array}|. For the environment |{pNiceMatrix}|, +% |{pNiceArray}| and their variants, the value will programmatically be fixed to +% |c|. For the environment |{NiceArray}|, however, the three values |t|, |c| and +% |b| are possible. +% \begin{macrocode} +\str_new:N \l_@@_pos_env_str +\str_set:Nn \l_@@_pos_env_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|. +% \begin{macrocode} +\bool_new:N \l_@@_hlines_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 cell of the potential exterior columns). +% \begin{macrocode} +\bool_new:N \l_@@_auto_columns_width_bool +% \end{macrocode} +% +% +% \bigskip +% We don't want to patch any existing code. That's why some code must be +% executed in a |\group_insert_after:N|. That's why the parameters used in that +% code must be transfered outside the current group. To do this, we copy those +% quantities in global variables just before the |\group_insert_after:N|. +% Therefore, for those quantities, we have two parameters, one local and one +% global. For example, we have |\l_@@_name_str| and |\g_@@_name_str|. +% +% \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 +\str_new:N \g_@@_name_str +% \end{macrocode} +% +% \bigskip +% The boolean |\l_@@_extra_nodes_bool| will be used to indicate whether the +% ``medium nodes'' and ``large nodes'' are created in the array. +% \begin{macrocode} +\bool_new:N \l_@@_extra_nodes_bool +\bool_new:N \g_@@_extra_nodes_bool +% \end{macrocode} +% +% \bigskip +% The dimensions |\l_@@_left_margin_dim| and |\l_@@_right_margin_dim| correspond +% to the options |left-margin| and |right-margin|. +% \begin{macrocode} +\dim_new:N \l_@@_left_margin_dim +\dim_new:N \l_@@_right_margin_dim +\dim_new:N \g_@@_left_margin_dim +\dim_new:N \g_@@_right_margin_dim +\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 +\dim_new:N \g_@@_extra_right_margin_dim +% \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 / Global } + { + hlines .bool_set:N = \l_@@_hlines_bool , + parallelize-diags .bool_set:N = \l_@@_parallelize_diags_bool , + parallelize-diags .default:n = true , +% \end{macrocode} +% +% \bigskip +% With the option |renew-dots|, the command |\cdots|, |\ldots|, |\vdots| and +% |\ddots| are redefined and behave like the commands |\Cdots|, |\Ldots|, +% |\Vdots| and |\Ddots|. +% \begin{macrocode} + renew-dots .bool_set:N = \l_@@_renew_dots_bool , + renew-dots .default:n = true , + nullify-dots .bool_set:N = \l_@@_nullify_dots_bool , + nullify-dots .default:n = true , +% \end{macrocode} +% +% \bigskip +% An option to test whether the extra nodes will be created (these nodes are the +% ``medium nodes'' and ``large nodes''). In some circonstancies, the extra nodes +% are created automatically, for example when a dotted line has an ``open'' +% extremity.\footnote{In fact, we should not because, if there is a |w|~node, +% the |w|~node is used instead of the ``medium'' node.} +% \begin{macrocode} + create-extra-nodes .bool_set:N = \l_@@_extra_nodes_bool , + create-extra-nodes .default:n = true, + 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 } , + } +% \end{macrocode} +% +% \bigskip +% The following set of keys concerns the options to \emph{customize} the +% exterior columns, that is to say the options |code-for-first-row|, etc. +% \begin{macrocode} +\keys_define:nn { NiceMatrix / Code } + { + 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 , + } +% \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 } + { + 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 = + \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 .initial:n = \c_empty_tl , + code-after .value_required:n = true , + } +% \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 , + NiceMatrix / Code + } , + NiceMatrix .inherit:n = + { + NiceMatrix / Global , + NiceMatrix / Env + } , + NiceArray .inherit:n = + { + NiceMatrix / Global , + NiceMatrix / Env , + NiceMatrix / Code + } , + pNiceArray .inherit:n = + { + NiceMatrix / Global , + NiceMatrix / Env , + NiceMatrix / Code + } + } +% \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 , + RenewMatrix .code:n = \@@_error:n { Option~RenewMatrix~suppressed } + \@@_renew_matrix: , + transparent .meta:n = { renew-dots , renew-matrix } , + transparent .value_forbidden:n = true, + Transparent .code:n = \@@_error:n { Option~Transparent~suppressed } + \@@_renew_matrix: + \bool_set_true:N \l_@@_renew_dots_bool , +% \end{macrocode} +% +% +% \bigskip +% The option |exterior-arraycolsep| will have effect only in |{NiceArray}| for +% those who want to have for |{NiceArray}| the same behaviour as |{array}|. +% \begin{macrocode} + exterior-arraycolsep .bool_set:N = \l_@@_exterior_arraycolsep_bool , + exterior-arraycolsep .default:n = true , +% \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 } = \c_one_int } + { \tl_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 , + letter-for-dotted-lines .initial:n = \c_colon_str , +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} + unknown .code:n = \@@_error:n { Unknown~key~for~NiceMatrixOptions } } +% \end{macrocode} +% +% +% \bigskip +% \begin{macrocode} +\@@_msg_new:nn { Bad~value~for~letter~for~dotted~lines } + { + The~value~of~key~'\tl_use:N\l_keys_key_tl'~must~be~of~length~1.\\ + If~you~go~on,~it~will~be~ignored. + } +% \end{macrocode} +% +% +% \bigskip +% \begin{macrocode} +\@@_msg_new:nnn { Unknown~key~for~NiceMatrixOptions } + { + The~key~'\tl_use:N\l_keys_key_tl'~is~unknown~for~the~command~ + \token_to_str:N \NiceMatrixOptions. \\ + If~you~go~on,~it~will~be~ignored. \\ + For~a~list~of~the~available~keys,~type~H~. + } + { + The~available~keys~are~(in~alphabetic~order):~ + allow-duplicate-names,~ + code-for-first-col,~ + code-for-first-row,~ + code-for-last-col,~ + code-for-last-row,~ + exterior-arraycolsep,~ + hlines,~ + left-margin,~ + letter-for-dotted-lines,~ + nullify-dots,~ + parallelize-diags,~ + renew-dots,~ + renew-matrix,~ + right-margin,~ + and~transparent + } +% \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} +% +% \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 } + { unknown .code:n = \@@_error:n { Unknown~option~for~NiceMatrix } } +% \end{macrocode} +% +% \begin{macrocode} +\@@_msg_new:nnn { Unknown~option~for~NiceMatrix } + { + The~option~'\tl_use:N\l_keys_key_tl'~is~unknown~for~the~environment~ + \{NiceMatrix\}~and~its~variants. \\ + If~you~go~on,~it~will~be~ignored. \\ + For~a~list~of~the~available~options,~type~H~. + } + { + The~available~options~are~(in~alphabetic~order):~ + code-after,~ + columns-width,~ + create-extra-nodes,~ + extra-left-margin,~ + extra-right-margin,~ + hlines,~ + left-margin,~ + name,~ + nullify-dots,~ + parallelize-diags,~ + renew-dots~ + and~right-margin. + } +% \end{macrocode} +% +% \bigskip +% \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'. \\ + For~a~list~of~the~names~already~used,~type~H~. \\ + If~you~don't~want~to~see~this~message~again,~use~the~option~ + 'allow-duplicate-names'. + } + { + The~names~already~defined~in~this~document~are:~ + \seq_use:Nnnn \g_@@_names_seq { ,~ } { ,~ } { ~and~ }. + } +% \end{macrocode} +% +% \bigskip +% +% \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} +% +% \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_@@_pos_env_str c , + t .code:n = \str_set:Nn \l_@@_pos_env_str t , + b .code:n = \str_set:Nn \l_@@_pos_env_str b , + first-col .code:n = \int_zero:N \l_@@_first_col_int , + last-col .bool_set:N = \l_@@_last_col_bool , + 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~NiceArray } + } +% \end{macrocode} +% +% \begin{macrocode} +\@@_msg_new:nnn { Unknown~option~for~NiceArray } + { + The~option~'\tl_use:N\l_keys_key_tl'~is~unknown~for~the~environment~ + \{NiceArray\}. \\ + If~you~go~on,~it~will~be~ignored. \\ + For~a~list~of~the~available~options,~type~H~. + } + { + The~available~options~are~(in~alphabetic~order):~ + b,~ + c,~ + code-after,~ + code-for-first-col,~ + code-for-first-row,~ + code-for-last-col,~ + code-for-last-row,~ + columns-width,~ + create-extra-nodes,~ + extra-left-margin,~ + extra-right-margin,~ + hlines,~ + left-margin,~ + name,~ + nullify-dots,~ + parallelize-diags,~ + renew-dots,~ + right-margin,~ + and~t. + } +% \end{macrocode} +% +% +% \begin{macrocode} +\keys_define:nn { NiceMatrix / pNiceArray } + { + first-col .code:n = \int_zero:N \l_@@_first_col_int , + last-col .bool_set:N = \l_@@_last_col_bool , + 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~pNiceArray } + } +% \end{macrocode} +% +% +% \begin{macrocode} +\@@_msg_new:nnn { Unknown~option~for~pNiceArray } + { + The~option~'\tl_use:N\l_keys_key_tl'~is~unknown~for~the~environment~ + \{\@currenvir\}. \\ + If~you~go~on,~it~will~be~ignored. \\ + For~a~list~of~the~available~options,~type~H~. + } + { + The~available~options~are~(in~alphabetic~order):~ + code-after,~ + code-for-first-col,~ + code-for-first-row,~ + code-for-last-col,~ + code-for-last-row,~ + columns-width,~ + create-extra-nodes,~ + extra-left-margin,~ + extra-right-margin,~ + first-col,~ + first-row,~ + last-col,~ + last-row,~ + hlines,~ + left-margin,~ + name,~ + nullify-dots,~ + parallelize-diags,~ + renew-dots,~ + and~right-margin. + } +% \end{macrocode} +% +% \subsection{Code common to \{NiceArrayWithDelims\} and \{NiceMatrix\}} +% +% 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:Nn \@@_Cell: + { +% \end{macrocode} +% We increment |\g_@@_col_int|, which is the counter of the columns. +% \begin{macrocode} + \int_gincr:N \g_@@_col_int +% \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 \g_@@_col_int = \c_one_int + { + \int_compare:nNnT \l_@@_first_col_int = \c_one_int + \@@_begin_of_row: + } + \int_gset:Nn \g_@@_col_total_int + { \int_max:nn \g_@@_col_total_int \g_@@_col_int } +% \end{macrocode} +% The content of the cell is composed in the box |\l_tmpa_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_tmpa_box + \c_math_toggle_token + \int_compare:nNnTF \g_@@_row_int = \c_zero_int + \l_@@_code_for_first_row_tl + { + \int_compare:nNnT \g_@@_row_int = \l_@@_last_row_int + \l_@@_code_for_last_row_tl + } + } +% \end{macrocode} +% +% \interitem +% The following macro |\@@_begin_of_row| is usually used in the cell +% number~$1$ of the array. However, when the key |first-col| is used, +% |\@@_begin_of_row| is executed in the cell number~$0$ of the array. +% \begin{macrocode} +\cs_new_protected:Nn \@@_begin_of_row: + { + \int_gincr:N \g_@@_row_int + \dim_gset_eq:NN \g_@@_dp_ante_last_row_dim \g_@@_dp_last_row_dim + \dim_gzero:N \g_@@_dp_last_row_dim + \dim_gzero:N \g_@@_ht_last_row_dim + } +% \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. +% \begin{macrocode} +\cs_new_protected:Npn \@@_actualization_for_first_and_last_row: + { + \int_compare:nNnT \g_@@_row_int = \c_zero_int + { + \dim_gset:Nn \g_@@_dp_row_zero_dim + { \dim_max:nn \g_@@_dp_row_zero_dim { \box_dp:N \l_tmpa_box } } + \dim_gset:Nn \g_@@_ht_row_zero_dim + { \dim_max:nn \g_@@_ht_row_zero_dim { \box_ht:N \l_tmpa_box } } + } + \int_compare:nNnT \g_@@_row_int = \c_one_int + { + \dim_gset:Nn \g_@@_ht_row_one_dim + { \dim_max:nn \g_@@_ht_row_one_dim { \box_ht:N \l_tmpa_box } } + } + \dim_gset:Nn \g_@@_ht_last_row_dim + { \dim_max:nn \g_@@_ht_last_row_dim { \box_ht:N \l_tmpa_box } } + \dim_gset:Nn \g_@@_dp_last_row_dim + { \dim_max:nn \g_@@_dp_last_row_dim { \box_dp:N \l_tmpa_box } } + } +% \end{macrocode} +% +% \begin{macrocode} +\cs_new_protected:Nn \@@_end_Cell: + { + \c_math_toggle_token + \hbox_set_end: +% \end{macrocode} +% +% We want to compute in |\l_@@_max_cell_width_dim| the width of the widest cell +% of the array (except the cells of the ``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_tmpa_box } } +% \end{macrocode} +% +% The following computations are for the ``first row'' and the ``last row''. +% \begin{macrocode} + \@@_actualization_for_first_and_last_row: +% \end{macrocode} +% +% Now, we can create the Tikz node of the cell. +% \begin{macrocode} + \tikz + [ + remember~picture , + inner~sep = \c_zero_dim , + minimum~width = \c_zero_dim , + baseline + ] + \node + [ + anchor = base , + name = nm - \int_use:N \g_@@_env_int - + \int_use:N \g_@@_row_int - + \int_use:N \g_@@_col_int , + alias = + \str_if_empty:NF \l_@@_name_str + { + \l_@@_name_str - + \int_use:N \g_@@_row_int - + \int_use:N \g_@@_col_int + } + ] + \bgroup + \box_use:N \l_tmpa_box + \egroup ; + } +% \end{macrocode} +% +% +% \begin{macrocode} +\cs_generate_variant:Nn \dim_set:Nn { N x } +% \end{macrocode} +% +% \bigskip +% In the environment |{NiceArrayWithDelims}|, we will have to redefine the +% column types |w| and |W|. These definitions are rather long because we have to +% construct the |w|-nodes in these columns. The redefinition of these two column +% types are very close and that's why we use a macro |\@@_renewcolumntype:nn|. +% The first argument is the type of the column (|w| or |W|) and the second +% argument is a code inserted at a special place and which is the only +% difference between the two definitions. +% \begin{macrocode} +\cs_new_protected:Nn \@@_renewcolumntype:nn + { + \newcolumntype #1 [ 2 ] + { + > { + \hbox_set:Nw \l_tmpa_box + \@@_Cell: + } + c + < { + \@@_end_Cell: + \hbox_set_end: + #2 + \hbox_set:Nn \l_tmpb_box + { \makebox [ ##2 ] [ ##1 ] { \box_use:N \l_tmpa_box } } + \dim_set:Nn \l_tmpa_dim { \box_dp:N \l_tmpb_box } + \box_move_down:nn \l_tmpa_dim + { + \vbox:n + { + \hbox_to_wd:nn { \box_wd:N \l_tmpb_box } + { + \hfil + \tikz [ remember~picture , overlay ] + \coordinate (@@~north~east) ; + } + \hbox:n + { + \tikz [ remember~picture , overlay ] + \coordinate (@@~south~west) ; + \box_move_up:nn \l_tmpa_dim { \box_use:N \l_tmpb_box } + } + } + } +% \end{macrocode} +% The |w|-node is created using the Tikz library |fit| after construction of the +% nodes |(@@~south~west)| and |(@@~north~east)|. It's not possible to construct +% by a standard |node| instruction because such a construction give an erroneous +% result with some engines (|XeTeX|, |LuaTeX|) although the result is good with +% |pdflatex| (why?). +% \begin{macrocode} + \tikz [ remember~picture , overlay ] + \node + [ + node~contents = { } , + name = nm - \int_use:N \g_@@_env_int - + \int_use:N \g_@@_row_int - + \int_use:N \g_@@_col_int - w, + alias = + \str_if_empty:NF \l_@@_name_str + { + \l_@@_name_str - + \int_use:N \g_@@_row_int - + \int_use:N \g_@@_col_int - w + } , + inner~sep = \c_zero_dim , + fit = (@@~south~west) (@@~north~east) + ] + ; + } + } + } +% \end{macrocode} +% +% +% \interitem +% The argument of the following command |\@@_instruction_of_type:n| defined +% below is the type of the instruction (|Cdots|, |Vdots|, |Ddots|, etc.). This +% command writes in |\g_@@_lines_to_draw_tl| the instruction that will really +% 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 & \Hdotsfor{2} \\ +% \end{pNiceMatrix} +% \end{BVerbatim} +% $\begin{pNiceMatrix} +% 1 & 2 & 3 & 4 \\ +% 5 & \Cdots & & 6 \\ +% 7 & \Hdotsfor{2} \\ +% \end{pNiceMatrix}$ +% +% the content of |\g_@@_lines_to_draw_tl| will be: +% +% \begin{scope} +% \color{gray} +% \verb|\@@_draw_Cdots:nn {2}{2}| +% +% \verb|\@@_draw_Hdotsfor:nnn {3}{2}{2}| +% \end{scope} +% +% +% 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:n #1 { } } + { + \cs_new_protected:Npn \@@_instruction_of_type:n #1 + { + \tl_gput_right:Nx \g_@@_lines_to_draw_tl + { + \use:c { @@ _ draw _ #1 : nn } + { \int_use:N \g_@@_row_int } + { \int_use:N \g_@@_col_int } + } + } + } +% \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_@@_pos_env_str| may have the value |t|, |c| or |b|. +% \begin{macrocode} + [ \l_@@_pos_env_str ] + } +% \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 \g_@@_col_int + \bool_if:NT \l_@@_hlines_bool + { +% \end{macrocode} +% The counter |\g_@@_row_int| 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 \g_@@_row_int > { -1 } + { + \int_compare:nNnF \g_@@_row_int = \g_@@_last_row_int + { + \hrule \@height \arrayrulewidth + \skip_vertical:n { - \arrayrulewidth } + } + } + } + } +% \end{macrocode} +% +% \bigskip +% The following code |\@@_pre_array:| is used in |{NiceArray}| and in +% |{NiceMatrix}|. It contains code that will be executed \emph{before} the +% construction of the array. +% \label{prearray} +% +% \begin{macrocode} +\cs_new_protected:Npn \@@_pre_array: + { +% \end{macrocode} +% +% If the user requires all the columns to have a width equal to the widest cell +% of the array, we read this length in the file |.aux| (of, course, this is +% possible only on the second run of LaTeX: on the first run, the dimension +% |\l_@@_columns_width_dim| will be set to zero --- and the columns will have +% their natural width). Remark that, even if the environment has a name (see +% just below) we have to write in the |aux| file the information with the number +% of environment because of |auto-columns-width| of |{NiceMatrixBlock}|. +% \begin{macrocode} + \bool_if:NT \l_@@_auto_columns_width_bool + { + \group_insert_after:N \@@_write_max_cell_width: + \cs_if_free:cTF { _@@_max_cell_width_ \int_use:N \g_@@_env_int } + { \dim_zero:N \l_@@_columns_width_dim } + { + \dim_set:Nx \l_@@_columns_width_dim + { \use:c { _@@_max_cell_width _ \int_use:N \g_@@_env_int } } + } +% \end{macrocode} +% If the environment has a name, we read the value of the maximal value of the +% columns from |_@@_name_cell_width|{\ttfamily\slshape name} (the value will be +% the correct value even if the number of the environment has changed (for +% example because the user has created or deleted an environment before the +% current one)). +% \begin{macrocode} + \str_if_empty:NF \l_@@_name_str + { + \cs_if_free:cF { _@@_max_cell_width_ \l_@@_name_str } + { + \dim_set:Nx \l_@@_columns_width_dim + { \use:c { _@@_max_cell_width_ \l_@@_name_str } } + } + } + } +% \end{macrocode} +% We don't want to patch any code and that's why some code is executed in a +% |\group_insert_after:N|. In particular, in this |\group_insert_after:N|, we +% will have to know the value of some parameters like |\l_@@_extra_nodes_bool|. +% That's why we transit via a global version for some variables. +% \begin{macrocode} + \bool_gset_eq:NN \g_@@_extra_nodes_bool \l_@@_extra_nodes_bool + \dim_gset_eq:NN \g_@@_left_margin_dim \l_@@_left_margin_dim + \dim_gset_eq:NN \g_@@_right_margin_dim \l_@@_right_margin_dim + \dim_gset_eq:NN \g_@@_extra_right_margin_dim \l_@@_extra_right_margin_dim + \int_gset_eq:NN \g_@@_last_row_int \l_@@_last_row_int + \tl_gset_eq:NN \g_@@_name_str \l_@@_name_str + \int_gset_eq:NN \g_@@_first_row_int \l_@@_first_row_int + \int_gset_eq:NN \g_@@_first_col_int \l_@@_first_col_int + \bool_gset_eq:NN \g_@@_NiceArray_bool \l_@@_NiceArray_bool + \bool_gset_eq:NN \g_@@_last_row_without_value_bool + \l_@@_last_row_without_value_bool +% \end{macrocode} +% The environment |{array}| uses internally the command |\ialign| and, in +% particular, this command |\ialign| sets |\everycr| to |{}|. However, we want +% to use |\everycr| in our array. The solution is to give to |\ialign| a new +% definition (giving to |\everycr| the value we want) that will revert +% automatically to its default definition after the first +% utilisation.\footnote{With this programmation, we will have, in the cells of +% the array, a clean version of |\ialign|. That's necessary: the user will +% probably not employ directly |\ialign| in the array... but more likely +% environments that utilize |\ialign| internally (e.g.: |{substack}|)} +% \begin{macrocode} + \cs_set:Npn \ialign + { + \bool_if:NTF \c_@@_colortbl_loaded_bool + { + \CT@everycr + { + \noalign { \global\let\CT@row@color\relax } + \@@_everycr: + } + } + { \everycr { \@@_everycr: } } + \tabskip = \c_zero_skip + \cs_set:Npn \ialign + { + \everycr { } + \tabskip = \c_zero_skip + \halign + } + \halign + } +% \end{macrocode} +% +% We define the new column types |L|, |C| and |R| that must be used instead of +% |l|, |c| and |r| in the preamble of |{NiceArray}|. +% \begin{macrocode} + \dim_compare:nNnTF \l_@@_columns_width_dim = \c_zero_dim + { + \newcolumntype L { > \@@_Cell: l < \@@_end_Cell: } + \newcolumntype C { > \@@_Cell: c < \@@_end_Cell: } + \newcolumntype R { > \@@_Cell: r < \@@_end_Cell: } + } +% \end{macrocode} +% If there is an option that specify that all the columns must have the same +% width, the column types~|L|, |C| and~|R| are in fact defined upon the column +% type~|w| of \pkg{array} which is, in fact, redefined below. +% \begin{macrocode} + { + \newcolumntype L { w l { \dim_use:N \l_@@_columns_width_dim } } + \newcolumntype C { w c { \dim_use:N \l_@@_columns_width_dim } } + \newcolumntype R { w r { \dim_use:N \l_@@_columns_width_dim } } + } +% \end{macrocode} +% +% +% \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 \hdottedline \@@_hdottedline: + \cs_set_eq:NN \Hspace \@@_Hspace: + \cs_set_eq:NN \Hdotsfor \@@_Hdotsfor: + \cs_set_eq:NN \multicolumn \@@_multicolumn:nnn + \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_@@_empty_cells_seq| will contain a list of ``empty'' cells +% (not all the empty cells of the matrix). If we want to indicate that the cell +% in row~$i$ and column~$j$ must be considered as empty, the token list +% ``|i-j|'' will be put in this sequence. +% \begin{macrocode} + \seq_gclear_new:N \g_@@_empty_cells_seq +% \end{macrocode} +% +% The 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 |\g_@@_row_int| will be used to count the rows of the array (its +% incrementation will be in the first cell of the row). +% \begin{macrocode} + \int_gzero_new:N \g_@@_row_int + \int_gset:Nn \g_@@_row_int { \l_@@_first_row_int - 1 } +% \end{macrocode} +% +% At the end of the environment |{array}|, |\g_@@_row_int| will be the total +% number de rows and |\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 |\g_@@_col_int| 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_int + \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 + \@@_renewcolumntype:nn w { } + \@@_renewcolumntype:nn W { \cs_set_eq:NN \hss \hfil } + \dim_gzero_new:N \g_@@_dp_row_zero_dim + \dim_gzero_new:N \g_@@_ht_row_zero_dim + \dim_gzero_new:N \g_@@_ht_row_one_dim + \dim_gzero_new:N \g_@@_dp_ante_last_row_dim + \dim_gzero_new:N \g_@@_ht_last_row_dim + \dim_gzero_new:N \g_@@_dp_last_row_dim +% \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 extensions, 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|. +% \begin{macrocode} + \exp_args:Nx \newcolumntype \l_@@_letter_for_dotted_lines_str + { + ! + { + \skip_horizontal:n { 0.53 pt } + \bool_gset_true:N \g_@@_extra_nodes_bool +% \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 \g_@@_col_int > \g_@@_last_vdotted_col_int + { + \int_gset_eq:NN \g_@@_last_vdotted_col_int \g_@@_col_int + \tl_gput_right:Nx \g_@@_code_after_tl +% \end{macrocode} +% The command |\@@_vdottedline:n| is protected, and, therefore, won't be expanded +% before writing on |\g_@@_code_after_tl|. +% \begin{macrocode} + { \@@_vdottedline:n { \int_use:N \g_@@_col_int } } + } + } + } + \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} +% +% +% +% \bigskip +% \subsection{The environment \{NiceArrayWithDelims\}} +% +% \begin{macrocode} +\NewDocumentEnvironment { NiceArrayWithDelims } { m m O { } m ! O { } } + { + \@@_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 (since we use Tikz pictures with the +% options |overlay| and |remember picture|, there would be errors). +% \begin{macrocode} + \cs_if_exist:NT \tikz@library@external@loaded + { \tikzset { external / export = false } } +% \end{macrocode} +% In |{NiceArrayWithDelims}|, it would have been possible to avoid the +% |\group_insert_after:N| and to put |\@@_after_array| in the second +% part of the environment |{NiceArrayWithDelims}|. However, it's not possible to +% do that in |{NiceMatrix}| (because of the option |renew-matrix|) and that's +% why we use this technique in |{NiceArrayWithDelims}| and in |{NiceMatrix}|. +% \begin{macrocode} + \group_insert_after:N \@@_after_array: + \tl_gclear_new:N \g_@@_lines_to_draw_tl +% \end{macrocode} +% +% We increment the counter |\g_@@_env_int| which counts the environments +% of the extension. +% \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| and |b|. +% \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 = { -1 } + { + \bool_set_true:N \l_@@_last_row_without_value_bool +% \end{macrocode} +% A value based the name is more reliable than a value based on the number of +% the environment. +% \begin{macrocode} + \str_if_empty:NTF \g_@@_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_ \g_@@_name_str } + { + \int_set:Nn \l_@@_last_row_int + { \use:c { @@_last_row_ \g_@@_name_str } } + } + } + } +% \end{macrocode} +% +% The code in |\@@_pre_array:| is common to |{NiceArrayWithDelims}| and |{NiceMatrix}|. +% \begin{macrocode} + \@@_pre_array: +% \end{macrocode} +% +% \medskip +% We compute the width of the two delimiters. +% \begin{macrocode} + \dim_zero_new:N \g_@@_left_delim_dim + \dim_zero_new:N \g_@@_right_delim_dim + \bool_if:NTF \l_@@_NiceArray_bool + { + \dim_gset:Nn \g_@@_left_delim_dim { 2 \arraycolsep } + \dim_gset:Nn \g_@@_right_delim_dim { 2 \arraycolsep } + } + { + \group_begin: + \dim_set_eq:NN \nulldelimiterspace \c_zero_dim + \hbox_set:Nn \l_tmpa_box + { + \c_math_toggle_token + \left #1 \vcenter to 1 cm { } \right. + \c_math_toggle_token + + } + \dim_gset:Nn \g_@@_left_delim_dim { \box_wd:N \l_tmpa_box } + \hbox_set:Nn \l_tmpa_box + { + \dim_set_eq:NN \nulldelimiterspace \c_zero_dim + \c_math_toggle_token + \left. \vcenter to 1 cm { } \right #2 + \c_math_toggle_token + } + \dim_gset:Nn \g_@@_right_delim_dim { \box_wd:N \l_tmpa_box } + \group_end: + } +% \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 (such +% construction in a box is not possible for |{NiceMatrix}|). +% \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 = \c_zero_int + { \tl_put_left:NV \l_tmpa_tl \c_@@_preamble_first_col_tl } + { + \bool_if:NT \l_@@_NiceArray_bool + { + \bool_if:NF \l_@@_exterior_arraycolsep_bool + { \tl_put_left:Nn \l_tmpa_tl { @ { } } } + } + } + \bool_if:NTF \l_@@_last_col_bool + { \tl_put_right:NV \l_tmpa_tl \c_@@_preamble_last_col_tl } + { + \bool_if:NT \l_@@_NiceArray_bool + { + \bool_if:NF \l_@@_exterior_arraycolsep_bool + { \tl_put_right:Nn \l_tmpa_tl { @ { } } } + } + } +% \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 + \skip_horizontal:n \l_@@_left_margin_dim + \skip_horizontal:n \l_@@_extra_left_margin_dim + \c_math_toggle_token +% \end{macrocode} +% Here is the call to |\array| (we have a dedicated macro |\@@_array:| because +% of compatibility with \cls{revtex4-1} and \cls{revtex4-2}). +% \begin{macrocode} + \exp_args:NV \@@_array: \l_tmpa_tl + } +% \end{macrocode} +% +% \bigskip +% We begin the second part of the environment |{NiceArrayWithDelims}|. +% \begin{macrocode} + { + \endarray + \c_math_toggle_token + \skip_horizontal:n \g_@@_right_margin_dim + \skip_horizontal:n \g_@@_extra_right_margin_dim + \hbox_set_end: +% \end{macrocode} +% Now, we compute |\l_tmpa_dim| which is the vertical dimension of the ``first +% row'' above the array (when the key |first-row| is used). +% \begin{macrocode} + \int_compare:nNnTF \l_@@_first_row_int = \c_zero_int + { + \dim_compare:nNnTF + { \g_@@_ht_row_one_dim + \g_@@_dp_row_zero_dim + \lineskiplimit } + > \baselineskip + { + \dim_set:Nn \l_tmpa_dim + { + \g_@@_ht_row_one_dim + \g_@@_dp_row_zero_dim + \lineskip + + \g_@@_ht_row_zero_dim - \g_@@_ht_row_one_dim + } + } + { + \dim_set:Nn \l_tmpa_dim + { \baselineskip + \g_@@_ht_row_zero_dim - \g_@@_ht_row_one_dim } + } + } + { \dim_zero:N \l_tmpa_dim } +% \end{macrocode} +% We compute |\l_tmpb_dim| which is the vertical dimension 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 +% number of that row is unknown (the user have not set the value with the option +% |last row|).} +% \begin{macrocode} + \int_compare:nNnTF \l_@@_last_row_int > { -2 } + { + \dim_compare:nNnTF + { + \g_@@_ht_last_row_dim + \g_@@_dp_ante_last_row_dim + \lineskiplimit + } + > + \baselineskip + { + \dim_set:Nn \l_tmpb_dim + { + \g_@@_ht_last_row_dim + \g_@@_dp_ante_last_row_dim + \lineskip + + \g_@@_dp_last_row_dim - \g_@@_dp_ante_last_row_dim + } + } + { + \dim_set:Nn \l_tmpb_dim + { + \baselineskip + + \g_@@_dp_last_row_dim - \g_@@_dp_ante_last_row_dim + } + } + } + { \dim_zero:N \l_tmpb_dim } +% \end{macrocode} +% +% \bigskip +% 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 \g_@@_first_col_int = \c_zero_int + { + \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 its +% variants (|{pNiceArray}|, etc.) because, in |{NiceArray}|, we have to take +% into account the option of position (|t|, |c| or |b|). We begin with +% |{NiceArray}|. +% \begin{macrocode} + \bool_if:NTF \g_@@_NiceArray_bool + { + \int_compare:nNnT \g_@@_first_row_int = \c_zero_int + { + \str_if_eq:VnTF \l_@@_pos_env_str { t } + { + \box_move_up:nn + { \l_tmpa_dim - \g_@@_ht_row_zero_dim + \g_@@_ht_row_one_dim } + } + } + { + \bool_if:NT \g_@@_last_row_int + { + \str_if_eq:VnT \l_@@_pos_env_str { b } + { + \box_move_down:nn + { + \l_tmpb_dim + - \g_@@_dp_last_row_dim + \g_@@_dp_ante_last_row_dim + } + } + } + } + { \box_use_drop:N \l_@@_the_array_box } + } +% \end{macrocode} +% +% Now, in the case of an environment |{pNiceArray}|, |{bNiceArray}|, etc. +% \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 size +% in |\l_tmpa_dim|). +% \begin{macrocode} + \skip_vertical:n { - \l_tmpa_dim } + \hbox:n + { + \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 size +% in |\l_tmpb_dim|). +% \begin{macrocode} + \skip_vertical:n { - \l_tmpb_dim } + } + \right #2 + \c_math_toggle_token + } + \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 } + \box_use_drop:N \l_tmpa_box + } +% \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 + } + } +% \end{macrocode} +% This is the end of the environment |{NiceArrayWithDelims}|. +% +% \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_tmpa_box| because we +% have to compute some dimensions of this box. +% \begin{macrocode} + \hbox_set:Nw \l_tmpa_box + \c_math_toggle_token + \l_@@_code_for_first_col_tl + } + l + < + { + \c_math_toggle_token + \hbox_set_end: + \@@_actualization_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_tmpa_box } + } +% \end{macrocode} +% The content of the cell is inserted in an overlapping position. +% \label{overlap-left} +% \begin{macrocode} + \hbox_overlap_left:n + { + \tikz + [ + remember~picture , + inner~sep = \c_zero_dim , + minimum~width = \c_zero_dim , + baseline + ] + \node + [ + anchor = base , + name = + nm - + \int_use:N \g_@@_env_int - + \int_use:N \g_@@_row_int - + 0 , + alias = + \str_if_empty:NF \l_@@_name_str + { + \l_@@_name_str - + \int_use:N \g_@@_row_int - + 0 + } + ] + { \box_use:N \l_tmpa_box } ; + \skip_horizontal:n + { + \g_@@_left_delim_dim + + \l_@@_left_margin_dim + + \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'' i s really used. +% \begin{macrocode} + \bool_gset_true:N \g_@@_last_col_found_bool + \int_gincr:N \g_@@_col_int + \int_gset:Nn \g_@@_col_total_int + { \int_max:nn \g_@@_col_total_int \g_@@_col_int } +% \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_tmpa_box + \c_math_toggle_token + \l_@@_code_for_last_col_tl + } + l + < + { + \c_math_toggle_token + \hbox_set_end: + \@@_actualization_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_tmpa_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 + { + \skip_horizontal:n + { + \g_@@_right_delim_dim + + \l_@@_right_margin_dim + + \l_@@_extra_right_margin_dim + } + \tikz + [ + remember~picture , + inner~sep = \c_zero_dim , + minimum~width = \c_zero_dim , + baseline + ] + \node + [ + anchor = base , + name = + nm - + \int_use:N \g_@@_env_int - + \int_use:N \g_@@_row_int - + \int_use:N \g_@@_col_int , + alias = + \str_if_empty:NF \l_@@_name_str + { + \l_@@_name_str - + \int_use:N \g_@@_row_int - + \int_use:N \g_@@_col_int + } + ] + { \box_use:N \l_tmpa_box } ; + } + } + } +% \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 +% \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}|. These +% variants exist since the version 3.0 of \pkg{nicematrix}. +% +% \begin{macrocode} +\NewDocumentEnvironment { pNiceArray } { } + { + \@@_test_if_math_mode: + \NiceArrayWithDelims ( ) + } + { \endNiceArrayWithDelims } +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment { bNiceArray } { } + { + \@@_test_if_math_mode: + \NiceArrayWithDelims [ ] + } + { \endNiceArrayWithDelims } +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment { BNiceArray } { } + { + \@@_test_if_math_mode: + \NiceArrayWithDelims \{ \} + } + { \endNiceArrayWithDelims } +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment { vNiceArray } { } + { + \@@_test_if_math_mode: + \NiceArrayWithDelims | | + } + { \endNiceArrayWithDelims } +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment { VNiceArray } { } + { + \@@_test_if_math_mode: + \NiceArrayWithDelims \| \| + } + { \endNiceArrayWithDelims } +% \end{macrocode} +% +% \bigskip +% \subsection{The environment \{NiceMatrix\} and its variants} +% +% Our environment |{NiceMatrix}| must have the same second part as the +% environment |{matrix}| of \pkg{amsmath} (because of the programmation of the +% option |renew-matrix|). Hence, this second part is the following: +% +% \begin{Verbatim} +% \endarray +% \skip_horizontal:n { - \arraycolsep } +% \end{Verbatim} +% +% That's why in the definition of |{NiceMatrix}|, we have to use |\array| and +% not |\begin{array}|. This command |\array| is in |\@@_array:| (we have written +% this command because of the redefinition of |\array| done in \cls{revtex4-1} +% and \cls{revtex4-2}). +% +% In order to execute code after the array, we use a command +% |\group_insert_after:N|. +% +% \medskip +% Here's the definition of |{NiceMatrix}|: +% \begin{macrocode} +\NewDocumentEnvironment { NiceMatrix } { ! O { } } + { + \@@_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 have to deactivate the potential externalisation of Tikz because +% \pkg{nicematrix} uses Tikz with |remember picture|. +% \begin{macrocode} + \cs_if_exist:NT \tikz@library@external@loaded + { \tikzset { external / export = false } } +% \end{macrocode} +% The instruction for actual drawing of the dotted lines must be in a +% |\group_insert_after:N| because the second part of the environment must be the +% same as in |{array}| (for the option |renew-matrix|). +% \begin{macrocode} + \group_insert_after:N \@@_after_array: + \tl_gclear_new:N \g_@@_lines_to_draw_tl + \int_gincr:N \g_@@_env_int + \bool_if:NF \l_@@_block_auto_columns_width_bool + { \dim_gzero_new:N \g_@@_max_cell_width_dim } + \keys_set:nn { NiceMatrix / NiceMatrix } { #1 } +% \end{macrocode} +% The macro |\@@_pre_array:| is defined above (see p.~\pageref{prearray}). It +% is also used in |{NiceArrayWithDelims}|. +% \begin{macrocode} + \@@_pre_array: + \skip_horizontal:n { - \arraycolsep } + \skip_horizontal:n \l_@@_left_margin_dim + \skip_horizontal:n \l_@@_extra_left_margin_dim + \str_set:Nn \l_@@_pos_env_str c + \bool_set_false:N \l_@@_exterior_arraycolsep_bool + \@@_array: { * \c@MaxMatrixCols C } + } + { + \endarray + \skip_horizontal:n { - \arraycolsep } +% \end{macrocode} +% The two following lines are, of course, not in the second part of |{array}|, +% but that doesn't matter because, when |renew-matrix| is used, +% |\g_@@_right_margin_dim| and |\g_@@_extra_right_margin_dim| will be equal to $0$~pt. +% \begin{macrocode} + \skip_horizontal:n \g_@@_right_margin_dim + \skip_horizontal:n \g_@@_extra_right_margin_dim + } +% \end{macrocode} +% +% \interitem +% We create the variants of the environment |{NiceMatrix}|. +% \begin{macrocode} +\NewDocumentEnvironment { pNiceMatrix } { } + { + \@@_test_if_math_mode: + \left( \begin{NiceMatrix} + } + { \end{NiceMatrix} \right) } +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment { bNiceMatrix } { } + { + \@@_test_if_math_mode: + \left[ \begin{NiceMatrix} + } + { \end{NiceMatrix} \right] } +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment { BNiceMatrix } { } + { + \@@_test_if_math_mode: + \left\{ \begin{NiceMatrix} + } + { \end{NiceMatrix} \right\} } +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment { vNiceMatrix } { } + { + \@@_test_if_math_mode: + \left\lvert \begin{NiceMatrix} + } + { \end{NiceMatrix} \right\rvert } +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment { VNiceMatrix } { } + { + \@@_test_if_math_mode: + \left\lVert \begin{NiceMatrix} + } + { \end{NiceMatrix} \right\rVert } +% \end{macrocode} +% +% +% \bigskip +% \subsection{Automatic width of the cells} +% +% For the option |columns-width=auto| (or the option |auto-columns-width| +% of the environment |{NiceMatrixBlock}|), we want to know the maximal width of +% the cells of the array (except the cells of the ``exterior'' column of an +% environment of the kind of |{pNiceAccayC}|). This length can be known only +% after the end of the construction of the array (or at the end of the +% environment |{NiceMatrixBlock}|). That's why we store this value in the main +% |.aux| file and it will be available in the next run. We write a dedicated +% command for this because it will be called in a~|\group_insert_after:N|. +% \begin{macrocode} +\cs_new_protected:Nn \@@_write_max_cell_width: + { + \bool_if:NF \l_@@_block_auto_columns_width_bool + { + \iow_now:Nn \@mainaux \ExplSyntaxOn + \iow_now:Nx \@mainaux + { + \cs_gset:cpn { @@_max_cell_width_ \int_use:N \g_@@_env_int } + { \dim_use:N \g_@@_max_cell_width_dim } + } +% \end{macrocode} +% If the environment has a name, we also create an alias named +% |\@@_max_cell_width_|{\ttfamily\slshape name}. +% \begin{macrocode} + \str_if_empty:NF \g_@@_name_str + { + \iow_now:Nx \@mainaux + { + \cs_gset:cpn { @@_max_cell_width_ \g_@@_name_str } + { \dim_use:N \g_@@_max_cell_width_dim } + } + } + \iow_now:Nn \@mainaux \ExplSyntaxOff + } + } +% \end{macrocode} +% +% \bigskip +% \subsection{How to know whether a cell is ``empty''} +% +% The conditionnal |\@@_if_not_empty_cell:nnT| tests whether a cell is empty. The +% first two arguments must be LaTeX3 counters for the row and the column of the +% considered cell. +% \begin{macrocode} +\prg_set_conditional:Npnn \@@_if_not_empty_cell:nn #1 #2 { T , TF } +% \end{macrocode} +% If the cell is an implicit cell (that is after the symbol |\\| of end of row), +% the cell must, of course, be considered as empty. It's easy to check whether we +% are in this situation considering the correspondant Tikz node. +% \begin{macrocode} + { + \cs_if_free:cTF + { pgf@sh@ns@nm -\int_use:N \g_@@_env_int - \int_use:N #1 - \int_use:N #2 } + \prg_return_false: +% \end{macrocode} +% We manage a list of ``empty cells'' called |\g_@@_empty_cells_seq|. In fact, +% this list is not a list of all the empty cells of the array but only those +% explicitly declared empty for some reason. It's easy to check if the current +% cell is in this list. +% \begin{macrocode} + { + \seq_if_in:NxTF \g_@@_empty_cells_seq { \int_use:N #1 - \int_use:N #2 } + \prg_return_false: +% \end{macrocode} +% In the general case, we consider the width of the Tikz node corresponding to +% the cell. In order to compute this width, we have to extract the coordinate of +% the west and east anchors of the node. This extraction needs a command +% environment |{pgfpicture}| but, in fact, nothing is drawn. +% \begin{macrocode} + { + \begin { pgfpicture } +% \end{macrocode} +% We store the name of the node corresponding to the cell in |\l_tmpa_tl|. +% \begin{macrocode} + \tl_set:Nx \l_tmpa_tl + { nm - \int_use:N \g_@@_env_int - \int_use:N #1 - \int_use:N #2 } + \pgfpointanchor \l_tmpa_tl { east } + \dim_gset:Nn \g_tmpa_dim \pgf@x + \pgfpointanchor \l_tmpa_tl { west } + \dim_gset:Nn \g_tmpb_dim \pgf@x + \end { pgfpicture } + \dim_compare:nNnTF + { \dim_abs:n { \g_tmpb_dim - \g_tmpa_dim } } < { 0.5 pt } + \prg_return_false: + \prg_return_true: + } + } + } +% \end{macrocode} +% +% +% \subsection{After the construction of the array} +% +% The macro |\@@_after_array:| is called (via +% |\group_insert_after:N|) in |{NiceArrayWithDelims}| and +% |{NiceMatrix}|. +% +% \begin{macrocode} +\cs_new_protected:Nn \@@_after_array: + { + \int_compare:nNnTF \g_@@_row_int > \c_zero_int + \@@_after_array_i: + { \@@_error:n { Zero~row } } + } +% \end{macrocode} +% +% \begin{macrocode} +\@@_msg_new:nn { Zero~row } + { + There~is~a~problem.~Maybe~your~environment~\{\@currenvir\}~is~empty.~ + Maybe~you~have~used~l,~c~and~r~instead~of~L,~C~and~R~in~the~preamble~ + of~your~environment. \\ + If~you~go~on,~the~result~may~be~incorrect. + } +% \end{macrocode} +% +% \medskip +% We deactivate Tikz externalization (since we use Tikz pictures with the +% options |overlay| and |remember picture|, there would be errors). +% \begin{macrocode} +\cs_new_protected:Nn \@@_after_array_i: + { + \group_begin: + \cs_if_exist:NT \tikz@library@external@loaded + { \tikzset { external / export = false } } +% \end{macrocode} +% Now, the definition of |\g_@@_col_int| and +% |\g_@@_col_total_int| change: |\g_@@_col_int| 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'' has the number~$0$.} +% \begin{macrocode} + \int_gset_eq:NN \g_@@_col_int \g_@@_col_total_int + \bool_if:nT \g_@@_last_col_found_bool { \int_gdecr:N \g_@@_col_int } +% \end{macrocode} +% +% We fix also the value of |\g_@@_row_int| and |\g_@@_row_total_int| with the +% same principle. +% \begin{macrocode} + \int_gset_eq:NN \g_@@_row_total_int \g_@@_row_int + \int_compare:nNnT \g_@@_last_row_int > { -1 } + { \int_gsub:Nn \g_@@_row_int \c_one_int } +% \end{macrocode} +% +% In the user has 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 \g_@@_last_row_without_value_bool + { + \iow_now:Nn \@mainaux \ExplSyntaxOn + \iow_now: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 \g_@@_name_str + { + \iow_now:Nx \@mainaux + { + \cs_gset:cpn { @@_last_row_ \g_@@_name_str } + { \int_use:N \g_@@_row_total_int } + } + } + \iow_now:Nn \@mainaux \ExplSyntaxOff + } +% \end{macrocode} +% +% The sequence |\g_@@_yet_drawn_seq| contains a list of lines which have been +% drawn previously in the matrix. We maintain this sequence because we don't +% want to draw two overlapping lines. +% \begin{macrocode} + \seq_gclear_new:N \g_@@_yet_drawn_seq +% \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_zero_new:N \l_@@_ddots_int + \int_zero_new:N \l_@@_iddots_int +% \end{macrocode} +% +% The dimensions |\l_@@_delta_x_one_dim| and |\l_@@_delta_y_one_dim| will +% 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 |\l_@@_delta_x_two_dim| and +% |\l_@@_delta_y_two_dim| are the $\Delta_x$ and $\Delta_y$ of the first +% |\Iddots| diagonal. +% \begin{macrocode} + \dim_zero_new:N \l_@@_delta_x_one_dim + \dim_zero_new:N \l_@@_delta_y_one_dim + \dim_zero_new:N \l_@@_delta_x_two_dim + \dim_zero_new:N \l_@@_delta_y_two_dim + } +% \end{macrocode} +% +% If the user has used the option |create-extra-nodes|, the ``medium nodes'' and +% ``large nodes'' are created. We recall that the command +% |\@@_create_extra_nodes:|, when used once, becomes no-op (in the current TeX +% group). +% \begin{macrocode} + \bool_if:NT \g_@@_extra_nodes_bool \@@_create_extra_nodes: +% \end{macrocode} +% +% \bigskip +% Now, we really draw the lines. The code to draw the lines has been constructed +% in the token list |\g_@@_lines_to_draw_tl|. +% \begin{macrocode} + \tl_if_empty:NF \g_@@_lines_to_draw_tl + { + \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 + \g_@@_lines_to_draw_tl + } + \tl_gclear:N \g_@@_lines_to_draw_tl +% \end{macrocode} +% +% \bigskip +% Now, the |code-after|. +% \begin{macrocode} + \tikzset + { + every~picture / .style = + { + overlay , + remember~picture , + name~prefix = nm - \int_use:N \g_@@_env_int - + } + } + \cs_set_eq:NN \line \@@_line:nn + \g_@@_code_after_tl + \tl_gclear:N \g_@@_code_after_tl + \group_end: + } +% \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}\] +% For a closed extremity, we use the normal node and for a open one, we use the +% ``medium node'' or, if it exists, the |w|~node (the medium and large nodes are +% created with |\@@_create_extra_nodes:| if they have not been created yet). +% \[ \begin{pNiceMatrix}[create-extra-nodes, +% code-after = {\begin{tikzpicture} +% \node [highlight, fit={(2-1)}] {} ; +% \node [highlight, fit={(2-3-medium)}] {}; +% \end{tikzpicture} +% }] +% 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:Nn \@@_find_extremities_of_line:nnnn + { + \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. +% \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 > \g_@@_row_int + { + \int_compare:nNnT { #3 } = 1 + { \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 > \g_@@_col_int + { + \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 a \emph{open} extremity. +% \begin{macrocode} + { +% \end{macrocode} +% We do a step backwards because we will draw the dotted line upon the last cell +% in the matrix (we will use the ``medium node'' of this cell). +% \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 if the cell is empty. If it's not the case, +% we stop the loop because we have found the correct values for +% |\l_@@_final_i_int| and |\l_@@_final_j_int|. +% \begin{macrocode} + { + \@@_if_not_empty_cell:nnT \l_@@_final_i_int \l_@@_final_j_int + { \bool_set_true:N \l_@@_stop_loop_bool } + } + } +% \end{macrocode} +% +% \interitem +% 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:nNnT { #3 } = 1 + { \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 > \g_@@_col_int + { + \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 + } + { + \@@_if_not_empty_cell:nnT + \l_@@_initial_i_int \l_@@_initial_j_int + { \bool_set_true:N \l_@@_stop_loop_bool } + } + } +% \end{macrocode} +% If we have at least one open extremity, we create the ``medium nodes'' in the +% matrix\footnote{We should change this. Indeed, for an open extremity of an +% \emph{horizontal} dotted line, we use the |w|~node, if, it exists, and not the +% ``medium node''.}. We remind that, when used once, the command +% |\@@_create_extra_nodes:| becomes no-op in the current TeX group. +% \begin{macrocode} + \bool_if:nT { \l_@@_initial_open_bool || \l_@@_final_open_bool } + \@@_create_extra_nodes: + } +% \end{macrocode} +% +% \interitem +% If the dotted line to draw is in the list of the previously drawn lines +% (|\g_@@_yet_drawn_seq|), we don't draw (so, we won't have overlapping lines in +% the \textsc{pdf}). The token list |\l_tmpa_tl| is the $4$-list characteristic +% of the line. +% \begin{macrocode} +\prg_set_conditional:Npnn \@@_if_yet_drawn: { F } + { + \tl_set:Nx \l_tmpa_tl + { + \int_use:N \l_@@_initial_i_int - + \int_use:N \l_@@_initial_j_int - + \int_use:N \l_@@_final_i_int - + \int_use:N \l_@@_final_j_int + } + \seq_if_in:NVTF \g_@@_yet_drawn_seq \l_tmpa_tl +% \end{macrocode} +% +% If the dotted line to draw is not in the list, we add it to the list +% |\g_@@_yet_drawn_seq|. +% \begin{macrocode} + \prg_return_true: + { + \seq_gput_left:NV \g_@@_yet_drawn_seq \l_tmpa_tl + \prg_return_false: + } + } +% \end{macrocode} +% +% +% \interitem +% The command |\@@_retrieve_coords:nn| retrieves the Tikz coordinates of the two +% extremities of the dotted line we will have to draw \footnote{In fact, with +% diagonal lines, or vertical lines in columns of type |L| or |R|, an adjustment +% of one of the coordinates may be done.}. This command has four implicit +% arguments which are |\l_@@_initial_i_int|, |\l_@@_initial_j_int|, +% |\l_@@_final_i_int| and |\l_@@_final_j_int|. +% +% The two arguments of the command |\@@_retrieve_coords:nn| are the suffix and +% the anchor that must be used for the two nodes. +% +% The coordinates are stored in |\g_@@_x_initial_dim|, |\g_@@_y_initial_dim|, +% |\g_@@_x_final_dim|, |\g_@@_y_final_dim|. These variables are global for +% technical reasons: we have to do an affectation in an environment +% |{tikzpicture}|. +% \begin{macrocode} +\cs_new_protected:Nn \@@_retrieve_coords:nn + { + \dim_gzero_new:N \g_@@_x_initial_dim + \dim_gzero_new:N \g_@@_y_initial_dim + \dim_gzero_new:N \g_@@_x_final_dim + \dim_gzero_new:N \g_@@_y_final_dim + \begin { tikzpicture } [ remember~picture ] + \tikz@parse@node \pgfutil@firstofone + ( nm - \int_use:N \g_@@_env_int - + \int_use:N \l_@@_initial_i_int - + \int_use:N \l_@@_initial_j_int #1 ) + \dim_gset:Nn \g_@@_x_initial_dim \pgf@x + \dim_gset:Nn \g_@@_y_initial_dim \pgf@y + \tikz@parse@node \pgfutil@firstofone + ( nm - \int_use:N \g_@@_env_int - + \int_use:N \l_@@_final_i_int - + \int_use:N \l_@@_final_j_int #2 ) + \dim_gset:Nn \g_@@_x_final_dim \pgf@x + \dim_gset:Nn \g_@@_y_final_dim \pgf@y + \end { tikzpicture } + } +\cs_generate_variant:Nn \@@_retrieve_coords:nn { x x } +% \end{macrocode} +% +% \interitem +% \begin{macrocode} +\cs_new_protected:Nn \@@_draw_Ldots:nn + { + \@@_find_extremities_of_line:nnnn { #1 } { #2 } \c_zero_int \c_one_int + \@@_if_yet_drawn:F \@@_actually_draw_Ldots: + } +% \end{macrocode} +% +% \medskip +% The command |\@@_actually_draw_Ldots:| draws the |Ldots| line using +% |\l_@@_initial_i_int|, |\l_@@_initial_j_int|, |\l_@@_initial_open_bool|, +% |\l_@@_final_i_int|, |\l_@@_final_j_int| and |\l_@@_final_open_bool|. We have +% a dedicated command because if is used also by |\Hdotsfor|. +% \begin{macrocode} +\cs_new_protected:Nn \@@_actually_draw_Ldots: + { + \@@_retrieve_coords:xx + { + \bool_if:NTF \l_@@_initial_open_bool + { +% \end{macrocode} +% If a |w| node exists (created when the key |columns-width| is used), we use +% the |w| node for the extremity. +% \begin{macrocode} + \cs_if_exist:cTF + { + pgf@sh@ns@nm + - \int_use:N \g_@@_env_int + - \int_use:N \l_@@_initial_i_int + - \int_use:N \l_@@_initial_j_int - w + } + { - w.base~west } + { - medium.base~west } + } + { .base~east } + } + { + \bool_if:NTF \l_@@_final_open_bool + { + \cs_if_exist:cTF + { + pgf@sh@ns@nm + - \int_use:N \g_@@_env_int + - \int_use:N \l_@@_final_i_int + - \int_use:N \l_@@_final_j_int - w + } + { - w.base~east } + { - medium.base~east } + } + { .base~west } + } + \bool_if:NT \l_@@_initial_open_bool + { \dim_gset_eq:NN \g_@@_y_initial_dim \g_@@_y_final_dim } + \bool_if:NT \l_@@_final_open_bool + { \dim_gset_eq:NN \g_@@_y_final_dim \g_@@_y_initial_dim } +% \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_gadd:Nn \g_@@_y_initial_dim { 0.53 pt } + \dim_gadd:Nn \g_@@_y_final_dim { 0.53 pt } + \@@_draw_tikz_line: + } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\cs_new_protected:Nn \@@_draw_Cdots:nn + { + \@@_find_extremities_of_line:nnnn { #1 } { #2 } \c_zero_int \c_one_int + \@@_if_yet_drawn:F + { + \@@_retrieve_coords:xx + { + \bool_if:NTF \l_@@_initial_open_bool + { + \cs_if_exist:cTF + { + pgf@sh@ns@nm + - \int_use:N \g_@@_env_int + - \int_use:N \l_@@_initial_i_int + - \int_use:N \l_@@_initial_j_int - w + } + { - w.mid~west } + { - medium.mid~west } + } + { .mid~east } + } + { + \bool_if:NTF \l_@@_final_open_bool + { + \cs_if_exist:cTF + { + pgf@sh@ns@nm + - \int_use:N \g_@@_env_int + - \int_use:N \l_@@_final_i_int + - \int_use:N \l_@@_final_j_int - w + } + { - w.mid~east } + { - medium.mid~east } + } + { .mid~west } + } + \bool_if:NT \l_@@_initial_open_bool + { \dim_gset_eq:NN \g_@@_y_initial_dim \g_@@_y_final_dim } + \bool_if:NT \l_@@_final_open_bool + { \dim_gset_eq:NN \g_@@_y_final_dim \g_@@_y_initial_dim } + \@@_draw_tikz_line: + } + } +% \end{macrocode} +% +% \bigskip +% For the vertical dots, we have to distinguish different instances because we +% want really vertical lines. Be careful: it's not possible to insert the +% command |\@@_retrieve_coords:nn| in the arguments |T| and |F| of the +% \pkg{expl3} commands (why?). +% \begin{macrocode} +\cs_new_protected:Nn \@@_draw_Vdots:nn + { + \@@_find_extremities_of_line:nnnn { #1 } { #2 } \c_one_int \c_zero_int + \@@_if_yet_drawn:F + { \@@_retrieve_coords:xx + { + \bool_if:NTF \l_@@_initial_open_bool + { - medium.north~west } + { .south~west } + } + { + \bool_if:NTF \l_@@_final_open_bool + { - medium.south~west } + { .north~west } + } +% \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:Nn \l_tmpa_bool + { \dim_compare_p:nNn \g_@@_x_initial_dim = \g_@@_x_final_dim } + \@@_retrieve_coords:xx + { + \bool_if:NTF \l_@@_initial_open_bool + { - medium.north } + { .south } + } + { + \bool_if:NTF \l_@@_final_open_bool + { - medium.south } + { .north } + } +% \end{macrocode} +% The boolean |\l_tmpb_bool| indicates whether the column is of type |c| (|C| of +% |{NiceArray}|) or may be considered as if. +% \begin{macrocode} + \bool_set:Nn \l_tmpb_bool + { \dim_compare_p:nNn \g_@@_x_initial_dim = \g_@@_x_final_dim } + \bool_if:NF \l_tmpb_bool + { + \dim_gset:Nn \g_@@_x_initial_dim + { + \bool_if:NTF \l_tmpa_bool \dim_min:nn \dim_max:nn + \g_@@_x_initial_dim \g_@@_x_final_dim + } + \dim_gset_eq:NN \g_@@_x_final_dim \g_@@_x_initial_dim + } + \@@_draw_tikz_line: + } + } +% \end{macrocode} +% +% \interitem +% For the diagonal lines, the situation is a bit more complicated because, by +% default, we parallelize the diagonals lines. The first diagonal line is drawn +% and then, all the other diagonal lines are drawn parallel to the first one. +% \begin{macrocode} +\cs_new_protected:Nn \@@_draw_Ddots:nn + { + \@@_find_extremities_of_line:nnnn { #1 } { #2 } \c_one_int \c_one_int + \@@_if_yet_drawn:F + { + \@@_retrieve_coords:xx + { + \bool_if:NTF \l_@@_initial_open_bool + { - medium.north~west } + { .south~east } + } + { + \bool_if:NTF \l_@@_final_open_bool + { - medium.south~east } + { .north~west } + } +% \end{macrocode} +% We have retrieved the coordinates in the usual way (they are stored in +% |\g_@@_x_initial_dim|, etc.). If the parallelization of the diagonals is set, +% we will have (maybe) to adjust the fourth coordinate. +% \begin{macrocode} + \bool_if:NT \l_@@_parallelize_diags_bool + { + \int_incr:N \l_@@_ddots_int +% \end{macrocode} +% We test if the diagonal line is the first one (the counter |\l_@@_ddots_int| +% is created for this usage). +% \begin{macrocode} + \int_compare:nNnTF \l_@@_ddots_int = \c_one_int +% \end{macrocode} +% If the diagonal line is the first one, we have no adjustment of the line to do +% but we store the $\Delta_x$ and the $\Delta_y$ of the line because these +% values will be used to draw the others diagonal lines parallels to the first +% one. +% \begin{macrocode} + { + \dim_set:Nn \l_@@_delta_x_one_dim + { \g_@@_x_final_dim - \g_@@_x_initial_dim } + \dim_set:Nn \l_@@_delta_y_one_dim + { \g_@@_y_final_dim - \g_@@_y_initial_dim } + } +% \end{macrocode} +% If the diagonal line is not the first one, we have to adjust the second +% extremity of the line by modifying the coordinate |\g_@@_y_initial_dim|. +% \begin{macrocode} + { + \dim_gset:Nn \g_@@_y_final_dim + { + \g_@@_y_initial_dim + + ( \g_@@_x_final_dim - \g_@@_x_initial_dim ) * + \dim_ratio:nn \l_@@_delta_y_one_dim \l_@@_delta_x_one_dim + } + } + } +% \end{macrocode} +% Now, we can draw the dotted line (after a possible change of +% |\g_@@_y_initial_dim|). +% \begin{macrocode} + \@@_draw_tikz_line: + } + } +% \end{macrocode} +% +% \bigskip +% We draw the |\Iddots| diagonals in the same way. +% \begin{macrocode} +\cs_new_protected:Nn \@@_draw_Iddots:nn + { + \@@_find_extremities_of_line:nnnn { #1 } { #2 } 1 { -1 } + \@@_if_yet_drawn:F + { \@@_retrieve_coords:xx + { + \bool_if:NTF \l_@@_initial_open_bool + { - medium.north~east } + { .south~west } + } + { + \bool_if:NTF \l_@@_final_open_bool + { - medium.south~west } + { .north~east } + } + \bool_if:NT \l_@@_parallelize_diags_bool + { + \int_incr:N \l_@@_iddots_int + \int_compare:nNnTF \l_@@_iddots_int = \c_one_int + { + \dim_set:Nn \l_@@_delta_x_two_dim + { \g_@@_x_final_dim - \g_@@_x_initial_dim } + \dim_set:Nn \l_@@_delta_y_two_dim + { \g_@@_y_final_dim - \g_@@_y_initial_dim } + } + { + \dim_gset:Nn \g_@@_y_final_dim + { + \g_@@_y_initial_dim + + ( \g_@@_x_final_dim - \g_@@_x_initial_dim ) * + \dim_ratio:nn \l_@@_delta_y_two_dim \l_@@_delta_x_two_dim + } + } + } + \@@_draw_tikz_line: + } + } +% \end{macrocode} +% +% \bigskip +% \subsection{The actual instructions for drawing the dotted line with Tikz} +% +% The command |\@@_draw_tikz_line:| draws the line using four implicit arguments: +% +% \quad |\g_@@_x_initial_dim|, |\g_@@_y_initial_dim|, |\g_@@_x_final_dim| and |\g_@@_y_final_dim|. +% These variables are global for technical reasons: their first affectation was in an instruction |\tikz|. +% +% \begin{macrocode} +\cs_new_protected:Nn \@@_draw_tikz_line: + { +% \end{macrocode} +% The dimension |\l_@@_l_dim| is the length $\ell$ of the line to draw. We use +% the floating point reals of \pkg{expl3} to compute this length. +% \begin{macrocode} + \dim_zero_new:N \l_@@_l_dim + \dim_set:Nn \l_@@_l_dim + { + \fp_to_dim:n + { + sqrt + ( + ( \dim_use:N \g_@@_x_final_dim + - \dim_use:N \g_@@_x_initial_dim + ) ^ 2 + + + ( \dim_use:N \g_@@_y_final_dim + - \dim_use:N \g_@@_y_initial_dim + ) ^ 2 + ) + } + } +% \end{macrocode} +% We draw only if the length is not equal to zero (in fact, in the first +% compilation, the length may be equal to zero). +% \begin{macrocode} + \dim_compare:nNnF \l_@@_l_dim = \c_zero_dim +% \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 { 0.45 em } } + } + { + \int_set:Nn \l_tmpa_int + { \dim_ratio:nn { \l_@@_l_dim - 0.3 em } { 0.45 em } } + } + } + { + \bool_if:NTF \l_@@_final_open_bool + { + \int_set:Nn \l_tmpa_int + { \dim_ratio:nn { \l_@@_l_dim - 0.3 em } { 0.45 em } } + } + { + \int_set:Nn \l_tmpa_int + { \dim_ratio:nn { \l_@@_l_dim - 0.6 em } { 0.45 em }} + } + } +% \end{macrocode} +% The dimensions |\l_tmpa_dim| and |\l_tmpb_dim| are the coordinates of the +% vector between two dots in the dotted line. +% \begin{macrocode} + \dim_set:Nn \l_tmpa_dim + { + ( \g_@@_x_final_dim - \g_@@_x_initial_dim ) * + \dim_ratio:nn { 0.45 em } \l_@@_l_dim + } + \dim_set:Nn \l_tmpb_dim + { + ( \g_@@_y_final_dim - \g_@@_y_initial_dim ) * + \dim_ratio:nn { 0.45 em } \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 (|\int_step_inline:nnnn|), the dimensions +% |\g_@@_x_initial_dim| and |\g_@@_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 \g_@@_x_initial_dim + { + ( \g_@@_x_final_dim - \g_@@_x_initial_dim ) * + \dim_ratio:nn + { \l_@@_l_dim - 0.45 em * \l_tmpa_int } { \l_@@_l_dim * 2 } * + \l_tmpb_int + } +% \end{macrocode} +% (In a multiplication of a dimension and an integer, the integer must always be +% put in second position.) +% \begin{macrocode} + \dim_gadd:Nn \g_@@_y_initial_dim + { + ( \g_@@_y_final_dim - \g_@@_y_initial_dim ) * + \dim_ratio:nn + { \l_@@_l_dim - 0.45 em * \l_tmpa_int } + { \l_@@_l_dim * 2 } * + \l_tmpb_int + } + \begin { tikzpicture } [ overlay ] + \int_step_inline:nnnn 0 1 \l_tmpa_int + { + \pgfpathcircle + { \pgfpoint { \g_@@_x_initial_dim } { \g_@@_y_initial_dim } } + { 0.53 pt } + \pgfusepath { fill } + \dim_gadd:Nn \g_@@_x_initial_dim \l_tmpa_dim + \dim_gadd:Nn \g_@@_y_initial_dim \l_tmpb_dim + } + \end { tikzpicture } + } + } +% \end{macrocode} +% +% \subsection{User commands available in the new environments} +% +% We give new names for the commands |\ldots|, |\cdots|, |\vdots| and |\ddots| +% because these commands will be redefined (if the option |renew-dots| is used). +% \begin{macrocode} +\cs_set_eq:NN \@@_ldots \ldots +\cs_set_eq:NN \@@_cdots \cdots +\cs_set_eq:NN \@@_vdots \vdots +\cs_set_eq:NN \@@_ddots \ddots +\cs_set_eq:NN \@@_iddots \iddots +% \end{macrocode} +% +% \interitem +% The command |\@@_add_to_empty_cells:| adds the current cell to +% |\g_@@_empty_cells_seq| which is the list of the empty cells (the cells +% explicitly declared ``empty'': there may be, of course, other empty cells in +% the matrix). +% \begin{macrocode} +\cs_new_protected:Nn \@@_add_to_empty_cells: + { + \seq_gput_right:Nx \g_@@_empty_cells_seq + { \int_use:N \g_@@_row_int - \int_use:N \g_@@_col_int } + } +% \end{macrocode} +% +% \interitem +% The commands |\@@_Ldots|, |\@@_Cdots|, |\@@_Vdots|, |\@@_Ddots| and +% |\@@_Iddots| will be linked to |\Ldots|, |\Cdots|, |\Vdots|, |\Ddots| and +% |\Iddots| in the environments |{NiceArray}| (the other environments of +% \pkg{nicematrix} rely upon |{NiceArray}|). +% \begin{macrocode} +\NewDocumentCommand \@@_Ldots { s } + { + \bool_if:nF { #1 } { \@@_instruction_of_type:n { Ldots } } + \bool_if:NF \l_@@_nullify_dots_bool { \phantom \@@_ldots } + \@@_add_to_empty_cells: + } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\NewDocumentCommand \@@_Cdots { s } + { + \bool_if:nF { #1 } { \@@_instruction_of_type:n { Cdots } } + \bool_if:NF \l_@@_nullify_dots_bool { \phantom \@@_cdots } + \@@_add_to_empty_cells: + } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\NewDocumentCommand \@@_Vdots { s } + { + \bool_if:nF { #1 } { \@@_instruction_of_type:n { Vdots } } + \bool_if:NF \l_@@_nullify_dots_bool { \phantom \@@_vdots } + \@@_add_to_empty_cells: + } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\NewDocumentCommand \@@_Ddots { s } + { + \bool_if:nF { #1 } { \@@_instruction_of_type:n { Ddots } } + \bool_if:NF \l_@@_nullify_dots_bool { \phantom \@@_ddots } + \@@_add_to_empty_cells: + } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\NewDocumentCommand \@@_Iddots { s } + { + \bool_if:nF { #1 } { \@@_instruction_of_type:n { Iddots } } + \bool_if:NF \l_@@_nullify_dots_bool { \phantom \@@_iddots } + \@@_add_to_empty_cells: + } +% \end{macrocode} +% +% +% \bigskip +% The command |\@@_Hspace:| will be linked to |\hspace| in |{NiceArray}|. +% \begin{macrocode} +\cs_new_protected:Nn \@@_Hspace: + { + \@@_add_to_empty_cells: + \hspace + } +% \end{macrocode} +% +% +% \bigskip +% 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 \g_@@_row_int - \int_use:N \g_@@_col_int } + \seq_gput_left:Nn \g_@@_multicolumn_sizes_seq { #1 } + } + \int_gadd:Nn \g_@@_col_int { #1 - 1 } + } +% \end{macrocode} +% +% +% \bigskip +% The command |\@@_Hdotsfor| will be linked to |\Hdotsfor| in |{NiceArray}|. +% This command uses an optional argument like |\hdotsfor| but this argument is +% discarded (in |\hdotsfor|, this argument is used for fine tuning of the space +% beetween two consecutive dots). Tikz nodes are created for all the cells of +% the array, even the implicit cells of the |\Hdotsfor|. +% +% \medskip +% This command must not be protected since it begins with |\multicolumn|. +% \begin{macrocode} +\cs_new:Npn \@@_Hdotsfor: + { + \multicolumn { 1 } { C } { } + \@@_Hdotsfor_i + } +% \end{macrocode} +% +% The command |\@@_Hdotsfor_i| is defined with the tools of \pkg{xparse} because +% it has an optionnal argument. Note that such a command defined by +% |\multicolumn| is protected and that's why we have put the |\multicolumn| +% before (in the definition of |\@@_Hdotsfor:|). +% \begin{macrocode} +\bool_if:NTF \c_@@_draft_bool + { + \NewDocumentCommand \@@_Hdotsfor_i { O { } m } + { + \prg_replicate:nn { #2 - 1 } { & \multicolumn { 1 } { C } { } } + } + } + { + \NewDocumentCommand \@@_Hdotsfor_i { O { } m } + { + \tl_gput_right:Nx \g_@@_lines_to_draw_tl + { + \@@_draw_Hdotsfor:nnn + { \int_use:N \g_@@_row_int } + { \int_use:N \g_@@_col_int } + { #2 } + } + \prg_replicate:nn { #2 - 1 } { & \multicolumn { 1 } { C } { } } + } + } +% \end{macrocode} +% +% \medskip +% \begin{macrocode} +\cs_new_protected:Nn \@@_draw_Hdotsfor:nnn + { + \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:Nn \l_@@_final_i_int { #1 } +% \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 + } + { + \int_set:Nn \l_tmpa_int { #2 - 1 } + \@@_if_not_empty_cell:nnTF \l_@@_initial_i_int \l_tmpa_int + { \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 } = \g_@@_col_int + { + \int_set:Nn \l_@@_final_j_int { #2 + #3 - 1 } + \bool_set_true:N \l_@@_final_open_bool + } + { + \int_set:Nn \l_tmpa_int { #2 + #3 } + \@@_if_not_empty_cell:nnTF \l_@@_final_i_int \l_tmpa_int + { \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 + } + } + \bool_if:nT { \l_@@_initial_open_bool || \l_@@_final_open_bool } + \@@_create_extra_nodes: + \@@_actually_draw_Ldots: + } +% \end{macrocode} +% +% +% +% \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 specification of two cells in the +% array (in the format $i$-$j$) and draws a dotted line between these cells. +% \begin{macrocode} +\cs_new_protected:Nn \@@_line:nn + { + \dim_zero_new:N \g_@@_x_initial_dim + \dim_zero_new:N \g_@@_y_initial_dim + \dim_zero_new:N \g_@@_x_final_dim + \dim_zero_new:N \g_@@_y_final_dim + \bool_set_false:N \l_@@_initial_open_bool + \bool_set_false:N \l_@@_final_open_bool + \begin { tikzpicture } + \path~(#1)~--~(#2)~node[at~start]~(i)~{}~node[at~end]~(f)~{} ; + \tikz@parse@node \pgfutil@firstofone ( i ) + \dim_gset:Nn \g_@@_x_initial_dim \pgf@x + \dim_gset:Nn \g_@@_y_initial_dim \pgf@y + \tikz@parse@node \pgfutil@firstofone ( f ) + \dim_gset:Nn \g_@@_x_final_dim \pgf@x + \dim_gset:Nn \g_@@_y_final_dim \pgf@y + \end { tikzpicture } + \@@_draw_tikz_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 commands to draw dotted lines to separate columns and rows} +% +% The command |\hdottedline| draws an horizontal dotted line to separate two +% rows. Similarly, the letter ``:'' in the preamble draws a vertical dotted line +% (the letter can be changed with the option |letter-for-dotted-lines|). Both +% mechanisms write instructions in the |code-after|. The actual instructions in +% the |code-after| use the commands |\@@_hdottedline:n| and |\@@_vdottedline:n|. +% +% \bigskip +% We want the horizontal lines at the same position\footnote{In fact, almost the +% same position because of the width of the line: the width of a dotted line is +% not the same as the width of a line created by |\hline|.} as the line created +% by |\hline| (or |\hdashline| of \pkg{arydshln}). To this end, we construct a +% ``false row'' and, in this row, we create a Tikz node (|\coordinate|) that +% will be used to have the $y$-value of the line. +% +% \begin{macrocode} +\cs_generate_variant:Nn \dim_set:Nn { N v } +% \end{macrocode} +% +% +% \medskip +% Some extensions, like the extension \pkg{doc}, do a redefinition of the command +% |\dotfill| of LaTeX. That's why we define a command |\@@_dotfill:| as we wish. +% We test whether we are in draft mode because, in this case, we don't draw the +% dotted lines. +% \begin{macrocode} +\bool_if:NTF \c_@@_draft_bool + { \cs_set_eq:NN \@@_dotfill: \prg_do_nothing: } + { + \cs_set:Npn \@@_dotfill: + { + \cleaders \hbox_to_wd:nn { .44 em } { \hss . \hss } \hfill + \skip_horizontal:n \c_zero_dim + } + } +% \end{macrocode} +% +% This command must \emph{not} be protected because it starts with |\noalign|. +% \begin{macrocode} +\cs_new:Npn \@@_hdottedline: + { + \noalign + { + \bool_gset_true:N \g_@@_extra_nodes_bool + \cs_if_exist:cTF { @@_width_ \int_use:N \g_@@_env_int } + { \dim_set:Nv \l_tmpa_dim { @@_width_ \int_use:N \g_@@_env_int } } + { \dim_set:Nn \l_tmpa_dim { 5 mm } } + \hbox_overlap_right:n + { + \hbox_to_wd:nn + { + \l_tmpa_dim + 2 \arraycolsep + - \l_@@_left_margin_dim - \g_@@_right_margin_dim + } + \@@_dotfill: + } + } + } +% \end{macrocode} +% +% +% +% \bigskip +% \begin{macrocode} +\cs_new_protected:Nn \@@_vdottedline:n + { +% \end{macrocode} +% We should allow the letter ``|:|'' in the first position of the preamble +% but that would need a special programmation. +% \begin{macrocode} + \int_compare:nNnTF #1 = \c_zero_int + { \@@_error:n { Use~of~:~in~first~position } } + { + \@@_create_extra_nodes: + \bool_if:NF \c_@@_draft_bool + { + \dim_zero_new:N \g_@@_x_initial_dim + \dim_zero_new:N \g_@@_y_initial_dim + \dim_zero_new:N \g_@@_x_final_dim + \dim_zero_new:N \g_@@_y_final_dim + \bool_set_true:N \l_@@_initial_open_bool + \bool_set_true:N \l_@@_final_open_bool +% \end{macrocode} +% In order to have the coordinates of the line to draw, we use the ``large nodes''. +% \begin{macrocode} + \begin { tikzpicture } [ remember~picture ] + \tikz@parse@node\pgfutil@firstofone + ( 1 - #1 - large .north~east ) + \dim_gset:Nn \g_@@_x_initial_dim \pgf@x + \dim_gset:Nn \g_@@_y_initial_dim \pgf@y + \tikz@parse@node\pgfutil@firstofone + ( \int_use:N \g_@@_row_int - #1 - large .south~east ) + \dim_gset:Nn \g_@@_x_final_dim \pgf@x + \dim_gset:Nn \g_@@_y_final_dim \pgf@y + \end { tikzpicture } +% \end{macrocode} +% However, if the |w|-nodes are created in the previous column (that is if the +% previous column was constructed explicitly or implicitly\footnote{A column is +% constructed implicitly with the letter |w| if the option |columns-width| is +% used or if the environment |{NiceMatrixBlock}| is used with the option +% |auto-columns-width|.} with a letter |w|), we use the |w|-nodes to change the +% $x$-value of the nodes in order to have the dotted lines perfectly aligned +% when we use the environment |{NiceMatrixBlock}| with the option +% |auto-columns-width|. +% \begin{macrocode} + \cs_if_exist:cT + { pgf@sh@ns@nm -\int_use:N \g_@@_env_int - 1 - #1 - w } + { + \begin { tikzpicture } [ remember~picture ] + \tikz@parse@node\pgfutil@firstofone + ( 1 - #1 - w .north~east ) + \dim_gset:Nn \g_@@_x_initial_dim \pgf@x + \tikz@parse@node\pgfutil@firstofone + ( \int_use:N \g_@@_row_int - #1 - w .south~east ) + \dim_gset:Nn \g_@@_x_final_dim \pgf@x + \end { tikzpicture } + \dim_gadd:Nn \g_@@_x_initial_dim \arraycolsep + \dim_gadd:Nn \g_@@_x_final_dim \arraycolsep + } + \@@_draw_tikz_line: + } + } + } +% \end{macrocode} +% +% +% \begin{macrocode} +\@@_msg_new:nn { Use~of~:~in~first~position } + { + You~can't~use~the~column~specifier~"\l_@@_letter_for_dotted_lines_str"~in~the~ + first~position~of~the~preamble~of~the~environment~\{\@currenvir\}. \\ + If~you~go~on,~this~dotted~line~will~be~ignored. + } +% \end{macrocode} +% +% \bigskip +% \subsection{The vertical rules} +% +% We don't want that a vertical rule drawn by the specifier ``"|"'' extends +% in the eventual ``first row'' and ``last row'' of the array. +% +% The natural way to do that would be to redefine the specifier ``"|"'' +% with |\newcolumntype|: +% \begin{Verbatim}[commandchars=\~\#\+] +% \newcolumntype { | } +% { ! { \int_compare:nNnF \g_@@_row_int = \c_zero_int \vline } } +% \end{Verbatim} +% +% However, this code fails is 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 will do a redefinition of the macro |\@arrayrule| of \pkg{array} +% and this redefinition will add |\@@_vline:| instead of |\vline| to the +% preamble. +% +% 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 must be effective in each row and not once when the +% preamble is constructed). +% \begin{macrocode} +\cs_new_protected:Npn \@@_vline: + { + \int_compare:nNnTF \l_@@_first_col_int = \c_zero_int + { + \int_compare:nNnTF \g_@@_col_int = \c_zero_int + { + \int_compare:nNnTF \l_@@_first_row_int = \c_zero_int + { + \int_compare:nNnF \g_@@_row_int = \c_zero_int + { + \int_compare:nNnF \g_@@_row_int = \l_@@_last_row_int \vline + } + } + { + \int_compare:nNnF \g_@@_row_int = \c_zero_int + { + \int_compare:nNnF \g_@@_row_int = \l_@@_last_row_int \vline + } + } + } + { + \int_compare:nNnF \g_@@_row_int = \c_zero_int + { \int_compare:nNnF \g_@@_row_int = \l_@@_last_row_int \vline } + } + } + { + \int_compare:nNnTF \g_@@_col_int = \c_zero_int + { + \int_compare:nNnF \g_@@_row_int = { -1 } + { + \int_compare:nNnF \g_@@_row_int = { \l_@@_last_row_int - 1 } + \vline + } + } + { + \int_compare:nNnF \g_@@_row_int = \c_zero_int + { \int_compare:nNnF \g_@@_row_int = \l_@@_last_row_int \vline } + } + } + } +% \end{macrocode} +% +% +% +% \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 { } } + { + \keys_set:nn { NiceMatrix / NiceMatrixBlock } { #1 } + \int_zero_new:N \l_@@_first_env_block_int + \int_set:Nn \l_@@_first_env_block_int { \g_@@_env_int + 1 } + } +% \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_now:Nn \@mainaux \ExplSyntaxOn + \int_step_inline:nnnn \l_@@_first_env_block_int 1 \g_@@_env_int + { + \iow_now:Nx \@mainaux + { + \cs_gset:cpn { @@ _ max _ cell _ width _ ##1 } + { \dim_use:N \g_@@_max_cell_width_dim } + } + } + \iow_now:Nn \@mainaux \ExplSyntaxOff + } + } +% \end{macrocode} +% +% +% \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 +% 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:Nn \@@_create_extra_nodes: + { + \begin { tikzpicture } [ remember~picture , overlay ] + \int_step_variable:nnNn \g_@@_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 \g_@@_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 \g_@@_first_row_int \g_@@_row_total_int \@@_i: + { + \int_step_variable:nnNn + \g_@@_first_col_int \g_@@_col_total_int \@@_j: +% \end{macrocode} +% Maybe the cell ($i$-$j$) is an implicit cell (that is to say a cell after +% implicit ampersands |&|). In this case, of course, we don't update the +% dimensions we want to compute. +% \begin{macrocode} + { \cs_if_exist:cT + { pgf@sh@ns@nm - \int_use:N \g_@@_env_int - \@@_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} + { + \tikz@parse@node \pgfutil@firstofone + ( nm - \int_use:N \g_@@_env_int + - \@@_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} + \tikz@parse@node \pgfutil@firstofone + ( nm - \int_use:N \g_@@_env_int - \@@_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 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'' +% (after changing the value of |name-suffix|). +% \begin{macrocode} + \tikzset { name~suffix = -medium } + \@@_create_nodes: +% \end{macrocode} +% +% \bigskip +% For ``large nodes'', the exterior rows and columns don't interfer. +% That's why the loop over the rows will start at 1 and the loop over the columns +% will stop at $|\g_@@_col_int|$ (and not |\g_@@_col_total_int|). Idem for the rows. +% \begin{macrocode} + \int_set:Nn \g_@@_first_row_int 1 + \int_set:Nn \g_@@_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 { \g_@@_row_int - 1 } \@@_i: + { + \dim_set:cn { l_@@_row _ \@@_i: _ min _ dim } + { + ( + \dim_use:c { l_@@_row _ \@@_i: _ min _ dim } + + \dim_use:c { l_@@_row _ \int_eval:n { \@@_i: + 1 } _ max _ dim } + ) + / 2 + } + \dim_set_eq:cc { l_@@_row _ \int_eval:n { \@@_i: + 1 } _ max _ dim } + { l_@@_row_\@@_i: _min_dim } + } + \int_step_variable:nNn { \g_@@_col_int - 1 } \@@_j: + { + \dim_set:cn { l_@@_column _ \@@_j: _ max _ dim } + { + ( + \dim_use:c + { l_@@_column _ \@@_j: _ max _ dim } + + \dim_use:c + { l_@@_column _ \int_eval:n { \@@_j: + 1 } _ min _ dim } + ) + / 2 + } + \dim_set_eq:cc { l_@@_column _ \int_eval:n { \@@_j: + 1 } _ min _ dim } + { l_@@_column _ \@@_j: _ max _ dim } + } + \dim_sub:cn + { l_@@_column _ 1 _ min _ dim } + \g_@@_left_margin_dim + \dim_add:cn + { l_@@_column _ \int_use:N \g_@@_col_int _ max _ dim } + \g_@@_right_margin_dim +% \end{macrocode} +% Now, we can actually create the ``large nodes''. +% \begin{macrocode} + \tikzset { name~suffix = -large } + \@@_create_nodes: + \end{tikzpicture} +% \end{macrocode} +% +% \medskip +% When used once, the command |\@@_create_extra_nodes:| must become no-op (in +% the current TeX group). That's why we put a nullification of the command. +% \begin{macrocode} + \cs_set:Npn \@@_create_extra_nodes: { } +% \end{macrocode} +% +% \medskip +% We can now compute the width of the array (used by |\hdottedline|). +% \begin{macrocode} + \begin { tikzpicture } [ remember~picture , overlay ] + \tikz@parse@node \pgfutil@firstofone + ( nm - \int_use:N \g_@@_env_int - 1 - 1 - large .north~west ) + \dim_gset:Nn \g_tmpa_dim \pgf@x + \tikz@parse@node \pgfutil@firstofone + ( nm - \int_use:N \g_@@_env_int - 1 - + \int_use:N \g_@@_col_int - large .north~east ) + \dim_gset:Nn \g_tmpb_dim \pgf@x + \end { tikzpicture } + \iow_now:Nn \@mainaux \ExplSyntaxOn + \iow_now:Nx \@mainaux + { + \cs_gset:cpn { @@_width_ \int_use:N \g_@@_env_int } + { \dim_eval:n { \g_tmpb_dim - \g_tmpa_dim } } + } + \iow_now:Nn \@mainaux \ExplSyntaxOff + } +% \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. +% \begin{macrocode} +\cs_new_protected:Nn \@@_create_nodes: + { + \int_step_variable:nnNn \g_@@_first_row_int \g_@@_row_total_int \@@_i: + { + \int_step_variable:nnNn \g_@@_first_col_int \g_@@_col_total_int \@@_j: +% \end{macrocode} +% We create two ponctual nodes for the extremities of a diagonal of the +% rectangular node we want to create. These nodes |(@@~south~west)| and +% |(@@~north~east)| are not available for the user of \pkg{nicematrix}. That's +% why their names are independent of the row and the column. In the two nested +% loops, they will be overwritten until the last cell. +% \begin{macrocode} + { + \coordinate ( @@~south~west ) + at ( \dim_use:c { l_@@_column_ \@@_j: _min_dim } , + \dim_use:c { l_@@_row_ \@@_i: _min_dim } ) ; + \coordinate ( @@~north~east ) + at ( \dim_use:c { l_@@_column_ \@@_j: _max_dim } , + \dim_use:c { l_@@_row_ \@@_i: _max_dim } ) ; +% \end{macrocode} +% We can eventually draw the rectangular node for the cell (|\@@_i|-|\@@_j|). +% This node is created with the Tikz library \pkg{fit}. Don't forget that the +% Tikz option |name suffix| has been set to |-medium| or |-large|. +% \begin{macrocode} + \node + [ + node~contents = { } , + fit = ( @@~south~west ) ( @@~north~east ) , + inner~sep = \c_zero_dim , + name = nm - \int_use:N \g_@@_env_int - \@@_i: - \@@_j: , + alias = + \str_if_empty:NF \g_@@_name_str + { \g_@@_name_str - \@@_i: - \@@_j: } + ] + ; + } + } +% \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} +% +% +% \begin{macrocode} +\cs_new_protected:Npn \@@_extract_coords: #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:Nn \@@_node_for_multicolumn:nn + { + \@@_extract_coords: #1 \q_stop + \coordinate ( @@~south~west ) at + ( + \dim_use:c { l_@@_column _ \@@_j: _ min _ dim } , + \dim_use:c { l_@@_row _ \@@_i: _ min _ dim } + ) ; + \coordinate ( @@~north~east ) at + ( + \dim_use:c { l_@@_column _ \int_eval:n { \@@_j: + #2 - 1 } _ max _ dim} , + \dim_use:c { l_@@_row _ \@@_i: _ max _ dim } + ) ; + \node + [ + node~contents = { } , + fit = ( @@~south~west ) ( @@~north~east ) , + inner~sep = \c_zero_dim , + name = nm - \int_use:N \g_@@_env_int - \@@_i: - \@@_j: , + alias = + \str_if_empty:NF \g_@@_name_str { \g_@@_name_str - \@@_i: - \@@_j: } + ] + ; + } +% \end{macrocode} +% +% +% \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} +\ProcessKeysOptions { NiceMatrix } +% \end{macrocode} +% +% +% \subsection{Code for \textbackslash seq_mapthread_function:NNN} +% +% In |\@@_create_nodes:| (used twice in |\@@_create_extra_nodes:| to create the +% ``medium nodes'' and ``large nodes''), we want to use +% |\seq_mapthread_function:NNN| which is in \pkg{l3candidates}). For security, +% we define a function |\@@_seq_mapthread_function:NNN|. We will delete the +% following code when |\seq_mapthread_function:NNN| will be in \pkg{l3seq}. +% \begin{macrocode} +\cs_new:Npn \@@_seq_mapthread_function:NNN #1 #2 #3 + { + \group_begin: +% \end{macrocode} +% In the group, we can use |\seq_pop:NN| safely. +% \begin{macrocode} + \int_step_inline:nn { \seq_count:N #1 } + { + \seq_pop:NN #1 \l_tmpa_tl + \seq_pop:NN #2 \l_tmpb_tl + \exp_args:NVV #3 \l_tmpa_tl \l_tmpb_tl + } + \group_end: + } +% \end{macrocode} +% +% \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} +% +% +% +% \subsection{Obsolete environments} +% +% \begin{macrocode} +\NewDocumentEnvironment { pNiceArrayC } { } + { + \bool_set_true:N \l_@@_last_col_bool + \pNiceArray + } + { \endpNiceArray } +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment { bNiceArrayC } { } + { + \bool_set_true:N \l_@@_last_col_bool + \bNiceArray + } + { \endbNiceArray } +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment { BNiceArrayC } { } + { + \bool_set_true:N \l_@@_last_col_bool + \BNiceArray + } + { \endBNiceArray } +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment { vNiceArrayC } { } + { + \bool_set_true:N \l_@@_last_col_bool + \vNiceArray + } + { \endvNiceArray } +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment { VNiceArrayC } { } + { + \bool_set_true:N \l_@@_last_col_bool + \VNiceArray + } + { \endVNiceArray } +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment { pNiceArrayRC } { } + { + \bool_set_true:N \l_@@_last_col_bool + \int_set:Nn \l_@@_first_row_int \c_zero_int + \pNiceArray + } + { \endpNiceArray } +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment { bNiceArrayRC } { } + { + \bool_set_true:N \l_@@_last_col_bool + \int_set:Nn \l_@@_first_row_int \c_zero_int + \bNiceArray + } + { \endbNiceArray } +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment { BNiceArrayRC } { } + { + \bool_set_true:N \l_@@_last_col_bool + \int_set:Nn \l_@@_first_row_int \c_zero_int + \BNiceArray + } + { \endBNiceArray } +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment { vNiceArrayRC } { } + { + \bool_set_true:N \l_@@_last_col_bool + \int_set:Nn \l_@@_first_row_int \c_zero_int + \vNiceArray + } + { \endvNiceArray } +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment { VNiceArrayRC } { } + { + \bool_set_true:N \l_@@_last_col_bool + \int_set:Nn \l_@@_first_row_int \c_zero_int + \VNiceArray + } + { \endVNiceArray } +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment { NiceArrayCwithDelims } { } + { + \bool_set_true:N \l_@@_last_col_bool + \NiceArrayWithDelims + } + { \endNiceArrayWithDelims } +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment { NiceArrayRCwithDelims } { } + { + \bool_set_true:N \l_@@_last_col_bool + \int_set:Nn \l_@@_first_row_int \c_zero_int + \NiceArrayWithDelims + } + { \endNiceArrayWithDelims } +% \end{macrocode} +% +% +% +% \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''. New names are in lowercase and hyphens (but backward compatibility is +% kept). +% +% +% \subsection*{Changes between version 1.3 and 1.4} +% +% The column types |w| and |W| can now be used in the environments +% |{NiceArray}|, |{pNiceArrayC}| and its variants with the same meaning as in +% the package \pkg{array}. +% +% New option |columns-width| to fix the same width for all the columns of the +% array. +% +% +% \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 +% extension \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 column |C|), the cells in the column |C| 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{pNiceArrayRC}{Wc{5mm}CWc{5mm}} +% & C_j & \\ +% \mbox{\Large $0$} & \Vdots & \mbox{\Large $0$} \\ +% & \strut a & \Cdots & L_i \\ +% \mbox{\Large $0$} & & \mbox{\Large $0$} \\ +% \end{pNiceArrayRC}\] +% +% \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 |https://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.2.1 and 2.3} +% +% Modification of |\Hdotsfor|. Now |\Hdotsfor| erases the |\vlines| (of ``"|"'') +% as |\hdotsfor| does. +% +% \subsection*{Changes between version 2.3 and 3.0} +% +% Composition of exterior rows and columns of the four sides of the matrix (and +% not only on two sides) with the options |first-row|, |last-row|, |first-col| +% and |last-col|. +% +% \PrintIndex +% +% \tableofcontents +% \endinput +% Local Variables: +% TeX-fold-mode: nil +% fill-column: 80 +% End: diff --git a/macros/latex/contrib/nicematrix/nicematrix.ins b/macros/latex/contrib/nicematrix/nicematrix.ins new file mode 100644 index 0000000000..316530c421 --- /dev/null +++ b/macros/latex/contrib/nicematrix/nicematrix.ins @@ -0,0 +1,47 @@ +%% +%% Copyright (C) 2017-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. +%% +\input l3docstrip.tex +\keepsilent +\usedir{tex/latex/nicematrix} +\preamble + +Copyright (C) 2017-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. + +\endpreamble +\generate{\file{nicematrix.sty}{\from{nicematrix.dtx}{package}}} +\Msg{*********************************************************} +\Msg{*} +\Msg{* To finish the installation you have to move the} +\Msg{* following file into a directory searched by TeX:} +\Msg{*} +\Msg{* \space\space nicematrix.sty} +\Msg{*} +\Msg{* To produce the documentation run the file nicematrix.dtx} +\Msg{* through XeLaTeX.} +\Msg{*} +\Msg{* Happy TeXing!} +\Msg{*********************************************************} +\endbatchfile + diff --git a/macros/latex/contrib/nicematrix/nicematrix.pdf b/macros/latex/contrib/nicematrix/nicematrix.pdf new file mode 100644 index 0000000000..3574573505 Binary files /dev/null and b/macros/latex/contrib/nicematrix/nicematrix.pdf differ -- cgit v1.2.3