在 TeX 中编写非平凡算法

在 TeX 中编写非平凡算法

这个问题很难正确表述,所以如果我稍后必须澄清这个问题,请原谅我。

我想绘制许多比较复杂的 TikZ 图,要有效地完成这些工作,需要绘制这些图的宏具有一定程度的“智能行为”。为了实现这一点,我认为我有几种选择,但都不理想:

  • 使用 TikZ 和/或 TeX/LaTeX 宏对整个内容进行编码。这是一个巨大的挑战,因为虽然我非常擅长使用 LaTeX 和 TikZ 进行排版,但我不知道如何实现一个非平凡的算法,而且感觉获得所需的专业知识需要投入大量时间。

  • 使用 LuaLaTeX。这显然是正确的解决方案,但不幸的是,这意味着我无法将使用该系统编写的任何内容发布到 arXiv,因此必须放弃它。

  • 用 Julia 或 Python 等编写布局代码,然后输出我粘贴到文档中的 TikZ 代码。这是迄今为止最简单的解决方案,但这意味着我必须将所有图表与正文分开管理,我希望避免这种情况。

  • 使用我选择的语言编写代码,作为 .tex 文件的预处理器。这可以避免上述选项的问题,但意味着我无法使用 Overleaf 进行协作。

  • [编辑中添加] 使用 PythonTeX - 这比编写我自己的预处理器更加巧妙,可能是迄今为止最好的选择,但它确实存在同样的问题,我必须教我的同事使用 git,因为它不适用于 Overleaf。

因为这些都不理想,所以我想知道是否可能存在其他选择:TeX 是一种图灵完备的宏处理语言,因此原则上应该可以实现一种更具现代感的基本脚本语言之内TeX。

我知道这是一个长远的想法,但我的问题是这是否已经实现:是否有一个软件包可以让你用 TeX 编写代码,并且“感觉”就像在用现代脚本语言编写代码一样,这样我就可以自动生成 TikZ 图表,而不需要了解 TeX 宏如何工作的所有深层复杂性?

我也愿意接受其他建议,并且很高兴这成为一个一般性问题,即当你想自动化某些事情但又不是 TeX 专家时如何完成任务。

答案1

建议什么样的工作流程取决于很多情况。

假如要求您的 .tex 输入文件的接收者能够通过在任何(可能是较新的)TeX 平台上对主 .tex 文件运行 LaTeX 来获取 .pdf 文件,那么您可能无法绕过在 TeX 中实现的事情,因为只有 TeX 平台本身的可用性才是理所当然的。

如果您可以对计算机平台、TeX 平台以及在 TeX 内部运行/执行外部程序的可能性做出一些假设,那么事情可能会有所不同:

例如,在 LaTeX 中,您可以使用 -environmentfilecontents*\immediate\openout\write\closeout创建包含程序源代码的外部文本文件,而源代码又是您首选编程语言中所需的算法的实现。程序的输出可以是外部文本文件,其中包含表示执行算法结果的 .tex 代码。(\immediate\write但是,可能需要一些关于 TeX 如何以及何时将标记写入文件以及可能发生的扩展的知识。)

使用\write18(传统 TeX 和 XeTeX)或os.execute(LuaTeX)— 软件包壳牌提供统一的界面——您可以在计算机上执行命令,在源代码上运行您选择的编译器,然后运行生成的可执行文件,这样就得到了包含代表执行算法结果的.tex 代码的文本文件。

反过来,这个文本文件可以通过 TeX 进行处理\input

然而,这种方法高度依赖于平台,您可能需要做大量的(shellscript)编程来赶上 TeX 运行外部程序时出现错误的情况。

在当今的一些计算机平台上,配置事物(运行外部程序的权限、启用\write18/ )也可能变得麻烦。os.execute

如果您使用 overleaf 或类似的在线平台,这种工作流程对您来说实际上不是一个选择。


下面我认为这个问题的标题是关于在 TeX 中实现算法时的一般策略/程序的问题。

当在 TeX 中实现事物时,你可能需要“实质性地”考虑事物:

TeX 读取输入并将输入视为一组指令,将漂亮闪亮的东西一个接一个地放到装配线上。这些漂亮闪亮的东西被称为“标记”。

