用 LaTeX 编写较长的程序代码是否方便?

用 LaTeX 编写较长的程序代码是否方便?

之前只会用ifthenelse循环for,很少用复杂的数据结构,不知道有什么方便的方法可以写长一点的代码。

举个例子,我想生成一个从 0 到 9 的随机数字排列。这不是一个复杂的问题,但我不知道如何轻松解决它。有没有可以让编程变得轻松的包?

答案1

通过LuaTeX您可以使用脚本语言Lua:

\documentclass{article}
\usepackage{luacode}
\begin{luacode}
function permute(n)
  local tab = {}
  for i = 1, n do tab[i] = i end
  for i = 1, n do
    local j = math.random(i, n)
    tab[i], tab[j] = tab[j], tab[i]
  end
  for i = 1, n do
    tex.print("\\shortstack{"..i.."\\\\"..tostring(tab[i]).."} ")
  end
end
\end{luacode}

\begin{document}

\directlua{permute(20)}

\end{document}

在此处输入图片描述

答案2

以下是Knuth 洗牌算法expl3

\documentclass{article}
\usepackage{amsmath,xparse}
\input{random}

\ExplSyntaxOn

\cs_new_eq:NN \knuthshuffle_get_random:Nnn \setrannum

\tl_new:N \l_knuthshuffle_tempa_tl
\tl_new:N \l_knuthshuffle_tempb_tl
\int_new:N \l_knuthshuffle_random_int
\prop_new:N \l_knuthshuffle_newperm_prop
\prop_new:N \g_knuthshuffle_identity_prop % the identity
\seq_new:N \l_knuthshuffle_permutation_seq

