我想修改一个命令,使它不需要包,ifthen
不一定是因为这个,为什么 ifthen 包已经过时了?,但只是使用了 中的功能Tikz/PGF
。问题是我尝试过的所有方法都不起作用。我以为它们\pgfmathifthenelse{}{}{}
会\pgfmathequal{}{}
起作用,但它们不起作用。我收到未知的控制序列错误。我是否遗漏了一些简单的东西?
% !TEX TS-program = lualatexmk
% !TEX encoding = UTF-8 Unicode
\documentclass{article}
\RequirePackage{unicode-math}
\unimathsetup{math-style=ISO}
\setmathfont[Scale=MatchLowercase]{TeX Gyre DejaVu Math} % Good g everywhere. Based on
\setmathfont[Scale=MatchLowercase,range={\mathscr,\mathbfscr}]{XITS Math}
\setmathfont[Scale=MatchLowercase,range={\mathcal,\mathbfcal},StylisticSet=1]{XITS Math}
\setmathfont[Scale=MatchLowercase,range= it/{greek,Greek}]{Latin Modern Math}
\setmathfont[Scale=MatchLowercase,range= bfit/{greek,Greek}]{Latin Modern Math}
\setmathfont[Scale=MatchLowercase,range= up/{greek,Greek}]{Latin Modern Math}
\setmathfont[Scale=MatchLowercase,range= bfup/{greek,Greek}]{Latin Modern Math}
\setmathfont[Scale=MatchLowercase,range=bfsfup/{greek,Greek}]{Latin Modern Math}
\usepackage{tikz}
\usepackage{xstring} % needed for \StrCount
\usepackage{ifthen}
\ExplSyntaxOn
\NewDocumentCommand{\reverselist}{ m m }{%
\clist_clear_new:N #1
\clist_set:Nx #1 { \clist_reverse:n { #2 } }
}%
\ExplSyntaxOff
\NewDocumentCommand{\TensorMachine}{ m O{} O{} }{%
% For aesthetic reasons, we need to reverse the order of #1.
\reverselist{\revslots}{#1}
\begin{tikzpicture}[baseline]
\pgfmathsetmacro{\cubex}{4}
\pgfmathsetmacro{\cubey}{1}
\pgfmathsetmacro{\cubez}{3}
\pgfmathsetmacro{\slotwidth}{1}
% front
\draw[fill=white,thick,line join=round] (0.5*\cubex,0.5*\cubey,0.5*\cubez) --
++(-\cubex,0,0) -- ++(0,-\cubey,0) -- ++(\cubex,0,0) -- cycle
% label the machine
node at (-0.30*\cubex,0,0.5*\cubez) {\(\symbf{#2}\)}
node at (0.30*\cubex,0,0.5*\cubez) {\(\symbf{#3}\)};
% side
\draw[fill=white,thick,line join=round] (0.5*\cubex,0.5*\cubey,-0.5*\cubez) --
++(0,0,\cubez) -- ++(0,-\cubey,0) -- ++(0,0,-\cubez) -- cycle;
% top
\draw[fill=white,thick,line join=round] (0.5*\cubex,0.5*\cubey,-0.5*\cubez) --
++(-\cubex,0,0) -- ++(0,0,\cubez) -- ++(\cubex,0,0) -- cycle;
% output slot
\draw[fill=black,ultra thick] (-0.5*\slotwidth,0,0.5*\cubez) --
++(0,0.03,0) -- ++(\slotwidth,0,0) -- ++(0,-0.03,0) -- cycle;
%\fill (0,0,0) circle (2pt); % origin
\ifthenelse{\equal{#1}{}}%
{% We have a scalar. Fill the output slot and we're done.
\draw[fill=white,thin,-] (-0.5*\slotwidth+0.1,0,0.5*\cubez)
-- ++(-0.25,-\slotwidth,0) -- ++(\slotwidth-0.2,0,0)
-- ++(0.25,\slotwidth,0)
node at (-0.125*\slotwidth,-0.5*\cubey,0.5*\cubez) {\(\symbb{R}\)};
}%
{% We have slots, which may be filled or unfilled.
% Set some values.
\StrCount{#1,}{,}[\numslots]
\StrCount{#1}{+}[\numfilledslots]
\pgfmathsetmacro{\startvslotx}{-0.25*\cubex-0.5*\slotwidth}
\pgfmathsetmacro{\startoslotx}{+0.25*\cubex-0.5*\slotwidth}
\pgfmathsetmacro{\sloty}{0.5*\cubey}
\pgfmathsetmacro{\totalnumslots}{\numslots}
\pgfmathsetmacro{\slotspace}{\cubez / (\totalnumslots + 1)}
\pgfmathsetmacro{\islotspaceindex}{1}
% Loop through the reversed list of slots.
\foreach \currentslot in \revslots {%
%\node at (4,0,0) {\currentslot}; % debug
\IfBeginWith{\currentslot}{v}%
{% Draw a vector slot.
\draw[fill=black,ultra thick]
(\startvslotx,\sloty,-0.5*\cubez+\islotspaceindex*\slotspace)
-- ++(0,0,0.04) -- ++(\slotwidth,0,0) -- ++(0,0,-0.04) -- cycle;
% Test to see if we need to fill the slot.
\IfEndWith{\currentslot}{+}%
{% Fill the slot.
\draw[fill=white,thin]
(\startvslotx+0.1,\sloty,-0.5*\cubez+\islotspaceindex*\slotspace)
-- ++(0,\slotwidth,0) -- ++(\slotwidth-0.2,0,0) -- ++(0,-\slotwidth,0);
}%
{% Leave it empty.
}%
}%
{% Draw a 1-form slot.
\draw[fill=black,ultra thick]
(\startoslotx,\sloty,-0.5*\cubez+\islotspaceindex*\slotspace)
-- ++(0,0,0.04) -- ++(\slotwidth,0,0)-- ++(0,0,-0.04) -- cycle;
% Test to see if we need to fill the slot.
\IfEndWith{\currentslot}{+}%
{% Fill the slot.
\draw[fill=lightgray,thin]
(\startoslotx+0.1,\sloty,-0.5*\cubez+\islotspaceindex*\slotspace)
-- ++(0,\slotwidth,0) -- ++(\slotwidth-0.2,0,0) -- ++(0,-\slotwidth,0);
}%
{% Leave it empty.
}%
}%
\pgfmathparse{\islotspaceindex+1}
\xdef\islotspaceindex{\pgfmathresult}
}%
% Test to see if we need to fill the output slot.
\ifthenelse{\equal{\numslots}{\numfilledslots}}%
{% Fill the output slot.
\draw[fill=white,thin,-] (-0.5*\slotwidth+0.1,0,0.5*\cubez)
-- ++(-0.25,-\slotwidth,0) -- ++(\slotwidth-0.2,0,0)
-- ++(0.25,\slotwidth,0)
node at (-0.125*\slotwidth,-0.5*\cubey,0.5*\cubez) {\(\symbb{R}\)};
}%
{% Leave it empty.
}%
}%
\end{tikzpicture}
}%
\begin{document}
\[
\TensorMachine{v,o}[T][e]
\]
%\[
%\TensorMachine{o+,v+}[T][e']
%\]
%\[
%\TensorMachine{o+,o+,v+}[T]
%\]
%\[
%\TensorMachine{}[\phi]
%\]
\end{document}
输出:
答案1
我用 LaTeX3 重写了你的代码。现在它不再依赖了ifthen
。我还改进了插槽的放置。
\documentclass{article}
\RequirePackage{unicode-math}
\unimathsetup{math-style=ISO}
\setmathfont[Scale=MatchLowercase]{TeX Gyre DejaVu Math} % Good g everywhere. Based on
\setmathfont[Scale=MatchLowercase,range={\mathscr,\mathbfscr}]{XITS Math}
\setmathfont[Scale=MatchLowercase,range={\mathcal,\mathbfcal},StylisticSet=1]{XITS Math}
\setmathfont[Scale=MatchLowercase,range= it/{greek,Greek}]{Latin Modern Math}
\setmathfont[Scale=MatchLowercase,range= bfit/{greek,Greek}]{Latin Modern Math}
\setmathfont[Scale=MatchLowercase,range= up/{greek,Greek}]{Latin Modern Math}
\setmathfont[Scale=MatchLowercase,range= bfup/{greek,Greek}]{Latin Modern Math}
\setmathfont[Scale=MatchLowercase,range=bfsfup/{greek,Greek}]{Latin Modern Math}
\usepackage{tikz}
\usepackage{xstring} % needed for \StrCount
\usepackage{ifthen}
\ExplSyntaxOn
% temp variables
\clist_new:N \g_tm_slot_clist
\clist_new:N \l_tm_tmpa_clist
\seq_new:N \l_tm_tmpa_seq
\seq_new:N \l_tm_tmpb_seq
\tl_new:N \l_tm_tmpa_tl
\str_new:N \l_tm_tmpa_str
\str_new:N \l_tm_tmpb_str
\str_new:N \l_tm_tmpc_str
\bool_new:N \l_tm_tmpa_bool
\dim_new:N \g_tm_tmpa_dim
\dim_new:N \g_tm_tmpb_dim
\int_new:N \l_tm_tmpa_int
\int_new:N \l_tm_tmpb_int
% ------drawing parameters
\dim_new:N \g_tm_cube_width_dim
\dim_new:N \g_tm_cube_height_dim
\dim_new:N \g_tm_cube_perspective_shift_x_dim
\dim_new:N \g_tm_cube_perspective_shift_y_dim
\dim_gset:Nn \g_tm_cube_width_dim {3.5cm}
\dim_gset:Nn \g_tm_cube_height_dim {1cm}
\dim_gset:Nn \g_tm_cube_perspective_shift_x_dim {1.5cm}
\dim_gset:Nn \g_tm_cube_perspective_shift_y_dim {1cm}
\fp_new:N \g_tm_slot_width_coef_fp
\fp_new:N \g_tm_slot_height_coef_fp
% width and height of slots
\fp_gset:Nn \g_tm_slot_width_coef_fp {0.2}
\fp_gset:Nn \g_tm_slot_height_coef_fp {0.08}
% width and height of filled regions
\fp_new:N \g_tm_fill_width_coef_fp
\fp_new:N \g_tm_fill_height_coef_fp
\fp_gset:Nn \g_tm_fill_width_coef_fp {0.18}
\fp_gset:Nn \g_tm_fill_height_coef_fp {0.9}
% slot fill parameter
\fp_new:N \g_tm_slot_fill_start_coef_fp
\fp_new:N \g_tm_slot_fill_end_coef_fp
\fp_gset:Nn \g_tm_slot_fill_start_coef_fp {0.15}
\fp_gset:Nn \g_tm_slot_fill_end_coef_fp {0.85}
% ------end drawing parameters
% compute important points/vectors and store them in the array
% values are initialized with 0, so we dont need to change everything
% each side takes 6 values
% origin_x, origin_y; right_x, right_y; up_x, up_y
\fparray_new:Nn \g_tm_point_fparr {18}
% front side
\fparray_gset:Nnn \g_tm_point_fparr {2} {\fp_eval:n {-\g_tm_cube_height_dim}}
\fparray_gset:Nnn \g_tm_point_fparr {3} {\fp_eval:n {\g_tm_cube_width_dim}}
\fparray_gset:Nnn \g_tm_point_fparr {6} {\fp_eval:n {\g_tm_cube_height_dim}}
% top side
\fparray_gset:Nnn \g_tm_point_fparr {9} {\fp_eval:n {\g_tm_cube_width_dim}}
\fparray_gset:Nnn \g_tm_point_fparr {11} {\fp_eval:n {\g_tm_cube_perspective_shift_x_dim}}
\fparray_gset:Nnn \g_tm_point_fparr {12} {\fp_eval:n {\g_tm_cube_perspective_shift_y_dim}}
% right side
\fparray_gset:Nnn \g_tm_point_fparr {13} {\fp_eval:n {\g_tm_cube_width_dim}}
\fparray_gset:Nnn \g_tm_point_fparr {14} {\fp_eval:n {-\g_tm_cube_height_dim}}
\fparray_gset:Nnn \g_tm_point_fparr {15} {\fp_eval:n {\g_tm_cube_perspective_shift_x_dim}}
\fparray_gset:Nnn \g_tm_point_fparr {16} {\fp_eval:n {\g_tm_cube_perspective_shift_y_dim}}
\fparray_gset:Nnn \g_tm_point_fparr {18} {\fp_eval:n {\g_tm_cube_height_dim}}
% o_x, o_y, a_x, a_y, b_x, b_y, c, d
% output: o + ca + db
\cs_set:Npn \tm_interp:nnnnnnnn #1#2#3#4#5#6#7#8 {
\fp_eval:n {(#1) + (#7) * (#3) + (#8) * (#5)}pt
,
\fp_eval:n {(#2) + (#7) * (#4) + (#8) * (#6)}pt
}
\cs_set:Npn \tm_indexed_interp:nnnnnnnn #1#2#3#4#5#6#7#8 {
\tm_interp:nnnnnnnn
{\fparray_item:Nn \g_tm_point_fparr {#1}}
{\fparray_item:Nn \g_tm_point_fparr {#2}}
{\fparray_item:Nn \g_tm_point_fparr {#3}}
{\fparray_item:Nn \g_tm_point_fparr {#4}}
{\fparray_item:Nn \g_tm_point_fparr {#5}}
{\fparray_item:Nn \g_tm_point_fparr {#6}}
{#7} {#8}
}
\cs_set:Npn \tm_front_interp:nn #1#2 {
\tm_indexed_interp:nnnnnnnn {1}{2}{3}{4}{5}{6}{#1}{#2}
}
\cs_set:Npn \tm_top_interp:nn #1#2 {
\tm_indexed_interp:nnnnnnnn {7}{8}{9}{10}{11}{12}{#1}{#2}
}
\cs_set:Npn \tm_right_interp:nn #1#2 {
\tm_indexed_interp:nnnnnnnn {13}{14}{15}{16}{17}{18}{#1}{#2}
}
% center_x, center_y, c, d
\cs_set:Npn \tm_top_fill_interp:nn #1#2 {
\tm_interp:nnnnnnnn
{\g_tm_tmpa_dim - 0.5 * \g_tm_fill_width_coef_fp * \g_tm_cube_width_dim}
{\g_tm_tmpb_dim}
{\g_tm_fill_width_coef_fp * \g_tm_cube_width_dim}
{0}
{0}
{\g_tm_fill_height_coef_fp * \g_tm_cube_height_dim}
{#1}
{#2}
}
\cs_set:Npn \tm_front_fill_interp:nn #1#2 {
\tm_interp:nnnnnnnn
{\g_tm_tmpa_dim + 0.5 * \g_tm_fill_width_coef_fp * \g_tm_cube_width_dim}
{\g_tm_tmpb_dim}
{-\g_tm_fill_width_coef_fp * \fparray_item:Nn \g_tm_point_fparr {9}}
{-\g_tm_fill_height_coef_fp * \fparray_item:Nn \g_tm_point_fparr {10}}
{-\g_tm_fill_width_coef_fp * \fparray_item:Nn \g_tm_point_fparr {11}}
{-\g_tm_fill_height_coef_fp * \fparray_item:Nn \g_tm_point_fparr {12}}
{#1}
{#2}
}
\cs_set:Npn \tm_interp_draw:nn #1#2 {
\draw[#2] (\use:c {tm_#1_interp:nn} {0}{0})
--(\use:c {tm_#1_interp:nn} {1}{0})
--(\use:c {tm_#1_interp:nn} {1}{1})
--(\use:c {tm_#1_interp:nn} {0}{1})
--(\use:c {tm_#1_interp:nn} {0}{0});
}
% index, total slots, x
\cs_set:Npn \tm_top_slot_y:nn #1#2 {
\int_case:nnF {#2} {
{1} {0.5}
{2} {\fp_eval:n {0.3 + (#1) * 0.4}}
} {
\fp_eval:n {
\g_tm_slot_fill_start_coef_fp + (#1) / (#2 - 1) *
(\g_tm_slot_fill_end_coef_fp - \g_tm_slot_fill_start_coef_fp)
}
}
}
% sets offset variable and draw the filled region
% the fill interp command will be valid until this command is called the next time
\cs_set:Npn \tm_fill_interp_draw:nnnn #1#2#3#4 {
\clist_set:Nx \l_tm_tmpa_clist {\use:c {tm_#1_interp:nn} {#2} {#3}}
\dim_gset:Nn \g_tm_tmpa_dim {\clist_item:Nn \l_tm_tmpa_clist {1}}
\dim_gset:Nn \g_tm_tmpb_dim {\clist_item:Nn \l_tm_tmpa_clist {2}}
\tm_interp_draw:nn {#1_fill} {#4}
}
% side, center_x, center_y, style
\cs_set:Npn \tm_draw_slot:n #1#2#3#4 {
\draw[#4]
(\use:c {tm_#1_interp:nn} {#2-0.5*\g_tm_slot_width_coef_fp}{#3-0.5*\g_tm_slot_height_coef_fp})
--(\use:c {tm_#1_interp:nn} {#2+0.5*\g_tm_slot_width_coef_fp}{#3-0.5*\g_tm_slot_height_coef_fp})
--(\use:c {tm_#1_interp:nn} {#2+0.5*\g_tm_slot_width_coef_fp}{#3+0.5*\g_tm_slot_height_coef_fp})
--(\use:c {tm_#1_interp:nn} {#2-0.5*\g_tm_slot_width_coef_fp}{#3+0.5*\g_tm_slot_height_coef_fp})
--(\use:c {tm_#1_interp:nn} {#2-0.5*\g_tm_slot_width_coef_fp}{#3-0.5*\g_tm_slot_height_coef_fp});
}
\NewDocumentCommand{\TensorMachine}{ m O{} O{} }{
\clist_gset:Nn \g_tm_slot_clist {#1}
\clist_greverse:N \g_tm_slot_clist
\begin{tikzpicture}[baseline]
% draw the cube
\tm_interp_draw:nn {front} {}
\tm_interp_draw:nn {top} {}
\tm_interp_draw:nn {right} {}
% draw slot in front side
\tm_draw_slot:n {front}{0.5}{0.5}{fill=black}
% put text
\node at (\tm_front_interp:nn {0.2}{0.5}) {$\symbf{#2}$};
\node at (\tm_front_interp:nn {0.8}{0.5}) {$\symbf{#3}$};
\int_set:Nn \l_tm_tmpa_int {0} % number of slots
\int_set:Nn \l_tm_tmpb_int {0} % number of filled slots
% group v's and o's in different sequences
\seq_clear:N \l_tm_tmpa_seq % store v's
\seq_clear:N \l_tm_tmpb_seq % store n's
\clist_map_variable:NNn \g_tm_slot_clist \l_tm_tmpa_tl {
\tl_set:Nx \l_tm_tmpa_tl {\exp_args:NV \tl_trim_spaces:n \l_tm_tmpa_tl}
\str_set:Nx \l_tm_tmpa_str {\tl_head:N \l_tm_tmpa_tl}
\str_case:Vn \l_tm_tmpa_str {
{v} {\seq_put_right:NV \l_tm_tmpa_seq \l_tm_tmpa_tl}
{o} {\seq_put_right:NV \l_tm_tmpb_seq \l_tm_tmpa_tl}
}
}
% draw v slots
\int_step_inline:nn {\seq_count:N \l_tm_tmpa_seq} {
\int_incr:N \l_tm_tmpa_int % increment #slots
\str_set:Nx \l_tm_tmpa_str {\seq_item:Nn \l_tm_tmpa_seq {##1}}
\str_set:Nx \l_tm_tmpb_str {\str_item:Nn \l_tm_tmpa_str {2}}
\str_if_eq:VnTF \l_tm_tmpb_str {+} {\bool_set_true:N \l_tm_tmpa_bool} {\bool_set_false:N \l_tm_tmpa_bool}
% get y location
\tl_set:Nx \l_tm_tmpa_tl {\tm_top_slot_y:nn {\seq_count:N \l_tm_tmpa_seq - ##1}{\seq_count:N \l_tm_tmpa_seq}}
\tm_draw_slot:n {top}{0.25}{\l_tm_tmpa_tl}{fill=black}
\bool_if:NT \l_tm_tmpa_bool {
\int_incr:N \l_tm_tmpb_int % increment #filled slots
\tm_fill_interp_draw:nnnn {top} {0.25} {\l_tm_tmpa_tl} {fill=gray}
}
}
% draw o slots
\int_step_inline:nn {\seq_count:N \l_tm_tmpb_seq} {
\int_incr:N \l_tm_tmpa_int % increment #slots
\str_set:Nx \l_tm_tmpa_str {\seq_item:Nn \l_tm_tmpb_seq {##1}}
\str_set:Nx \l_tm_tmpb_str {\str_item:Nn \l_tm_tmpa_str {2}}
\str_if_eq:VnTF \l_tm_tmpb_str {+} {\bool_set_true:N \l_tm_tmpa_bool} {\bool_set_false:N \l_tm_tmpa_bool}
% get y location
\tl_set:Nx \l_tm_tmpa_tl {\tm_top_slot_y:nn {\seq_count:N \l_tm_tmpb_seq - ##1}{\seq_count:N \l_tm_tmpb_seq}}
\tm_draw_slot:n {top}{0.75}{\l_tm_tmpa_tl}{fill=black}
\bool_if:NT \l_tm_tmpa_bool {
\int_incr:N \l_tm_tmpb_int % increment #filled slots
\tm_fill_interp_draw:nnnn {top} {0.75} {\l_tm_tmpa_tl} {fill=white}
}
}
\int_compare:nNnT {\l_tm_tmpa_int} = {\l_tm_tmpb_int} {
\tm_fill_interp_draw:nnnn {front}{0.5}{0.5}{fill=white}
\node at (\tm_front_fill_interp:nn {0.5}{0.5}) {$\mathbb{R}$};
}
\end{tikzpicture}
}
\ExplSyntaxOff
\begin{document}
\[
\TensorMachine{v,o}[T][e]
\]
\[
\TensorMachine{o+,v+}[T][e']
\]
\[
\TensorMachine{o+,o+,v+}[T]
\]
\[
\TensorMachine{o+,o+,o,v+}[T][e]
\]
\[
\TensorMachine{o+,o+,o,v+,v+,v,v+,v+}[T][e]
\]
\[
\TensorMachine{}[\phi]
\]
\end{document}