# Iteratively define a matrix

I was wondering if there is any way to iteratively define a matrix in LaTeX? For example, say I wanted to write the following matrix:

Of course, I could write this matrix by hand using a bmatrix enviroment, but for argument's sake, what if the example was much larger, such that it would be a pain to add each entry by hand. Then it would be much better to be able to define the matrix like so with macros (using pseudocode syntax for clarity):

#the matrix is size [m,n]
mymatrix = []
for i in range(m)
for j in range(n)
mymatrix[i,j] = \frac{G}{r^{2}_{i,j}}
endfor
endfor


Unfortunately, although I have used LaTeX before, I have never used macros, so I don't know where to start doing something like this, or if it is even possible. I am re-posting this question as I posted it on stack overflow before and it didn't get any comments.

Thanks for the help!

It is easy with nicematrix.

\documentclass{article}
\usepackage{nicematrix}

\begin{document}
\NiceMatrixOptions{cell-space-top-limit = 2pt,cell-space-bottom-limit = 2pt}
$F=\bAutoNiceMatrix{5-5}{\frac{G}{r^{2}_{\arabic{iRow}, \arabic{jCol}}}}$
\end{document}


A fairly general matrix generation macro:

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse,xfp}

\ExplSyntaxOn

\NewDocumentCommand{\generatematrix}{O{b}mmmO{0pt}}
{% #1 = fence (default b)
% #2 = n. of rows
% #3 = n. of cols
% #4 = entry template
% #5 = extra spacing
\sandalwood_matrix_generate:nnnnn { #1 } { #2 } { #3 } { #4 } { #5 }
}

\tl_new:N \l__sandalwood_matrix_body_tl

\cs_new_protected:Nn \sandalwood_matrix_generate:nnnnn
{
\group_begin:
\cs_set_protected:Nn \__sandalwood_matrix_entry:nn { #4 }
\tl_clear:N \l__sandalwood_matrix_body_tl
% generate the first m-1 rows, with the possible extra spacing in between
\int_step_inline:nn { #2 - 1 }
{
% the first object in a row gobbles a spurious &
\tl_put_right:Nn \l__sandalwood_matrix_body_tl { \use_none:n }
% fill the row
\int_step_inline:nn { #3 }
{
\tl_put_right:Nn \l__sandalwood_matrix_body_tl
{
& \__sandalwood_matrix_entry:nn { ##1 } { ####1 }
}
}
% add the extra spacing at the end of a row
\tl_put_right:Nn \l__sandalwood_matrix_body_tl { \\ \noalign{\vspace{#5}} }
}
% fill the last row
\tl_put_right:Nn \l__sandalwood_matrix_body_tl { \use_none:n }
\int_step_inline:nn { #3 }
{
\tl_put_right:Nn \l__sandalwood_matrix_body_tl
{
& \__sandalwood_matrix_entry:nn { #2 } { ##1 }
}
}
\begin{#1matrix}
\tl_use:N \l__sandalwood_matrix_body_tl
\end{#1matrix}
\group_end:
}

\ExplSyntaxOff

\newcommand{\hilbertmatrix}[1]{%
\generatematrix{#1}{#1}{\frac{1}{\inteval{##1+##2-1}}}[1ex]%
}

\begin{document}

$\generatematrix{5}{5}{\dfrac{G}{r_{#1#2}^2}}[1ex]= \generatematrix[v]{6}{4}{a_{#1,#2}}+\hilbertmatrix{4}$

\end{document}


The leading optional argument (default b) is meant to state the shape of the fences, in the standard amsmath way. The trailing mandatory argument should be a length (extra space between rows).

The third mandatory argument to \generatematrix is a template, where #1 denotes the row index and #2 the column index. I added how to define a macro based on \generatematrix to show that if we use it in a definition, we need to transform them into ##1 and ##2.

I know that the operations don't make sense. 😉

This is the output of

$\generatematrix{2}{3}{\generatematrix[p]{2}{2}{A_{#1,##1}^{#2,##2}}[2pt]}[1ex]$


• I have some trouble understanding the effect of \group_begin: and \group_end: in your code or some general case. Would you explain the effect of these command? Thanks a lot Commented Jun 11, 2020 at 9:25
• @ZhiyuanLck They're in just in case you plan to nest \generatematrix, so the setting of the template macro inside will not clobber the setting at the upper level. I added an example. Commented Jun 11, 2020 at 9:31
• Get it. Thanks again. Commented Jun 11, 2020 at 10:05