\int_step_inline:nnnn { 1 } { 1 } { 100 }
 {
  \prop_gput:Nnn \g_knuthshuffle_identity_prop { #1 } { #1 }
 }


\NewDocumentCommand{\generatepermutation}{m}
 {
  \knuthshuffle_generate:n { #1 }
 }

\NewDocumentCommand{\printpermutation}{}
 {
  \left(
  \int_step_inline:nnnn { 1 } { 1 } { \seq_count:N \l_knuthshuffle_permutation_seq }
   {
    \begin{array}{c}
    ##1 \\ \seq_item:Nn \l_knuthshuffle_permutation_seq { ##1 }
    \end{array}
   }
  \right)
 }

\cs_new_protected:Nn \knuthshuffle_generate:n
 {
  \prop_set_eq:NN \l_knuthshuffle_newperm_prop \g_knuthshuffle_identity_prop
  \int_step_inline:nnnn { #1 } { -1 } { 2 }
   {
    \knuthshuffle_get_random:Nnn \l_knuthshuffle_random_int { 1 } { ##1 }
    \prop_get:NnN \l_knuthshuffle_newperm_prop { ##1 } \l_knuthshuffle_tempa_tl 
    \prop_get:NVN \l_knuthshuffle_newperm_prop \l_knuthshuffle_random_int \l_knuthshuffle_tempb_tl 
    \prop_put:NnV \l_knuthshuffle_newperm_prop { ##1 } \l_knuthshuffle_tempb_tl
    \prop_put:NVV \l_knuthshuffle_newperm_prop \l_knuthshuffle_random_int \l_knuthshuffle_tempa_tl
   }
  \seq_clear:N \l_knuthshuffle_permutation_seq
  \int_step_inline:nnnn { 1 } { 1 } { #1 }
   {
    \seq_put_right:Nx \l_knuthshuffle_permutation_seq
     {
      \prop_item:Nn \l_knuthshuffle_newperm_prop { ##1 }
     }
   }
  %\seq_show:N \l_knuthshuffle_permutation_seq % for debugging
 }
\ExplSyntaxOff


\begin{document}

\generatepermutation{20}

\[
\printpermutation
\]

\end{document}

排列存储在一个序列中,然后由您来决定如何处理它。我添加了一个\printpermutation宏只是为了展示如何打印最近生成的排列。

在此处输入图片描述

我使用的工具是

  1. 表示 1 至 1000 之间的数字的恒等排列的固定属性列表

  2. 从最后一处向下循环;在步骤,一个随机数r1 至由 D. Arsenau生成random.tex(希望它能很快集成到expl3);元素位于与位置处的元素交换r

  3. 另一个循环加载具有确定元素的序列,以供进一步处理。

身份最多定义为 100,这应该是一个足够的界限,并且可以缩短处理时间。


有一种更快的方法(尽管会浪费更多内存),使用一个\csname技巧。以前的解决方案旨在通过一个玩具问题展示可用的工具,而不是寻找有效的实现。

\documentclass{article}
\usepackage{amsmath,xparse}
\input{random}

\ExplSyntaxOn

\cs_new_eq:NN \knuthshuffle_get_random:Nnn \setrannum

\tl_new:N \l_knuthshuffle_tempa_tl
\tl_new:N \l_knuthshuffle_tempb_tl
\int_new:N \l_knuthshuffle_random_int
\seq_new:N \l_knuthshuffle_permutation_seq

\NewDocumentCommand{\generatepermutation}{m}
 {
  \knuthshuffle_generate:n { #1 }
 }

\NewDocumentCommand{\printpermutation}{}
 {
  \left(
  \int_step_inline:nnnn { 1 } { 1 } { \seq_count:N \l_knuthshuffle_permutation_seq }
   {
    \begin{array}{c}
    ##1 \\ \seq_item:Nn \l_knuthshuffle_permutation_seq { ##1 }
    \end{array}
   }
  \right)
 }

\cs_new_protected:Nn \knuthshuffle_generate:n
 {
  \int_step_inline:nnnn { 1 } { 1 } { #1 }
   {
    \tl_clear_new:c { l_knuthshuffle_##1_element_tl }
    \tl_set:cn { l_knuthshuffle_##1_element_tl } { ##1 }
   }
  \prop_set_eq:NN \l_knuthshuffle_newperm_prop \g_knuthshuffle_identity_prop
  \int_step_inline:nnnn { #1 } { -1 } { 2 }
   {
    \knuthshuffle_get_random:Nnn \l_knuthshuffle_random_int { 1 } { ##1 }
    \tl_set_eq:Nc \l_knuthshuffle_tempa_tl
     { l_knuthshuffle_##1_element_tl }
    \tl_set_eq:Nc \l_knuthshuffle_tempb_tl
     { l_knuthshuffle_ \int_to_arabic:n \l_knuthshuffle_random_int _element_tl }
    \tl_set_eq:cN { l_knuthshuffle_##1_element_tl }
     \l_knuthshuffle_tempb_tl
    \tl_set_eq:cN { l_knuthshuffle_ \int_to_arabic:n \l_knuthshuffle_random_int _element_tl }
     \l_knuthshuffle_tempa_tl
   }
  \seq_clear:N \l_knuthshuffle_permutation_seq
  \int_step_inline:nnnn { 1 } { 1 } { #1 }
   {
    \seq_put_right:Nv \l_knuthshuffle_permutation_seq { l_knuthshuffle_##1_element_tl }
   }
%  \seq_show:N \l_knuthshuffle_permutation_seq % for debugging
 }
\ExplSyntaxOff

\begin{document}
\generatepermutation{20}

\[
\printpermutation
\]

\end{document}

这些值使用标记列表变量数组存储在关联数组中,这使得寻址速度更快,但会占用大量内存。

在此处输入图片描述


在 Plain TeX 中也是一样:

\input random
\newcount\myrandom
\newcount\tempcount

\def\generatepermutation#1{%
  \def\lastlength{#1}%
  \tempcount=0
  \loop\ifnum\tempcount<#1\relax
    \advance\tempcount 1
    \expandafter\edef\csname shuffle\the\tempcount element\endcsname{\the\tempcount}%
  \repeat
  \loop\ifnum\tempcount>1
    \setrannum\myrandom{1}{\tempcount}
    \edef\tempa{\csname shuffle\the\tempcount element\endcsname}%
    \edef\tempb{\csname shuffle\the\myrandom element\endcsname}%
    \expandafter\edef\csname shuffle\the\tempcount element\endcsname{\tempb}%
    \expandafter\edef\csname shuffle\the\myrandom element\endcsname{\tempa}%
    \advance\tempcount -1
  \repeat
}

\long\def\gobble#1{}

\def\printpermutation{%
  \left(
  \def\tempa{\gobble}%
  \def\tempb{\gobble}%
  \tempcount=0
  \loop\ifnum\tempcount<\lastlength
    \advance\tempcount 1
    \edef\tempa{\tempa & \the\tempcount}%
    \edef\tempb{\tempb & \csname shuffle\the\tempcount element\endcsname}%
  \repeat
  \vcenter{\tabskip=3pt\halign{&\hfil##\hfil\cr\tempa\cr\tempb\cr}}
  \right)
}

\generatepermutation{20}

$$
\printpermutation
$$

\bye

相关内容