我似乎一直遇到同样的问题。为了更多地了解扩展,我编写了一个程序,该程序以 1 的序列开始,然后在每一步之后将其递增以生成 2 的序列,等等。然后,生成的所有不同序列必须tikz
以以下格式显示在矩阵中:
我使用了以下代码:
\documentclass[11pt]{article}
\usepackage{tikz}
\usetikzlibrary{matrix}
\ExplSyntaxOn
\NewDocumentCommand{\indexprod}{ m } % indices
{
\seq_set_from_clist:Nn \l_tmpc_seq { #1 }
\int_step_inline:nn {\seq_count:N \l_tmpc_seq}
{
\seq_put_right:Nn \l_tmpa_seq {1}
\seq_put_right:Nn \l_tmpb_seq {1}
}
\int_step_inline:nn {\seq_count:N \l_tmpc_seq - 1}
{
\tl_put_right:Nn \l_tmpa_tl {\mbox{\tiny $ \seq_item:Nn \l_tmpc_seq {##1} = 1$} \&}
}
\tl_put_right:Nn \l_tmpa_tl {\mbox{\tiny $ \seq_item:Nn \l_tmpc_seq {\seq_count:N \l_tmpc_seq} = 1$} \\}
\int_new:N \l_tmpc_int
\int_new:N \l_tmpd_int
\int_set:Nn \l_tmpc_int {4}
\int_step_inline:nnn {2} {\seq_count:N \l_tmpc_seq}
{
\int_set:Nn \l_tmpc_int {\l_tmpc_int * 4}
}
\int_log:N \l_tmpc_int
\int_step_inline:nnn {2} {\l_tmpc_int}
{
\int_set:Nn \l_tmpb_int {##1}
\int_log:N \l_tmpb_int
\int_step_inline:nn {\seq_count:N \l_tmpc_seq}
{
\int_set:Nn \l_tmpa_int {\seq_item:Nn \l_tmpa_seq{####1}}
\int_set:Nn \l_tmpd_int { \int_eval:n {\l_tmpa_int + 1}}
\int_log:N \l_tmpd_int
\seq_set_item:NnV \l_tmpb_seq {####1} \l_tmpd_int
}
\seq_log:N \l_tmpb_seq
\int_step_inline:nn {\seq_count:N \l_tmpc_seq - 1}
{
\tl_put_right:Nn \l_tmpa_tl {\mbox{\tiny $ \seq_item:Nn \l_tmpc_seq {####1} = \seq_item:Nn \l_tmpb_seq{####1} $} \&}
}
\tl_put_right:Nn \l_tmpa_tl {\mbox{\tiny $ \seq_item:Nn \l_tmpc_seq {\seq_count:N \l_tmpc_seq} = \seq_item:Nn \l_tmpb_seq {\seq_count:N \l_tmpb_seq}$} \\}
\int_step_inline:nn {\seq_count:N \l_tmpc_seq}
{
\int_set:Nn \l_tmpa_int {\int_eval:n {\seq_item:Nn \l_tmpb_seq{####1}}}
\int_log:N \l_tmpa_int
\seq_set_item:NnV \l_tmpa_seq {####1} \l_tmpa_int
}
\seq_log:N \l_tmpa_seq
}
\begin{tikzpicture}[baseline={([yshift=-0ex]current~bounding~box.center)}]
\matrix(m) [
matrix~of~nodes,
ampersand~replacement=\&,
column~sep=1ex,
nodes~in~empty~cells,
nodes={
shape=rectangle,
minimum~height=3ex,
anchor=center
},
]{
\tl_use:N \l_tmpa_tl
};
\end{tikzpicture}
}
\cs_generate_variant:Nn \seq_set_item:Nnn { NnV }
\ExplSyntaxOff
\begin{document}
\[
\indexprod{i,j}
\]
\end{document}
但结果当然是,
因为标记列表中的命令被冻结,并且诸如评估之类的命令\seq_item:Nn \l_tmpb_seq{####1}
使用其最新值来计算,而这些最新值恰好等于 16。
我查阅了相关文档,试图找到一种方法来改变这样的表达方式,
\tl_put_right:Nn \l_tmpa_tl {\mbox{\tiny $ \seq_item:Nn \l_tmpc_seq {####1} = \seq_item:Nn \l_tmpb_seq{####1} $} \&}
所以我利用了这些价值观\seq_item:Nn \l_tmpb_seq{####1}
,但却没能取得突破。
欢迎任何想法...
答案1
您需要\tl_put_right:Nx
让参数完全展开。但您不想完全展开\mbox
和\tiny
,因此需要一个强大的包装器。用定义的命令\NewDocumentCommand
永远不会在e
-expansion 或x
-expansion 中展开。
\documentclass[11pt]{article}
\usepackage{tikz}
\usetikzlibrary{matrix}
\NewDocumentCommand{\tinybox}{m}{\mbox{\tiny#1}}
\ExplSyntaxOn
\NewDocumentCommand{\indexprod}{ m } % indices
{
\seq_set_from_clist:Nn \l_tmpc_seq { #1 }
\int_step_inline:nn {\seq_count:N \l_tmpc_seq}
{
\seq_put_right:Nn \l_tmpa_seq {1}
\seq_put_right:Nn \l_tmpb_seq {1}
}
\int_step_inline:nn {\seq_count:N \l_tmpc_seq - 1}
{
\tl_put_right:Nx \l_tmpa_tl {\tinybox{$ \seq_item:Nn \l_tmpc_seq {##1} = 1$} \&}
}
\tl_put_right:Nx \l_tmpa_tl {\tinybox{$ \seq_item:Nn \l_tmpc_seq {\seq_count:N \l_tmpc_seq} = 1$} \\}
\int_new:N \l_tmpc_int
\int_new:N \l_tmpd_int
\int_set:Nn \l_tmpc_int {4}
\int_step_inline:nnn {2} {\seq_count:N \l_tmpc_seq}
{
\int_set:Nn \l_tmpc_int {\l_tmpc_int * 4}
}
\int_log:N \l_tmpc_int
\int_step_inline:nnn {2} {\l_tmpc_int}
{
\int_set:Nn \l_tmpb_int {##1}
\int_log:N \l_tmpb_int
\int_step_inline:nn {\seq_count:N \l_tmpc_seq}
{
\int_set:Nn \l_tmpa_int {\seq_item:Nn \l_tmpa_seq{####1}}
\int_set:Nn \l_tmpd_int { \int_eval:n {\l_tmpa_int + 1}}
\int_log:N \l_tmpd_int
\seq_set_item:NnV \l_tmpb_seq {####1} \l_tmpd_int
}
\seq_log:N \l_tmpb_seq
\int_step_inline:nn {\seq_count:N \l_tmpc_seq - 1}
{
\tl_put_right:Nx \l_tmpa_tl {\tinybox{$ \seq_item:Nn \l_tmpc_seq {####1} = \seq_item:Nn \l_tmpb_seq{####1} $} \&}
}
\tl_put_right:Nx \l_tmpa_tl {\tinybox{$ \seq_item:Nn \l_tmpc_seq {\seq_count:N \l_tmpc_seq} = \seq_item:Nn \l_tmpb_seq {\seq_count:N \l_tmpb_seq}$} \\}
\int_step_inline:nn {\seq_count:N \l_tmpc_seq}
{
\int_set:Nn \l_tmpa_int {\int_eval:n {\seq_item:Nn \l_tmpb_seq{####1}}}
\int_log:N \l_tmpa_int
\seq_set_item:NnV \l_tmpa_seq {####1} \l_tmpa_int
}
\seq_log:N \l_tmpa_seq
}
\begin{tikzpicture}[baseline={([yshift=-0ex]current~bounding~box.center)}]
\matrix(m) [
matrix~of~nodes,
ampersand~replacement=\&,
column~sep=1ex,
nodes~in~empty~cells,
nodes={
shape=rectangle,
minimum~height=3ex,
anchor=center
},
]{
\tl_use:N \l_tmpa_tl
};
\end{tikzpicture}
}
\cs_generate_variant:Nn \seq_set_item:Nnn { NnV }
\ExplSyntaxOff
\begin{document}
\[
\indexprod{i,j}
\]
\end{document}
您可能会喜欢研究下面更简单的代码。
\documentclass[11pt]{article}
\usepackage{tikz}
\usetikzlibrary{matrix}
\NewDocumentCommand{\tinybox}{m}{\mbox{\tiny#1}}
\ExplSyntaxOn
\NewDocumentCommand{\indexprod}{ O{16} m } % indices
{
% the indices
\seq_set_from_clist:Nn \l_tmpa_seq { #2 }
\seq_set_map:NNn \l_tmpb_seq \l_tmpa_seq { \tinybox{$##1=\int_eval:n { \l_tmpa_int }$} }
\tl_clear:N \l_tmpa_tl
\int_zero:N \l_tmpa_int
\prg_replicate:nn { #1 }
{
\int_incr:N \l_tmpa_int
\tl_set:Nx \l_tmpb_tl { \seq_use:Nn \l_tmpb_seq { \& } }
\tl_put_right:Nx \l_tmpa_tl { \l_tmpb_tl \exp_not:N \\ }
}
\begin{tikzpicture}[baseline={([yshift=-0ex]current~bounding~box.center)}]
\matrix(m) [
matrix~of~nodes,
ampersand~replacement=\&,
column~sep=1ex,
nodes~in~empty~cells,
nodes={
shape=rectangle,
minimum~height=3ex,
anchor=center
},
]{
\tl_use:N \l_tmpa_tl
};
\end{tikzpicture}
}
\ExplSyntaxOff
\begin{document}
\[
\indexprod{i,j}\qquad
\indexprod[5]{i,j,k}
\]
\end{document}
对上述代码的一些注释。如果我们设置它们之后,我们\seq_show:N \l_tmpa_seq
得到\seq_show:N \l_tmpb_seq
The sequence \l_tmpa_seq contains the items (without outer braces):
> {i}
> {j}.
The sequence \l_tmpb_seq contains the items (without outer braces):
> {\tinybox {$i=\int_eval:n {\l_tmpa_int }$}}
> {\tinybox {$j=\int_eval:n {\l_tmpa_int }$}}.
现在添加\tl_show:N \l_tmpb_tl
并在循环\tl_show:N \l_tmpa_tl
中设置它们\prg_replicate:nn
:在第一次迭代中我们得到
> \l_tmpb_tl=\tinybox {$i=\int_eval:n {\l_tmpa_int }$}\&\tinybox
{$j=\int_eval:n {\l_tmpa_int }$}.
> \l_tmpa_tl=\tinybox {$i=1$}\&\tinybox {$j=1$}\\.
这利用了这样一个事实:序列中的项目在\exp_not:n
它们周围返回,因此\tl_set:Nx
刚好到达“表面”标记列表;但在\tl_put_right:Nx
项目之后是完全展开。在这种情况下,我利用了 中的项目\l_tmpa_seq
是“扩展安全的”。其他用例可能需要其他注意。
更安全的版本
\documentclass[11pt]{article}
\usepackage{tikz}
\usetikzlibrary{matrix}
\NewDocumentCommand{\tinybox}{m}{\mbox{\tiny#1}}
\NewDocumentCommand{\tbinnermatrix}{m}{%
\begin{tikzpicture}[baseline={([yshift=-0ex]current bounding box.center)}]
\matrix(m) [
matrix of nodes,
ampersand replacement=\&,
column sep=1ex,
nodes in empty cells,
nodes={
shape=rectangle,
minimum height=3ex,
anchor=center
},
]{ #1 };
\end{tikzpicture}%
}
\ExplSyntaxOn
\NewDocumentCommand{\indexprod}{ O{16} m } % indices
{
\tedblack_indexprod:nn { #1 } { #2 }
}
\cs_generate_variant:Nn \cs_set:Nn { NV }
\cs_set_eq:NN \tedblack_innermatrix:n \tbinnermatrix
\cs_generate_variant:Nn \tedblack_mymatrix:n { V }
\cs_new_protected:Nn \tedblack_indexprod:nn
{
% the indices
\seq_set_from_clist:Nn \l_tmpa_seq { #2 }
\seq_set_map:NNn \l_tmpa_seq \l_tmpa_seq { \tinybox{$\exp_not:n { ##1 }=####1$} }
\tl_set:Nx \l_tmpa_tl { \seq_use:Nn \l_tmpa_seq { \& } }
\cs_set:NV \__tedblack_temp:n \l_tmpa_tl
\tl_clear:N \l_tmpa_tl
\int_step_inline:nn { #1 }
{
\tl_put_right:Nx \l_tmpa_tl { \__tedblack_temp:n { ##1 } \exp_not:N \\ }
}
\tedblack_innermatrix:V \l_tmpa_tl
}
\ExplSyntaxOff
\begin{document}
\[
\indexprod{i,j}\qquad
\indexprod[5]{i,j,\mathbf{k}}
\]
\end{document}
这不仅表明诸如的“危险”命令\mathbf
在的参数中是安全的\indexprod
,而且还表明了更好的编程风格,其中区分了用户级命令和内部函数。
“矩阵构建”命令在外部执行\ExplSyntaxOn
,这在 Ti 时始终是最好的钾涉及 Z。稍后将定义内部版本,并有可能定义其变体。
定义了一个“本地”函数,以便可以使用它来替换循环中的当前值\int_step_inline:nn
。
\documentclass[11pt]{article}
\usepackage{tikz}
\usetikzlibrary{matrix}
\NewDocumentCommand{\tinybox}{m}{\mbox{\tiny#1}}
\NewDocumentCommand{\tbinnermatrix}{m}{%
\begin{tikzpicture}[baseline={([yshift=-0ex]current bounding box.center)}]
\matrix(m) [
matrix of nodes,
ampersand replacement=\&,
column sep=1ex,
nodes in empty cells,
nodes={
shape=rectangle,
minimum height=3ex,
anchor=center
},
]{ #1 };
\end{tikzpicture}%
}
\ExplSyntaxOn
\NewDocumentCommand{\indexprod}{ O{16} m } % indices
{
\tedblack_indexprod:nn { #1 } { #2 }
}
\cs_generate_variant:Nn \cs_set:Nn { NV }
\cs_set_eq:NN \tedblack_innermatrix:n \tbinnermatrix
\cs_generate_variant:Nn \tedblack_innermatrix:n { V }
\cs_new_protected:Nn \tedblack_indexprod:nn
{
% the indices
\seq_set_from_clist:Nn \l_tmpa_seq { #2 }
\seq_set_map:NNn \l_tmpa_seq \l_tmpa_seq { \tinybox{$\exp_not:n { ##1 }=####1$} }
\tl_set:Nx \l_tmpa_tl { \seq_use:Nn \l_tmpa_seq { \& } }
\cs_set:NV \__tedblack_temp:n \l_tmpa_tl
\tl_clear:N \l_tmpa_tl
\int_step_inline:nn { #1 }
{
\tl_put_right:Nx \l_tmpa_tl { \__tedblack_temp:n { ##1 } \exp_not:N \\ }
}
\tedblack_innermatrix:V \l_tmpa_tl
}
\ExplSyntaxOff
\begin{document}
\[
\indexprod{i,j}\qquad
\indexprod[5]{i,j,\mathbf{k}}
\]
\end{document}
答案2
我知道这是 LaTeX3 中的一项练习,但我想提供我的 PGFKeys 版本。
值键也只存储我们可以修改的标记(其中包括)
\pgfkeyssetvalue{/key}{<value>}
和\pgfkeysaddvalue{/key}{<prefix>}{<suffix>}
或其处理程序替代方案(其中包括)
/key/.initial=<value>
(或者/key=<value>
如果/key
之前已经初始化)/key/.add={<prefix>}{<suffix>}
,/key/.prefix=<prefix>
和/key/.append=<suffix>
。
可以通过处理程序实现未分组的 PGFFor 循环,.list
从而允许我们重复使用一个键。
通过嵌套.list
应用程序,可以构建一个矩阵。我们只需确保将一个\pgfmatrixnextcell
(所有元素的&
/ )放入比列数少的元素中。这是通过不将其放入行的第一个单元格来实现的。这就是为什么在其自己的定义中重新定义的\&
原因。/tikz/matrix/create cell
我选择anchor = base
矩阵内的节点,使它们的基线对齐。矩阵本身固定在其中心,这意味着它的中心将位于是= 0pt 这是为 选择的值baseline
。
除了使用i, j, \mathbf{k}
列表之外,您还可以使用
\indexprod[
indexprod/rows=5,
column 3/.style={set matrix macro={$\mathbf{##2}=##1$}}
]{i, j, k}
达到同样的效果。当然,你可以使用另一个不那么冗长的顶级接口。
代码
\documentclass{article}
\usepackage{tikz}
\tikzset{
matrix node/.style 2 args={
name=\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn},
set matrix macro/.code=
\protected\def\tikzmatrixcell##1##2{\node[matrix node={##1}{##2}]{#1};},
set matrix macro'/.code=\protected\def\tikzmatrixcell##1##2{#1},
create matrix/.code 2 args=% quicker https://tex.stackexchange.com/a/692610
\pgfkeyssetvalue{/tikz/matrix/content}{}%
\pgfkeysdef{/tikz/matrix/create rows}{%
\pgfkeysvalueof{/tikz/matrix/reset create cell/.@cmd}\pgfeov
\pgfkeysdef{/tikz/matrix/create columns}{%
\pgfkeysvalueof{/tikz/matrix/create cell/.@cmd}{##1}{####1}\pgfeov}%
\tikzset{matrix/create columns/.list={#2}}%
\pgfkeysaddvalue{/tikz/matrix/content}{}{\pgfmatrixendrow}}%
\tikzset{matrix/create rows/.list={#1},
node contents=\pgfkeysvalueof{/tikz/matrix/content}},
matrix/reset create cell/.code=
\pgfkeysdefargs{/tikz/matrix/create cell}{##1##2}{%
\pgfkeysaddvalue{/tikz/matrix/content}{}{\tikzmatrixcell{##1}{##2}}%
\pgfkeysdefargs{/tikz/matrix/create cell}{####1####2}{%
\pgfkeysaddvalue{/tikz/matrix/content}{}{%
\pgfmatrixnextcell\tikzmatrixcell{####1}{####2}}}}}
\tikzset{
indexprod/rows/.initial=16,
indexprod/list/.initial={1, ..., \pgfkeysvalueof{/tikz/indexprod/rows}},
every indexprod diagram/.style={
baseline=+0pt, column sep=1ex, set matrix macro={$##2 = ##1$},
every outer matrix/.style={shape=rectangle, inner sep=+0pt, outer sep=+0pt},
every matrix/.style={
anchor=center, nodes={shape=rectangle, anchor=base, minimum height=3ex}}}}
\NewDocumentCommand{\indexprod}{O{} m}{%
\tikz[every indexprod diagram,#1]
\matrix[create matrix/.expanded=
{\pgfkeysvalueof{/tikz/indexprod/list}}{\unexpanded{#2}}];}
\begin{document}
\indexprod{i, j}
\quad
\indexprod[indexprod/rows=5]{i, j, \mathbf{k}}
\end{document}