From 1bf53a1df338cff0bfd274cd81f5fe2c4b64ad6e Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Wed, 14 Feb 2018 00:06:17 +0000 Subject: nicematrix (13feb18) git-svn-id: svn://tug.org/texlive/trunk@46627 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/doc/latex/nicematrix/README.md | 9 + .../texmf-dist/doc/latex/nicematrix/nicematrix.pdf | Bin 0 -> 139518 bytes .../source/latex/nicematrix/nicematrix.dtx | 1487 ++++++++++++++++++++ .../source/latex/nicematrix/nicematrix.ins | 47 + .../texmf-dist/tex/latex/nicematrix/nicematrix.sty | 386 +++++ Master/tlpkg/bin/tlpkg-ctan-check | 2 +- Master/tlpkg/tlpsrc/collection-mathscience.tlpsrc | 1 + Master/tlpkg/tlpsrc/nicematrix.tlpsrc | 0 8 files changed, 1931 insertions(+), 1 deletion(-) create mode 100644 Master/texmf-dist/doc/latex/nicematrix/README.md create mode 100644 Master/texmf-dist/doc/latex/nicematrix/nicematrix.pdf create mode 100644 Master/texmf-dist/source/latex/nicematrix/nicematrix.dtx create mode 100644 Master/texmf-dist/source/latex/nicematrix/nicematrix.ins create mode 100644 Master/texmf-dist/tex/latex/nicematrix/nicematrix.sty create mode 100644 Master/tlpkg/tlpsrc/nicematrix.tlpsrc (limited to 'Master') diff --git a/Master/texmf-dist/doc/latex/nicematrix/README.md b/Master/texmf-dist/doc/latex/nicematrix/README.md new file mode 100644 index 00000000000..8aefad15a5a --- /dev/null +++ b/Master/texmf-dist/doc/latex/nicematrix/README.md @@ -0,0 +1,9 @@ +The LaTeX extension nicematrix is distributed under the LPPL 1.3 license. + +This extension has been written by F. Pantigny (fpantigny@wanadoo.fr). + +This extension is entirely contained in a single file : nicematrix.sty + +The LaTeX package nicematrix gives an environment NiceMatrix which is similar to environment +matrix of mathtools but gives the possibility to draw beautiful ellipis dots between the cells +of the matrix. \ No newline at end of file diff --git a/Master/texmf-dist/doc/latex/nicematrix/nicematrix.pdf b/Master/texmf-dist/doc/latex/nicematrix/nicematrix.pdf new file mode 100644 index 00000000000..0f80f3f17d4 Binary files /dev/null and b/Master/texmf-dist/doc/latex/nicematrix/nicematrix.pdf differ diff --git a/Master/texmf-dist/source/latex/nicematrix/nicematrix.dtx b/Master/texmf-dist/source/latex/nicematrix/nicematrix.dtx new file mode 100644 index 00000000000..bead31a579d --- /dev/null +++ b/Master/texmf-dist/source/latex/nicematrix/nicematrix.dtx @@ -0,0 +1,1487 @@ +% \iffalse meta-comment +% +% Copyright (C) 2017 by F. Pantigny +% ----------------------------------- +% +% This file may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3 +% of this license or (at your option) any later version. +% The latest version of this license is in: +% +% http://www.latex-project.org/lppl.txt +% +% and version 1.3 or later is part of all distributions of LaTeX +% version 2005/12/01 or later. +% +% \fi +% \iffalse +\def\myfileversion{1.0} +\def\myfiledate{2018/02/13} +% +% +%<*batchfile> +\begingroup +\input l3docstrip.tex +\keepsilent +\usedir{tex/latex/nicematrix} +\preamble + +Copyright (C) 2017 by F. Pantigny +----------------------------------- + +This file may be distributed and/or modified under the +conditions of the LaTeX Project Public License, either version 1.3 +of this license or (at your option) any later version. +The latest version of this license is in: + +http://www.latex-project.org/lppl.txt + +and version 1.3 or later is part of all distributions of LaTeX +version 2005/12/01 or later. + +\endpreamble +\askforoverwritefalse +\endgroup +% +% +%<@@=nm> +%<*driver> +\documentclass{l3doc} % load fancyvrb, amsmath, array, color, etc. +\VerbatimFootnotes +\usepackage{xltxtra} +\usepackage{lmodern} +\usepackage{geometry} +\usepackage[dvipsnames]{xcolor} % color is already loaded with l3doc (?) +\geometry{left=2.8cm,right=2.8cm,top=2.5cm,bottom=2.5cm,papersize={21cm,29.7cm}} +\usepackage{mathtools} +\usepackage{amsfonts} +\usepackage{stmaryrd} +\usepackage{nicematrix} +\NewDocumentEnvironment {scope} {} {} {} +\def\interitem{\vskip 7mm plus 2 mm minus 3mm} +\def\emphase#1{{\color{RoyalPurple}#1}} +\fvset{commandchars=\~\#\@,formatcom={\color{gray}}} +\parindent 0pt +\DisableCrossrefs +\begin{document} +\DocInput{nicematrix.dtx} +\end{document} +% +% \fi +% \title{The package \pkg{nicematrix}\thanks{This document corresponds to the version~\myfileversion\space of \pkg{nicematrix}, +% at the date of~\myfiledate.}} \author{F. Pantigny \\ \texttt{fpantigny@wanadoo.fr}} +% +% \maketitle +% +% \begin{abstract} +% The LaTeX package \pkg{nicematrix} gives an environment |{NiceMatrix}| which is similar to the environment +% |{matrix}| but gives the possibility to draw ellipis dots between the cells of the matrix. +% \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 compilations may be necessary. This package requires the +% packages \pkg{expl3}, \pkg{l3keys2e}, \pkg{xparse}, \pkg{array}, \pkg{mathtools} and \pkg{tikz}. The Tikz +% libraries \pkg{calc} and \pkg{math} are also required. +% +% \medskip +% The package \pkg{nicematrix} aims to draw beautiful matrices in a way almost transparent for the user. +% +% \medskip +% Consider, for exemple, the matrix\enskip +% $A = \begin{pmatrix} +% 1 &\cdots &\cdots &1 \\ +% 0 &\ddots & &\vdots \\ +% \vdots &\ddots &\ddots &\vdots \\ +% 0 &\cdots &0 &1 +% \end{pmatrix}$ +% +% \medskip +% Usually, when using LaTeX and \pkg{amsmath} (or \pkg{mathtools}), such a matrix is composed with an environment +% |{pmatrix}| and the following code: +% \begin{Verbatim} +% $A = \begin{pmatrix} +% 1 & \cdots & \cdots & 1 \\ +% 0 & \ddots & & \vdots \\ +% \vdots & \ddots & \ddots & \vdots \\ +% 0 & \cdots & 0 & 1 +% \end{pmatrix}$ +% \end{Verbatim} +% +% \medskip +% If we load the package \pkg{nicematrix} with the option |Transparent|, the same code will give the +% following result: +% +% \begin{scope} +% \NiceMatrixOptions{Transparent} +% \[A = \begin{pmatrix} +% 1 & \cdots & \cdots & 1 \\ +% 0 & \ddots & & \vdots \\ +% \vdots & \ddots & \ddots & \vdots \\ +% 0 & \cdots & 0 & 1 +% \end{pmatrix}\] +% \end{scope} +% +% \medskip +% The dotted lines are drawn with Tikz. Two compilations may be necessary. +% +% +% \section{How to use nicematrix for new code} +% +% \subsection{The environment NiceMatrix and its variants} +% +% The package \pkg{nicematrix} gives six new environments |{NiceMatrix}|, |{pNiceMatrix}|, |{bNiceMatrix}|, +% |{BNiceMatrix}|, |{vNiceMatrix}| and |{VNiceMatrix}|. By default, these environments behave almost exactly as the +% corresponding environments of \pkg{amsmath} (and \pkg{mathtools}): |{matrix}|, |{pmatrix}|, |{bmatrix}|, +% |{Bmatrix}|, |{vmatrix}| and |{Vmatrix}|. +% +% \smallskip +% Inside these environments, five new commands are defined: |\Ldots|, |\Cdots|, |\Vdots|, |\Ddots| and |\Iddots|. +% These commands are intended to be used in place of |\dots|, |\cdots|, |\vdots|, |\ddots| and +% |\iddots|.\footnote{The command |\iddots|, defined in \pkg{nicematrix}, is a variant of +% |\ddots| with dots going forward: \smash{$\iddots$}. If |mathdots| is loaded, the version of |mathdots| is used.} +% +% \smallskip +% Each of them must be used alone in the cell of the array and it draws a dotted line between the first non-empty +% cells\footnote{The precise definition of a ``non-empty cell'' is given below.} on both sides of the current cell. +% Of course, for |\Ldots| and |\Cdots|, it's an horizontal line; for |\Vdots|, it's a vertical line and for +% |\Ddots| and |\Iddots| diagonals ones.\par\nobreak +% \bigskip +% \begin{BVerbatim}[baseline=c,boxwidth=10cm] +% \begin{bNiceMatrix} +% a_1 & \Cdots & & & a_1 \\ +% \Vdots & a_2 & \Cdots & & a_2 \\ +% & \Vdots & \Ddots \\ +% \\ +% a_1 & a_2 & & & a_n \\ +% \end{bNiceMatrix} +% \end{BVerbatim} +% $\begin{bNiceMatrix} +% a_1 & \Cdots & & & a_1 \\ +% \Vdots & a_2 & \Cdots & & a_2 \\ +% & \Vdots & \Ddots \\ +% \\ +% a_1 & a_2 & & & a_n \\ +% \end{bNiceMatrix}$ +% +% \interitem +% In order to represent the null matrix, one can use the following codage:\par\nobreak +% \bigskip +% \begin{BVerbatim}[baseline=c,boxwidth=10cm] +% \begin{bNiceMatrix} +% 0 & \Cdots & 0 \\ +% \Vdots & & \Vdots \\ +% 0 & \Cdots & 0 +% \end{bNiceMatrix} +% \end{BVerbatim} +% $\begin{bNiceMatrix} +% 0 & \Cdots & 0 \\ +% \Vdots & & \Vdots \\ +% 0 & \Cdots & 0 +% \end{bNiceMatrix}$ +% +% \bigskip +% However, one may want a larger matrix. Usually, in such a case, the users of LaTeX add a new row and a new +% column. It's possible to use the same method with \pkg{nicematrix}:\par\nobreak +% \bigskip +% \begin{BVerbatim}[baseline=c,boxwidth=10cm] +% \begin{bNiceMatrix} +% 0 & \Cdots & \Cdots & 0 \\ +% \Vdots & & & \Vdots \\ +% \Vdots & & & \Vdots \\ +% 0 & \Cdots & \Cdots & 0 +% \end{bNiceMatrix} +% \end{BVerbatim} +% $\begin{bNiceMatrix} +% 0 & \Cdots & \Cdots & 0 \\ +% \Vdots & & & \Vdots \\ +% \Vdots & & & \Vdots \\ +% 0 & \Cdots & \Cdots & 0 +% \end{bNiceMatrix}$ +% +% \bigskip +% In the first column of this exemple, there are two instructions |\Vdots| but only one dotted line is drawn (there +% is no overlapping graphic objects in the resulting \textsc{pdf}). +% +% However, useless computations are performed by TeX before detecting that both instructions would eventually yield +% the same dotted line. That's why the package \pkg{nicematrix} provides starred versions of |\Ldots|, |\Cdots|, +% etc.: |\Ldots*|, |\Cdots*|, etc.. These versions are simply equivalent to |\hphantom{\ldots}|, +% |\hphantom{\cdots}|, etc. The user should use these starred versions whenever a classical version has already +% been used for the same dotted line.\par\nobreak +% \bigskip +% \begin{BVerbatim}[baseline=c,boxwidth=10cm] +% \begin{bNiceMatrix} +% 0 & \Cdots & ~emphase#\Cdots*@ & 0 \\ +% \Vdots & & & \Vdots \\ +% ~emphase#\Vdots*@ & & & ~emphase#\Vdots*@ \\ +% 0 & \Cdots & ~emphase#\Cdots*@ & 0 +% \end{bNiceMatrix} +% \end{BVerbatim} +% $\begin{bNiceMatrix} +% 0 & \Cdots & & 0 \\ +% \Vdots & & & \\ +% & & & \Vdots \\ +% 0 & & \Cdots & 0 +% \end{bNiceMatrix}$ +% +% \bigskip +% In fact, in this example, it would be possible to draw the same matrix without starred commands with the +% following code:\par\nobreak +% \bigskip +% \begin{BVerbatim}[baseline=c,boxwidth=10cm] +% \begin{bNiceMatrix} +% 0 & \Cdots & & 0 \\ +% \Vdots & & & \\ +% & & & \Vdots \\ +% 0 & & \Cdots & 0 +% \end{bNiceMatrix} +% \end{BVerbatim} +% $\begin{bNiceMatrix} +% 0 & \Cdots & & 0 \\ +% \Vdots & & & \\ +% & & & \Vdots \\ +% 0 & & \Cdots & 0 +% \end{bNiceMatrix}$ +% +% \bigskip +% There are also other means to change the size of the matrix. Someone might want to use the optional argument of +% the command~|\\| for the vertical dimension and a command~|\hspace*| in a cell for the horizontal dimension. +% However, a command~|\hspace*| might interfer with the construction of the dotted lines. That's why the package +% \pkg{nicematrix} provides a command~|\Hspace| which is a variant of |\hspace| transparent for the dotted lines of +% \pkg{nicematrix}.\par\nobreak +% \bigskip +% \begin{BVerbatim}[baseline=c,boxwidth=10cm] +% \begin{bNiceMatrix} +% 0 & \Cdots & ~emphase#\Hspace*{1cm}@ & 0 \\ +% \Vdots & & & \Vdots \\~emphase#[1cm]@ +% 0 & \Cdots & & 0 +% \end{bNiceMatrix} +% \end{BVerbatim} +% $\begin{bNiceMatrix} +% 0 & \Cdots & \Hspace*{1cm} & 0 \\ +% \Vdots & & & \Vdots \\[1cm] +% 0 & \Cdots & & 0 +% \end{bNiceMatrix}$ +% +% \vskip1cm +% \subsection{The option NullifyDots} +% +% Consider the following matrix composed classicaly with the environment |{pmatrix}|.\par\nobreak +% \medskip +% \begin{BVerbatim}[baseline=c,boxwidth=7cm] +% $A = \begin{pmatrix} +% a_0 & b \\ +% a_1 & \\ +% a_2 & \\ +% a_3 & \\ +% a_4 & \\ +% a_5 & b +% \end{pmatrix}$ +% \end{BVerbatim} +% $A = \begin{pmatrix} +% a_0 & b \\ +% a_1 & \\ +% a_2 & \\ +% a_3 & \\ +% a_4 & \\ +% a_5 & b +% \end{pmatrix}$ +% +% +% \bigskip +% If we add |\vdots| instructions in the second column, the geometry of the matrix is modified.\par\nobreak +% \medskip +% \begin{BVerbatim}[baseline=c,boxwidth=7cm] +% $B = \begin{pmatrix} +% a_0 & b \\ +% a_1 & \vdots \\ +% a_2 & \vdots \\ +% a_3 & \vdots \\ +% a_4 & \vdots \\ +% a_5 & b +% \end{pmatrix}$ +% \end{BVerbatim} +% $B = \begin{pmatrix} +% a_0 & b \\ +% a_1 & \vdots \\ +% a_2 & \vdots \\ +% a_3 & \vdots \\ +% a_4 & \vdots \\ +% a_5 & b +% \end{pmatrix}$ +% +% \bigskip +% By default, with \pkg{nicematrix}, if we replace |{pmatrix}| by |{pNiceMatrix}| and |\vdots| by +% |\Vdots| (or |\Vdots*| for efficiency), the geometry of the matrix is not changed.\par\nobreak +% \medskip +% \begin{BVerbatim}[baseline=c,boxwidth=7cm] +% $C = \begin{pNiceMatrix} +% a_0 & b \\ +% a_1 & \Vdots \\ +% a_2 & \Vdots* \\ +% a_3 & \Vdots* \\ +% a_4 & \Vdots* \\ +% a_5 & b +% \end{pNiceMatrix}$ +% \end{BVerbatim} +% $C = \begin{pNiceMatrix} +% a_0 & b \\ +% a_1 & \Vdots \\ +% a_2 & \Vdots* \\ +% a_3 & \Vdots* \\ +% a_4 & \Vdots* \\ +% a_5 & b +% \end{pNiceMatrix}$ +% +% \bigskip +% However, one may prefer the geometry of the first matrix $A$ and would like to have such a geometry with a dotted +% line in the second column. It's possible by using the option |NullifyDots| (and only one instruction |\Vdots| is +% necessary).\par\nobreak +% \medskip +% \begin{BVerbatim}[baseline=c,boxwidth=7cm] +% ~emphase#\NiceMatrixOptions{NullifyDots}@ +% $D = \begin{pNiceMatrix} +% a_0 & b \\ +% a_1 & \Vdots \\ +% a_2 & \\ +% a_3 & \\ +% a_4 & \\ +% a_5 & b +% \end{pNiceMatrix}$ +% \end{BVerbatim} +% {\NiceMatrixOptions{NullifyDots} +% $D = \begin{pNiceMatrix} +% a_0 & b \\ +% a_1 & \Vdots \\ +% a_2 & \\ +% a_3 & \\ +% a_4 & \\ +% a_5 & b +% \end{pNiceMatrix}$} +% +% \medskip +% The option |NullifyDots| smashes the instructions |\Ldots| (and the variants) vertically but also horizontally. +% +% \section{How to use nicematrix for existing code} +% +% The package \pkg{nicematrix} provides an option called |Transparent| for using existing code transparently (this +% option --- and the others --- can be set with the |\usepackage| command but \pkg{nicematrix} provides also a +% dedicated command called |\NiceMatrixOptions|). +% +% In fact, this option is an alias for the conjonction of two options : |RenewDots| and |RenewMatrix|. +% +% \smallskip +% +% \begin{itemize} +% \item The option |RenewDots|\par\nobreak +% With this option, the commands |\ldots|, |\cdots|, |\vdots|, |\ddots| and |\iddots|\footnote{The command +% |\iddots| is not a command of LaTeX but is defined by the package \pkg{nicematrix}. If |mathdots| is loaded, the +% version of |mathdots| is used.} are redefined within the environments |{NiceMatrix}| and behave like |\Ldots|, +% |\Cdots|, |\Vdots|, |\Ddots| and |\Iddots|; the command |\dots| (``automatic dots'' of |amsmath| --- and +% |mathtools|) is also redefined to behave like |\Ldots|. +% +% \item The option |RenewMatrix|\par\nobreak +% With this option, the environment |{matrix}| is redefined and behave like |{NiceMatrix}|, and so on for the five +% variants. +% \end{itemize} +% +% \bigskip +% Therefore, with the option |Transparent|, a classical code gives directly the ouput of \pkg{nicematrix}.\par\nobreak +% \bigskip +% \begin{BVerbatim}[baseline=c] +% ~emphase#\NiceMatrixOptions{Transparent}@ +% \begin{pmatrix} +% 1 & \cdots & \cdots & 1 \\ +% 0 & \ddots & & \vdots \\ +% \vdots & \ddots & \ddots & \vdots \\ +% 0 & \cdots & 0 & 1 +% \end{pmatrix} +% \end{BVerbatim} +% \hspace{2cm} +% \begin{scope} +% \NiceMatrixOptions{Transparent} +% $\begin{pmatrix} +% 1 & \cdots & \cdots & 1 \\ +% 0 & \ddots & & \vdots \\ +% \vdots & \ddots & \ddots & \vdots \\ +% 0 & \cdots & 0 & 1 +% \end{pmatrix}$ +% \end{scope} +% +% +% \section{Technical remarks} +% +% \subsection{Diagonal lines} +% +% By default, all the diagonal lines of a same matrix 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 matrix 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{ParallelizeDiagonals=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 |ParallelizeDiagonals| set to |false|: \par\nobreak +% +% \medskip +% \NiceMatrixOptions{ParallelizeDiagonals=false}% +% \begin{minipage}{9.5cm} +% The same example without parallelization:\\ +% |\NiceMatrixOptions{ParallelizeDiagonals=false}|. +% \end{minipage} +% $A = \begin{pNiceMatrix} +% 1 & \Cdots & & 1 \\ +% a+b & \Ddots & & \Vdots \\ +% \Vdots & \Ddots & & \\ +% a+b & \Cdots & a+b & 1 +% \end{pNiceMatrix}$ +% +% +% \end{scope} +% +% \vskip1cm +% \subsection{The ``empty'' cells} +% +% An instruction like |\Ldots|, |\Cdots|, etc. tries to determine the first non-empty cell on both sides. However, +% a empty cell is not necessarily a cell with no TeX content (that is to say a cell with no token between the two +% ampersands~|&|). Indeed, a cell with contents |\hspace*{1cm}| may be considered as empty. +% +% \interitem +% For \pkg{nicematrix}, the precise rules are as follow. +% +% \begin{itemize} +% \item An implicit cell is empty. For example, in the following matrix: +% +% \begin{Verbatim} +% \begin{pmatrix} +% a & b \\ +% c \\ +% \end{pmatrix} +% \end{Verbatim} +% +% the last cell (second row and second column) is empty. +% +% \medskip +% \item Each cell whose TeX ouput has a width less than 0.5~pt is empty. +% +% \medskip +% \item A cell which contains a command |\Ldots|, |\Cdots|, |\Vdots|, |\Ddots| or |\Iddots| and their starred +% versions is empty. We recall that theses commands should be used alone in a cell. +% +% \medskip +% \item A cell with a command |\Hspace| (or |\Hspace*|) is empty. This command |\Hspace| is a command defined by +% the package \pkg{nicematrix} with the same meaning that |\hspace| except that the cell where it is used is +% considered as empty. This command can be used to fix the width of some columns of the matrix without interfering +% with \pkg{nicematrix}. +% % \end{itemize} +% +% \interitem +% A dotted line must be delimited by two non-empty cells. If it's not possible to find one of these cells whitin +% the boudaries of the matrix, an error is issued and the instruction is ignored. +% +% +% +% \section{Examples} +% +% +% \bigskip +% A tridiagonal matrix : +% +% \bigskip +% \begin{BVerbatim}[baseline=c] +% \NiceMatrixOptions{NullifyDots} +% $\begin{pNiceMatrix} +% 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{scope} +% \NiceMatrixOptions{NullifyDots} +% $\begin{pNiceMatrix} +% 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{scope} +% +% \vspace{2cm} +% +% A permutation matrix : +% +% \bigskip +% \begin{BVerbatim}[baseline=c] +% $\begin{pNiceMatrix} +% 0 & 1 & 0 & & \Cdots & 0 \\ +% \Vdots & & & \Ddots & & \Vdots \\ +% & & & \Ddots & & \\ +% & & & \Ddots & & 0 \\ +% 0 & 0 & & & & 1 \\ +% 1 & 0 & & \Cdots & & 0 +% \end{pNiceMatrix}$ +% \end{BVerbatim} +% \hspace{2.5cm} +% $\begin{pNiceMatrix} +% 0 & 1 & 0 & & \Cdots & 0 \\ +% \Vdots & & & \Ddots & & \Vdots \\ +% & & & \Ddots & & \\ +% & & & \Ddots & & 0 \\ +% 0 & 0 & & & & 1 \\ +% 1 & 0 & & \Cdots & & 0 +% \end{pNiceMatrix}$ +% +% \vspace{2cm} +% +% An example with |\Iddots|: +% +% \bigskip +% \begin{BVerbatim}[baseline=c] +% $\begin{pNiceMatrix} +% 1 & \Cdots & & 1 \\ +% \Vdots & & & 0 \\ +% & ~emphase#\Iddots@ & ~emphase#\Iddots@ & \Vdots \\ +% 1 & 0 & \Cdots & 0 +% \end{pNiceMatrix}$ +% \end{BVerbatim} +% \hspace{4cm} +% $\begin{pNiceMatrix} +% 1 & \Cdots & & 1 \\ +% \Vdots & & & 0 \\ +% & \Iddots & \Iddots & \Vdots \\ +% 1 & 0 & \Cdots & 0 +% \end{pNiceMatrix}$ +% +% +% +% \vspace{1cm} +% +% \section{Implementation} +% +% \subsection{Declaration of the package and extensions loaded} +% +% +% First, Tikz and the Tikz libraries \pkg{calc} and \pkg{math} 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} +\RequirePackage{tikz} +\usetikzlibrary{calc,math} +% \end{macrocode} +% +% \bigskip +% Then, we can give the traditionnal declaration of a package written with |expl3|: +% \begin{macrocode} +\RequirePackage{l3keys2e} +\ProvidesExplPackage + {nicematrix} + {\myfiledate} + {\myfileversion} + {Draws nice dotted lines in matrix environments} +% \end{macrocode} +% +% The command for the treatment of the options of |\usepackage| is at the end of this package for technical reasons. +% +% \bigskip +% We load \pkg{array} and \pkg{mathtools} (\pkg{mathtools} may be considered as the successor of \pkg{amsmath}). +% \begin{macrocode} +\RequirePackage{array} +\RequirePackage{mathtools} +% \end{macrocode} +% +% \bigskip +% The package \pkg{xparse} will be used to define the environment |{NiceMatrix}|, its variants and the +% document-level commands (|\NiceMatrixOptions|, etc.). +% \begin{macrocode} +\RequirePackage{xparse} +% \end{macrocode} +% +% \bigskip +% \subsection{Technical definitions} +% +% First, we define a command |\iddots| similar to |\ddots| ($\ddots$) but with dots going forward ($\iddots$). We +% use |\ProvideDocumentCommand|, and so, if the command |\iddots| has already been defined (for example by the +% package \pkg{mathdots}), we don't define it again. +% +% \begin{macrocode} +\ProvideDocumentCommand \iddots {} + {\mathinner{\mkern 1mu + \raise 1pt \hbox{.} + \mkern 2mu + \raise 4pt\hbox{.} + \mkern 2mu + \raise7pt \vbox{\kern 7pt + \hbox{.}} + \mkern1mu}} +% \end{macrocode} +% +% This definition is a variant of the standard definition of |\ddots|. +% +% \bigskip +% In the environment |{NiceMatrix}|, the command |\multicolumn| will be linked to the following command +% |\@@_multicolumn:| but only if the option |RenewMatrix| is not set. Indeed, if the option |RenewMatrix| is used, +% we want to let the possibility to the user to use |\multicolumn| (or |\hdotsfor| of \pkg{amsmath}) in some +% matrices without dotted lines and to have the automatic dotted lines of \pkg{nicematrix} in other matrices. +% \begin{macrocode} +\cs_new_protected:Nn \@@_multicolumn:nn + {\msg_error:nn {nicematrix} {multicolumn~forbidden}} +% \end{macrocode} +% This command |\@@_multicolumn:nn| takes two arguments, and therefore, the first two arguments of |\column| will +% be gobbled. +% +% \bigskip +% The following counter will count the environments |{NiceMatrix}|. The value of this counter will be used to +% prefix the names of the Tikz nodes created in the matrix. +% \begin{macrocode} +\int_new:N \g_@@_env_int +% \end{macrocode} +% +% \bigskip +% \subsection{The options} +% +% The flag |\l_@@_parallelize_diags_bool| controls wether the diagonals are parallelized. The default +% is~|true|. +% \begin{macrocode} +\bool_new:N \l_@@_parallelize_diags_bool +\bool_set_true:N \l_@@_parallelize_diags_bool +% \end{macrocode} +% +% \bigskip +% The flag |\l_@@_nullify_dots_bool| corresponds to the option |NullifyDots|. When the flag is down, the +% instructions like |\vdots| are inserted within a |\hphantom| (and so the constructed matrix has exactly the same +% size as a matrix constructed with the classical |{matrix}| and |\ldots|, |\vdots|, etc.) +% \begin{macrocode} +\bool_new:N \l_@@_nullify_dots_bool +% \end{macrocode} +% +% \bigskip +% The flag |\l_@@_renew_matrix_bool| will be raised if the option |RenewMatrix| is used. +% \begin{macrocode} +\bool_new:N \l_@@_renew_matrix_bool +% \end{macrocode} +% +% \bigskip +% We define a set of options which will be used with the command |NiceMatrixOptions|. +% \begin{macrocode} +\keys_define:nn {NiceMatrix} + {ParallelizeDiagonals .bool_set:N = \l_@@_parallelize_diags_bool, + ParallelizeDiagonals .default:n = true, +% \end{macrocode} +% +% \bigskip +% With the option |RenewDots|, the command |\cdots|, |\ldots|, |\vdots| and |\ddots| are redefined and behave like the +% commands |\Cdots|, |\Ldots|, |\Vdots| and |\Ddots|. +% \begin{macrocode} + RenewDots .bool_set:N = \l_@@_renew_dots_bool, + RenewDots .default:n = true, +% \end{macrocode} +% +% \bigskip +% With the option |RenewMatrix|, the environment |{matrix}| of \pkg{amsmath} and its variants are redefined to +% behave like the environment |{NiceMatrix}| and its variants. +% \begin{macrocode} + RenewMatrix .code:n = {\cs_set_eq:NN \env@matrix \NiceMatrix + \bool_set_true:N \l_@@_renew_matrix_bool}, + RenewMatrix .default:n = true, + Transparent .meta:n = {RenewDots,RenewMatrix}, + Transparent .value_forbidden:n = true, +% \end{macrocode} +% +% \bigskip +% Without the option |NullifyDots|, the instructions like |\vdots| are inserted within a +% |\hphantom| (and so the constructed matrix has exactly the same size as a matrix constructed with the +% classical |{matrix}| and |\ldots|, |\vdots|, etc.). This option is set by default. +% \begin{macrocode} + NullifyDots .bool_set:N = \l_@@_nullify_dots_bool , + NullifyDots .default:n = true} +% \end{macrocode} +% +% \bigskip +% |\NiceMatrixOptions| is the command of the \pkg{nicematrix} package to fix options at the document level. The +% scope of these specification is the current TeX group. +% \begin{macrocode} +\NewDocumentCommand \NiceMatrixOptions {m} + {\keys_set:nn {NiceMatrix} {#1}} +% \end{macrocode} +% +% \bigskip +% \subsection{The main functions} +% +% The pseudo-environment |\@@_Cell:|--|\@@_end_Cell:| is used to format the cells of the array (except the cells of +% the first column: see below). +% \begin{macrocode} +\cs_new_protected:Nn \@@_Cell: + { +% \end{macrocode} +% We increment |\g_@@_column_int|, which is the counter of the columns. We need a global affectation because this +% command will be used in the cell of a |\halign| (via an environment |{array}|). +% \begin{macrocode} + \int_gincr:N \g_@@_column_int +% \end{macrocode} +% At the end of the array, the counter |\g_@@_nb_column_int| will contain the total number of columns of the array +% (even if all the lines don't have the same number of ampersands). +% \begin{macrocode} + \int_gset:Nn \g_@@_nb_column_int {\int_max:nn \g_@@_nb_column_int \g_@@_column_int} +% \end{macrocode} +% We create a Tikz node for the current cell of the array. +% \begin{macrocode} + \tikz[remember~picture, inner~sep = 0pt, minimum~width = 0pt, baseline] + \node [anchor=base] (nm-\int_use:N \g_@@_env_int- + \int_use:N \g_@@_line_int- + \int_use:N \g_@@_column_int) + \bgroup $} % $ +% \end{macrocode} +% +% \begin{macrocode} +\cs_new_protected:Nn \@@_end_Cell: + {$\egroup ;} % $ +% \end{macrocode} +% +% \interitem +% The pseudo-environment |\@@_Cell_First_Column:|--|\@@_end_Cell:| is used to format the cells of the first column +% of the array. For such a column, we have to increment the counter of the lines (|\g_@@_line_int|) and to +% initialize the counter of the columns (|\g_@@_column_int|). +% \begin{macrocode} +\cs_new_protected:Nn \@@_Cell_First_Column: + {\int_gincr:N \g_@@_line_int + \int_gset:Nn \g_@@_column_int 0 + \@@_Cell:} +% \end{macrocode} +% +% +% \interitem +% The environment |{NiceMatrix}| is the main environment of the package |nicematrix|. This environment creates an +% array similar to the array created by the environment |{matrix}| of \pkg{amsmath} but with Tikz nodes for each +% cell of the matrix. +% \begin{macrocode} +\NewDocumentEnvironment {NiceMatrix} {} + { +% \end{macrocode} +% We use a |\aftergroup| to execute |\@@_draw_lines| at the end of the environment (all the LaTeX environments are +% TeX groups). With this technic, the second part of the environment is the same that the second part of the +% environment |{matrix}| of \pkg{amsmath}. Therefore, it's easier to redefine the environment |{matrix}| (when the +% option |RenewMatrix| is used). +% \begin{macrocode} + \aftergroup \@@_draw_lines: +% \end{macrocode} +% +% The commands |\Ldots|, |\Cdots|, etc. will be defined only within the environment |{NiceMatrix}|. +% \begin{macrocode} + \cs_set_eq:NN \Ldots \@@_Ldots + \cs_set_eq:NN \Cdots \@@_Cdots + \cs_set_eq:NN \Vdots \@@_Vdots + \cs_set_eq:NN \Ddots \@@_Ddots + \cs_set_eq:NN \Iddots \@@_Iddots + \cs_set_eq:NN \Hspace \@@_Hspace: + \cs_set_eq:NN \NiceMatrixEndPoint \@@_NiceMatrixEndPoint: + \bool_if:NF \l_@@_renew_matrix_bool + {\cs_set_eq:NN \multicolumn \@@_multicolumn:nn} +% \end{macrocode} +% If the option |RenewDots| is used, we redefine the commands |\ldots|, |\cdots|, etc. +% \begin{macrocode} + \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} +% \end{macrocode} +% +% We increment the counter |\g_@@_env_int| which counts the environments |{NiceMatrix}|. +% \begin{macrocode} + \int_gincr:N \g_@@_env_int +% \end{macrocode} +% +% The sequence |\g_@@_empty_cells_seq| will contains a list of ``empty'' cells (not all the empty cells of the +% matrix). If we want to indicate that the cell in line~$i$ and line~$j$ must be considered as empty, the token +% list ``|i-j|'' will be put in this sequence. +% \begin{macrocode} + \seq_gclear_new:N \g_@@_empty_cells_seq +% \end{macrocode} +% +% The counter |\g_@@_instruction_int| will count the instructions (|\Cdots|, |\Vdots|, |\Ddots|, etc.) in the matrix. +% \begin{macrocode} + \int_gzero_new:N \g_@@_instruction_int +% \end{macrocode} +% The counter |\g_@@_line_int| will be used to count the lines of the array. At the end of the environment +% |{array}|, this counter will give the total number of lines of the matrix. +% \begin{macrocode} + \int_gzero_new:N \g_@@_line_int +% \end{macrocode} +% The counter |\g_@@_column_int| will be used to count the colums of the array. Since we want to known the total +% number of columns of the matrix, we also create a counter |\g_@@_nb_column_int|. These counters are updated in +% the command |\@@_Cell:| executed at the beginning of each cell. +% \begin{macrocode} + \int_gzero_new:N \g_@@_column_int + \int_gzero_new:N \g_@@_nb_column_int +% \end{macrocode} +% The next two lines are the same as in the command |\env@matrix| of \pkg{amsmath} on which all the matrix +% constructions are built. +% \begin{macrocode} + \hskip -\arraycolsep + \cs_set_eq:NN \@ifnextchar \new@ifnextchar +% \end{macrocode} +% Eventually, the environment |{NiceMatrix}| is defined upon the environment |{array}|. We maintain the +% signification of the counter |\c@MaxMatrixCols| of \pkg{amsmath}. +% \begin{macrocode} + \int_set:Nn \l_tmpa_int {\c@MaxMatrixCols - 1} + \array{>{\@@_Cell_First_Column:}c<{\@@_end_Cell:} + *\l_tmpa_int{>{\@@_Cell:}c<{\@@_end_Cell:}}}} +% \end{macrocode} +% \bigskip +% The second part of the environment |{NiceMatrix}| is the same as the second part of the environment |{matrix}| of +% \pkg{amsmath}. However, at the end of the environment, the instruction |\@@_draw_lines:| will +% be executed because we have put a ``|\aftergroup \@@_draw_lines:|'' in the beginning of the environment +% (therefore, it's possible to implement the option |RenewMatrix| with |\cs_set_eq:NN \env@matrix \NiceMatrix|). +% \begin{macrocode} + {\endarray + \hskip -\arraycolsep} +% \end{macrocode} +% +% \interitem +% We create the variants of the environment |{NiceMatrix}|. +% \begin{macrocode} +\NewDocumentEnvironment {pNiceMatrix} {} + {\left(\begin{NiceMatrix}} + {\end{NiceMatrix}\right)} +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment {bNiceMatrix} {} + {\left[\begin{NiceMatrix}} + {\end{NiceMatrix}\right]} +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment {BNiceMatrix} {} + {\left\{\begin{NiceMatrix}} + {\end{BNiceMatrix}\right\}} +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment {vNiceMatrix} {} + {\left\lvert\begin{NiceMatrix}} + {\end{BNiceMatrix}\right\rvert} +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentEnvironment {VNiceMatrix} {} + {\left\lVert\begin{NiceMatrix}} + {\end{BNiceMatrix}\right\rVert} +% \end{macrocode} +% +% \interitem +% The conditionnal |\@@_if_not_empty_cell:nnT| test wether a cell is empty. The first two arguments must be LaTeX3 +% counters for the row and the column of the considered cell. +% \begin{macrocode} +\prg_set_conditional:Npnn \@@_if_not_empty_cell:nn #1#2 {T} +% \end{macrocode} +% If the cell is a implicit cell (that is after the symbol |\\| of end of row), the cell must, of course, be +% considered as empty. It's easy to check wether we are in this situation considering the correspondant Tikz node. +% \begin{macrocode} + {\cs_if_exist:cTF {pgf@sh@ns@nm- + \int_use:N \g_@@_env_int- + \int_use:N #1- + \int_use:N #2} +% \end{macrocode} +% We manage a list of ``empty cells'' called |\g_@@_empty_cells_seq|. In fact, this list is not a list of all the +% empty cells of the array but only those explicitely declared empty for some reason. It's easy to check if the +% current cell is in this list. +% \begin{macrocode} + {\seq_if_in:NxTF \g_@@_empty_cells_seq + {\int_use:N #1-\int_use:N #2} + {\prg_return_false:} +% \end{macrocode} +% In the general case, we consider the width of the Tikz node corresponding to the cell. In order to compute this +% width, we have to extract the coordinate of the west and east anchors of the node. This extraction needs a +% command |\tikz| but, in fact, nothing is drawn. +% \begin{macrocode} + {\tikz[remember~picture] + \path let \p1 = (nm- + \int_use:N \g_@@_env_int- + \int_use:N #1- + \int_use:N #2.east), + \p2 = (nm- + \int_use:N \g_@@_env_int- + \int_use:N #1- + \int_use:N #2.west) + in \pgfextra {\dim_gset:Nn \g_tmpa_dim {\x1} + \dim_gset:Nn \g_tmpb_dim {\x2}} ; +% \end{macrocode} +% We compute in |\g_tmpa_dim| the width of the Tikz node. +% \begin{macrocode} + \dim_gsub:Nn \g_tmpa_dim \g_tmpb_dim + \dim_compare:nNnTF {\dim_abs:n \g_tmpa_dim} < {0.5 pt} + {\prg_return_false:} + {\prg_return_true:}}} + {\prg_return_false:} + } +% \end{macrocode} +% +% \interitem +% For each drawing instruction in the matrix (like |\Cdots|, etc.), we create a global property list to store the +% informations corresponding to the instruction. Such an property list will have three fields: +% \begin{itemize} +% \item a field ``type'' with the type of the instruction (|cdots|, |vdots|, |ddots|, etc.); +% \item a field ``line'' with the number of the line of the matrix where the instruction appeared; +% \item a field ``column'' with the number of the column of the matrix where the instruction appeared. +% \end{itemize} +% +% \interitem +% The argument of the following command |\@@_instruction_of_type:n| is the type of the instruction (|cdots|, +% |vdots|, |ddots|, etc.). This command creates the corresponding property list. +% \begin{macrocode} +\cs_new_protected:Nn \@@_instruction_of_type:n +% \end{macrocode} +% First, we increment the counter of the instructions (this counter is initialized in the beginning of the +% environment |{NiceMatrix}|). This incrementation is global because the command will be used in the cell of a |\halign|). +% \begin{macrocode} + {\int_gincr:N \g_@@_instruction_int + \prop_put:Nnn \l_tmpa_prop {type} {#1} + \prop_put:NnV \l_tmpa_prop {line} \g_@@_line_int + \prop_put:NnV \l_tmpa_prop {column} \g_@@_column_int +% \end{macrocode} +% The property list has been created in a local variable for convenience. Now, it will be stored in a +% global variable indicating the number of the instruction. +% \begin{macrocode} + \prop_gclear_new:c + {g_@@_instruction_\int_use:N\g_@@_instruction_int _prop} + \prop_gset_eq:cN + {g_@@_instruction_\int_use:N\g_@@_instruction_int _prop} + \l_tmpa_prop + } +% \end{macrocode} +% +% +% \bigskip +% \subsection{We draw the lines in the matrix} + +% \begin{macrocode} +\cs_new_protected:Nn \@@_draw_lines: + { +% \end{macrocode} +% +% The sequence |\l_@@_yet_drawn_seq| contains a list of lines which have been drawn previously in the matrix. We +% maintain this sequence because we don't want to draw two overlapping lines. +% \begin{macrocode} + \seq_clear_new:N \l_@@_yet_drawn_seq +% \end{macrocode} +% +% +% The following variables will be used further. +% \begin{macrocode} + \int_zero_new:N \l_@@_type_int + \int_zero_new:N \l_@@_line_int + \int_zero_new:N \l_@@_column_int + \int_zero_new:N \l_@@_di_int + \int_zero_new:N \l_@@_dj_int +% \end{macrocode} +% +% By befault, the diagonal lines will be parallelized\footnote{It's possible to use the option +% |ParallelizeDiagonals| to disable this parallelization.}. There are two types of diagonals lines: the $|\Ddots|$ +% diagonals and the |\Iddots| diagonals. We have to count the both types in order to known wether a diagonal is the +% first of its type in the current |{NiceMatrix}| environment. +% \begin{macrocode} + \bool_if:NT \l_@@_parallelize_diags_bool + {\int_zero_new:N \l_@@_ddots_int + \int_zero_new:N \l_@@_iddots_int +% \end{macrocode} +% +% The dimensions |\l_@@_delta_x_one_dim| and |\l_@@_delta_y_one_dim| will contains the $\Delta_x$ and $\Delta_y$ of the +% first |\Ddots| diagonal. We have to store these values in order to draw the others |\Ddots| diagonals parallel to +% the first one. Similarly |\l_@@_delta_x_two_dim| and |\l_@@_delta_y_two_dim| are the $\Delta_x$ and $\Delta_y$ of +% the first |\Iddots| diagonal. +% \begin{macrocode} + \dim_zero_new:N \l_@@_delta_x_one_dim + \dim_zero_new:N \l_@@_delta_y_one_dim + \dim_zero_new:N \l_@@_delta_x_two_dim + \dim_zero_new:N \l_@@_delta_y_two_dim} +% \end{macrocode} +% +% \interitem +% The counter |\l_@@_instruction_int| will be the index of the loop over the instructions. The first value is~$1$. +% \begin{macrocode} + \int_zero_new:N \l_@@_instruction_int + \int_incr:N \l_@@_instruction_int +% \end{macrocode} +% +% \interitem +% We begin the loop over the instructions (the incrementation is at the end of the loop). +% \begin{macrocode} + \int_until_do:nNnn \l_@@_instruction_int > \g_@@_instruction_int + { +% \end{macrocode} +% +% \interitem +% We extract from the property list of the current instruction the fields ``type'', ``line'' and ``column''and we +% store these values. We have to do a conversion because the components of a property list are token lists (and not +% integers). +% \begin{macrocode} + \prop_get:cnN {g_@@_instruction_\int_use:N \l_@@_instruction_int _prop} + {type} \l_tmpa_tl + \int_set:Nn \l_@@_type_int {\l_tmpa_tl} + \prop_get:cnN {g_@@_instruction_\int_use:N \l_@@_instruction_int _prop} + {line} \l_tmpa_tl + \int_set:Nn \l_@@_line_int {\l_tmpa_tl} + \prop_get:cnN {g_@@_instruction_\int_use:N \l_@@_instruction_int _prop} + {column} \l_tmpa_tl + \int_set:Nn \l_@@_column_int {\l_tmpa_tl} +% \end{macrocode} +% +% \interitem +% We fix the values of |\l_@@_di_int| and |\l_@@_dj_int| which indicate the direction of the dotted line to draw in +% the matrix. +% \begin{macrocode} + \int_case:nn \l_@@_type_int + { 0 {\int_set:Nn \l_@@_di_int 0 + \int_set:Nn \l_@@_dj_int 1} + 1 {\int_set:Nn \l_@@_di_int 0 + \int_set:Nn \l_@@_dj_int 1} + 2 {\int_set:Nn \l_@@_di_int 1 + \int_set:Nn \l_@@_dj_int 0} + 3 {\int_set:Nn \l_@@_di_int 1 + \int_set:Nn \l_@@_dj_int 1} + 4 {\int_set:Nn \l_@@_di_int 1 + \int_set:Nn \l_@@_dj_int {-1}}} +% \end{macrocode} +% +% \interitem +% An instruction for a dotted line must have a initial cell and a final cell which are both not empty. If it's not +% the case, the instruction is said \emph{impossible}. An error will be raised if an impossible instruction is +% encountered. +% \begin{macrocode} + \bool_if_exist:NTF \l_@@_impossible_instruction_bool + {\bool_set_false:N \l_@@_impossible_instruction_bool} + {\bool_new:N \l_@@_impossible_instruction_bool} +% \end{macrocode} +% +% \interitem +% We will determine |\l_@@_final_i_int| and |\l_@@_final_j_int| which will be the ``coordinates'' of the end of the +% dotted line we have to draw. +% \begin{macrocode} + \int_zero_new:N \l_@@_final_i_int + \int_zero_new:N \l_@@_final_j_int + \int_set:Nn \l_@@_final_i_int \l_@@_line_int + \int_set:Nn \l_@@_final_j_int \l_@@_column_int + \bool_if_exist:NTF \l_@@_stop_loop_bool + {\bool_set_false:N \l_@@_stop_loop_bool} + {\bool_new:N \l_@@_stop_loop_bool} + \bool_do_until:Nn \l_@@_stop_loop_bool + {\int_add:Nn \l_@@_final_i_int \l_@@_di_int + \int_add:Nn \l_@@_final_j_int \l_@@_dj_int +% \end{macrocode} +% We test if we are still in the matrix. +% \begin{macrocode} + \bool_if:nTF { \int_compare_p:nNn \l_@@_final_i_int < 1 + || \int_compare_p:nNn \l_@@_final_i_int > \g_@@_line_int + || \int_compare_p:nNn \l_@@_final_j_int < 1 + || \int_compare_p:nNn \l_@@_final_j_int > \g_@@_nb_column_int} +% \end{macrocode} +% If we are outside the matrix, the instruction is impossible and, of course, we stop the loop. +% \begin{macrocode} + {\bool_set_true:N \l_@@_impossible_instruction_bool + \bool_set_true:N \l_@@_stop_loop_bool} +% \end{macrocode} +% If we are in the matrix, we test if the cell is empty. If it's not the case, we stop the loop because we have +% found the correct values for |\l_@@_final_i_int| and |\l_@@_final_j_int|. +% \begin{macrocode} + {\@@_if_not_empty_cell:nnT \l_@@_final_i_int \l_@@_final_j_int + {\bool_set_true:N \l_@@_stop_loop_bool}} + } +% \end{macrocode} +% +% \interitem +% We will determine |\l_@@_initial_i_int| and |\l_@@_initial_j_int| which will be the ``coordinates'' of the +% beginning of the dotted line we have to draw. The programmation is similar to the previous one. +% \begin{macrocode} + \int_zero_new:N \l_@@_initial_i_int + \int_zero_new:N \l_@@_initial_j_int + \int_set:Nn \l_@@_initial_i_int \l_@@_line_int + \int_set:Nn \l_@@_initial_j_int \l_@@_column_int +% \end{macrocode} +% If we known that the instruction is impossible (because it was not possible to found the correct value for +% |\l_@@_final_i_int| and |\l_@@_final_j_int|), we don't do this loop. +% \begin{macrocode} + \bool_set_eq:NN \l_@@_stop_loop_bool \l_@@_impossible_instruction_bool + \bool_do_until:Nn \l_@@_stop_loop_bool + {\int_sub:Nn \l_@@_initial_i_int \l_@@_di_int + \int_sub:Nn \l_@@_initial_j_int \l_@@_dj_int + \bool_if:nTF + { \int_compare_p:nNn \l_@@_initial_i_int < 1 + || \int_compare_p:nNn \l_@@_initial_i_int > \g_@@_line_int + || \int_compare_p:nNn \l_@@_initial_j_int < 1 + || \int_compare_p:nNn \l_@@_initial_j_int > \g_@@_nb_column_int} + {\bool_set_true:N \l_@@_impossible_instruction_bool + \bool_set_true:N \l_@@_stop_loop_bool} + {\@@_if_not_empty_cell:nnT \l_@@_initial_i_int \l_@@_initial_j_int + {\bool_set_true:N \l_@@_stop_loop_bool}} + } +% \end{macrocode} +% +% \interitem +% Now, we can determine wether we have to draw a line. +% If the line is impossible, of course, we won't draw any line. +% \begin{macrocode} + \bool_if:NTF \l_@@_impossible_instruction_bool + {\msg_error:nn {nicematrix} {Impossible~instruction}} +% \end{macrocode} +% +% If the dotted line to draw is in the list of the previously drawn lines (|\l_@@_yet_drawn_seq|), we don't draw +% (so, we won't have overlapping lines in the \textsc{pdf}). The token list |\l_tmpa_tl| is the $4$-uplet +% characteristic of the line. +% \begin{macrocode} + {\tl_set:Nx \l_tmpa_tl {\int_use:N \l_@@_initial_i_int- + \int_use:N \l_@@_initial_j_int- + \int_use:N \l_@@_final_i_int- + \int_use:N \l_@@_final_j_int} + \seq_if_in:NVF \l_@@_yet_drawn_seq \l_tmpa_tl +% \end{macrocode} +% +% If the dotted line to draw is not in the list, we add it the list |\l_@@_yet_drawn_seq|. +% \begin{macrocode} + {\seq_put_left:NV \l_@@_yet_drawn_seq \l_tmpa_tl +% \end{macrocode} +% +% \medskip +% The four following variables are global because we will have to do affectations in a Tikz instruction (in order +% to extract the coordinates of two extremities of the line to draw). +% \begin{macrocode} + \dim_zero_new:N \g_@@_x_initial_dim + \dim_zero_new:N \g_@@_y_initial_dim + \dim_zero_new:N \g_@@_x_final_dim + \dim_zero_new:N \g_@@_y_final_dim +% \end{macrocode} +% +% +% We draw the line. +% \begin{macrocode} + \int_case:nn \l_@@_type_int + {0 \@@_draw_ldots_line: + 1 \@@_draw_cdots_line: + 2 \@@_draw_vdots_line: + 3 \@@_draw_ddots_line: + 4 \@@_draw_iddots_line:}}} +% \end{macrocode} +% +% \bigskip +% Incrementation of the index of the loop (and end of the loop). +% \begin{macrocode} + \int_incr:N \l_@@_instruction_int + } +} +% \end{macrocode} +% +% +% \interitem +% The command |\@@_retrieve_coords:nn| retrieves the Tikz coordinates of the two extremities of the dotted line we +% will have to draw \footnote{In fact, with diagonals lines, a adjustment of one of the coordinates may be done.}. +% This command has four implicit arguments which are |\l_@@_initial_i_int|, |\l_@@_initial_j_int|, +% |\l_@@_final_i_int| and |\l_@@_final_j_int|. +% +% The two arguments of the command |\@@_retrieve_coords:nn| are the anchors that must be used for the two nodes. +% These anchors must be given with the point (e.g.: |.north|, |.south|, etc.). +% +% 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 a Tikz +% picture. +% \begin{macrocode} +\cs_new_protected:Nn \@@_retrieve_coords:nn + {\tikz[remember~picture] + \path let \p1 = (nm-\int_use:N \g_@@_env_int- + \int_use:N \l_@@_initial_i_int- + \int_use:N \l_@@_initial_j_int #1), + \p2 = (nm-\int_use:N \g_@@_env_int- + \int_use:N \l_@@_final_i_int- + \int_use:N \l_@@_final_j_int #2) + in \pgfextra {\dim_gset:Nn \g_@@_x_initial_dim {\x1} + \dim_gset:Nn \g_@@_y_initial_dim {\y1} + \dim_gset:Nn \g_@@_x_final_dim {\x2} + \dim_gset:Nn \g_@@_y_final_dim {\y2}} ; } +% \end{macrocode} +% +% \interitem +% \begin{macrocode} +\cs_new_protected:Nn \@@_draw_ldots_line: + {\@@_retrieve_coords:nn {.south~east} {.south~west} + \@@_draw_tikz_line:} +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\cs_new_protected:Nn \@@_draw_cdots_line: + {\@@_retrieve_coords:nn {.mid~east} {.mid~west} + \@@_draw_tikz_line:} +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\cs_new_protected:Nn \@@_draw_vdots_line: + {\@@_retrieve_coords:nn {.south} {.north} + \@@_draw_tikz_line:} +% \end{macrocode} +% +% \interitem +% For the diagonal lines, the situation is a bit more complicated because, by default, we parallelize the diagonals +% lines. The first diagonal line is drawn and then, all the other diagonal lines are drawn parallel to the first +% one. +% \begin{macrocode} +\cs_new_protected:Nn \@@_draw_ddots_line: + {\@@_retrieve_coords:nn {.south~east} {.north~west} +% \end{macrocode} +% We have retrieved the coordinates in the usual way (they are stored in |\g_@@_x_initial_dim|, etc.). +% If the parallelization of the diagonals is set, we will have (maybe) to adjust the fourth coordinate. +% \begin{macrocode} + \bool_if:NT \l_@@_parallelize_diags_bool + {\int_incr:N \l_@@_ddots_int +% \end{macrocode} +% We test if the diagonal line is the first one (the counter |\l_@@_ddots_int| is created for this usage). +% \begin{macrocode} + \int_compare:nNnTF \l_@@_ddots_int = 1 +% \end{macrocode} +% If the diagonal line is the first one, we have no adjustment of the line to do but we store the $\Delta_x$ and the +% $\Delta_y$ of the line because these values will be used to draw the others diagonal lines parallels to the first one. +% \begin{macrocode} + {\dim_set:Nn \l_@@_delta_x_one_dim {\g_@@_x_final_dim - \g_@@_x_initial_dim } + \dim_set:Nn \l_@@_delta_y_one_dim {\g_@@_y_final_dim - \g_@@_y_initial_dim }} +% \end{macrocode} +% If the diagonal line is not the first one, we have to adjust the second extremity of the line by modifying +% the coordinate |\g_@@_y_initial_dim|. +% \begin{macrocode} + {\dim_gset:Nn \g_@@_y_final_dim + {\g_@@_y_initial_dim + + (\g_@@_x_final_dim - \g_@@_x_initial_dim) + * \dim_ratio:nn \l_@@_delta_y_one_dim \l_@@_delta_x_one_dim }}} +% \end{macrocode} +% Now, we can draw the dotted line (after a possible change of |\g_@@_y_initial_dim|). +% \begin{macrocode} + \@@_draw_tikz_line:} +% \end{macrocode} +% +% \bigskip +% We draw the |\Iddots| diagonals in the same way. +% \begin{macrocode} +\cs_new_protected:Nn \@@_draw_iddots_line: + {\_@@_retrieve_coords:nn {.south~west} {.north~east} + \bool_if:NT \l_@@_parallelize_diags_bool + {\int_incr:N \l_@@_iddots_int + \int_compare:nNnTF \l_@@_iddots_int = 1 + {\dim_set:Nn \l_@@_delta_x_two_dim {\g_@@_x_final_dim - \g_@@_x_initial_dim } + \dim_set:Nn \l_@@_delta_y_two_dim {\g_@@_y_final_dim - \g_@@_y_initial_dim }} + {\dim_gset:Nn \g_@@_y_final_dim + {\g_@@_y_initial_dim + + (\g_@@_x_final_dim - \g_@@_x_initial_dim) + * \dim_ratio:nn \l_@@_delta_y_two_dim \l_@@_delta_x_two_dim }}} + \@@_draw_tikz_line:} +% \end{macrocode} +% +% \bigskip +% \subsection{The actual instructions for drawing the dotted line with Tikz} +% +% The command |\@@_draw_tikz_line:| draws the line using four implicit arguments: +% +% \quad |\g_@@_x_initial_dim|, |\g_@@_y_initial_dim|, |\g_@@_x_final_dim| and |\g_@@_y_final_dim|. + +% These variables are global for technical reasons: we have to do affectations in an instruction |\tikz|. +% +% \begin{macrocode} +\cs_new_protected:Nn \@@_draw_tikz_line: + {\begin{tikzpicture}[overlay] + \tikzmath{ + coordinate~\a , \b ; + real~\l, \x, \d ; + integer~\n ; + \a = (\g_@@_x_initial_dim, \g_@@_y_initial_dim) ; + \b = (\g_@@_x_final_dim, \g_@@_y_final_dim) ; + \l = veclen(\bx-\ax,\by-\ay) ; + \n = (\l - 0.54em)/(0.45em) ; + \x = (\l - \n*0.45em)/(2*\l) ; + \d = 0.45em / \l ; + if~\n>0 + then~{ for~\k in~{0,...,\n} + { {\node at ($(\a)!\x+\k*\d!(\b)$) {.} ; } ; } ; + } ; + } + \end{tikzpicture}} +% \end{macrocode} +% +% \bigskip +% \subsection{User commands available in environments {NiceMatrix}} +% +% We give new names for the commands |\ldots|, |\cdots|, |\vdots| and |\ddots| because these commands will be +% redefined (if the option |RenewDots| 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_@@_line_int- + \int_use:N \g_@@_column_int}} +% \end{macrocode} +% +% \interitem +% The commands |\@@_Ldots|, |\@@_Cdots|, |\@@_Vdots|, |\@@_Ddots| and |\@@_Iddots| will be linked to |\Ldots|, +% |\Cdots|, |\Vdots|, |\Ddots| and |\Iddots| in the environment |{NiceMatrix}|. +% \begin{macrocode} +\NewDocumentCommand \@@_Ldots {s} + {\IfBooleanF {#1} {\@@_instruction_of_type:n 0} + \bool_if:NF \l_@@_nullify_dots_bool {\phantom \@@_ldots} + \@@_add_to_empty_cells:} +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\NewDocumentCommand \@@_Cdots {s} + {\IfBooleanF {#1} {\@@_instruction_of_type:n 1} + \bool_if:NF \l_@@_nullify_dots_bool {\phantom \@@_cdots} + \@@_add_to_empty_cells:} +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\NewDocumentCommand \@@_Vdots {s} + {\IfBooleanF {#1} {\@@_instruction_of_type:n 2} + \bool_if:NF \l_@@_nullify_dots_bool {\phantom \@@_vdots} + \@@_add_to_empty_cells:} +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\NewDocumentCommand \@@_Ddots {s} + {\IfBooleanF {#1} {\@@_instruction_of_type:n 3} + \bool_if:NF \l_@@_nullify_dots_bool {\phantom \@@_ddots} + \@@_add_to_empty_cells:} +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\NewDocumentCommand \@@_Iddots {s} + {\IfBooleanF {#1} {\@@_instruction_of_type:n 4} + \bool_if:NF \l_@@_nullify_dots_bool {\phantom \@@_iddots} + \@@_add_to_empty_cells:} +% \end{macrocode} +% +% +% \bigskip +% The command |\@@_Hspace:| will be linked to |\hspace| in the environment |{NiceMatrix}|. +% \begin{macrocode} +\cs_new_protected:Nn \@@_Hspace: + {\@@_add_to_empty_cells: + \hspace} +% \end{macrocode} +% +% \bigskip +% The command |\@@_NiceMatrixEndPoint:| will be linked to |\NiceMatrixEndPoint| in the environment |{NiceMatrix}|. +% \begin{macrocode} +\cs_new_protected:Nn \@@_NiceMatrixEndPoint: + {\kern 0.5pt} +% \end{macrocode} +% +% \bigskip +% \subsection{We process the options} +% +% We process the options when the package is loaded (with |\usepackage|) but we recommend to use +% |\NiceMatrixOptions| instead. +% +% We must process these options after the definition of the environment |{NiceMatrix}| because the option +% |RenewMatrix| execute the code |\cs_set_eq:NN \env@matrix \NiceMatrix|. +% +% Of course, the command |\NiceMatrix| must be defined before such an instruction is executed. +% \begin{macrocode} +\ProcessKeysOptions {NiceMatrix} +% \end{macrocode} +% +% +% \bigskip +% \subsection{The error messages} +% \begin{macrocode} +\msg_new:nnnn {nicematrix} + {Impossible~instruction} + {It's~not~possible~to~execute~the~instruction~ + \int_case:nn \l_@@_type_int + {0 {\token_to_str:N \Ldots} + 1 {\token_to_str:N \Cdots} + 2 {\token_to_str:N \Vdots} + 3 {\token_to_str:N \Ddots}}~in~the~line~\int_use:N\l_@@_line_int\ + ~and~the~column~\int_use:N\l_@@_column_int\space of~the~matrix~ + because~it's~impossible~to~find~one~of~its~extremities~ + (both~extremities~must~be~non~empty~cells~of~the~matrix).~ + If~you~go~on,~the~instruction~will~be~ignored.} + {You~can~specify~a~end~of~line~on~a~empty~cell~ + with~\token_to_str:N \NiceMatrixEndPoint.} +% \end{macrocode} +% +% \begin{macrocode} +\msg_new:nnn {nicematrix} + {multicolumn~forbidden} + {The~command~\token_to_str:N \multicolumn\ + is~forbidden~in~the~environment~\{NiceMatrix\}~ + and~its~variants.~The~command~\token_to_str:N \hdotsfor\ + of~amsmath~is~also~forbidden~since~it~uses~ + \token_to_str:N \multicolumn.~You~can~go~on~but~your~line~will~ + probably~be~wrong.} +% \end{macrocode} +% +% \endinput +% +% Local Variables: +% TeX-fold-mode: nil +% End: diff --git a/Master/texmf-dist/source/latex/nicematrix/nicematrix.ins b/Master/texmf-dist/source/latex/nicematrix/nicematrix.ins new file mode 100644 index 00000000000..ce8a59e12b8 --- /dev/null +++ b/Master/texmf-dist/source/latex/nicematrix/nicematrix.ins @@ -0,0 +1,47 @@ +%% +%% Copyright (C) 2017 by F. Pantigny +%% +%% +%% This file may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either +%% version 1.3 of this license or (at your option) any later +%% version. The latest version of this license is in: +%% +%% http://www.latex-project.org/lppl.txt +%% +%% and version 1.3 or later is part of all distributions of +%% LaTeX version 2005/12/01 or later. +%% +\input l3docstrip.tex +\keepsilent +\usedir{tex/latex/nicematrix} +\preamble + +Copyright (C) 2017 by F. Pantigny + +This file may be distributed and/or modified under the +conditions of the LaTeX Project Public License, either +version 1.3 of this license or (at your option) any later +version. The latest version of this license is in: + + http://www.latex-project.org/lppl.txt + +and version 1.3 or later is part of all distributions of +LaTeX version 2005/12/01 or later. + +\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/Master/texmf-dist/tex/latex/nicematrix/nicematrix.sty b/Master/texmf-dist/tex/latex/nicematrix/nicematrix.sty new file mode 100644 index 00000000000..d0c2e771cc6 --- /dev/null +++ b/Master/texmf-dist/tex/latex/nicematrix/nicematrix.sty @@ -0,0 +1,386 @@ +%% +%% This is file `nicematrix.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% nicematrix.dtx (with options: `package') +%% +%% Copyright (C) 2017 by F. Pantigny +%% +%% This file may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either +%% version 1.3 of this license or (at your option) any later +%% version. The latest version of this license is in: +%% +%% http://www.latex-project.org/lppl.txt +%% +%% and version 1.3 or later is part of all distributions of +%% LaTeX version 2005/12/01 or later. +%% +\def\myfileversion{1.0} +\def\myfiledate{2018/02/13} +\RequirePackage{tikz} +\usetikzlibrary{calc,math} +\RequirePackage{l3keys2e} +\ProvidesExplPackage + {nicematrix} + {\myfiledate} + {\myfileversion} + {Draws nice dotted lines in matrix environments} +\RequirePackage{array} +\RequirePackage{mathtools} +\RequirePackage{xparse} +\ProvideDocumentCommand \iddots {} + {\mathinner{\mkern 1mu + \raise 1pt \hbox{.} + \mkern 2mu + \raise 4pt\hbox{.} + \mkern 2mu + \raise7pt \vbox{\kern 7pt + \hbox{.}} + \mkern1mu}} +\cs_new_protected:Nn \__nm_multicolumn:nn + {\msg_error:nn {nicematrix} {multicolumn~forbidden}} +\int_new:N \g__nm_env_int +\bool_new:N \l__nm_parallelize_diags_bool +\bool_set_true:N \l__nm_parallelize_diags_bool +\bool_new:N \l__nm_nullify_dots_bool +\bool_new:N \l__nm_renew_matrix_bool +\keys_define:nn {NiceMatrix} + {ParallelizeDiagonals .bool_set:N = \l__nm_parallelize_diags_bool, + ParallelizeDiagonals .default:n = true, + RenewDots .bool_set:N = \l__nm_renew_dots_bool, + RenewDots .default:n = true, + RenewMatrix .code:n = {\cs_set_eq:NN \env@matrix \NiceMatrix + \bool_set_true:N \l__nm_renew_matrix_bool}, + RenewMatrix .default:n = true, + Transparent .meta:n = {RenewDots,RenewMatrix}, + Transparent .value_forbidden:n = true, + NullifyDots .bool_set:N = \l__nm_nullify_dots_bool , + NullifyDots .default:n = true} +\NewDocumentCommand \NiceMatrixOptions {m} + {\keys_set:nn {NiceMatrix} {#1}} +\cs_new_protected:Nn \__nm_Cell: + { + \int_gincr:N \g__nm_column_int + \int_gset:Nn \g__nm_nb_column_int {\int_max:nn \g__nm_nb_column_int \g__nm_column_int} + \tikz[remember~picture, inner~sep = 0pt, minimum~width = 0pt, baseline] + \node [anchor=base] (nm-\int_use:N \g__nm_env_int- + \int_use:N \g__nm_line_int- + \int_use:N \g__nm_column_int) + \bgroup $} % $ +\cs_new_protected:Nn \__nm_end_Cell: + {$\egroup ;} % $ +\cs_new_protected:Nn \__nm_Cell_First_Column: + {\int_gincr:N \g__nm_line_int + \int_gset:Nn \g__nm_column_int 0 + \__nm_Cell:} +\NewDocumentEnvironment {NiceMatrix} {} + { + \aftergroup \__nm_draw_lines: + \cs_set_eq:NN \Ldots \__nm_Ldots + \cs_set_eq:NN \Cdots \__nm_Cdots + \cs_set_eq:NN \Vdots \__nm_Vdots + \cs_set_eq:NN \Ddots \__nm_Ddots + \cs_set_eq:NN \Iddots \__nm_Iddots + \cs_set_eq:NN \Hspace \__nm_Hspace: + \cs_set_eq:NN \NiceMatrixEndPoint \__nm_NiceMatrixEndPoint: + \bool_if:NF \l__nm_renew_matrix_bool + {\cs_set_eq:NN \multicolumn \__nm_multicolumn:nn} + \bool_if:NT \l__nm_renew_dots_bool + {\cs_set_eq:NN \ldots \__nm_Ldots + \cs_set_eq:NN \cdots \__nm_Cdots + \cs_set_eq:NN \vdots \__nm_Vdots + \cs_set_eq:NN \ddots \__nm_Ddots + \cs_set_eq:NN \iddots \__nm_Iddots + \cs_set_eq:NN \dots \__nm_Ldots} + \int_gincr:N \g__nm_env_int + \seq_gclear_new:N \g__nm_empty_cells_seq + \int_gzero_new:N \g__nm_instruction_int + \int_gzero_new:N \g__nm_line_int + \int_gzero_new:N \g__nm_column_int + \int_gzero_new:N \g__nm_nb_column_int + \hskip -\arraycolsep + \cs_set_eq:NN \@ifnextchar \new@ifnextchar + \int_set:Nn \l_tmpa_int {\c@MaxMatrixCols - 1} + \array{>{\__nm_Cell_First_Column:}c<{\__nm_end_Cell:} + *\l_tmpa_int{>{\__nm_Cell:}c<{\__nm_end_Cell:}}}} + {\endarray + \hskip -\arraycolsep} +\NewDocumentEnvironment {pNiceMatrix} {} + {\left(\begin{NiceMatrix}} + {\end{NiceMatrix}\right)} +\NewDocumentEnvironment {bNiceMatrix} {} + {\left[\begin{NiceMatrix}} + {\end{NiceMatrix}\right]} +\NewDocumentEnvironment {BNiceMatrix} {} + {\left\{\begin{NiceMatrix}} + {\end{BNiceMatrix}\right\}} +\NewDocumentEnvironment {vNiceMatrix} {} + {\left\lvert\begin{NiceMatrix}} + {\end{BNiceMatrix}\right\rvert} +\NewDocumentEnvironment {VNiceMatrix} {} + {\left\lVert\begin{NiceMatrix}} + {\end{BNiceMatrix}\right\rVert} +\prg_set_conditional:Npnn \__nm_if_not_empty_cell:nn #1#2 {T} + {\cs_if_exist:cTF {pgf@sh@ns@nm- + \int_use:N \g__nm_env_int- + \int_use:N #1- + \int_use:N #2} + {\seq_if_in:NxTF \g__nm_empty_cells_seq + {\int_use:N #1-\int_use:N #2} + {\prg_return_false:} + {\tikz[remember~picture] + \path let \p1 = (nm- + \int_use:N \g__nm_env_int- + \int_use:N #1- + \int_use:N #2.east), + \p2 = (nm- + \int_use:N \g__nm_env_int- + \int_use:N #1- + \int_use:N #2.west) + in \pgfextra {\dim_gset:Nn \g_tmpa_dim {\x1} + \dim_gset:Nn \g_tmpb_dim {\x2}} ; + \dim_gsub:Nn \g_tmpa_dim \g_tmpb_dim + \dim_compare:nNnTF {\dim_abs:n \g_tmpa_dim} < {0.5 pt} + {\prg_return_false:} + {\prg_return_true:}}} + {\prg_return_false:} + } +\cs_new_protected:Nn \__nm_instruction_of_type:n + {\int_gincr:N \g__nm_instruction_int + \prop_put:Nnn \l_tmpa_prop {type} {#1} + \prop_put:NnV \l_tmpa_prop {line} \g__nm_line_int + \prop_put:NnV \l_tmpa_prop {column} \g__nm_column_int + \prop_gclear_new:c + {g__nm_instruction_\int_use:N\g__nm_instruction_int _prop} + \prop_gset_eq:cN + {g__nm_instruction_\int_use:N\g__nm_instruction_int _prop} + \l_tmpa_prop + } + +\cs_new_protected:Nn \__nm_draw_lines: + { + \seq_clear_new:N \l__nm_yet_drawn_seq + \int_zero_new:N \l__nm_type_int + \int_zero_new:N \l__nm_line_int + \int_zero_new:N \l__nm_column_int + \int_zero_new:N \l__nm_di_int + \int_zero_new:N \l__nm_dj_int + \bool_if:NT \l__nm_parallelize_diags_bool + {\int_zero_new:N \l__nm_ddots_int + \int_zero_new:N \l__nm_iddots_int + \dim_zero_new:N \l__nm_delta_x_one_dim + \dim_zero_new:N \l__nm_delta_y_one_dim + \dim_zero_new:N \l__nm_delta_x_two_dim + \dim_zero_new:N \l__nm_delta_y_two_dim} + \int_zero_new:N \l__nm_instruction_int + \int_incr:N \l__nm_instruction_int + \int_until_do:nNnn \l__nm_instruction_int > \g__nm_instruction_int + { + \prop_get:cnN {g__nm_instruction_\int_use:N \l__nm_instruction_int _prop} + {type} \l_tmpa_tl + \int_set:Nn \l__nm_type_int {\l_tmpa_tl} + \prop_get:cnN {g__nm_instruction_\int_use:N \l__nm_instruction_int _prop} + {line} \l_tmpa_tl + \int_set:Nn \l__nm_line_int {\l_tmpa_tl} + \prop_get:cnN {g__nm_instruction_\int_use:N \l__nm_instruction_int _prop} + {column} \l_tmpa_tl + \int_set:Nn \l__nm_column_int {\l_tmpa_tl} + \int_case:nn \l__nm_type_int + { 0 {\int_set:Nn \l__nm_di_int 0 + \int_set:Nn \l__nm_dj_int 1} + 1 {\int_set:Nn \l__nm_di_int 0 + \int_set:Nn \l__nm_dj_int 1} + 2 {\int_set:Nn \l__nm_di_int 1 + \int_set:Nn \l__nm_dj_int 0} + 3 {\int_set:Nn \l__nm_di_int 1 + \int_set:Nn \l__nm_dj_int 1} + 4 {\int_set:Nn \l__nm_di_int 1 + \int_set:Nn \l__nm_dj_int {-1}}} + \bool_if_exist:NTF \l__nm_impossible_instruction_bool + {\bool_set_false:N \l__nm_impossible_instruction_bool} + {\bool_new:N \l__nm_impossible_instruction_bool} + \int_zero_new:N \l__nm_final_i_int + \int_zero_new:N \l__nm_final_j_int + \int_set:Nn \l__nm_final_i_int \l__nm_line_int + \int_set:Nn \l__nm_final_j_int \l__nm_column_int + \bool_if_exist:NTF \l__nm_stop_loop_bool + {\bool_set_false:N \l__nm_stop_loop_bool} + {\bool_new:N \l__nm_stop_loop_bool} + \bool_do_until:Nn \l__nm_stop_loop_bool + {\int_add:Nn \l__nm_final_i_int \l__nm_di_int + \int_add:Nn \l__nm_final_j_int \l__nm_dj_int + \bool_if:nTF { \int_compare_p:nNn \l__nm_final_i_int < 1 + || \int_compare_p:nNn \l__nm_final_i_int > \g__nm_line_int + || \int_compare_p:nNn \l__nm_final_j_int < 1 + || \int_compare_p:nNn \l__nm_final_j_int > \g__nm_nb_column_int} + {\bool_set_true:N \l__nm_impossible_instruction_bool + \bool_set_true:N \l__nm_stop_loop_bool} + {\__nm_if_not_empty_cell:nnT \l__nm_final_i_int \l__nm_final_j_int + {\bool_set_true:N \l__nm_stop_loop_bool}} + } + \int_zero_new:N \l__nm_initial_i_int + \int_zero_new:N \l__nm_initial_j_int + \int_set:Nn \l__nm_initial_i_int \l__nm_line_int + \int_set:Nn \l__nm_initial_j_int \l__nm_column_int + \bool_set_eq:NN \l__nm_stop_loop_bool \l__nm_impossible_instruction_bool + \bool_do_until:Nn \l__nm_stop_loop_bool + {\int_sub:Nn \l__nm_initial_i_int \l__nm_di_int + \int_sub:Nn \l__nm_initial_j_int \l__nm_dj_int + \bool_if:nTF + { \int_compare_p:nNn \l__nm_initial_i_int < 1 + || \int_compare_p:nNn \l__nm_initial_i_int > \g__nm_line_int + || \int_compare_p:nNn \l__nm_initial_j_int < 1 + || \int_compare_p:nNn \l__nm_initial_j_int > \g__nm_nb_column_int} + {\bool_set_true:N \l__nm_impossible_instruction_bool + \bool_set_true:N \l__nm_stop_loop_bool} + {\__nm_if_not_empty_cell:nnT \l__nm_initial_i_int \l__nm_initial_j_int + {\bool_set_true:N \l__nm_stop_loop_bool}} + } + \bool_if:NTF \l__nm_impossible_instruction_bool + {\msg_error:nn {nicematrix} {Impossible~instruction}} + {\tl_set:Nx \l_tmpa_tl {\int_use:N \l__nm_initial_i_int- + \int_use:N \l__nm_initial_j_int- + \int_use:N \l__nm_final_i_int- + \int_use:N \l__nm_final_j_int} + \seq_if_in:NVF \l__nm_yet_drawn_seq \l_tmpa_tl + {\seq_put_left:NV \l__nm_yet_drawn_seq \l_tmpa_tl + \dim_zero_new:N \g__nm_x_initial_dim + \dim_zero_new:N \g__nm_y_initial_dim + \dim_zero_new:N \g__nm_x_final_dim + \dim_zero_new:N \g__nm_y_final_dim + \int_case:nn \l__nm_type_int + {0 \__nm_draw_ldots_line: + 1 \__nm_draw_cdots_line: + 2 \__nm_draw_vdots_line: + 3 \__nm_draw_ddots_line: + 4 \__nm_draw_iddots_line:}}} + \int_incr:N \l__nm_instruction_int + } +} +\cs_new_protected:Nn \__nm_retrieve_coords:nn + {\tikz[remember~picture] + \path let \p1 = (nm-\int_use:N \g__nm_env_int- + \int_use:N \l__nm_initial_i_int- + \int_use:N \l__nm_initial_j_int #1), + \p2 = (nm-\int_use:N \g__nm_env_int- + \int_use:N \l__nm_final_i_int- + \int_use:N \l__nm_final_j_int #2) + in \pgfextra {\dim_gset:Nn \g__nm_x_initial_dim {\x1} + \dim_gset:Nn \g__nm_y_initial_dim {\y1} + \dim_gset:Nn \g__nm_x_final_dim {\x2} + \dim_gset:Nn \g__nm_y_final_dim {\y2}} ; } +\cs_new_protected:Nn \__nm_draw_ldots_line: + {\__nm_retrieve_coords:nn {.south~east} {.south~west} + \__nm_draw_tikz_line:} +\cs_new_protected:Nn \__nm_draw_cdots_line: + {\__nm_retrieve_coords:nn {.mid~east} {.mid~west} + \__nm_draw_tikz_line:} +\cs_new_protected:Nn \__nm_draw_vdots_line: + {\__nm_retrieve_coords:nn {.south} {.north} + \__nm_draw_tikz_line:} +\cs_new_protected:Nn \__nm_draw_ddots_line: + {\__nm_retrieve_coords:nn {.south~east} {.north~west} + \bool_if:NT \l__nm_parallelize_diags_bool + {\int_incr:N \l__nm_ddots_int + \int_compare:nNnTF \l__nm_ddots_int = 1 + {\dim_set:Nn \l__nm_delta_x_one_dim {\g__nm_x_final_dim - \g__nm_x_initial_dim } + \dim_set:Nn \l__nm_delta_y_one_dim {\g__nm_y_final_dim - \g__nm_y_initial_dim }} + {\dim_gset:Nn \g__nm_y_final_dim + {\g__nm_y_initial_dim + + (\g__nm_x_final_dim - \g__nm_x_initial_dim) + * \dim_ratio:nn \l__nm_delta_y_one_dim \l__nm_delta_x_one_dim }}} + \__nm_draw_tikz_line:} +\cs_new_protected:Nn \__nm_draw_iddots_line: + {\__nm_retrieve_coords:nn {.south~west} {.north~east} + \bool_if:NT \l__nm_parallelize_diags_bool + {\int_incr:N \l__nm_iddots_int + \int_compare:nNnTF \l__nm_iddots_int = 1 + {\dim_set:Nn \l__nm_delta_x_two_dim {\g__nm_x_final_dim - \g__nm_x_initial_dim } + \dim_set:Nn \l__nm_delta_y_two_dim {\g__nm_y_final_dim - \g__nm_y_initial_dim }} + {\dim_gset:Nn \g__nm_y_final_dim + {\g__nm_y_initial_dim + + (\g__nm_x_final_dim - \g__nm_x_initial_dim) + * \dim_ratio:nn \l__nm_delta_y_two_dim \l__nm_delta_x_two_dim }}} + \__nm_draw_tikz_line:} + +\cs_new_protected:Nn \__nm_draw_tikz_line: + {\begin{tikzpicture}[overlay] + \tikzmath{ + coordinate~\a , \b ; + real~\l, \x, \d ; + integer~\n ; + \a = (\g__nm_x_initial_dim, \g__nm_y_initial_dim) ; + \b = (\g__nm_x_final_dim, \g__nm_y_final_dim) ; + \l = veclen(\bx-\ax,\by-\ay) ; + \n = (\l - 0.54em)/(0.45em) ; + \x = (\l - \n*0.45em)/(2*\l) ; + \d = 0.45em / \l ; + if~\n>0 + then~{ for~\k in~{0,...,\n} + { {\node at ($(\a)!\x+\k*\d!(\b)$) {.} ; } ; } ; + } ; + } + \end{tikzpicture}} +\cs_set_eq:NN \__nm_ldots \ldots +\cs_set_eq:NN \__nm_cdots \cdots +\cs_set_eq:NN \__nm_vdots \vdots +\cs_set_eq:NN \__nm_ddots \ddots +\cs_set_eq:NN \__nm_iddots \iddots +\cs_new_protected:Nn \__nm_add_to_empty_cells: + {\seq_gput_right:Nx \g__nm_empty_cells_seq + {\int_use:N \g__nm_line_int- + \int_use:N \g__nm_column_int}} +\NewDocumentCommand \__nm_Ldots {s} + {\IfBooleanF {#1} {\__nm_instruction_of_type:n 0} + \bool_if:NF \l__nm_nullify_dots_bool {\phantom \__nm_ldots} + \__nm_add_to_empty_cells:} +\NewDocumentCommand \__nm_Cdots {s} + {\IfBooleanF {#1} {\__nm_instruction_of_type:n 1} + \bool_if:NF \l__nm_nullify_dots_bool {\phantom \__nm_cdots} + \__nm_add_to_empty_cells:} +\NewDocumentCommand \__nm_Vdots {s} + {\IfBooleanF {#1} {\__nm_instruction_of_type:n 2} + \bool_if:NF \l__nm_nullify_dots_bool {\phantom \__nm_vdots} + \__nm_add_to_empty_cells:} +\NewDocumentCommand \__nm_Ddots {s} + {\IfBooleanF {#1} {\__nm_instruction_of_type:n 3} + \bool_if:NF \l__nm_nullify_dots_bool {\phantom \__nm_ddots} + \__nm_add_to_empty_cells:} +\NewDocumentCommand \__nm_Iddots {s} + {\IfBooleanF {#1} {\__nm_instruction_of_type:n 4} + \bool_if:NF \l__nm_nullify_dots_bool {\phantom \__nm_iddots} + \__nm_add_to_empty_cells:} +\cs_new_protected:Nn \__nm_Hspace: + {\__nm_add_to_empty_cells: + \hspace} +\cs_new_protected:Nn \__nm_NiceMatrixEndPoint: + {\kern 0.5pt} +\ProcessKeysOptions {NiceMatrix} +\msg_new:nnnn {nicematrix} + {Impossible~instruction} + {It's~not~possible~to~execute~the~instruction~ + \int_case:nn \l__nm_type_int + {0 {\token_to_str:N \Ldots} + 1 {\token_to_str:N \Cdots} + 2 {\token_to_str:N \Vdots} + 3 {\token_to_str:N \Ddots}}~in~the~line~\int_use:N\l__nm_line_int\ + ~and~the~column~\int_use:N\l__nm_column_int\space of~the~matrix~ + because~it's~impossible~to~find~one~of~its~extremities~ + (both~extremities~must~be~non~empty~cells~of~the~matrix).~ + If~you~go~on,~the~instruction~will~be~ignored.} + {You~can~specify~a~end~of~line~on~a~empty~cell~ + with~\token_to_str:N \NiceMatrixEndPoint.} +\msg_new:nnn {nicematrix} + {multicolumn~forbidden} + {The~command~\token_to_str:N \multicolumn\ + is~forbidden~in~the~environment~\{NiceMatrix\}~ + and~its~variants.~The~command~\token_to_str:N \hdotsfor\ + of~amsmath~is~also~forbidden~since~it~uses~ + \token_to_str:N \multicolumn.~You~can~go~on~but~your~line~will~ + probably~be~wrong.} +\endinput +%% +%% End of file `nicematrix.sty'. diff --git a/Master/tlpkg/bin/tlpkg-ctan-check b/Master/tlpkg/bin/tlpkg-ctan-check index aa49e705774..568e3984743 100755 --- a/Master/tlpkg/bin/tlpkg-ctan-check +++ b/Master/tlpkg/bin/tlpkg-ctan-check @@ -450,7 +450,7 @@ my @TLP_working = qw( newcommand newenviron newfile newlfm newpx newsletr newspaper newtx newtxsf newtxtt newunicodechar newvbtm newverbs nextpage - nfssext-cfr nicefilelist niceframe niceframe-type1 nicetext + nfssext-cfr nicefilelist niceframe niceframe-type1 nicematrix nicetext nih nihbiosketch nimbus15 nkarta nlctdoc nmbib noconflict nodetree noindentafter noitcrul nolbreaks diff --git a/Master/tlpkg/tlpsrc/collection-mathscience.tlpsrc b/Master/tlpkg/tlpsrc/collection-mathscience.tlpsrc index 113c05ae53c..c185ef4cfb2 100644 --- a/Master/tlpkg/tlpsrc/collection-mathscience.tlpsrc +++ b/Master/tlpkg/tlpsrc/collection-mathscience.tlpsrc @@ -110,6 +110,7 @@ depend multiobjective depend mychemistry depend natded depend nath +depend nicematrix depend nuc depend nucleardata depend objectz diff --git a/Master/tlpkg/tlpsrc/nicematrix.tlpsrc b/Master/tlpkg/tlpsrc/nicematrix.tlpsrc new file mode 100644 index 00000000000..e69de29bb2d -- cgit v1.2.3