在 tikz 中向函数返回值

在 tikz 中向函数返回值
\begin{tikzpicture}[declare function=
{matmul(\a,\b)=
\def\product{}
\foreach \i in \b
{
\def\temp{}
\foreach \j in \a
{
\edef\temp{\temp,{\i}[0]*{\j}[0]+{\i}[1]*{\j}[1]+{\i}[2]*{\j}[2]}
}
\edef\product{\product,{\temp}}
}
}
]
\end{tikzpicture}

这是我的函数,它接受两个列表并对它们进行操作。我不知道如何将 \product 列表返回给函数。例如

output = matmul(list1,list2)

我现在希望输出包含 \product 包含的所有内容

答案1

\foreach您的方法存在分组执行操作的问题,并且\edef仅在本地定义宏。所以你可以\xdef改为这样做。因为您可能会用尽名称空间和/或覆盖其他宏,所以通常使用一些具有搞笑名称的临时宏和一些@来执行此操作,以尽量减少造成伤害的可能性。所以下面的怪物用进行一些矩阵乘法\foreach。还有其他方法可能更优雅,但也更难理解。您需要向函数提供包含矩阵matmult的宏的名称(否\)。怪物会进行一些最低限度的健全性检查。

\documentclass{article}
\usepackage{tikz}
\makeatletter
\pgfmathdeclarefunction{matmult}{2}{%
\begingroup%
\edef\pgfutil@tempA{\csname #1\endcsname}%
\edef\pgfutil@tempB{\csname #2\endcsname}%
\foreach \pgfutil@tempa [count=\pgfutil@tempc starting from 0] in \pgfutil@tempA
{\foreach \pgfutil@tempb [count=\pgfutil@tempd starting from 0] in \pgfutil@tempa 
{\xdef\pgfutil@tempe{\pgfutil@tempd}%
}\xdef\pgfutil@tempf{\pgfutil@tempc}%
}%
\edef\tmp@cols@A{\pgfutil@tempe}%
\edef\tmp@rows@A{\pgfutil@tempf}%
\foreach\pgfutil@tempa[count=\pgfutil@tempc starting from 0]in\pgfutil@tempB
{\foreach\pgfutil@tempb[count=\pgfutil@tempd starting from 0]in\pgfutil@tempa 
{\xdef\pgfutil@tempe{\pgfutil@tempd}%
}\xdef\pgfutil@tempf{\pgfutil@tempc}%
}%
\edef\tmp@cols@B{\pgfutil@tempe}%
\edef\tmp@rows@B{\pgfutil@tempf}%
 %\typeout{A:\the\numexpr\tmp@rows@A+1 x\the\numexpr\tmp@cols@A+1,B:\the\numexpr\tmp@rows@B+1\space x\the\numexpr\tmp@cols@B+1}%
\ifnum\tmp@rows@B=\tmp@cols@A
\foreach\pgfutil@tempa in{0,...,\tmp@rows@A}%
{\foreach\pgfutil@tempb in{0,...,\tmp@cols@B}%
{\foreach\pgfutil@tempc in{0,...,\tmp@cols@A}%
{\pgfmathparse{{\pgfutil@tempA}[\pgfutil@tempa][\pgfutil@tempc]*{\pgfutil@tempB}[\pgfutil@tempc][\pgfutil@tempb]}%
\ifnum\pgfutil@tempc=0\relax
 \xdef\pgfutil@tempd{\pgfmathresult}%
\else
 \pgfmathparse{\pgfmathresult+\pgfutil@tempd}%
 \xdef\pgfutil@tempd{\pgfmathresult}%
\fi
}%
\ifnum\pgfutil@tempb=0\relax
\xdef\pgfutil@tempe{\pgfutil@tempd}%
\else
\xdef\pgfutil@tempe{\pgfutil@tempe,\pgfutil@tempd}%
\fi
 %\typeout{curr row=\pgfutil@tempe}%
}%
\ifnum\pgfutil@tempa=0\relax
\xdef\pgfutil@tempf{{\pgfutil@tempe}}%
\else
\xdef\pgfutil@tempf{\pgfutil@tempf,{\pgfutil@tempe}}%
\fi
 %\typeout{a=\pgfutil@tempa:curr mat=\pgfutil@tempf}%
}%
\edef\pgfmathresult{\pgfutil@tempf}%
\else
\typeout{Dimensions do not match up.}%
\edef\pgfmathresult{}%
\fi
\pgfmathsmuggle\pgfmathresult\endgroup%
}%
\makeatother
\begin{document}
test:\edef\matA{{1,2,1},{-1,0,1},{1,2,3}}%
\edef\matB{{1,-2,0},{-1,2,0},{2,0,-3}}%
\pgfmathparse{matmult("matA","matB")}%
$A\cdot B=\pgfmathresult$\typeout{AxB=\pgfmathresult}
\end{document}

打字说

AxB={1.0,2.0,-3.0},{1.0,2.0,-3.0},{5.0,2.0,-9.0}

哪个是对的。

稍微短一点的版本是

\documentclass{article}
\usepackage{tikz}
\makeatletter
\pgfmathdeclarefunction{Dim}{1}{%
\begingroup%
\pgfutil@tempcnta0%
\@for\pgfutil@tempa:=#1\do{\advance\pgfutil@tempcnta1}%
\edef\pgfmathresult{\the\pgfutil@tempcnta}%
\pgfmathsmuggle\pgfmathresult\endgroup%
}
\pgfmathdeclarefunction{matmult}{2}{%
\begingroup%
\edef\pgfutil@tempA{\csname #1\endcsname}%
\edef\pgfutil@tempB{\csname #2\endcsname}%
\pgfmathtruncatemacro{\tmp@rows@A}{Dim("\pgfutil@tempA")-1}%
\pgfmathtruncatemacro{\tmp@cols@A}{Dim("\pgfutil@tempA[0]")-1}%
\pgfmathtruncatemacro{\tmp@rows@B}{Dim("\pgfutil@tempB")-1}%
\pgfmathtruncatemacro{\tmp@cols@B}{Dim("\pgfutil@tempB[0]")-1}%
 %\typeout{A:\the\numexpr\tmp@rows@A+1 x\the\numexpr\tmp@cols@A+1,B:\the\numexpr\tmp@rows@B+1\space x\the\numexpr\tmp@cols@B+1}%
\ifnum\tmp@rows@B=\tmp@cols@A
\foreach\pgfutil@tempa in{0,...,\tmp@rows@A}%
{\foreach\pgfutil@tempb in{0,...,\tmp@cols@B}%
{\foreach\pgfutil@tempc in{0,...,\tmp@cols@A}%
{\pgfmathparse{{\pgfutil@tempA}[\pgfutil@tempa][\pgfutil@tempc]*{\pgfutil@tempB}[\pgfutil@tempc][\pgfutil@tempb]}%
\ifnum\pgfutil@tempc=0\relax
 \xdef\pgfutil@tempd{\pgfmathresult}%
\else
 \pgfmathparse{\pgfmathresult+\pgfutil@tempd}%
 \xdef\pgfutil@tempd{\pgfmathresult}%
\fi
}%
\ifnum\pgfutil@tempb=0\relax
\xdef\pgfutil@tempe{\pgfutil@tempd}%
\else
\xdef\pgfutil@tempe{\pgfutil@tempe,\pgfutil@tempd}%
\fi
 %\typeout{curr row=\pgfutil@tempe}%
}%
\ifnum\pgfutil@tempa=0\relax
\xdef\pgfutil@tempf{{\pgfutil@tempe}}%
\else
\xdef\pgfutil@tempf{\pgfutil@tempf,{\pgfutil@tempe}}%
\fi
 %\typeout{a=\pgfutil@tempa:curr mat=\pgfutil@tempf}%
}%
\edef\pgfmathresult{\pgfutil@tempf}%
\else
\typeout{Dimensions do not match up.}%
\edef\pgfmathresult{}%
\fi
\pgfmathsmuggle\pgfmathresult\endgroup%
}%
\makeatother
\begin{document}
test:\edef\matA{{1,2,1},{-1,0,1},{1,2,3}}%
\edef\matB{{1,-2,0},{-1,2,0},{2,0,-3}}%
\pgfmathparse{matmult("matA","matB")}%
$A\cdot B=\pgfmathresult$\typeout{AxB=\pgfmathresult}

\pgfmathparse{Dim("\matA[0]")}%
\pgfmathresult
\end{document}

如果需要的话,可以继续使用更多\@fors 来避免\xdefs。这可能会变得越来越难以理解。

相关内容