我如何替换此 TikZ/PGF 命令中的 ifthen 包?

我如何替换此 TikZ/PGF 命令中的 ifthen 包?

我想修改一个命令,使它不需要包,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}

输出:

MWE 输出

答案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}

相关内容