4

Suppose I wanted to generate a 5x4 matrix. A good way to do it is to write the following commands:

    \[
    \begin{tikzpicture}
        \matrix(m) [matrix of nodes, ampersand replacement=\&, row sep=1ex, column sep=1ex, nodes in empty cells, nodes={shape=rectangle,minimum height=3ex, anchor=center},] {                                
            $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}$  \\
            $A_{51}$  \& $A_{52}$ \& $A_{53}$ \& $A_{54}$  \\
        };
        \node[fit= (m-1-1.north west) (m-5-4.south east), left delimiter={[}, right delimiter={]},inner sep=1ex] {};
    \end{tikzpicture}            
    \]

(I use tikz because it allows me to format individual matrix elements and insert graphics). This can get rather tiring if I have to populate a 10x9 matrix. The idea is to write a NewDocumentCommand with three inputs: the letter denoting the matrix, the number of rows and the number of columns. Using expl3 I should be able to generate the matrix contents. Then I should be able to write something like,

    \begin{tikzpicture}
        \matrix(m) [matrix of nodes, ampersand replacement=\&, row sep=1ex, column sep=1ex, nodes in empty cells, nodes={shape=rectangle,minimum height=3ex, anchor=center},] {    
           \matrixcontents                      
        };
        \node[fit= (m-1-1.north west) (m-#2-#3.south east), left delimiter={[}, right delimiter={]},inner sep=1ex] {};
    \end{tikzpicture}

where \matrixcontents contains

            $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}$  \\
            $A_{51}$  \& $A_{52}$ \& $A_{53}$ \& $A_{54}$  \\

and #2, #3 are respectively the number of rows, number of columns arguments of the NewDocumentCommand (in this example #1 is the letter A).

I am an absolute beginner with expl3 and so I have no idea how to generate \matrixcontents.

Ted Black
  • 453
  • 2
  • 8

3 Answers3

3

Here's how you can do it:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix,fit}

\ExplSyntaxOn \NewDocumentCommand{\matrixcontents}{mmm} {% #1 = symbol, #2 = number of rows, #3 = number of columns \tl_clear:N \l_tmpa_tl \int_step_inline:nn { #2 } {% ##1 = row index \int_step_inline:nn { #3 - 1 } {% ####1 = column index \tl_put_right:Nn \l_tmpa_tl { $#1\sb{##1####1}$ & } } \tl_put_right:Nn \l_tmpa_tl { $#1\sb{##1#3}$ \ } } \tl_use:N \l_tmpa_tl } \ExplSyntaxOff

\begin{document}

[ \begin{tikzpicture} \matrix(m) [ matrix of nodes, ampersand replacement=&, row sep=1ex, column sep=1ex, nodes in empty cells, nodes={ shape=rectangle, minimum height=3ex, anchor=center }, ]{ \matrixcontents{A}{5}{4} }; \node[ fit= (m-1-1.north west) (m-5-4.south east), left delimiter={[}, right delimiter={]}, inner sep=1ex ] {}; \end{tikzpicture} ]

\end{document}

The code performs a loop on the rows and in each one a loop on the columns (the last cell in a row is special).

enter image description here

Even shorter:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix,fit}

\NewDocumentCommand{\symbolicmatrix}{O{}mmm}{% % #1 = further options, #2 = symbol, #3 = number of rows, #4 = number of columns \matrix(m) [ matrix of nodes, ampersand replacement=&, row sep=1ex, column sep=1ex, nodes in empty cells, nodes={ shape=rectangle, minimum height=3ex, anchor=center },#1, ]{\matrixcontents{#2}{#3}{#4}}; \node[ fit= (m-1-1.north west) (m-#3-#4.south east), left delimiter={[}, right delimiter={]}, inner sep=1ex ] {}; }

\ExplSyntaxOn \NewDocumentCommand{\matrixcontents}{mmm} {% #1 = symbol, #2 = number of rows, #3 = number of columns \tl_clear:N \l_tmpa_tl \int_step_inline:nn { #2 } {% ##1 = row index \int_step_inline:nn { #3 - 1 } {% ####1 = column index \tl_put_right:Nn \l_tmpa_tl { $#1\sb{##1####1}$ & } } \tl_put_right:Nn \l_tmpa_tl { $#1\sb{##1#3}$ \ } } \tl_use:N \l_tmpa_tl } \ExplSyntaxOff

\begin{document}

[ \begin{tikzpicture} \symbolicmatrix{A}{5}{4} \end{tikzpicture} ]

\end{document}

The \symbolicmatrix command has a leading optional argument for more options to the \matrix command.

For instance

\[
\begin{tikzpicture}
  \symbolicmatrix[row sep=2ex,column sep=2ex]{A}{5}{4}
\end{tikzpicture}
\]

would produce

enter image description here

egreg
  • 1,121,712
3

For information, the package nicematrix provides commands to generated matrices where each cell is in a TikZ node (it's not a tikz-matrix).

\documentclass{article}
\usepackage{nicematrix,tikz}

\begin{document}

$\bAutoNiceMatrix[name=A]{5-4}{A_{\arabic{iRow},\arabic{jCol}}}$

\begin{tikzpicture}[remember picture, overlay] \draw [<-] (A-5-2) -- ++ (0,-5mm) node [below] {$x$} ; \end{tikzpicture}

\end{document}

Output of the above code

F. Pantigny
  • 40,250
  • Thanks. nice matrix is a great package; the reason I use tikz for matrices is because it allows for nested matrices (i.e. matrices whose elements are matrices) through the use of commands like fit= (m-1-1.north west) (m-#3-#4.south east),left delimiter={[},right delimiter={]},inner sep=1ex ] {}; tikz also allows multiple headers for columns and rows; so for a nested matrix I could have a separate line for each index, however many indices I use for rows and columns. – Ted Black Aug 31 '23 at 11:31
  • I understand. However, you should have a look at the command \Submatrix of nicematrix. – F. Pantigny Aug 31 '23 at 12:00
2

This is similar to @egreg's answer, but builds the matrix body with expandable code, the result should be faster code (but I didn't benchmark). Also the tikzpicture environment is included in the macro (you might remove it if you don't want this).

I hope the comments are enough to explain the code.

\documentclass{article}

\usepackage{tikz} \usetikzlibrary{matrix, fit}

\ExplSyntaxOn \int_new:N \l__ted_matrix_cols_int \tl_new:N \l__ted_matrix_variable_tl \cs_new:Npn __ted_matrix_row:n #1 { % after we built a row we need to remove the leading \exp_not:N &amp; from the % first cell \exp_last_unbraced:Ne \use_none:nn { % \prg_replicate:nn needs two steps of expansion % we use it instead of an \int_map_... because there is no \int_map_... % that allows us to expandably forward additional arguments (#1) \exp_args:No \use_ii_i:on { \prg_replicate:nn \l__ted_matrix_cols_int __ted_matrix_cell:nnN } { __ted_matrix_cell:nnN 1 {#1} } % the \use_none:nn ends the __ted_matrix_cell:nnN loop \use_none:nn } \exp_not:N \ } \cs_generate_variant:Nn \use_ii_i:nn { o } % simple loop to return each cell \cs_new:Npn __ted_matrix_cell:nnN #1#2#3 { % will be wrapped in two e-expansion contexts, inner one is from the row, % outer one is from building the entire body % $, #1, #2, and \sb don't need protection against further expansion. \exp_not:n { \exp_not:N &amp; $ \exp_not:V \l__ted_matrix_variable_tl \sb { #2#1 } $ } \exp_args:Ne #3 { \int_eval:n { #1 + 1 } } {#2} } \NewDocumentCommand \tmatrix { O{} m m m } { \begin{tikzpicture} \tl_set:Nn \l__ted_matrix_variable_tl {#2} % we store #4-1 because one is hardcoded by the way we start the loop to % build each cell of a row. \int_set:Nn \l__ted_matrix_cols_int { #4 - 1 } \exp_args:Nne \use:n { \matrix(m) [matrix~of~nodes, ampersand~replacement=&amp;, row~sep=1ex, column~sep=1ex, nodes~in~empty~cells, nodes={shape=rectangle,minimum~height=3ex, anchor=center}, #1] } { \int_step_function:nN {#3} __ted_matrix_row:n } ; \node[fit= (m-1-1.north~west) (m-#3-#4.south~east), left~delimiter={[}, right~delimiter={]},inner~sep=1ex] {}; \end{tikzpicture} } \ExplSyntaxOff

\begin{document} \tmatrix{A}{5}{4} \end{document}

Result:

enter image description here

Skillmon
  • 60,462
  • Thanks. I need to do some more reading to grasp code expansion. Your code is definitely fast I just need to make sure I understand what I am doing... – Ted Black Aug 31 '23 at 13:34
  • @TedBlack in practice the version by egreg should be fast enough (you'd have to produce loads of matrices to notice the difference, and even then, the real choke will most likely be the TikZ part, not the matrix body generation). This is more for educational purposes, imho. – Skillmon Aug 31 '23 at 13:49
  • Would be great if someone writes “expl3 expansion guide for idiots” Have been going through l3expan but still no light… – Ted Black Sep 01 '23 at 09:46
  • @TedBlack it's basically TeX expansion, so you should try to grasp that. All that expl3 does is give easier control over TeX expansion (by removing the need for long \expandafter-chains, instead you just use argument types like o or e). – Skillmon Sep 04 '23 at 05:57