(附记:这些标记要么是控制序列标记,要么是字符标记。控制序列标记是那些通常在 TeX 源代码中先写反斜杠的东西。例如\LaTeX,,\section...一些控制序列标记,例如宏,例如一些原语,像\romannumeral\string或是\csname..\endcsname可扩展的。也就是说,它们和它们的参数在处理的早期阶段被其他标记替换。
一些控制序列标记是不可扩展的。例如\relax\hbox{...}。它们在上述早期阶段不会被替换,而是保留并在后期阶段服务,例如作为排版文本的基本指令。
字符标记具有字符代码,该字符代码在 TeX 内部字符编码方案(ASCII 或 Unicode)中对应于相应字符的代码点编号,并且属于一个类别,该类别取决于 TeX 在处理相应字符标记时所做的事情。类别 13(活动)的字符标记可以像控制序列标记一样使用。它们与控制序列标记一起形成控制序列。附记结束。)

TeX 处理这些漂亮的闪闪发光的东西。标记在装配线上经过的第一个站是“扩展部门”。在这里,可扩展标记及其参数从装配线上取下,标记群被放到装配线上以替换这些标记。替换标记群的组成方式取决于被替换的可扩展标记的定义或含义。

当扩展部门的替换工作完成后,装配线上就不再有可扩展的令牌了。经过装配线上扩展部门产生的(不可扩展)令牌被运送到其他部门,在那里它们被视为排版文本、定义宏、为寄存器/参数分配值、将排版页面传送到 .pdf 或 .dvi 输出文件等的指令。

当我在 TeX 中实现算法并且只想使用宏/可扩展标记时,以便算法仅在扩展部门中完全处理,并且只有代表结果的标记才应该到达后续部门,我会这样想:

根据定义,宏最多可以有 9 个参数,这些参数必须放在流水线上相应宏标记的后面,每个参数都括在花括号中。花括号也是标记,参数本身也是标记的集合。(如果参数只包含一个标记,则可以省略其周围的花括号)。

宏表示算法的一个步骤。
宏的参数编号从#1到 (最多)#9,可以被认为是算法该步骤中使用的变量。构成扩展步骤中参数的标记可以被认为是该步骤中变量的值。

扩展步骤,即替换步骤,表示算法的一个步骤。在这样的步骤中,表示算法步骤的宏标记以及作为其参数的标记(因此表示变量的值)被从装配线上取下,并在装配线上被表示下一步的宏标记替换,后面跟着下一步所需的参数,由花括号标记和嵌套在其中的标记序列组成,这些标记表示下一步中变量的值。

您通常可以递归地执行此操作。这意味着,经过几个中间替换步骤(这些步骤仅用于重新排列参数的标记,这意味着更改算法变量的值,并在装配线上以正确的顺序放置参数)之后,将标记放在所有内容的前面,这表示算法的该步骤,扩展级联/替换级联从此开始。通过这种方式,可以递归重复算法的步骤,直到参数/变量的值满足某些条件。

原则上,这是一个逐步扩展标记以其他标记替换标记的问题,直到这些标记被视为算法的结果。如果您使用子程序,您可能需要知道经过多少个扩展步骤后其结果才存在。

了解 是如何\expandafter工作的、\romannumeral在某些情况下\the以及在最近的 TeX 引擎中\expanded是如何被(误)用于触发进一步的扩展步骤(例如,基于扩展的“子程序”的所有扩展步骤)、 以及 - - 分支是如何\csname. .\endcsname工作\number\if\else哪些\fi标记在\if/ \else/后面的哪些标记\fi在哪些条件下的哪些扩展步骤中被从标记装配线上移除或留在标记装配线上,这些都非常有帮助。

形象地说,标记是装配线上一个接一个的物品,再加上以下问题:应用于扩展部门当前处理的标记的扩展步骤如何改变装配线上的标记,以及扩展步骤本身如何触发进一步的扩展步骤(,,,,\romannumeral),或触发下一个标记的扩展步骤( ),从而影响装配线上标记扩展的时间顺序\number,这在 TeX 中的宏编程方面很有帮助。\csname\if\ifcat\expandafter

相关内容